mirror of
https://github.com/FossifyOrg/Gallery.git
synced 2024-11-26 14:37:59 +01:00
commit
7f34fa0537
59 changed files with 1508 additions and 716 deletions
35
CHANGELOG.md
35
CHANGELOG.md
|
@ -1,6 +1,41 @@
|
|||
Changelog
|
||||
==========
|
||||
|
||||
Version 2.15.1 *(2017-10-01)*
|
||||
----------------------------
|
||||
|
||||
* Updated commons library with minor fixes
|
||||
|
||||
Version 2.15.0 *(2017-10-01)*
|
||||
----------------------------
|
||||
|
||||
* Added fingerprint to hidden item protection
|
||||
* Added a new List view type
|
||||
* Fixed an issue with some hidden items being shown at "Show all folders content"
|
||||
* Fixed typing in color hex codes manually with some keyboards
|
||||
* Do not autosave rotated images in any case
|
||||
* Tons of other performance, stability and UX improvements
|
||||
|
||||
Version 2.14.4 *(2017-09-18)*
|
||||
----------------------------
|
||||
|
||||
* Revert to the old way of loading fullscreen images to avoid issues on Android 7+
|
||||
|
||||
Version 2.14.3 *(2017-09-17)*
|
||||
----------------------------
|
||||
|
||||
* Removed some error toast messages after delete, or if image loading failed
|
||||
* Fixed some visual glitches at horizontal scrolling
|
||||
* Disable pull-to-refresh at horizontal scrolling
|
||||
* Many other smaller bugfixes and improvements
|
||||
|
||||
Version 2.14.2 *(2017-09-11)*
|
||||
----------------------------
|
||||
|
||||
* Fixing some glitches with fullscreen images
|
||||
* Add an extra check to avoid displaying non-existing media
|
||||
* Fix opening media from third party intents
|
||||
|
||||
Version 2.14.1 *(2017-09-07)*
|
||||
----------------------------
|
||||
|
||||
|
|
208
LICENSE
208
LICENSE
|
@ -1,13 +1,201 @@
|
|||
Copyright 2016 SimpleMobileTools
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
1. Definitions.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2017 SimpleMobileTools
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
|
|
@ -10,8 +10,8 @@ android {
|
|||
applicationId "com.simplemobiletools.gallery"
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 23
|
||||
versionCode 129
|
||||
versionName "2.14.1"
|
||||
versionCode 134
|
||||
versionName "2.15.1"
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
|
@ -37,7 +37,7 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
compile 'com.simplemobiletools:commons:2.27.9'
|
||||
compile 'com.simplemobiletools:commons:2.29.1'
|
||||
compile 'com.davemorrissey.labs:subsampling-scale-image-view:3.6.0'
|
||||
compile 'com.theartofdev.edmodo:android-image-cropper:2.4.0'
|
||||
compile 'com.bignerdranch.android:recyclerview-multiselect:0.2'
|
||||
|
@ -52,7 +52,7 @@ dependencies {
|
|||
}
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.1.4-3'
|
||||
ext.kotlin_version = '1.1.51'
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
package com.simplemobiletools.gallery
|
||||
|
||||
import android.app.Application
|
||||
import com.github.ajalt.reprint.core.Reprint
|
||||
import com.squareup.leakcanary.LeakCanary
|
||||
|
||||
class App : Application() {
|
||||
val USE_LEAK_CANARY = false
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
Reprint.initialize(this)
|
||||
if (USE_LEAK_CANARY) {
|
||||
if (LeakCanary.isInAnalyzerProcess(this)) {
|
||||
return
|
||||
|
|
|
@ -2,10 +2,10 @@ package com.simplemobiletools.gallery.activities
|
|||
|
||||
import android.Manifest
|
||||
import android.app.Activity
|
||||
import android.content.ClipData
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.Uri
|
||||
import android.os.AsyncTask
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
|
@ -19,7 +19,11 @@ import android.widget.FrameLayout
|
|||
import com.google.gson.Gson
|
||||
import com.simplemobiletools.commons.dialogs.CreateNewFolderDialog
|
||||
import com.simplemobiletools.commons.dialogs.FilePickerDialog
|
||||
import com.simplemobiletools.commons.dialogs.RadioGroupDialog
|
||||
import com.simplemobiletools.commons.extensions.*
|
||||
import com.simplemobiletools.commons.helpers.SORT_BY_DATE_MODIFIED
|
||||
import com.simplemobiletools.commons.helpers.SORT_BY_DATE_TAKEN
|
||||
import com.simplemobiletools.commons.models.RadioItem
|
||||
import com.simplemobiletools.commons.models.Release
|
||||
import com.simplemobiletools.commons.views.MyScalableRecyclerView
|
||||
import com.simplemobiletools.gallery.BuildConfig
|
||||
|
@ -54,10 +58,10 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
|
|||
private var mStoredAnimateGifs = true
|
||||
private var mStoredCropThumbnails = true
|
||||
private var mStoredScrollHorizontally = true
|
||||
private var mStoredTextColor = 0
|
||||
private var mLoadedInitialPhotos = false
|
||||
private var mLastMediaModified = 0
|
||||
private var mLatestMediaId = 0L
|
||||
private var mLastMediaHandler = Handler()
|
||||
|
||||
private var mCurrAsyncTask: GetDirectoriesAsynctask? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
@ -79,6 +83,7 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
|
|||
mStoredAnimateGifs = config.animateGifs
|
||||
mStoredCropThumbnails = config.cropThumbnails
|
||||
mStoredScrollHorizontally = config.scrollHorizontally
|
||||
mStoredTextColor = config.textColor
|
||||
storeStoragePaths()
|
||||
checkWhatsNewDialog()
|
||||
|
||||
|
@ -92,8 +97,8 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
|
|||
menuInflater.inflate(R.menu.menu_main_intent, menu)
|
||||
} else {
|
||||
menuInflater.inflate(R.menu.menu_main, menu)
|
||||
menu.findItem(R.id.increase_column_count).isVisible = config.dirColumnCnt < 10
|
||||
menu.findItem(R.id.reduce_column_count).isVisible = config.dirColumnCnt > 1
|
||||
menu.findItem(R.id.increase_column_count).isVisible = config.viewTypeFolders == VIEW_TYPE_GRID && config.dirColumnCnt < 10
|
||||
menu.findItem(R.id.reduce_column_count).isVisible = config.viewTypeFolders == VIEW_TYPE_GRID && config.dirColumnCnt > 1
|
||||
}
|
||||
menu.findItem(R.id.temporarily_show_hidden).isVisible = !config.shouldShowHidden
|
||||
menu.findItem(R.id.stop_showing_hidden).isVisible = config.temporarilyShowHidden
|
||||
|
@ -106,6 +111,7 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
|
|||
R.id.filter -> showFilterMediaDialog()
|
||||
R.id.open_camera -> launchCamera()
|
||||
R.id.show_all -> showAllMedia()
|
||||
R.id.change_view_type -> changeViewType()
|
||||
R.id.temporarily_show_hidden -> tryToggleTemporarilyShowHidden()
|
||||
R.id.stop_showing_hidden -> tryToggleTemporarilyShowHidden()
|
||||
R.id.create_new_folder -> createNewFolder()
|
||||
|
@ -130,13 +136,17 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
|
|||
}
|
||||
|
||||
if (mStoredScrollHorizontally != config.scrollHorizontally) {
|
||||
directories_grid.adapter?.let {
|
||||
(it as DirectoryAdapter).scrollVertically = !config.scrollHorizontally
|
||||
it.notifyDataSetChanged()
|
||||
(directories_grid.adapter as? DirectoryAdapter)?.apply {
|
||||
scrollVertically = config.viewTypeFolders == VIEW_TYPE_LIST || !config.scrollHorizontally
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
setupScrollDirection()
|
||||
}
|
||||
|
||||
if (mStoredTextColor != config.textColor) {
|
||||
(directories_grid.adapter as? DirectoryAdapter)?.updateTextColor(config.textColor)
|
||||
}
|
||||
|
||||
tryloadGallery()
|
||||
invalidateOptionsMenu()
|
||||
directories_empty_text_label.setTextColor(config.textColor)
|
||||
|
@ -145,15 +155,16 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
|
|||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
mCurrAsyncTask?.shouldStop = true
|
||||
storeDirectories()
|
||||
directories_refresh_layout.isRefreshing = false
|
||||
mIsGettingDirs = false
|
||||
mStoredAnimateGifs = config.animateGifs
|
||||
mStoredCropThumbnails = config.cropThumbnails
|
||||
mStoredScrollHorizontally = config.scrollHorizontally
|
||||
mStoredTextColor = config.textColor
|
||||
directories_grid.listener = null
|
||||
mLastMediaHandler.removeCallbacksAndMessages(null)
|
||||
mCurrAsyncTask?.stopFetching()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
|
@ -178,6 +189,7 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
|
|||
showAllMedia()
|
||||
else
|
||||
getDirectories()
|
||||
|
||||
setupLayoutManager()
|
||||
checkIfColorChanged()
|
||||
} else {
|
||||
|
@ -216,12 +228,16 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
|
|||
mCurrAsyncTask = GetDirectoriesAsynctask(applicationContext, mIsPickVideoIntent || mIsGetVideoContentIntent, mIsPickImageIntent || mIsGetImageContentIntent) {
|
||||
gotDirectories(addTempFolderIfNeeded(it), false)
|
||||
}
|
||||
mCurrAsyncTask!!.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
|
||||
mCurrAsyncTask!!.execute()
|
||||
}
|
||||
|
||||
private fun showSortingDialog() {
|
||||
ChangeSortingDialog(this, true, false) {
|
||||
getDirectories()
|
||||
if (config.directorySorting and SORT_BY_DATE_MODIFIED > 0 || config.directorySorting and SORT_BY_DATE_TAKEN > 0) {
|
||||
getDirectories()
|
||||
} else {
|
||||
gotDirectories(mDirs, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -236,9 +252,28 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
|
|||
config.showAll = true
|
||||
Intent(this, MediaActivity::class.java).apply {
|
||||
putExtra(DIRECTORY, "/")
|
||||
startActivity(this)
|
||||
|
||||
if (mIsThirdPartyIntent) {
|
||||
handleMediaIntent(this)
|
||||
} else {
|
||||
startActivity(this)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun changeViewType() {
|
||||
val items = arrayListOf(
|
||||
RadioItem(VIEW_TYPE_GRID, getString(R.string.grid)),
|
||||
RadioItem(VIEW_TYPE_LIST, getString(R.string.list)))
|
||||
|
||||
RadioGroupDialog(this, items, config.viewTypeFolders) {
|
||||
config.viewTypeFolders = it as Int
|
||||
invalidateOptionsMenu()
|
||||
setupLayoutManager()
|
||||
directories_grid.adapter = null
|
||||
setupAdapter()
|
||||
}
|
||||
finish()
|
||||
}
|
||||
|
||||
private fun tryToggleTemporarilyShowHidden() {
|
||||
|
@ -278,6 +313,13 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
|
|||
private fun getRecyclerAdapter() = (directories_grid.adapter as DirectoryAdapter)
|
||||
|
||||
private fun setupLayoutManager() {
|
||||
if (config.viewTypeFolders == VIEW_TYPE_GRID)
|
||||
setupGridLayoutManager()
|
||||
else
|
||||
setupListLayoutManager()
|
||||
}
|
||||
|
||||
private fun setupGridLayoutManager() {
|
||||
val layoutManager = directories_grid.layoutManager as GridLayoutManager
|
||||
if (config.scrollHorizontally) {
|
||||
layoutManager.orientation = GridLayoutManager.HORIZONTAL
|
||||
|
@ -315,6 +357,16 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
|
|||
}
|
||||
}
|
||||
|
||||
private fun setupListLayoutManager() {
|
||||
directories_grid.isDragSelectionEnabled = true
|
||||
directories_grid.isZoomingEnabled = false
|
||||
|
||||
val layoutManager = directories_grid.layoutManager as GridLayoutManager
|
||||
layoutManager.spanCount = 1
|
||||
layoutManager.orientation = GridLayoutManager.VERTICAL
|
||||
directories_refresh_layout.layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
}
|
||||
|
||||
private fun createNewFolder() {
|
||||
FilePickerDialog(this, internalStoragePath, false, config.shouldShowHidden) {
|
||||
CreateNewFolderDialog(this, it) {
|
||||
|
@ -366,36 +418,22 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
|
|||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
if (requestCode == PICK_MEDIA && resultData?.data != null) {
|
||||
Intent().apply {
|
||||
if (requestCode == PICK_MEDIA && resultData != null) {
|
||||
val resultIntent = Intent()
|
||||
if (mIsGetImageContentIntent || mIsGetVideoContentIntent || mIsGetAnyContentIntent) {
|
||||
when {
|
||||
intent.extras?.containsKey(MediaStore.EXTRA_OUTPUT) == true -> fillExtraOutput(resultData)
|
||||
resultData.extras?.containsKey(PICKED_PATHS) == true -> fillPickedPaths(resultData, resultIntent)
|
||||
else -> fillIntentPath(resultData, resultIntent)
|
||||
}
|
||||
} else if ((mIsPickImageIntent || mIsPickVideoIntent)) {
|
||||
val path = resultData.data.path
|
||||
val uri = Uri.fromFile(File(path))
|
||||
if (mIsGetImageContentIntent || mIsGetVideoContentIntent || mIsGetAnyContentIntent) {
|
||||
if (intent.extras?.containsKey(MediaStore.EXTRA_OUTPUT) == true) {
|
||||
var inputStream: InputStream? = null
|
||||
var outputStream: OutputStream? = null
|
||||
try {
|
||||
val output = intent.extras.get(MediaStore.EXTRA_OUTPUT) as Uri
|
||||
inputStream = FileInputStream(File(path))
|
||||
outputStream = contentResolver.openOutputStream(output)
|
||||
inputStream.copyTo(outputStream)
|
||||
} catch (ignored: FileNotFoundException) {
|
||||
} finally {
|
||||
inputStream?.close()
|
||||
outputStream?.close()
|
||||
}
|
||||
} else {
|
||||
val type = File(path).getMimeType("image/jpeg")
|
||||
setDataAndTypeAndNormalize(uri, type)
|
||||
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||
}
|
||||
} else if (mIsPickImageIntent || mIsPickVideoIntent) {
|
||||
data = uri
|
||||
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||
}
|
||||
|
||||
setResult(Activity.RESULT_OK, this)
|
||||
resultIntent.data = uri
|
||||
resultIntent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||
}
|
||||
|
||||
setResult(Activity.RESULT_OK, resultIntent)
|
||||
finish()
|
||||
} else if (requestCode == PICK_WALLPAPER) {
|
||||
setResult(Activity.RESULT_OK)
|
||||
|
@ -405,10 +443,51 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
|
|||
super.onActivityResult(requestCode, resultCode, resultData)
|
||||
}
|
||||
|
||||
private fun fillExtraOutput(resultData: Intent) {
|
||||
val path = resultData.data.path
|
||||
var inputStream: InputStream? = null
|
||||
var outputStream: OutputStream? = null
|
||||
try {
|
||||
val output = intent.extras.get(MediaStore.EXTRA_OUTPUT) as Uri
|
||||
inputStream = FileInputStream(File(path))
|
||||
outputStream = contentResolver.openOutputStream(output)
|
||||
inputStream.copyTo(outputStream)
|
||||
} catch (ignored: FileNotFoundException) {
|
||||
} finally {
|
||||
inputStream?.close()
|
||||
outputStream?.close()
|
||||
}
|
||||
}
|
||||
|
||||
private fun fillPickedPaths(resultData: Intent, resultIntent: Intent) {
|
||||
val paths = resultData.extras.getStringArrayList(PICKED_PATHS)
|
||||
val uris = paths.map { Uri.fromFile(File(it)) } as ArrayList
|
||||
val clipData = ClipData("Attachment", arrayOf("image/*", "video/*"), ClipData.Item(uris.removeAt(0)))
|
||||
|
||||
uris.forEach {
|
||||
clipData.addItem(ClipData.Item(it))
|
||||
}
|
||||
|
||||
resultIntent.clipData = clipData
|
||||
}
|
||||
|
||||
private fun fillIntentPath(resultData: Intent, resultIntent: Intent) {
|
||||
val path = resultData.data.path
|
||||
val uri = Uri.fromFile(File(path))
|
||||
val type = File(path).getMimeType("image/jpeg")
|
||||
resultIntent.setDataAndTypeAndNormalize(uri, type)
|
||||
resultIntent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||
}
|
||||
|
||||
private fun itemClicked(path: String) {
|
||||
Intent(this, MediaActivity::class.java).apply {
|
||||
putExtra(DIRECTORY, path)
|
||||
handleMediaIntent(this)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleMediaIntent(intent: Intent) {
|
||||
intent.apply {
|
||||
if (mIsSetWallpaperIntent) {
|
||||
putExtra(SET_WALLPAPER_INTENT, true)
|
||||
startActivityForResult(this, PICK_WALLPAPER)
|
||||
|
@ -416,13 +495,16 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
|
|||
putExtra(GET_IMAGE_INTENT, mIsPickImageIntent || mIsGetImageContentIntent)
|
||||
putExtra(GET_VIDEO_INTENT, mIsPickVideoIntent || mIsGetVideoContentIntent)
|
||||
putExtra(GET_ANY_INTENT, mIsGetAnyContentIntent)
|
||||
putExtra(Intent.EXTRA_ALLOW_MULTIPLE, intent.getBooleanExtra(Intent.EXTRA_ALLOW_MULTIPLE, false))
|
||||
startActivityForResult(this, PICK_MEDIA)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun gotDirectories(dirs: ArrayList<Directory>, isFromCache: Boolean) {
|
||||
mLastMediaModified = getLastMediaModified()
|
||||
private fun gotDirectories(newDirs: ArrayList<Directory>, isFromCache: Boolean) {
|
||||
val dirs = getSortedDirectories(newDirs)
|
||||
|
||||
mLatestMediaId = getLatestMediaId()
|
||||
directories_refresh_layout.isRefreshing = false
|
||||
mIsGettingDirs = false
|
||||
|
||||
|
@ -430,8 +512,9 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
|
|||
directories_empty_text.beVisibleIf(dirs.isEmpty() && !isFromCache)
|
||||
|
||||
checkLastMediaChanged()
|
||||
if (dirs.hashCode() == mDirs.hashCode())
|
||||
if (dirs.hashCode() == mDirs.hashCode()) {
|
||||
return
|
||||
}
|
||||
|
||||
mDirs = dirs
|
||||
|
||||
|
@ -462,13 +545,16 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
|
|||
}
|
||||
|
||||
private fun setupScrollDirection() {
|
||||
val allowHorizontalScroll = config.scrollHorizontally && config.viewTypeFolders == VIEW_TYPE_GRID
|
||||
directories_refresh_layout.isEnabled = !config.scrollHorizontally
|
||||
|
||||
directories_vertical_fastscroller.isHorizontal = false
|
||||
directories_vertical_fastscroller.beGoneIf(config.scrollHorizontally)
|
||||
directories_vertical_fastscroller.beGoneIf(allowHorizontalScroll)
|
||||
|
||||
directories_horizontal_fastscroller.isHorizontal = true
|
||||
directories_horizontal_fastscroller.beVisibleIf(config.scrollHorizontally)
|
||||
directories_horizontal_fastscroller.beVisibleIf(allowHorizontalScroll)
|
||||
|
||||
if (config.scrollHorizontally) {
|
||||
if (allowHorizontalScroll) {
|
||||
directories_horizontal_fastscroller.setViews(directories_grid, directories_refresh_layout)
|
||||
} else {
|
||||
directories_vertical_fastscroller.setViews(directories_grid, directories_refresh_layout)
|
||||
|
@ -482,9 +568,9 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
|
|||
mLastMediaHandler.removeCallbacksAndMessages(null)
|
||||
mLastMediaHandler.postDelayed({
|
||||
Thread({
|
||||
val lastModified = getLastMediaModified()
|
||||
if (mLastMediaModified != lastModified) {
|
||||
mLastMediaModified = lastModified
|
||||
val mediaId = getLatestMediaId()
|
||||
if (mLatestMediaId != mediaId) {
|
||||
mLatestMediaId = mediaId
|
||||
runOnUiThread {
|
||||
getDirectories()
|
||||
}
|
||||
|
@ -503,6 +589,10 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
|
|||
directories_grid.setDragSelectActive(position)
|
||||
}
|
||||
|
||||
override fun recheckPinnedFolders() {
|
||||
gotDirectories(movePinnedDirectoriesToFront(mDirs), true)
|
||||
}
|
||||
|
||||
private fun checkWhatsNewDialog() {
|
||||
arrayListOf<Release>().apply {
|
||||
add(Release(46, R.string.release_46))
|
||||
|
@ -540,6 +630,7 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
|
|||
add(Release(123, R.string.release_123))
|
||||
add(Release(125, R.string.release_125))
|
||||
add(Release(127, R.string.release_127))
|
||||
add(Release(133, R.string.release_133))
|
||||
checkWhatsNew(this, BuildConfig.VERSION_CODE)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,9 @@ import com.bumptech.glide.request.transition.Transition
|
|||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.simplemobiletools.commons.dialogs.ConfirmationDialog
|
||||
import com.simplemobiletools.commons.dialogs.RadioGroupDialog
|
||||
import com.simplemobiletools.commons.extensions.*
|
||||
import com.simplemobiletools.commons.models.RadioItem
|
||||
import com.simplemobiletools.commons.views.MyScalableRecyclerView
|
||||
import com.simplemobiletools.gallery.R
|
||||
import com.simplemobiletools.gallery.adapters.MediaAdapter
|
||||
|
@ -36,8 +38,7 @@ import java.io.File
|
|||
import java.io.IOException
|
||||
|
||||
class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
|
||||
private val TAG = MediaActivity::class.java.simpleName
|
||||
private val SAVE_MEDIA_CNT = 40
|
||||
private val SAVE_MEDIA_CNT = 100
|
||||
private val LAST_MEDIA_CHECK_PERIOD = 3000L
|
||||
|
||||
private var mPath = ""
|
||||
|
@ -45,14 +46,17 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
|
|||
private var mIsGetVideoIntent = false
|
||||
private var mIsGetAnyIntent = false
|
||||
private var mIsGettingMedia = false
|
||||
private var mAllowPickingMultiple = false
|
||||
private var mShowAll = false
|
||||
private var mLoadedInitialPhotos = false
|
||||
private var mStoredAnimateGifs = true
|
||||
private var mStoredCropThumbnails = true
|
||||
private var mStoredScrollHorizontally = true
|
||||
private var mStoredTextColor = 0
|
||||
private var mLastDrawnHashCode = 0
|
||||
private var mLastMediaModified = 0
|
||||
private var mLatestMediaId = 0L
|
||||
private var mLastMediaHandler = Handler()
|
||||
private var mCurrAsyncTask: GetMediaAsynctask? = null
|
||||
|
||||
companion object {
|
||||
var mMedia = ArrayList<Medium>()
|
||||
|
@ -65,6 +69,7 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
|
|||
mIsGetImageIntent = getBooleanExtra(GET_IMAGE_INTENT, false)
|
||||
mIsGetVideoIntent = getBooleanExtra(GET_VIDEO_INTENT, false)
|
||||
mIsGetAnyIntent = getBooleanExtra(GET_ANY_INTENT, false)
|
||||
mAllowPickingMultiple = getBooleanExtra(Intent.EXTRA_ALLOW_MULTIPLE, false)
|
||||
}
|
||||
|
||||
media_refresh_layout.setOnRefreshListener({ getMedia() })
|
||||
|
@ -72,6 +77,7 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
|
|||
mStoredAnimateGifs = config.animateGifs
|
||||
mStoredCropThumbnails = config.cropThumbnails
|
||||
mStoredScrollHorizontally = config.scrollHorizontally
|
||||
mStoredTextColor = config.textColor
|
||||
mShowAll = config.showAll
|
||||
if (mShowAll)
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(false)
|
||||
|
@ -92,13 +98,17 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
|
|||
}
|
||||
|
||||
if (mStoredScrollHorizontally != config.scrollHorizontally) {
|
||||
media_grid.adapter?.let {
|
||||
(it as MediaAdapter).scrollVertically = !config.scrollHorizontally
|
||||
it.notifyDataSetChanged()
|
||||
(media_grid.adapter as? MediaAdapter)?.apply {
|
||||
scrollVertically = config.viewTypeFiles == VIEW_TYPE_LIST || !config.scrollHorizontally
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
setupScrollDirection()
|
||||
}
|
||||
|
||||
if (mStoredTextColor != config.textColor) {
|
||||
(media_grid.adapter as? MediaAdapter)?.updateTextColor(config.textColor)
|
||||
}
|
||||
|
||||
tryloadGallery()
|
||||
invalidateOptionsMenu()
|
||||
media_empty_text_label.setTextColor(config.textColor)
|
||||
|
@ -112,8 +122,10 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
|
|||
mStoredAnimateGifs = config.animateGifs
|
||||
mStoredCropThumbnails = config.cropThumbnails
|
||||
mStoredScrollHorizontally = config.scrollHorizontally
|
||||
mStoredTextColor = config.textColor
|
||||
media_grid.listener = null
|
||||
mLastMediaHandler.removeCallbacksAndMessages(null)
|
||||
mCurrAsyncTask?.stopFetching()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
|
@ -149,7 +161,7 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
|
|||
|
||||
val currAdapter = media_grid.adapter
|
||||
if (currAdapter == null) {
|
||||
media_grid.adapter = MediaAdapter(this, mMedia, this, mIsGetAnyIntent) {
|
||||
media_grid.adapter = MediaAdapter(this, mMedia, this, mIsGetAnyIntent, mAllowPickingMultiple) {
|
||||
itemClicked(it.path)
|
||||
}
|
||||
} else {
|
||||
|
@ -159,13 +171,16 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
|
|||
}
|
||||
|
||||
private fun setupScrollDirection() {
|
||||
val allowHorizontalScroll = config.scrollHorizontally && config.viewTypeFiles == VIEW_TYPE_GRID
|
||||
media_refresh_layout.isEnabled = !config.scrollHorizontally
|
||||
|
||||
media_vertical_fastscroller.isHorizontal = false
|
||||
media_vertical_fastscroller.beGoneIf(config.scrollHorizontally)
|
||||
media_vertical_fastscroller.beGoneIf(allowHorizontalScroll)
|
||||
|
||||
media_horizontal_fastscroller.isHorizontal = true
|
||||
media_horizontal_fastscroller.beVisibleIf(config.scrollHorizontally)
|
||||
media_horizontal_fastscroller.beVisibleIf(allowHorizontalScroll)
|
||||
|
||||
if (config.scrollHorizontally) {
|
||||
if (allowHorizontalScroll) {
|
||||
media_horizontal_fastscroller.setViews(media_grid, media_refresh_layout)
|
||||
} else {
|
||||
media_vertical_fastscroller.setViews(media_grid, media_refresh_layout)
|
||||
|
@ -179,9 +194,9 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
|
|||
mLastMediaHandler.removeCallbacksAndMessages(null)
|
||||
mLastMediaHandler.postDelayed({
|
||||
Thread({
|
||||
val lastModified = getLastMediaModified()
|
||||
if (mLastMediaModified != lastModified) {
|
||||
mLastMediaModified = lastModified
|
||||
val mediaId = getLatestMediaId()
|
||||
if (mLatestMediaId != mediaId) {
|
||||
mLatestMediaId = mediaId
|
||||
runOnUiThread {
|
||||
getMedia()
|
||||
}
|
||||
|
@ -207,8 +222,10 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
|
|||
findItem(R.id.temporarily_show_hidden).isVisible = !config.shouldShowHidden
|
||||
findItem(R.id.stop_showing_hidden).isVisible = config.temporarilyShowHidden
|
||||
|
||||
findItem(R.id.increase_column_count).isVisible = config.mediaColumnCnt < 10
|
||||
findItem(R.id.reduce_column_count).isVisible = config.mediaColumnCnt > 1
|
||||
findItem(R.id.increase_column_count).isVisible = config.viewTypeFiles == VIEW_TYPE_GRID && config.mediaColumnCnt < 10
|
||||
findItem(R.id.reduce_column_count).isVisible = config.viewTypeFiles == VIEW_TYPE_GRID && config.mediaColumnCnt > 1
|
||||
|
||||
findItem(R.id.toggle_filename).isVisible = config.viewTypeFiles == VIEW_TYPE_GRID
|
||||
}
|
||||
|
||||
return true
|
||||
|
@ -221,6 +238,7 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
|
|||
R.id.toggle_filename -> toggleFilenameVisibility()
|
||||
R.id.open_camera -> launchCamera()
|
||||
R.id.folder_view -> switchToFolderView()
|
||||
R.id.change_view_type -> changeViewType()
|
||||
R.id.hide_folder -> tryHideFolder()
|
||||
R.id.unhide_folder -> unhideFolder()
|
||||
R.id.exclude_folder -> tryExcludeFolder()
|
||||
|
@ -260,6 +278,20 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
|
|||
finish()
|
||||
}
|
||||
|
||||
private fun changeViewType() {
|
||||
val items = arrayListOf(
|
||||
RadioItem(VIEW_TYPE_GRID, getString(R.string.grid)),
|
||||
RadioItem(VIEW_TYPE_LIST, getString(R.string.list)))
|
||||
|
||||
RadioGroupDialog(this, items, config.viewTypeFiles) {
|
||||
config.viewTypeFiles = it as Int
|
||||
invalidateOptionsMenu()
|
||||
setupLayoutManager()
|
||||
media_grid.adapter = null
|
||||
setupAdapter()
|
||||
}
|
||||
}
|
||||
|
||||
private fun tryHideFolder() {
|
||||
if (config.wasHideFolderTooltipShown) {
|
||||
hideFolder()
|
||||
|
@ -309,7 +341,7 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
|
|||
|
||||
mIsGettingMedia = true
|
||||
val token = object : TypeToken<List<Medium>>() {}.type
|
||||
val media = Gson().fromJson<ArrayList<Medium>>(config.loadFolderMedia(mPath), token) ?: ArrayList<Medium>(1)
|
||||
val media = Gson().fromJson<ArrayList<Medium>>(config.loadFolderMedia(mPath), token) ?: ArrayList(1)
|
||||
if (media.isNotEmpty() && !mLoadedInitialPhotos) {
|
||||
gotMedia(media, true)
|
||||
} else {
|
||||
|
@ -317,9 +349,10 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
|
|||
}
|
||||
|
||||
mLoadedInitialPhotos = true
|
||||
GetMediaAsynctask(applicationContext, mPath, mIsGetVideoIntent, mIsGetImageIntent, mShowAll) {
|
||||
mCurrAsyncTask = GetMediaAsynctask(applicationContext, mPath, mIsGetVideoIntent, mIsGetImageIntent, mShowAll) {
|
||||
gotMedia(it)
|
||||
}.execute()
|
||||
}
|
||||
mCurrAsyncTask!!.execute()
|
||||
}
|
||||
|
||||
private fun isDirEmpty(): Boolean {
|
||||
|
@ -350,6 +383,13 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
|
|||
private fun getRecyclerAdapter() = (media_grid.adapter as MediaAdapter)
|
||||
|
||||
private fun setupLayoutManager() {
|
||||
if (config.viewTypeFiles == VIEW_TYPE_GRID)
|
||||
setupGridLayoutManager()
|
||||
else
|
||||
setupListLayoutManager()
|
||||
}
|
||||
|
||||
private fun setupGridLayoutManager() {
|
||||
val layoutManager = media_grid.layoutManager as GridLayoutManager
|
||||
if (config.scrollHorizontally) {
|
||||
layoutManager.orientation = GridLayoutManager.HORIZONTAL
|
||||
|
@ -387,6 +427,16 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
|
|||
}
|
||||
}
|
||||
|
||||
private fun setupListLayoutManager() {
|
||||
media_grid.isDragSelectionEnabled = true
|
||||
media_grid.isZoomingEnabled = false
|
||||
|
||||
val layoutManager = media_grid.layoutManager as GridLayoutManager
|
||||
layoutManager.spanCount = 1
|
||||
layoutManager.orientation = GridLayoutManager.VERTICAL
|
||||
media_refresh_layout.layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
}
|
||||
|
||||
private fun increaseColumnCount() {
|
||||
config.mediaColumnCnt = ++(media_grid.layoutManager as GridLayoutManager).spanCount
|
||||
invalidateOptionsMenu()
|
||||
|
@ -461,7 +511,7 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
|
|||
}
|
||||
|
||||
private fun gotMedia(media: ArrayList<Medium>, isFromCache: Boolean = false) {
|
||||
mLastMediaModified = getLastMediaModified()
|
||||
mLatestMediaId = getLatestMediaId()
|
||||
mIsGettingMedia = false
|
||||
media_refresh_layout.isRefreshing = false
|
||||
|
||||
|
@ -513,4 +563,12 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener {
|
|||
override fun itemLongClicked(position: Int) {
|
||||
media_grid.setDragSelectActive(position)
|
||||
}
|
||||
|
||||
override fun selectedPaths(paths: ArrayList<String>) {
|
||||
Intent().apply {
|
||||
putExtra(PICKED_PATHS, paths)
|
||||
setResult(Activity.RESULT_OK, this)
|
||||
}
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import com.simplemobiletools.gallery.extensions.*
|
|||
import com.simplemobiletools.gallery.fragments.PhotoFragment
|
||||
import com.simplemobiletools.gallery.fragments.VideoFragment
|
||||
import com.simplemobiletools.gallery.fragments.ViewPagerFragment
|
||||
import com.simplemobiletools.gallery.helpers.IS_FROM_GALLERY
|
||||
import com.simplemobiletools.gallery.helpers.IS_VIEW_INTENT
|
||||
import com.simplemobiletools.gallery.helpers.MEDIUM
|
||||
import com.simplemobiletools.gallery.models.Medium
|
||||
|
@ -31,6 +32,7 @@ open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentList
|
|||
private val STORAGE_PERMISSION = 1
|
||||
private var mMedium: Medium? = null
|
||||
private var mIsFullScreen = false
|
||||
private var mIsFromGallery = false
|
||||
private var mFragment: ViewPagerFragment? = null
|
||||
|
||||
lateinit var mUri: Uri
|
||||
|
@ -52,6 +54,7 @@ open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentList
|
|||
|
||||
private fun checkIntent(savedInstanceState: Bundle? = null) {
|
||||
mUri = intent.data ?: return
|
||||
mIsFromGallery = intent.getBooleanExtra(IS_FROM_GALLERY, false)
|
||||
|
||||
if (mUri.scheme == "file") {
|
||||
scanPath(mUri.path) {}
|
||||
|
@ -126,6 +129,7 @@ open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentList
|
|||
private fun sendViewPagerIntent(path: String) {
|
||||
Intent(this, ViewPagerActivity::class.java).apply {
|
||||
putExtra(IS_VIEW_INTENT, true)
|
||||
putExtra(IS_FROM_GALLERY, mIsFromGallery)
|
||||
putExtra(MEDIUM, path)
|
||||
startActivity(this)
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import com.simplemobiletools.commons.dialogs.RadioGroupDialog
|
|||
import com.simplemobiletools.commons.dialogs.SecurityDialog
|
||||
import com.simplemobiletools.commons.extensions.handleHiddenFolderPasswordProtection
|
||||
import com.simplemobiletools.commons.extensions.updateTextColors
|
||||
import com.simplemobiletools.commons.helpers.PROTECTION_FINGERPRINT
|
||||
import com.simplemobiletools.commons.helpers.SHOW_ALL_TABS
|
||||
import com.simplemobiletools.commons.models.RadioItem
|
||||
import com.simplemobiletools.gallery.R
|
||||
|
@ -169,7 +170,9 @@ class SettingsActivity : SimpleActivity() {
|
|||
config.protectionType = type
|
||||
|
||||
if (config.isPasswordProtectionOn) {
|
||||
ConfirmationDialog(this, "", R.string.protection_setup_successfully, R.string.ok, 0) { }
|
||||
val confirmationTextId = if (config.protectionType == PROTECTION_FINGERPRINT)
|
||||
R.string.fingerprint_setup_successfully else R.string.protection_setup_successfully
|
||||
ConfirmationDialog(this, "", confirmationTextId, R.string.ok, 0) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -161,6 +161,10 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
|
|||
|
||||
if (config.isThirdPartyIntent) {
|
||||
config.isThirdPartyIntent = false
|
||||
|
||||
if (intent.extras == null || !intent.getBooleanExtra(IS_FROM_GALLERY, false)) {
|
||||
mMedia.clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -326,7 +330,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
|
|||
val dragPosition = animation.animatedValue as Int
|
||||
val dragOffset = dragPosition - oldDragPosition
|
||||
oldDragPosition = dragPosition
|
||||
view_pager.fakeDragBy(dragOffset * (if (forward) 1f else -1f))
|
||||
view_pager?.fakeDragBy(dragOffset * (if (forward) 1f else -1f))
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -433,34 +437,6 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
|
|||
}
|
||||
|
||||
private fun rotateImage() {
|
||||
val currentMedium = getCurrentMedium() ?: return
|
||||
if (currentMedium.isJpg() && !isPathOnSD(currentMedium.path)) {
|
||||
rotateByExif()
|
||||
} else {
|
||||
rotateByDegrees()
|
||||
}
|
||||
}
|
||||
|
||||
private fun rotateByExif() {
|
||||
val exif = ExifInterface(getCurrentPath())
|
||||
val orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)
|
||||
val newOrientation = getNewOrientation(orientation)
|
||||
exif.setAttribute(ExifInterface.TAG_ORIENTATION, newOrientation)
|
||||
exif.saveAttributes()
|
||||
File(getCurrentPath()).setLastModified(System.currentTimeMillis())
|
||||
(getCurrentFragment() as? PhotoFragment)?.refreshBitmap()
|
||||
}
|
||||
|
||||
private fun getNewOrientation(rotation: Int): String {
|
||||
return when (rotation) {
|
||||
ExifInterface.ORIENTATION_ROTATE_90 -> ExifInterface.ORIENTATION_ROTATE_180
|
||||
ExifInterface.ORIENTATION_ROTATE_180 -> ExifInterface.ORIENTATION_ROTATE_270
|
||||
ExifInterface.ORIENTATION_ROTATE_270 -> ExifInterface.ORIENTATION_NORMAL
|
||||
else -> ExifInterface.ORIENTATION_ROTATE_90
|
||||
}.toString()
|
||||
}
|
||||
|
||||
private fun rotateByDegrees() {
|
||||
mRotationDegrees = (mRotationDegrees + 90) % 360
|
||||
getCurrentFragment()?.let {
|
||||
(it as? PhotoFragment)?.rotateImageViewBy(mRotationDegrees)
|
||||
|
@ -474,7 +450,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
|
|||
Thread({
|
||||
toast(R.string.saving)
|
||||
val selectedFile = File(it)
|
||||
val tmpFile = File(selectedFile.parent, "tmp_${it.getFilenameFromPath()}")
|
||||
val tmpFile = File(selectedFile.parent, ".tmp_${it.getFilenameFromPath()}")
|
||||
try {
|
||||
val bitmap = BitmapFactory.decodeFile(currPath)
|
||||
getFileOutputStream(tmpFile) {
|
||||
|
@ -497,7 +473,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
|
|||
toast(R.string.out_of_memory_error)
|
||||
deleteFile(tmpFile) {}
|
||||
} catch (e: Exception) {
|
||||
toast(R.string.unknown_error_occurred)
|
||||
showErrorToast(e)
|
||||
deleteFile(tmpFile) {}
|
||||
}
|
||||
}).start()
|
||||
|
@ -510,11 +486,12 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
|
|||
val bmp = Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
|
||||
bmp.compress(file.getCompressionFormat(), 90, out)
|
||||
out.flush()
|
||||
toast(R.string.file_saved)
|
||||
out.close()
|
||||
toast(R.string.file_saved)
|
||||
mRotationDegrees = 0f
|
||||
invalidateOptionsMenu()
|
||||
}
|
||||
|
||||
|
||||
private fun isShowHiddenFlagNeeded(): Boolean {
|
||||
val file = File(mPath)
|
||||
if (file.isHidden)
|
||||
|
|
|
@ -20,9 +20,10 @@ import com.simplemobiletools.gallery.activities.SimpleActivity
|
|||
import com.simplemobiletools.gallery.dialogs.ExcludeFolderDialog
|
||||
import com.simplemobiletools.gallery.dialogs.PickMediumDialog
|
||||
import com.simplemobiletools.gallery.extensions.*
|
||||
import com.simplemobiletools.gallery.helpers.VIEW_TYPE_LIST
|
||||
import com.simplemobiletools.gallery.models.AlbumCover
|
||||
import com.simplemobiletools.gallery.models.Directory
|
||||
import kotlinx.android.synthetic.main.directory_item.view.*
|
||||
import kotlinx.android.synthetic.main.directory_item_list.view.*
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
|
@ -31,11 +32,13 @@ class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList<Direc
|
|||
|
||||
val multiSelector = MultiSelector()
|
||||
val config = activity.config
|
||||
val isListViewType = config.viewTypeFolders == VIEW_TYPE_LIST
|
||||
|
||||
var actMode: ActionMode? = null
|
||||
var itemViews = SparseArray<View>()
|
||||
val selectedPositions = HashSet<Int>()
|
||||
var primaryColor = config.primaryColor
|
||||
var textColor = config.textColor
|
||||
var pinnedFolders = config.pinnedFolders
|
||||
var scrollVertically = !config.scrollHorizontally
|
||||
|
||||
|
@ -56,12 +59,12 @@ class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList<Direc
|
|||
updateTitle(selectedPositions.size)
|
||||
}
|
||||
|
||||
fun updateTitle(cnt: Int) {
|
||||
private fun updateTitle(cnt: Int) {
|
||||
actMode?.title = "$cnt / ${dirs.size}"
|
||||
actMode?.invalidate()
|
||||
}
|
||||
|
||||
val adapterListener = object : MyAdapterListener {
|
||||
private val adapterListener = object : MyAdapterListener {
|
||||
override fun toggleItemSelectionAdapter(select: Boolean, position: Int) {
|
||||
toggleItemSelection(select, position)
|
||||
}
|
||||
|
@ -69,7 +72,7 @@ class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList<Direc
|
|||
override fun getSelectedPositions(): HashSet<Int> = selectedPositions
|
||||
}
|
||||
|
||||
val multiSelectorMode = object : ModalMultiSelectorCallback(multiSelector) {
|
||||
private val multiSelectorMode = object : ModalMultiSelectorCallback(multiSelector) {
|
||||
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
R.id.cab_properties -> showProperties()
|
||||
|
@ -119,7 +122,7 @@ class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList<Direc
|
|||
fun checkHideBtnVisibility(menu: Menu) {
|
||||
var hiddenCnt = 0
|
||||
var unhiddenCnt = 0
|
||||
selectedPositions.map { dirs.getOrNull(it)?.path }.filterNotNull().forEach {
|
||||
selectedPositions.mapNotNull { dirs.getOrNull(it)?.path }.forEach {
|
||||
if (File(it).containsNoMedia())
|
||||
hiddenCnt++
|
||||
else
|
||||
|
@ -134,7 +137,7 @@ class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList<Direc
|
|||
val pinnedFolders = config.pinnedFolders
|
||||
var pinnedCnt = 0
|
||||
var unpinnedCnt = 0
|
||||
selectedPositions.map { dirs.getOrNull(it)?.path }.filterNotNull().forEach {
|
||||
selectedPositions.mapNotNull { dirs.getOrNull(it)?.path }.forEach {
|
||||
if (pinnedFolders.contains(it))
|
||||
pinnedCnt++
|
||||
else
|
||||
|
@ -218,7 +221,7 @@ class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList<Direc
|
|||
config.removePinnedFolders(getSelectedPaths())
|
||||
|
||||
pinnedFolders = config.pinnedFolders
|
||||
listener?.refreshItems()
|
||||
listener?.recheckPinnedFolders()
|
||||
notifyDataSetChanged()
|
||||
actMode?.finish()
|
||||
}
|
||||
|
@ -242,7 +245,7 @@ class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList<Direc
|
|||
|
||||
fun selectAll() {
|
||||
val cnt = dirs.size
|
||||
for (i in 0..cnt - 1) {
|
||||
for (i in 0 until cnt) {
|
||||
selectedPositions.add(i)
|
||||
notifyItemChanged(i)
|
||||
}
|
||||
|
@ -286,13 +289,9 @@ class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList<Direc
|
|||
listener?.tryDeleteFolders(folders)
|
||||
|
||||
val newItems = SparseArray<View>()
|
||||
var curIndex = 0
|
||||
for (i in 0..itemViews.size() - 1) {
|
||||
if (itemViews[i] != null) {
|
||||
newItems.put(curIndex, itemViews[i])
|
||||
curIndex++
|
||||
}
|
||||
}
|
||||
(0 until itemViews.size())
|
||||
.filter { itemViews[it] != null }
|
||||
.forEachIndexed { curIndex, i -> newItems.put(curIndex, itemViews[i]) }
|
||||
|
||||
itemViews = newItems
|
||||
}
|
||||
|
@ -330,13 +329,14 @@ class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList<Direc
|
|||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder {
|
||||
val view = LayoutInflater.from(parent?.context).inflate(R.layout.directory_item, parent, false)
|
||||
val layoutType = if (isListViewType) R.layout.directory_item_list else R.layout.directory_item_grid
|
||||
val view = LayoutInflater.from(parent?.context).inflate(layoutType, parent, false)
|
||||
return ViewHolder(view, adapterListener, activity, multiSelectorMode, multiSelector, listener, isPickIntent, itemClick)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val dir = dirs[position]
|
||||
itemViews.put(position, holder.bindView(dir, pinnedFolders.contains(dir.path), scrollVertically))
|
||||
itemViews.put(position, holder.bindView(dir, pinnedFolders.contains(dir.path), scrollVertically, isListViewType, textColor))
|
||||
toggleItemSelection(selectedPositions.contains(position), position)
|
||||
holder.itemView.tag = holder
|
||||
}
|
||||
|
@ -351,6 +351,12 @@ class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList<Direc
|
|||
fun updateDirs(newDirs: ArrayList<Directory>) {
|
||||
dirs = newDirs
|
||||
notifyDataSetChanged()
|
||||
actMode?.finish()
|
||||
}
|
||||
|
||||
fun updateTextColor(textColor: Int) {
|
||||
this.textColor = textColor
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
fun selectItem(pos: Int) {
|
||||
|
@ -369,7 +375,7 @@ class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList<Direc
|
|||
toggleItemSelection(true, i)
|
||||
|
||||
if (min > -1 && min < to) {
|
||||
(min..to - 1).filter { it != from }
|
||||
(min until to).filter { it != from }
|
||||
.forEach { toggleItemSelection(false, it) }
|
||||
}
|
||||
if (max > -1) {
|
||||
|
@ -386,7 +392,7 @@ class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList<Direc
|
|||
}
|
||||
|
||||
if (min > -1) {
|
||||
for (i in min..from - 1)
|
||||
for (i in min until from)
|
||||
toggleItemSelection(false, i)
|
||||
}
|
||||
}
|
||||
|
@ -395,47 +401,52 @@ class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList<Direc
|
|||
class ViewHolder(val view: View, val adapterListener: MyAdapterListener, val activity: SimpleActivity, val multiSelectorCallback: ModalMultiSelectorCallback,
|
||||
val multiSelector: MultiSelector, val listener: DirOperationsListener?, val isPickIntent: Boolean, val itemClick: (Directory) -> (Unit)) :
|
||||
SwappingHolder(view, MultiSelector()) {
|
||||
fun bindView(directory: Directory, isPinned: Boolean, scrollVertically: Boolean): View {
|
||||
fun bindView(directory: Directory, isPinned: Boolean, scrollVertically: Boolean, isListView: Boolean, textColor: Int): View {
|
||||
itemView.apply {
|
||||
dir_name.text = directory.name
|
||||
dir_path?.text = "${directory.path.substringBeforeLast("/")}/"
|
||||
photo_cnt.text = directory.mediaCnt.toString()
|
||||
activity.loadImage(directory.tmb, dir_thumbnail, scrollVertically)
|
||||
dir_pin.beVisibleIf(isPinned)
|
||||
dir_sd_card.beVisibleIf(activity.isPathOnSD(directory.path))
|
||||
|
||||
if (isListView) {
|
||||
dir_name.setTextColor(textColor)
|
||||
dir_path.setTextColor(textColor)
|
||||
photo_cnt.setTextColor(textColor)
|
||||
dir_pin.setColorFilter(textColor, PorterDuff.Mode.SRC_IN)
|
||||
dir_sd_card.setColorFilter(textColor, PorterDuff.Mode.SRC_IN)
|
||||
}
|
||||
|
||||
setOnClickListener { viewClicked(directory) }
|
||||
setOnLongClickListener { if (isPickIntent) viewClicked(directory) else viewLongClicked(); true }
|
||||
|
||||
|
||||
}
|
||||
return itemView
|
||||
}
|
||||
|
||||
fun viewClicked(directory: Directory) {
|
||||
private fun viewClicked(directory: Directory) {
|
||||
if (multiSelector.isSelectable) {
|
||||
val isSelected = adapterListener.getSelectedPositions().contains(layoutPosition)
|
||||
adapterListener.toggleItemSelectionAdapter(!isSelected, layoutPosition)
|
||||
val isSelected = adapterListener.getSelectedPositions().contains(adapterPosition)
|
||||
adapterListener.toggleItemSelectionAdapter(!isSelected, adapterPosition)
|
||||
} else {
|
||||
itemClick(directory)
|
||||
}
|
||||
}
|
||||
|
||||
fun viewLongClicked() {
|
||||
private fun viewLongClicked() {
|
||||
if (listener != null) {
|
||||
if (!multiSelector.isSelectable) {
|
||||
activity.startSupportActionMode(multiSelectorCallback)
|
||||
adapterListener.toggleItemSelectionAdapter(true, layoutPosition)
|
||||
adapterListener.toggleItemSelectionAdapter(true, adapterPosition)
|
||||
}
|
||||
|
||||
listener.itemLongClicked(layoutPosition)
|
||||
listener.itemLongClicked(adapterPosition)
|
||||
}
|
||||
}
|
||||
|
||||
fun stopLoad() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && activity.isDestroyed)
|
||||
return
|
||||
|
||||
Glide.with(activity).clear(view.dir_thumbnail)
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1 || !activity.isDestroyed)
|
||||
Glide.with(activity).clear(view.dir_thumbnail)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -451,5 +462,7 @@ class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList<Direc
|
|||
fun tryDeleteFolders(folders: ArrayList<File>)
|
||||
|
||||
fun itemLongClicked(position: Int)
|
||||
|
||||
fun recheckPinnedFolders()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,21 +18,24 @@ import com.simplemobiletools.commons.extensions.beVisibleIf
|
|||
import com.simplemobiletools.gallery.R
|
||||
import com.simplemobiletools.gallery.activities.SimpleActivity
|
||||
import com.simplemobiletools.gallery.extensions.*
|
||||
import com.simplemobiletools.gallery.helpers.VIEW_TYPE_LIST
|
||||
import com.simplemobiletools.gallery.models.Medium
|
||||
import kotlinx.android.synthetic.main.photo_video_item.view.*
|
||||
import kotlinx.android.synthetic.main.photo_video_item_grid.view.*
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
class MediaAdapter(val activity: SimpleActivity, var media: MutableList<Medium>, val listener: MediaOperationsListener?, val isPickIntent: Boolean,
|
||||
val itemClick: (Medium) -> Unit) : RecyclerView.Adapter<MediaAdapter.ViewHolder>() {
|
||||
val allowMultiplePicks: Boolean, val itemClick: (Medium) -> Unit) : RecyclerView.Adapter<MediaAdapter.ViewHolder>() {
|
||||
|
||||
val multiSelector = MultiSelector()
|
||||
val config = activity.config
|
||||
val isListViewType = config.viewTypeFiles == VIEW_TYPE_LIST
|
||||
|
||||
var actMode: ActionMode? = null
|
||||
var itemViews = SparseArray<View>()
|
||||
val selectedPositions = HashSet<Int>()
|
||||
var primaryColor = config.primaryColor
|
||||
var textColor = config.textColor
|
||||
var displayFilenames = config.displayFileNames
|
||||
var scrollVertically = !config.scrollHorizontally
|
||||
|
||||
|
@ -53,12 +56,12 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList<Medium>,
|
|||
updateTitle(selectedPositions.size)
|
||||
}
|
||||
|
||||
fun updateTitle(cnt: Int) {
|
||||
private fun updateTitle(cnt: Int) {
|
||||
actMode?.title = "$cnt / ${media.size}"
|
||||
actMode?.invalidate()
|
||||
}
|
||||
|
||||
val adapterListener = object : MyAdapterListener {
|
||||
private val adapterListener = object : MyAdapterListener {
|
||||
override fun toggleItemSelectionAdapter(select: Boolean, position: Int) {
|
||||
toggleItemSelection(select, position)
|
||||
}
|
||||
|
@ -66,9 +69,10 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList<Medium>,
|
|||
override fun getSelectedPositions(): HashSet<Int> = selectedPositions
|
||||
}
|
||||
|
||||
val multiSelectorMode = object : ModalMultiSelectorCallback(multiSelector) {
|
||||
private val multiSelectorMode = object : ModalMultiSelectorCallback(multiSelector) {
|
||||
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
R.id.cab_confirm_selection -> confirmSelection()
|
||||
R.id.cab_properties -> showProperties()
|
||||
R.id.cab_rename -> renameFile()
|
||||
R.id.cab_edit -> editFile()
|
||||
|
@ -94,6 +98,7 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList<Medium>,
|
|||
override fun onPrepareActionMode(actionMode: ActionMode?, menu: Menu): Boolean {
|
||||
menu.findItem(R.id.cab_rename).isVisible = selectedPositions.size <= 1
|
||||
menu.findItem(R.id.cab_edit).isVisible = selectedPositions.size == 1 && media.size > selectedPositions.first() && media[selectedPositions.first()].isImage()
|
||||
menu.findItem(R.id.cab_confirm_selection).isVisible = isPickIntent && allowMultiplePicks && selectedPositions.size > 0
|
||||
|
||||
checkHideBtnVisibility(menu)
|
||||
|
||||
|
@ -112,7 +117,7 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList<Medium>,
|
|||
fun checkHideBtnVisibility(menu: Menu) {
|
||||
var hiddenCnt = 0
|
||||
var unhiddenCnt = 0
|
||||
selectedPositions.map { media.getOrNull(it) }.filterNotNull().forEach {
|
||||
selectedPositions.mapNotNull { media.getOrNull(it) }.forEach {
|
||||
if (it.name.startsWith('.'))
|
||||
hiddenCnt++
|
||||
else
|
||||
|
@ -124,6 +129,11 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList<Medium>,
|
|||
}
|
||||
}
|
||||
|
||||
private fun confirmSelection() {
|
||||
val paths = getSelectedMedia().map { it.path } as ArrayList<String>
|
||||
listener?.selectedPaths(paths)
|
||||
}
|
||||
|
||||
private fun showProperties() {
|
||||
if (selectedPositions.size <= 1) {
|
||||
PropertiesDialog(activity, media[selectedPositions.first()].path, config.shouldShowHidden)
|
||||
|
@ -184,7 +194,7 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList<Medium>,
|
|||
|
||||
fun selectAll() {
|
||||
val cnt = media.size
|
||||
for (i in 0..cnt - 1) {
|
||||
for (i in 0 until cnt) {
|
||||
selectedPositions.add(i)
|
||||
multiSelector.setSelected(i, 0, true)
|
||||
notifyItemChanged(i)
|
||||
|
@ -227,13 +237,9 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList<Medium>,
|
|||
listener?.deleteFiles(files)
|
||||
|
||||
val newItems = SparseArray<View>()
|
||||
var curIndex = 0
|
||||
for (i in 0..itemViews.size() - 1) {
|
||||
if (itemViews[i] != null) {
|
||||
newItems.put(curIndex, itemViews[i])
|
||||
curIndex++
|
||||
}
|
||||
}
|
||||
(0 until itemViews.size())
|
||||
.filter { itemViews[it] != null }
|
||||
.forEachIndexed { curIndex, i -> newItems.put(curIndex, itemViews[i]) }
|
||||
|
||||
itemViews = newItems
|
||||
}
|
||||
|
@ -246,12 +252,13 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList<Medium>,
|
|||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder {
|
||||
val view = LayoutInflater.from(parent?.context).inflate(R.layout.photo_video_item, parent, false)
|
||||
return ViewHolder(view, adapterListener, activity, multiSelectorMode, multiSelector, listener, isPickIntent, itemClick)
|
||||
val layoutType = if (isListViewType) R.layout.photo_video_item_list else R.layout.photo_video_item_grid
|
||||
val view = LayoutInflater.from(parent?.context).inflate(layoutType, parent, false)
|
||||
return ViewHolder(view, adapterListener, activity, multiSelectorMode, multiSelector, listener, allowMultiplePicks || !isPickIntent, itemClick)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
itemViews.put(position, holder.bindView(media[position], displayFilenames, scrollVertically))
|
||||
itemViews.put(position, holder.bindView(media[position], displayFilenames, scrollVertically, isListViewType, textColor))
|
||||
toggleItemSelection(selectedPositions.contains(position), position)
|
||||
holder.itemView.tag = holder
|
||||
}
|
||||
|
@ -266,6 +273,7 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList<Medium>,
|
|||
fun updateMedia(newMedia: ArrayList<Medium>) {
|
||||
media = newMedia
|
||||
notifyDataSetChanged()
|
||||
actMode?.finish()
|
||||
}
|
||||
|
||||
fun updateDisplayFilenames(display: Boolean) {
|
||||
|
@ -273,6 +281,11 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList<Medium>,
|
|||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
fun updateTextColor(textColor: Int) {
|
||||
this.textColor = textColor
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
fun selectItem(pos: Int) {
|
||||
toggleItemSelection(true, pos)
|
||||
}
|
||||
|
@ -289,7 +302,7 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList<Medium>,
|
|||
toggleItemSelection(true, i)
|
||||
|
||||
if (min > -1 && min < to) {
|
||||
(min..to - 1).filter { it != from }
|
||||
(min until to).filter { it != from }
|
||||
.forEach { toggleItemSelection(false, it) }
|
||||
}
|
||||
if (max > -1) {
|
||||
|
@ -306,53 +319,57 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList<Medium>,
|
|||
}
|
||||
|
||||
if (min > -1) {
|
||||
for (i in min..from - 1)
|
||||
for (i in min until from)
|
||||
toggleItemSelection(false, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ViewHolder(val view: View, val adapterListener: MyAdapterListener, val activity: SimpleActivity, val multiSelectorCallback: ModalMultiSelectorCallback,
|
||||
val multiSelector: MultiSelector, val listener: MediaOperationsListener?, val isPickIntent: Boolean, val itemClick: (Medium) -> (Unit)) :
|
||||
val multiSelector: MultiSelector, val listener: MediaOperationsListener?, val allowMultiplePicks: Boolean,
|
||||
val itemClick: (Medium) -> (Unit)) :
|
||||
SwappingHolder(view, MultiSelector()) {
|
||||
fun bindView(medium: Medium, displayFilenames: Boolean, scrollVertically: Boolean): View {
|
||||
fun bindView(medium: Medium, displayFilenames: Boolean, scrollVertically: Boolean, isListViewType: Boolean, textColor: Int): View {
|
||||
itemView.apply {
|
||||
play_outline.visibility = if (medium.video) View.VISIBLE else View.GONE
|
||||
photo_name.beVisibleIf(displayFilenames)
|
||||
photo_name.beVisibleIf(displayFilenames || isListViewType)
|
||||
photo_name.text = medium.name
|
||||
activity.loadImage(medium.path, medium_thumbnail, scrollVertically)
|
||||
|
||||
if (isListViewType) {
|
||||
photo_name.setTextColor(textColor)
|
||||
play_outline.setColorFilter(textColor, PorterDuff.Mode.SRC_IN)
|
||||
}
|
||||
|
||||
setOnClickListener { viewClicked(medium) }
|
||||
setOnLongClickListener { if (isPickIntent) viewClicked(medium) else viewLongClicked(); true }
|
||||
setOnLongClickListener { if (allowMultiplePicks) viewLongClicked() else viewClicked(medium); true }
|
||||
}
|
||||
return itemView
|
||||
}
|
||||
|
||||
fun viewClicked(medium: Medium) {
|
||||
private fun viewClicked(medium: Medium) {
|
||||
if (multiSelector.isSelectable) {
|
||||
val isSelected = adapterListener.getSelectedPositions().contains(layoutPosition)
|
||||
adapterListener.toggleItemSelectionAdapter(!isSelected, layoutPosition)
|
||||
val isSelected = adapterListener.getSelectedPositions().contains(adapterPosition)
|
||||
adapterListener.toggleItemSelectionAdapter(!isSelected, adapterPosition)
|
||||
} else {
|
||||
itemClick(medium)
|
||||
}
|
||||
}
|
||||
|
||||
fun viewLongClicked() {
|
||||
private fun viewLongClicked() {
|
||||
if (listener != null) {
|
||||
if (!multiSelector.isSelectable) {
|
||||
activity.startSupportActionMode(multiSelectorCallback)
|
||||
adapterListener.toggleItemSelectionAdapter(true, layoutPosition)
|
||||
adapterListener.toggleItemSelectionAdapter(true, adapterPosition)
|
||||
}
|
||||
|
||||
listener.itemLongClicked(layoutPosition)
|
||||
listener.itemLongClicked(adapterPosition)
|
||||
}
|
||||
}
|
||||
|
||||
fun stopLoad() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && activity.isDestroyed)
|
||||
return
|
||||
|
||||
Glide.with(activity).clear(view.medium_thumbnail)
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1 || !activity.isDestroyed)
|
||||
Glide.with(activity).clear(view.medium_thumbnail)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -368,5 +385,7 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList<Medium>,
|
|||
fun deleteFiles(files: ArrayList<File>)
|
||||
|
||||
fun itemLongClicked(position: Int)
|
||||
|
||||
fun selectedPaths(paths: ArrayList<String>)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,125 +6,70 @@ import com.simplemobiletools.commons.extensions.getFilenameFromPath
|
|||
import com.simplemobiletools.commons.extensions.hasWriteStoragePermission
|
||||
import com.simplemobiletools.commons.extensions.internalStoragePath
|
||||
import com.simplemobiletools.commons.extensions.sdCardPath
|
||||
import com.simplemobiletools.commons.helpers.SORT_DESCENDING
|
||||
import com.simplemobiletools.gallery.R
|
||||
import com.simplemobiletools.gallery.extensions.config
|
||||
import com.simplemobiletools.gallery.extensions.containsNoMedia
|
||||
import com.simplemobiletools.gallery.extensions.getFilesFrom
|
||||
import com.simplemobiletools.gallery.extensions.sumByLong
|
||||
import com.simplemobiletools.gallery.helpers.MediaFetcher
|
||||
import com.simplemobiletools.gallery.models.Directory
|
||||
import com.simplemobiletools.gallery.models.Medium
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
class GetDirectoriesAsynctask(val context: Context, val isPickVideo: Boolean, val isPickImage: Boolean,
|
||||
val callback: (dirs: ArrayList<Directory>) -> Unit) : AsyncTask<Void, Void, ArrayList<Directory>>() {
|
||||
var config = context.config
|
||||
var shouldStop = false
|
||||
val showHidden = config.shouldShowHidden
|
||||
val mediaFetcher = MediaFetcher(context)
|
||||
|
||||
override fun doInBackground(vararg params: Void): ArrayList<Directory> {
|
||||
if (!context.hasWriteStoragePermission())
|
||||
return ArrayList()
|
||||
|
||||
val media = context.getFilesFrom("", isPickImage, isPickVideo)
|
||||
val excludedPaths = config.excludedFolders
|
||||
val includedPaths = config.includedFolders
|
||||
val directories = groupDirectories(media)
|
||||
val dirs = ArrayList(directories.values
|
||||
.filter { File(it.path).exists() })
|
||||
.filter { shouldFolderBeVisible(it.path, excludedPaths, includedPaths) } as ArrayList<Directory>
|
||||
Directory.sorting = config.directorySorting
|
||||
dirs.sort()
|
||||
return movePinnedToFront(dirs)
|
||||
}
|
||||
|
||||
private fun groupDirectories(media: ArrayList<Medium>): Map<String, Directory> {
|
||||
val albumCovers = config.parseAlbumCovers()
|
||||
val config = context.config
|
||||
val groupedMedia = mediaFetcher.getMediaByDirectories(isPickVideo, isPickImage)
|
||||
val directories = ArrayList<Directory>()
|
||||
val hidden = context.resources.getString(R.string.hidden)
|
||||
val directories = LinkedHashMap<String, Directory>()
|
||||
for ((name, path, isVideo, dateModified, dateTaken, size) in media) {
|
||||
if (shouldStop)
|
||||
cancel(true)
|
||||
val albumCovers = config.parseAlbumCovers()
|
||||
for ((path, curMedia) in groupedMedia) {
|
||||
Medium.sorting = config.getFileSorting(path)
|
||||
curMedia.sort()
|
||||
|
||||
val parentDir = File(path).parent ?: continue
|
||||
if (directories.containsKey(parentDir.toLowerCase())) {
|
||||
val directory = directories[parentDir.toLowerCase()]!!
|
||||
val newImageCnt = directory.mediaCnt + 1
|
||||
directory.mediaCnt = newImageCnt
|
||||
directory.addSize(size)
|
||||
} else {
|
||||
var dirName = parentDir.getFilenameFromPath()
|
||||
if (parentDir == context.internalStoragePath) {
|
||||
dirName = context.getString(R.string.internal)
|
||||
} else if (parentDir == context.sdCardPath) {
|
||||
dirName = context.getString(R.string.sd_card)
|
||||
val firstItem = curMedia.first()
|
||||
val lastItem = curMedia.last()
|
||||
val parentDir = File(firstItem.path).parent
|
||||
var thumbnail = firstItem.path
|
||||
albumCovers.forEach {
|
||||
if (it.path == parentDir && File(it.tmb).exists()) {
|
||||
thumbnail = it.tmb
|
||||
}
|
||||
|
||||
if (File(parentDir).containsNoMedia()) {
|
||||
dirName += " $hidden"
|
||||
|
||||
if (!showHidden)
|
||||
continue
|
||||
}
|
||||
|
||||
var thumbnail = path
|
||||
albumCovers.forEach {
|
||||
if (it.path == parentDir && File(it.tmb).exists()) {
|
||||
thumbnail = it.tmb
|
||||
}
|
||||
}
|
||||
|
||||
val directory = Directory(parentDir, thumbnail, dirName, 1, dateModified, dateTaken, size)
|
||||
directories.put(parentDir.toLowerCase(), directory)
|
||||
}
|
||||
|
||||
var dirName = when (parentDir) {
|
||||
context.internalStoragePath -> context.getString(R.string.internal)
|
||||
context.sdCardPath -> context.getString(R.string.sd_card)
|
||||
else -> parentDir.getFilenameFromPath()
|
||||
}
|
||||
|
||||
if (File(parentDir).containsNoMedia()) {
|
||||
dirName += " $hidden"
|
||||
}
|
||||
|
||||
val lastModified = if (config.directorySorting and SORT_DESCENDING > 0) Math.max(firstItem.modified, lastItem.modified) else Math.min(firstItem.modified, lastItem.modified)
|
||||
val dateTaken = if (config.directorySorting and SORT_DESCENDING > 0) Math.max(firstItem.taken, lastItem.taken) else Math.min(firstItem.taken, lastItem.taken)
|
||||
val size = curMedia.sumByLong { it.size }
|
||||
val directory = Directory(parentDir, thumbnail, dirName, curMedia.size, lastModified, dateTaken, size)
|
||||
directories.add(directory)
|
||||
}
|
||||
|
||||
return directories
|
||||
}
|
||||
|
||||
private fun shouldFolderBeVisible(path: String, excludedPaths: MutableSet<String>, includedPaths: MutableSet<String>): Boolean {
|
||||
val file = File(path)
|
||||
return if (includedPaths.contains(path)) {
|
||||
true
|
||||
} else if (isThisOrParentExcluded(path, excludedPaths, includedPaths)) {
|
||||
false
|
||||
} else if (!config.shouldShowHidden && file.isDirectory && file.canonicalFile == file.absoluteFile) {
|
||||
var containsNoMediaOrDot = file.containsNoMedia() || path.contains("/.")
|
||||
if (!containsNoMediaOrDot) {
|
||||
containsNoMediaOrDot = checkParentHasNoMedia(file.parentFile)
|
||||
}
|
||||
!containsNoMediaOrDot
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkParentHasNoMedia(file: File): Boolean {
|
||||
var curFile = file
|
||||
while (true) {
|
||||
if (curFile.containsNoMedia()) {
|
||||
return true
|
||||
}
|
||||
curFile = curFile.parentFile
|
||||
if (curFile.absolutePath == "/")
|
||||
break
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun isThisOrParentExcluded(path: String, excludedPaths: MutableSet<String>, includedPaths: MutableSet<String>) =
|
||||
includedPaths.none { path.startsWith(it) } && excludedPaths.any { path.startsWith(it) }
|
||||
|
||||
private fun movePinnedToFront(dirs: ArrayList<Directory>): ArrayList<Directory> {
|
||||
val foundFolders = ArrayList<Directory>()
|
||||
val pinnedFolders = config.pinnedFolders
|
||||
|
||||
dirs.forEach { if (pinnedFolders.contains(it.path)) foundFolders.add(it) }
|
||||
dirs.removeAll(foundFolders)
|
||||
dirs.addAll(0, foundFolders)
|
||||
return dirs
|
||||
}
|
||||
|
||||
override fun onPostExecute(dirs: ArrayList<Directory>) {
|
||||
super.onPostExecute(dirs)
|
||||
callback(dirs)
|
||||
}
|
||||
|
||||
fun stopFetching() {
|
||||
mediaFetcher.shouldStop = true
|
||||
cancel(true)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,21 +2,39 @@ package com.simplemobiletools.gallery.asynctasks
|
|||
|
||||
import android.content.Context
|
||||
import android.os.AsyncTask
|
||||
import com.simplemobiletools.gallery.extensions.getFilesFrom
|
||||
import com.simplemobiletools.gallery.extensions.config
|
||||
import com.simplemobiletools.gallery.helpers.MediaFetcher
|
||||
import com.simplemobiletools.gallery.models.Medium
|
||||
import java.util.*
|
||||
|
||||
class GetMediaAsynctask(val context: Context, val mPath: String, val isPickVideo: Boolean = false, val isPickImage: Boolean = false,
|
||||
val showAll: Boolean, val callback: (media: ArrayList<Medium>) -> Unit) :
|
||||
AsyncTask<Void, Void, ArrayList<Medium>>() {
|
||||
val mediaFetcher = MediaFetcher(context)
|
||||
|
||||
override fun doInBackground(vararg params: Void): ArrayList<Medium> {
|
||||
val path = if (showAll) "" else mPath
|
||||
return context.getFilesFrom(path, isPickImage, isPickVideo)
|
||||
return if (showAll) {
|
||||
val mediaMap = mediaFetcher.getMediaByDirectories(isPickVideo, isPickImage)
|
||||
val media = ArrayList<Medium>()
|
||||
for ((path, curMedia) in mediaMap) {
|
||||
media.addAll(curMedia)
|
||||
}
|
||||
|
||||
Medium.sorting = context.config.getFileSorting("")
|
||||
media.sort()
|
||||
media
|
||||
} else {
|
||||
mediaFetcher.getFilesFrom(mPath, isPickImage, isPickVideo)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPostExecute(media: ArrayList<Medium>) {
|
||||
super.onPostExecute(media)
|
||||
callback(media)
|
||||
}
|
||||
|
||||
fun stopFetching() {
|
||||
mediaFetcher.shouldStop = true
|
||||
cancel(true)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@ import com.simplemobiletools.gallery.adapters.DirectoryAdapter
|
|||
import com.simplemobiletools.gallery.asynctasks.GetDirectoriesAsynctask
|
||||
import com.simplemobiletools.gallery.extensions.config
|
||||
import com.simplemobiletools.gallery.extensions.getCachedDirectories
|
||||
import com.simplemobiletools.gallery.extensions.getSortedDirectories
|
||||
import com.simplemobiletools.gallery.helpers.VIEW_TYPE_GRID
|
||||
import com.simplemobiletools.gallery.models.Directory
|
||||
import kotlinx.android.synthetic.main.dialog_directory_picker.view.*
|
||||
|
||||
|
@ -22,11 +24,12 @@ class PickDirectoryDialog(val activity: SimpleActivity, val sourcePath: String,
|
|||
var dialog: AlertDialog
|
||||
var shownDirectories: ArrayList<Directory> = ArrayList()
|
||||
var view: View = LayoutInflater.from(activity).inflate(R.layout.dialog_directory_picker, null)
|
||||
var isGridViewType = activity.config.viewTypeFolders == VIEW_TYPE_GRID
|
||||
|
||||
init {
|
||||
(view.directories_grid.layoutManager as GridLayoutManager).apply {
|
||||
orientation = if (activity.config.scrollHorizontally) GridLayoutManager.HORIZONTAL else GridLayoutManager.VERTICAL
|
||||
spanCount = activity.config.dirColumnCnt
|
||||
orientation = if (activity.config.scrollHorizontally && isGridViewType) GridLayoutManager.HORIZONTAL else GridLayoutManager.VERTICAL
|
||||
spanCount = if (isGridViewType) activity.config.dirColumnCnt else 1
|
||||
}
|
||||
|
||||
dialog = AlertDialog.Builder(activity)
|
||||
|
@ -47,19 +50,20 @@ class PickDirectoryDialog(val activity: SimpleActivity, val sourcePath: String,
|
|||
}
|
||||
}
|
||||
|
||||
fun showOtherFolder() {
|
||||
private fun showOtherFolder() {
|
||||
val showHidden = activity.config.shouldShowHidden
|
||||
FilePickerDialog(activity, sourcePath, false, showHidden, true) {
|
||||
callback(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun gotDirectories(directories: ArrayList<Directory>) {
|
||||
if (directories.hashCode() == shownDirectories.hashCode())
|
||||
private fun gotDirectories(newDirs: ArrayList<Directory>) {
|
||||
val dirs = activity.getSortedDirectories(newDirs)
|
||||
if (dirs.hashCode() == shownDirectories.hashCode())
|
||||
return
|
||||
|
||||
shownDirectories = directories
|
||||
val adapter = DirectoryAdapter(activity, directories, null, true) {
|
||||
shownDirectories = dirs
|
||||
val adapter = DirectoryAdapter(activity, dirs, null, true) {
|
||||
if (it.path.trimEnd('/') == sourcePath) {
|
||||
activity.toast(R.string.source_and_destination_same)
|
||||
return@DirectoryAdapter
|
||||
|
@ -69,7 +73,7 @@ class PickDirectoryDialog(val activity: SimpleActivity, val sourcePath: String,
|
|||
}
|
||||
}
|
||||
|
||||
val scrollHorizontally = activity.config.scrollHorizontally
|
||||
val scrollHorizontally = activity.config.scrollHorizontally && isGridViewType
|
||||
view.apply {
|
||||
directories_grid.adapter = adapter
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ class PickMediumDialog(val activity: SimpleActivity, val path: String, val callb
|
|||
return
|
||||
|
||||
shownMedia = media
|
||||
val adapter = MediaAdapter(activity, media, null, true) {
|
||||
val adapter = MediaAdapter(activity, media, null, true, false) {
|
||||
callback(it.path)
|
||||
dialog.dismiss()
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import com.simplemobiletools.commons.helpers.*
|
|||
import com.simplemobiletools.gallery.BuildConfig
|
||||
import com.simplemobiletools.gallery.R
|
||||
import com.simplemobiletools.gallery.activities.SimpleActivity
|
||||
import com.simplemobiletools.gallery.helpers.IS_FROM_GALLERY
|
||||
import com.simplemobiletools.gallery.helpers.NOMEDIA
|
||||
import com.simplemobiletools.gallery.helpers.REQUEST_EDIT_IMAGE
|
||||
import com.simplemobiletools.gallery.helpers.REQUEST_SET_AS
|
||||
|
@ -91,14 +92,14 @@ fun Activity.setAs(uri: Uri, file: File, showToast: Boolean = true): Boolean {
|
|||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
val chooser = Intent.createChooser(this, getString(R.string.set_as))
|
||||
|
||||
if (resolveActivity(packageManager) != null) {
|
||||
success = if (resolveActivity(packageManager) != null) {
|
||||
startActivityForResult(chooser, REQUEST_SET_AS)
|
||||
success = true
|
||||
true
|
||||
} else {
|
||||
if (showToast) {
|
||||
toast(R.string.no_capable_app_found)
|
||||
}
|
||||
success = false
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -130,6 +131,7 @@ fun Activity.openWith(file: File, forceChooser: Boolean = true) {
|
|||
action = Intent.ACTION_VIEW
|
||||
setDataAndType(uri, file.getMimeType())
|
||||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
putExtra(IS_FROM_GALLERY, true)
|
||||
|
||||
if (resolveActivity(packageManager) != null) {
|
||||
val chooser = Intent.createChooser(this, getString(R.string.open_with))
|
||||
|
@ -250,10 +252,10 @@ fun SimpleActivity.removeNoMedia(path: String, callback: () -> Unit) {
|
|||
fun SimpleActivity.toggleFileVisibility(oldFile: File, hide: Boolean, callback: (newFile: File) -> Unit) {
|
||||
val path = oldFile.parent
|
||||
var filename = oldFile.name
|
||||
if (hide) {
|
||||
filename = ".${filename.trimStart('.')}"
|
||||
filename = if (hide) {
|
||||
".${filename.trimStart('.')}"
|
||||
} else {
|
||||
filename = filename.substring(1, filename.length)
|
||||
filename.substring(1, filename.length)
|
||||
}
|
||||
val newFile = File(path, filename)
|
||||
renameFile(oldFile, newFile) {
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
package com.simplemobiletools.gallery.extensions
|
||||
|
||||
import java.util.*
|
||||
|
||||
fun <E> ArrayList<E>.sumByLong(selector: (E) -> Long) = map { selector(it) }.sum()
|
|
@ -4,21 +4,45 @@ import android.content.Context
|
|||
import android.content.Intent
|
||||
import android.content.res.Configuration
|
||||
import android.database.Cursor
|
||||
import android.graphics.Point
|
||||
import android.media.AudioManager
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.provider.MediaStore
|
||||
import com.simplemobiletools.commons.extensions.*
|
||||
import com.simplemobiletools.commons.helpers.SORT_BY_DATE_MODIFIED
|
||||
import com.simplemobiletools.commons.helpers.SORT_BY_NAME
|
||||
import com.simplemobiletools.commons.helpers.SORT_BY_SIZE
|
||||
import com.simplemobiletools.commons.helpers.SORT_DESCENDING
|
||||
import android.view.WindowManager
|
||||
import com.simplemobiletools.commons.extensions.humanizePath
|
||||
import com.simplemobiletools.gallery.activities.SettingsActivity
|
||||
import com.simplemobiletools.gallery.helpers.*
|
||||
import com.simplemobiletools.gallery.models.Medium
|
||||
import java.io.File
|
||||
import com.simplemobiletools.gallery.helpers.Config
|
||||
import com.simplemobiletools.gallery.models.Directory
|
||||
|
||||
val Context.portrait get() = resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT
|
||||
val Context.audioManager get() = getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
||||
val Context.windowManager: WindowManager get() = getSystemService(Context.WINDOW_SERVICE) as WindowManager
|
||||
val Context.navigationBarRight: Boolean get() = usableScreenSize.x < realScreenSize.x
|
||||
val Context.navigationBarBottom: Boolean get() = usableScreenSize.y < realScreenSize.y
|
||||
val Context.navigationBarHeight: Int get() = if (navigationBarBottom) navigationBarSize.y else 0
|
||||
|
||||
internal val Context.navigationBarSize: Point
|
||||
get() = when {
|
||||
navigationBarRight -> Point(realScreenSize.x - usableScreenSize.x, usableScreenSize.y)
|
||||
navigationBarBottom -> Point(usableScreenSize.x, realScreenSize.y - usableScreenSize.y)
|
||||
else -> Point()
|
||||
}
|
||||
|
||||
val Context.usableScreenSize: Point
|
||||
get() {
|
||||
val size = Point()
|
||||
windowManager.defaultDisplay.getSize(size)
|
||||
return size
|
||||
}
|
||||
|
||||
val Context.realScreenSize: Point
|
||||
get() {
|
||||
val size = Point()
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
|
||||
windowManager.defaultDisplay.getRealSize(size)
|
||||
return size
|
||||
}
|
||||
|
||||
fun Context.getRealPathFromURI(uri: Uri): String? {
|
||||
var cursor: Cursor? = null
|
||||
|
@ -47,213 +71,24 @@ fun Context.launchSettings() {
|
|||
|
||||
val Context.config: Config get() = Config.newInstance(this)
|
||||
|
||||
fun Context.getFilesFrom(curPath: String, isPickImage: Boolean, isPickVideo: Boolean): ArrayList<Medium> {
|
||||
val projection = arrayOf(MediaStore.Images.Media._ID,
|
||||
MediaStore.Images.Media.DISPLAY_NAME,
|
||||
MediaStore.Images.Media.DATE_TAKEN,
|
||||
MediaStore.Images.Media.DATE_MODIFIED,
|
||||
MediaStore.Images.Media.DATA,
|
||||
MediaStore.Images.Media.SIZE)
|
||||
val uri = MediaStore.Files.getContentUri("external")
|
||||
val selection = if (curPath.isEmpty()) null else "(${MediaStore.Images.Media.DATA} LIKE ? AND ${MediaStore.Images.Media.DATA} NOT LIKE ?)"
|
||||
val selectionArgs = if (curPath.isEmpty()) null else arrayOf("$curPath/%", "$curPath/%/%")
|
||||
fun Context.movePinnedDirectoriesToFront(dirs: ArrayList<Directory>): ArrayList<Directory> {
|
||||
val foundFolders = ArrayList<Directory>()
|
||||
val pinnedFolders = config.pinnedFolders
|
||||
|
||||
return try {
|
||||
val cur = contentResolver.query(uri, projection, selection, selectionArgs, getSortingForFolder(curPath))
|
||||
parseCursor(this, cur, isPickImage, isPickVideo, curPath)
|
||||
} catch (e: Exception) {
|
||||
ArrayList()
|
||||
dirs.forEach {
|
||||
if (pinnedFolders.contains(it.path))
|
||||
foundFolders.add(it)
|
||||
}
|
||||
|
||||
dirs.removeAll(foundFolders)
|
||||
dirs.addAll(0, foundFolders)
|
||||
return dirs
|
||||
}
|
||||
|
||||
private fun parseCursor(context: Context, cur: Cursor, isPickImage: Boolean, isPickVideo: Boolean, curPath: String): ArrayList<Medium> {
|
||||
val curMedia = ArrayList<Medium>()
|
||||
val config = context.config
|
||||
val filterMedia = config.filterMedia
|
||||
val showHidden = config.shouldShowHidden
|
||||
val includedFolders = config.includedFolders.map { "${it.trimEnd('/')}/" }
|
||||
val excludedFolders = config.excludedFolders.map { "${it.trimEnd('/')}/" }
|
||||
val noMediaFolders = context.getNoMediaFolders()
|
||||
val isThirdPartyIntent = config.isThirdPartyIntent
|
||||
|
||||
cur.use {
|
||||
if (cur.moveToFirst()) {
|
||||
do {
|
||||
try {
|
||||
val path = cur.getStringValue(MediaStore.Images.Media.DATA)
|
||||
var size = cur.getLongValue(MediaStore.Images.Media.SIZE)
|
||||
if (size == 0L) {
|
||||
size = File(path).length()
|
||||
}
|
||||
|
||||
if (size <= 0L) {
|
||||
continue
|
||||
}
|
||||
|
||||
var filename = cur.getStringValue(MediaStore.Images.Media.DISPLAY_NAME) ?: ""
|
||||
if (filename.isEmpty())
|
||||
filename = path.getFilenameFromPath()
|
||||
|
||||
val isImage = filename.isImageFast()
|
||||
val isVideo = if (isImage) false else filename.isVideoFast()
|
||||
val isGif = if (isImage || isVideo) false else filename.isGif()
|
||||
|
||||
if (!isImage && !isVideo && !isGif)
|
||||
continue
|
||||
|
||||
if (isVideo && (isPickImage || filterMedia and VIDEOS == 0))
|
||||
continue
|
||||
|
||||
if (isImage && (isPickVideo || filterMedia and IMAGES == 0))
|
||||
continue
|
||||
|
||||
if (isGif && filterMedia and GIFS == 0)
|
||||
continue
|
||||
|
||||
if (!showHidden && filename.startsWith('.'))
|
||||
continue
|
||||
|
||||
var isExcluded = false
|
||||
excludedFolders.forEach {
|
||||
if (path.startsWith(it)) {
|
||||
isExcluded = true
|
||||
includedFolders.forEach {
|
||||
if (path.startsWith(it)) {
|
||||
isExcluded = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isExcluded && !showHidden) {
|
||||
noMediaFolders.forEach {
|
||||
if (path.startsWith(it)) {
|
||||
isExcluded = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isExcluded && !showHidden && path.contains("/.")) {
|
||||
isExcluded = true
|
||||
}
|
||||
|
||||
if (!isExcluded || isThirdPartyIntent) {
|
||||
val dateTaken = cur.getLongValue(MediaStore.Images.Media.DATE_TAKEN)
|
||||
val dateModified = cur.getIntValue(MediaStore.Images.Media.DATE_MODIFIED) * 1000L
|
||||
|
||||
val medium = Medium(filename, path, isVideo, dateModified, dateTaken, size)
|
||||
curMedia.add(medium)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
continue
|
||||
}
|
||||
} while (cur.moveToNext())
|
||||
}
|
||||
}
|
||||
|
||||
config.includedFolders.filter { it.isNotEmpty() && (curPath.isEmpty() || it == curPath) }.forEach {
|
||||
getMediaInFolder(it, curMedia, isPickImage, isPickVideo, filterMedia)
|
||||
}
|
||||
|
||||
if (isThirdPartyIntent && curPath.isNotEmpty() && curMedia.isEmpty()) {
|
||||
getMediaInFolder(curPath, curMedia, isPickImage, isPickVideo, filterMedia)
|
||||
}
|
||||
|
||||
Medium.sorting = config.getFileSorting(curPath)
|
||||
curMedia.sort()
|
||||
|
||||
return curMedia
|
||||
}
|
||||
|
||||
private fun getMediaInFolder(folder: String, curMedia: ArrayList<Medium>, isPickImage: Boolean, isPickVideo: Boolean, filterMedia: Int) {
|
||||
val files = File(folder).listFiles() ?: return
|
||||
for (file in files) {
|
||||
val size = file.length()
|
||||
if (size <= 0L) {
|
||||
continue
|
||||
}
|
||||
|
||||
val filename = file.name
|
||||
val isImage = filename.isImageFast()
|
||||
val isVideo = if (isImage) false else filename.isVideoFast()
|
||||
val isGif = if (isImage || isVideo) false else filename.isGif()
|
||||
|
||||
if (!isImage && !isVideo)
|
||||
continue
|
||||
|
||||
if (isVideo && (isPickImage || filterMedia and VIDEOS == 0))
|
||||
continue
|
||||
|
||||
if (isImage && (isPickVideo || filterMedia and IMAGES == 0))
|
||||
continue
|
||||
|
||||
if (isGif && filterMedia and GIFS == 0)
|
||||
continue
|
||||
|
||||
val dateTaken = file.lastModified()
|
||||
val dateModified = file.lastModified()
|
||||
|
||||
val medium = Medium(filename, file.absolutePath, isVideo, dateModified, dateTaken, size)
|
||||
val isAlreadyAdded = curMedia.any { it.path == file.absolutePath }
|
||||
if (!isAlreadyAdded)
|
||||
curMedia.add(medium)
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.getSortingForFolder(path: String): String {
|
||||
val sorting = config.getFileSorting(path)
|
||||
val sortValue = when {
|
||||
sorting and SORT_BY_NAME > 0 -> MediaStore.Images.Media.DISPLAY_NAME
|
||||
sorting and SORT_BY_SIZE > 0 -> MediaStore.Images.Media.SIZE
|
||||
sorting and SORT_BY_DATE_MODIFIED > 0 -> MediaStore.Images.Media.DATE_MODIFIED
|
||||
else -> MediaStore.Images.Media.DATE_TAKEN
|
||||
}
|
||||
|
||||
return if (sorting and SORT_DESCENDING > 0)
|
||||
"$sortValue DESC"
|
||||
else
|
||||
"$sortValue ASC"
|
||||
}
|
||||
|
||||
fun Context.getNoMediaFolders(): ArrayList<String> {
|
||||
val folders = ArrayList<String>()
|
||||
val noMediaCondition = "${MediaStore.Files.FileColumns.MEDIA_TYPE} = ${MediaStore.Files.FileColumns.MEDIA_TYPE_NONE}"
|
||||
|
||||
val uri = MediaStore.Files.getContentUri("external")
|
||||
val columns = arrayOf(MediaStore.Files.FileColumns.DATA)
|
||||
val where = "$noMediaCondition AND ${MediaStore.Files.FileColumns.TITLE} LIKE ?"
|
||||
val args = arrayOf("%$NOMEDIA%")
|
||||
var cursor: Cursor? = null
|
||||
|
||||
try {
|
||||
cursor = contentResolver.query(uri, columns, where, args, null)
|
||||
if (cursor?.moveToFirst() == true) {
|
||||
do {
|
||||
val path = cursor.getString(cursor.getColumnIndex(MediaStore.Files.FileColumns.DATA)) ?: continue
|
||||
val noMediaFile = File(path)
|
||||
if (noMediaFile.exists())
|
||||
folders.add("${noMediaFile.parent}/")
|
||||
} while (cursor.moveToNext())
|
||||
}
|
||||
} finally {
|
||||
cursor?.close()
|
||||
}
|
||||
|
||||
return folders
|
||||
}
|
||||
|
||||
fun Context.getLastMediaModified(): Int {
|
||||
val max = "max"
|
||||
val uri = MediaStore.Files.getContentUri("external")
|
||||
val projection = arrayOf(MediaStore.Images.Media._ID, "MAX(${MediaStore.Images.Media.DATE_MODIFIED}) AS $max")
|
||||
var cursor: Cursor? = null
|
||||
try {
|
||||
cursor = contentResolver.query(uri, projection, null, null, null)
|
||||
if (cursor?.moveToFirst() == true) {
|
||||
return cursor.getIntValue(max)
|
||||
}
|
||||
} finally {
|
||||
cursor?.close()
|
||||
}
|
||||
return 0
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun Context.getSortedDirectories(source: ArrayList<Directory>): ArrayList<Directory> {
|
||||
Directory.sorting = config.directorySorting
|
||||
val dirs = source.clone() as ArrayList<Directory>
|
||||
dirs.sort()
|
||||
return movePinnedDirectoriesToFront(dirs)
|
||||
}
|
||||
|
|
|
@ -33,7 +33,6 @@ import com.simplemobiletools.gallery.extensions.config
|
|||
import com.simplemobiletools.gallery.extensions.getFileSignature
|
||||
import com.simplemobiletools.gallery.extensions.getRealPathFromURI
|
||||
import com.simplemobiletools.gallery.extensions.portrait
|
||||
import com.simplemobiletools.gallery.helpers.GlideDecoder
|
||||
import com.simplemobiletools.gallery.helpers.GlideRotateTransformation
|
||||
import com.simplemobiletools.gallery.helpers.MEDIUM
|
||||
import com.simplemobiletools.gallery.models.Medium
|
||||
|
@ -200,8 +199,7 @@ class PhotoFragment : ViewPagerFragment() {
|
|||
private fun addZoomableView() {
|
||||
if ((medium.isImage()) && isFragmentVisible && view.subsampling_view.visibility == View.GONE) {
|
||||
view.subsampling_view.apply {
|
||||
setBitmapDecoderClass(GlideDecoder::class.java)
|
||||
setMaxTileSize(10000)
|
||||
//setBitmapDecoderClass(GlideDecoder::class.java) // causing random crashes on Android 7+
|
||||
maxScale = 10f
|
||||
beVisible()
|
||||
setImage(ImageSource.uri(medium.path))
|
||||
|
@ -221,7 +219,7 @@ class PhotoFragment : ViewPagerFragment() {
|
|||
override fun onPreviewReleased() {
|
||||
}
|
||||
|
||||
override fun onImageLoadError(e: Exception?) {
|
||||
override fun onImageLoadError(e: Exception) {
|
||||
background = ColorDrawable(Color.TRANSPARENT)
|
||||
beGone()
|
||||
}
|
||||
|
@ -255,11 +253,6 @@ class PhotoFragment : ViewPagerFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
fun refreshBitmap() {
|
||||
view.subsampling_view.beGone()
|
||||
loadBitmap()
|
||||
}
|
||||
|
||||
fun rotateImageViewBy(degrees: Float) {
|
||||
view.subsampling_view.beGone()
|
||||
loadBitmap(degrees)
|
||||
|
|
|
@ -20,10 +20,7 @@ import com.simplemobiletools.commons.extensions.toast
|
|||
import com.simplemobiletools.commons.extensions.updateTextColors
|
||||
import com.simplemobiletools.gallery.R
|
||||
import com.simplemobiletools.gallery.activities.ViewPagerActivity
|
||||
import com.simplemobiletools.gallery.extensions.audioManager
|
||||
import com.simplemobiletools.gallery.extensions.config
|
||||
import com.simplemobiletools.gallery.extensions.getNavBarHeight
|
||||
import com.simplemobiletools.gallery.extensions.hasNavBar
|
||||
import com.simplemobiletools.gallery.extensions.*
|
||||
import com.simplemobiletools.gallery.helpers.MEDIUM
|
||||
import com.simplemobiletools.gallery.models.Medium
|
||||
import kotlinx.android.synthetic.main.pager_video_item.view.*
|
||||
|
@ -168,7 +165,9 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
|
|||
mLastTouchY = event.y
|
||||
}
|
||||
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
|
||||
if (System.currentTimeMillis() - mTouchDownTime < CLICK_MAX_DURATION) {
|
||||
val diffX = Math.abs(event.x - mTouchDownX)
|
||||
val diffY = Math.abs(event.y - mTouchDownY)
|
||||
if (System.currentTimeMillis() - mTouchDownTime < CLICK_MAX_DURATION && diffX < 20 && diffY < 20) {
|
||||
mView.video_holder.performClick()
|
||||
}
|
||||
}
|
||||
|
@ -204,7 +203,9 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
|
|||
mLastTouchY = event.y
|
||||
}
|
||||
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
|
||||
if (System.currentTimeMillis() - mTouchDownTime < CLICK_MAX_DURATION) {
|
||||
val diffX = Math.abs(event.x - mTouchDownX)
|
||||
val diffY = Math.abs(event.y - mTouchDownY)
|
||||
if (System.currentTimeMillis() - mTouchDownTime < CLICK_MAX_DURATION && diffX < 20 && diffY < 20) {
|
||||
mView.video_holder.performClick()
|
||||
}
|
||||
mTouchDownBrightness = mTempBrightness
|
||||
|
@ -273,6 +274,7 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee
|
|||
bottom += height
|
||||
} else {
|
||||
right += height
|
||||
bottom += context.navigationBarHeight
|
||||
}
|
||||
mTimeHolder!!.setPadding(left, top, right, bottom)
|
||||
}
|
||||
|
|
|
@ -28,17 +28,17 @@ class Config(context: Context) : BaseConfig(context) {
|
|||
if (path.isEmpty()) {
|
||||
fileSorting = value
|
||||
} else {
|
||||
prefs.edit().putInt(SORT_FOLDER_PREFIX + path, value).apply()
|
||||
prefs.edit().putInt(SORT_FOLDER_PREFIX + path.toLowerCase(), value).apply()
|
||||
}
|
||||
}
|
||||
|
||||
fun getFileSorting(path: String) = prefs.getInt(SORT_FOLDER_PREFIX + path, fileSorting)
|
||||
fun getFileSorting(path: String) = prefs.getInt(SORT_FOLDER_PREFIX + path.toLowerCase(), fileSorting)
|
||||
|
||||
fun removeFileSorting(path: String) {
|
||||
prefs.edit().remove(SORT_FOLDER_PREFIX + path).apply()
|
||||
prefs.edit().remove(SORT_FOLDER_PREFIX + path.toLowerCase()).apply()
|
||||
}
|
||||
|
||||
fun hasCustomSorting(path: String) = prefs.contains(SORT_FOLDER_PREFIX + path)
|
||||
fun hasCustomSorting(path: String) = prefs.contains(SORT_FOLDER_PREFIX + path.toLowerCase())
|
||||
|
||||
var wasHideFolderTooltipShown: Boolean
|
||||
get() = prefs.getBoolean(HIDE_FOLDER_TOOLTIP_SHOWN, false)
|
||||
|
@ -280,4 +280,12 @@ class Config(context: Context) : BaseConfig(context) {
|
|||
var tempFolderPath: String
|
||||
get() = prefs.getString(TEMP_FOLDER_PATH, "")
|
||||
set(tempFolderPath) = prefs.edit().putString(TEMP_FOLDER_PATH, tempFolderPath).apply()
|
||||
|
||||
var viewTypeFolders: Int
|
||||
get() = prefs.getInt(VIEW_TYPE_FOLDERS, VIEW_TYPE_GRID)
|
||||
set(viewTypeFolders) = prefs.edit().putInt(VIEW_TYPE_FOLDERS, viewTypeFolders).apply()
|
||||
|
||||
var viewTypeFiles: Int
|
||||
get() = prefs.getInt(VIEW_TYPE_FILES, VIEW_TYPE_GRID)
|
||||
set(viewTypeFiles) = prefs.edit().putInt(VIEW_TYPE_FILES, viewTypeFiles).apply()
|
||||
}
|
||||
|
|
|
@ -37,6 +37,8 @@ val REPLACE_SHARE_WITH_ROTATE = "replace_share_with_rotate"
|
|||
val DELETE_EMPTY_FOLDERS = "delete_empty_folders"
|
||||
val ALLOW_VIDEO_GESTURES = "allow_video_gestures"
|
||||
val TEMP_FOLDER_PATH = "temp_folder_path"
|
||||
val VIEW_TYPE_FOLDERS = "view_type_folders"
|
||||
val VIEW_TYPE_FILES = "view_type_files"
|
||||
|
||||
// slideshow
|
||||
val SLIDESHOW_INTERVAL = "slideshow_interval"
|
||||
|
@ -60,6 +62,8 @@ val GET_ANY_INTENT = "get_any_intent"
|
|||
val SET_WALLPAPER_INTENT = "set_wallpaper_intent"
|
||||
val DIRECTORIES = "directories2"
|
||||
val IS_VIEW_INTENT = "is_view_intent"
|
||||
val IS_FROM_GALLERY = "is_from_gallery"
|
||||
val PICKED_PATHS = "picked_paths"
|
||||
|
||||
val REQUEST_EDIT_IMAGE = 1
|
||||
val REQUEST_SET_AS = 2
|
||||
|
@ -77,3 +81,7 @@ val ORIENT_LANDSCAPE_RIGHT = 2
|
|||
val IMAGES = 1
|
||||
val VIDEOS = 2
|
||||
val GIFS = 4
|
||||
|
||||
// view types
|
||||
val VIEW_TYPE_GRID = 1
|
||||
val VIEW_TYPE_LIST = 2
|
||||
|
|
|
@ -8,7 +8,6 @@ import android.graphics.drawable.Drawable
|
|||
import android.media.ExifInterface
|
||||
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
|
||||
|
@ -26,11 +25,13 @@ class GlideDecoder : ImageDecoder {
|
|||
|
||||
val options = RequestOptions()
|
||||
.signature(uri.path.getFileSignature())
|
||||
.format(DecodeFormat.PREFER_ARGB_8888)
|
||||
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
||||
.transform(GlideRotateTransformation(context, getRotationDegrees(orientation)))
|
||||
.override(targetWidth, targetHeight)
|
||||
|
||||
val degrees = getRotationDegrees(orientation)
|
||||
if (degrees != 0f)
|
||||
options.transform(GlideRotateTransformation(context, getRotationDegrees(orientation)))
|
||||
|
||||
val drawable = Glide.with(context)
|
||||
.load(uri)
|
||||
.apply(options)
|
||||
|
|
|
@ -0,0 +1,321 @@
|
|||
package com.simplemobiletools.gallery.helpers
|
||||
|
||||
import android.content.Context
|
||||
import android.database.Cursor
|
||||
import android.provider.MediaStore
|
||||
import com.simplemobiletools.commons.extensions.*
|
||||
import com.simplemobiletools.commons.helpers.SORT_BY_DATE_MODIFIED
|
||||
import com.simplemobiletools.commons.helpers.SORT_BY_NAME
|
||||
import com.simplemobiletools.commons.helpers.SORT_BY_SIZE
|
||||
import com.simplemobiletools.commons.helpers.SORT_DESCENDING
|
||||
import com.simplemobiletools.gallery.extensions.config
|
||||
import com.simplemobiletools.gallery.extensions.containsNoMedia
|
||||
import com.simplemobiletools.gallery.models.Medium
|
||||
import java.io.File
|
||||
import java.util.LinkedHashMap
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.collections.component1
|
||||
import kotlin.collections.component2
|
||||
|
||||
class MediaFetcher(val context: Context) {
|
||||
var shouldStop = false
|
||||
|
||||
fun getMediaByDirectories(isPickVideo: Boolean, isPickImage: Boolean): HashMap<String, ArrayList<Medium>> {
|
||||
val media = getFilesFrom("", isPickImage, isPickVideo)
|
||||
val excludedPaths = context.config.excludedFolders
|
||||
val includedPaths = context.config.includedFolders
|
||||
val showHidden = context.config.shouldShowHidden
|
||||
val directories = groupDirectories(media)
|
||||
|
||||
val removePaths = ArrayList<String>()
|
||||
for ((path, curMedia) in directories) {
|
||||
// make sure the path has uppercase letters wherever appropriate
|
||||
val groupPath = File(curMedia.first().path).parent
|
||||
if (!File(groupPath).exists() || !shouldFolderBeVisible(groupPath, excludedPaths, includedPaths, showHidden)) {
|
||||
removePaths.add(groupPath.toLowerCase())
|
||||
}
|
||||
}
|
||||
|
||||
removePaths.forEach {
|
||||
directories.remove(it)
|
||||
}
|
||||
|
||||
return directories
|
||||
}
|
||||
|
||||
fun getFilesFrom(curPath: String, isPickImage: Boolean, isPickVideo: Boolean): ArrayList<Medium> {
|
||||
val projection = arrayOf(MediaStore.Images.Media._ID,
|
||||
MediaStore.Images.Media.DISPLAY_NAME,
|
||||
MediaStore.Images.Media.DATE_TAKEN,
|
||||
MediaStore.Images.Media.DATE_MODIFIED,
|
||||
MediaStore.Images.Media.DATA,
|
||||
MediaStore.Images.Media.SIZE)
|
||||
val uri = MediaStore.Files.getContentUri("external")
|
||||
val selection = getSelectionQuery(curPath)
|
||||
val selectionArgs = getSelectionArgsQuery(curPath)
|
||||
|
||||
return try {
|
||||
val cur = context.contentResolver.query(uri, projection, selection, selectionArgs, getSortingForFolder(curPath))
|
||||
parseCursor(context, cur, isPickImage, isPickVideo, curPath)
|
||||
} catch (e: Exception) {
|
||||
ArrayList()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSelectionQuery(path: String): String {
|
||||
val dataQuery = "${MediaStore.Images.Media.DATA} LIKE ?"
|
||||
return if (path.isEmpty()) {
|
||||
var query = "($dataQuery)"
|
||||
if (context.hasExternalSDCard()) {
|
||||
query += " OR ($dataQuery)"
|
||||
}
|
||||
query
|
||||
} else {
|
||||
"($dataQuery AND ${MediaStore.Images.Media.DATA} NOT LIKE ?)"
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSelectionArgsQuery(path: String): Array<String> {
|
||||
return if (path.isEmpty()) {
|
||||
if (context.hasExternalSDCard()) arrayOf("${context.internalStoragePath}/%", "${context.sdCardPath}/%") else arrayOf("${context.internalStoragePath}/%")
|
||||
} else {
|
||||
arrayOf("$path/%", "$path/%/%")
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseCursor(context: Context, cur: Cursor, isPickImage: Boolean, isPickVideo: Boolean, curPath: String): ArrayList<Medium> {
|
||||
val curMedia = ArrayList<Medium>()
|
||||
val config = context.config
|
||||
val filterMedia = config.filterMedia
|
||||
val showHidden = config.shouldShowHidden
|
||||
val includedFolders = config.includedFolders.map { "${it.trimEnd('/')}/" }
|
||||
val excludedFolders = config.excludedFolders.map { "${it.trimEnd('/')}/" }
|
||||
val noMediaFolders = getNoMediaFolders()
|
||||
val isThirdPartyIntent = config.isThirdPartyIntent
|
||||
|
||||
cur.use {
|
||||
if (cur.moveToFirst()) {
|
||||
do {
|
||||
try {
|
||||
if (shouldStop)
|
||||
break
|
||||
|
||||
val path = cur.getStringValue(MediaStore.Images.Media.DATA)
|
||||
var filename = cur.getStringValue(MediaStore.Images.Media.DISPLAY_NAME) ?: ""
|
||||
if (filename.isEmpty())
|
||||
filename = path.getFilenameFromPath()
|
||||
|
||||
val isImage = filename.isImageFast()
|
||||
val isVideo = if (isImage) false else filename.isVideoFast()
|
||||
val isGif = if (isImage || isVideo) false else filename.isGif()
|
||||
|
||||
if (!isImage && !isVideo && !isGif)
|
||||
continue
|
||||
|
||||
if (isVideo && (isPickImage || filterMedia and VIDEOS == 0))
|
||||
continue
|
||||
|
||||
if (isImage && (isPickVideo || filterMedia and IMAGES == 0))
|
||||
continue
|
||||
|
||||
if (isGif && filterMedia and GIFS == 0)
|
||||
continue
|
||||
|
||||
if (!showHidden && filename.startsWith('.'))
|
||||
continue
|
||||
|
||||
var size = cur.getLongValue(MediaStore.Images.Media.SIZE)
|
||||
val file = File(path)
|
||||
if (size == 0L) {
|
||||
size = file.length()
|
||||
}
|
||||
|
||||
if (size <= 0L)
|
||||
continue
|
||||
|
||||
var isExcluded = false
|
||||
excludedFolders.forEach {
|
||||
if (path.startsWith(it)) {
|
||||
isExcluded = true
|
||||
includedFolders.forEach {
|
||||
if (path.startsWith(it)) {
|
||||
isExcluded = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isExcluded && !showHidden) {
|
||||
noMediaFolders.forEach {
|
||||
if (path.startsWith(it)) {
|
||||
isExcluded = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isExcluded && !showHidden && path.contains("/.")) {
|
||||
isExcluded = true
|
||||
}
|
||||
|
||||
if (!isExcluded || isThirdPartyIntent) {
|
||||
if (!file.exists())
|
||||
continue
|
||||
|
||||
val dateTaken = cur.getLongValue(MediaStore.Images.Media.DATE_TAKEN)
|
||||
val dateModified = cur.getIntValue(MediaStore.Images.Media.DATE_MODIFIED) * 1000L
|
||||
|
||||
val medium = Medium(filename, path, isVideo, dateModified, dateTaken, size)
|
||||
curMedia.add(medium)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
continue
|
||||
}
|
||||
} while (cur.moveToNext())
|
||||
}
|
||||
}
|
||||
|
||||
config.includedFolders.filter { it.isNotEmpty() && (curPath.isEmpty() || it == curPath) }.forEach {
|
||||
getMediaInFolder(it, curMedia, isPickImage, isPickVideo, filterMedia)
|
||||
}
|
||||
|
||||
if (isThirdPartyIntent && curPath.isNotEmpty() && curMedia.isEmpty()) {
|
||||
getMediaInFolder(curPath, curMedia, isPickImage, isPickVideo, filterMedia)
|
||||
}
|
||||
|
||||
Medium.sorting = config.getFileSorting(curPath)
|
||||
curMedia.sort()
|
||||
|
||||
return curMedia
|
||||
}
|
||||
|
||||
private fun groupDirectories(media: ArrayList<Medium>): HashMap<String, ArrayList<Medium>> {
|
||||
val directories = LinkedHashMap<String, ArrayList<Medium>>()
|
||||
for (medium in media) {
|
||||
if (shouldStop)
|
||||
break
|
||||
|
||||
val parentDir = File(medium.path).parent?.toLowerCase() ?: continue
|
||||
if (directories.containsKey(parentDir)) {
|
||||
directories[parentDir]!!.add(medium)
|
||||
} else {
|
||||
directories.put(parentDir, arrayListOf(medium))
|
||||
}
|
||||
}
|
||||
return directories
|
||||
}
|
||||
|
||||
private fun shouldFolderBeVisible(path: String, excludedPaths: MutableSet<String>, includedPaths: MutableSet<String>, showHidden: Boolean): Boolean {
|
||||
val file = File(path)
|
||||
return if (includedPaths.contains(path)) {
|
||||
true
|
||||
} else if (isThisOrParentExcluded(path, excludedPaths, includedPaths)) {
|
||||
false
|
||||
} else if (!showHidden && file.isDirectory && file.canonicalFile == file.absoluteFile) {
|
||||
var containsNoMediaOrDot = file.containsNoMedia() || path.contains("/.")
|
||||
if (!containsNoMediaOrDot) {
|
||||
containsNoMediaOrDot = checkParentHasNoMedia(file.parentFile)
|
||||
}
|
||||
!containsNoMediaOrDot
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkParentHasNoMedia(file: File): Boolean {
|
||||
var curFile = file
|
||||
while (true) {
|
||||
if (curFile.containsNoMedia()) {
|
||||
return true
|
||||
}
|
||||
curFile = curFile.parentFile
|
||||
if (curFile.absolutePath == "/")
|
||||
break
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun isThisOrParentExcluded(path: String, excludedPaths: MutableSet<String>, includedPaths: MutableSet<String>) =
|
||||
includedPaths.none { path.startsWith(it) } && excludedPaths.any { path.startsWith(it) }
|
||||
|
||||
|
||||
private fun getMediaInFolder(folder: String, curMedia: ArrayList<Medium>, isPickImage: Boolean, isPickVideo: Boolean, filterMedia: Int) {
|
||||
val files = File(folder).listFiles() ?: return
|
||||
for (file in files) {
|
||||
if (shouldStop)
|
||||
break
|
||||
|
||||
val filename = file.name
|
||||
val isImage = filename.isImageFast()
|
||||
val isVideo = if (isImage) false else filename.isVideoFast()
|
||||
val isGif = if (isImage || isVideo) false else filename.isGif()
|
||||
|
||||
if (!isImage && !isVideo)
|
||||
continue
|
||||
|
||||
if (isVideo && (isPickImage || filterMedia and VIDEOS == 0))
|
||||
continue
|
||||
|
||||
if (isImage && (isPickVideo || filterMedia and IMAGES == 0))
|
||||
continue
|
||||
|
||||
if (isGif && filterMedia and GIFS == 0)
|
||||
continue
|
||||
|
||||
val size = file.length()
|
||||
if (size <= 0L)
|
||||
continue
|
||||
|
||||
val dateTaken = file.lastModified()
|
||||
val dateModified = file.lastModified()
|
||||
|
||||
val medium = Medium(filename, file.absolutePath, isVideo, dateModified, dateTaken, size)
|
||||
val isAlreadyAdded = curMedia.any { it.path == file.absolutePath }
|
||||
if (!isAlreadyAdded) {
|
||||
curMedia.add(medium)
|
||||
context.scanPath(file.absolutePath) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSortingForFolder(path: String): String {
|
||||
val sorting = context.config.getFileSorting(path)
|
||||
val sortValue = when {
|
||||
sorting and SORT_BY_NAME > 0 -> MediaStore.Images.Media.DISPLAY_NAME
|
||||
sorting and SORT_BY_SIZE > 0 -> MediaStore.Images.Media.SIZE
|
||||
sorting and SORT_BY_DATE_MODIFIED > 0 -> MediaStore.Images.Media.DATE_MODIFIED
|
||||
else -> MediaStore.Images.Media.DATE_TAKEN
|
||||
}
|
||||
|
||||
return if (sorting and SORT_DESCENDING > 0)
|
||||
"$sortValue DESC"
|
||||
else
|
||||
"$sortValue ASC"
|
||||
}
|
||||
|
||||
private fun getNoMediaFolders(): ArrayList<String> {
|
||||
val folders = ArrayList<String>()
|
||||
val noMediaCondition = "${MediaStore.Files.FileColumns.MEDIA_TYPE} = ${MediaStore.Files.FileColumns.MEDIA_TYPE_NONE}"
|
||||
|
||||
val uri = MediaStore.Files.getContentUri("external")
|
||||
val columns = arrayOf(MediaStore.Files.FileColumns.DATA)
|
||||
val where = "$noMediaCondition AND ${MediaStore.Files.FileColumns.TITLE} LIKE ?"
|
||||
val args = arrayOf("%$NOMEDIA%")
|
||||
var cursor: Cursor? = null
|
||||
|
||||
try {
|
||||
cursor = context.contentResolver.query(uri, columns, where, args, null)
|
||||
if (cursor?.moveToFirst() == true) {
|
||||
do {
|
||||
val path = cursor.getString(cursor.getColumnIndex(MediaStore.Files.FileColumns.DATA)) ?: continue
|
||||
val noMediaFile = File(path)
|
||||
if (noMediaFile.exists())
|
||||
folders.add("${noMediaFile.parent}/")
|
||||
} while (cursor.moveToNext())
|
||||
}
|
||||
} finally {
|
||||
cursor?.close()
|
||||
}
|
||||
|
||||
return folders
|
||||
}
|
||||
}
|
|
@ -16,29 +16,23 @@ data class Directory(val path: String, val tmb: String, val name: String, var me
|
|||
|
||||
override fun compareTo(other: Directory): Int {
|
||||
var result: Int
|
||||
if (sorting and SORT_BY_NAME != 0) {
|
||||
result = AlphanumComparator().compare(name.toLowerCase(), other.name.toLowerCase())
|
||||
} else if (sorting and SORT_BY_SIZE != 0) {
|
||||
result = if (size == other.size)
|
||||
0
|
||||
else if (size > other.size)
|
||||
1
|
||||
else
|
||||
-1
|
||||
} else if (sorting and SORT_BY_DATE_MODIFIED != 0) {
|
||||
result = if (modified == other.modified)
|
||||
0
|
||||
else if (modified > other.modified)
|
||||
1
|
||||
else
|
||||
-1
|
||||
} else {
|
||||
result = if (taken == other.taken)
|
||||
0
|
||||
else if (taken > other.taken)
|
||||
1
|
||||
else
|
||||
-1
|
||||
when {
|
||||
sorting and SORT_BY_NAME != 0 -> result = AlphanumericComparator().compare(name.toLowerCase(), other.name.toLowerCase())
|
||||
sorting and SORT_BY_SIZE != 0 -> result = when {
|
||||
size == other.size -> 0
|
||||
size > other.size -> 1
|
||||
else -> -1
|
||||
}
|
||||
sorting and SORT_BY_DATE_MODIFIED != 0 -> result = when {
|
||||
modified == other.modified -> 0
|
||||
modified > other.modified -> 1
|
||||
else -> -1
|
||||
}
|
||||
else -> result = when {
|
||||
taken == other.taken -> 0
|
||||
taken > other.taken -> 1
|
||||
else -> -1
|
||||
}
|
||||
}
|
||||
|
||||
if (sorting and SORT_DESCENDING != 0) {
|
||||
|
|
|
@ -25,29 +25,23 @@ data class Medium(var name: String, var path: String, val video: Boolean, val mo
|
|||
|
||||
override fun compareTo(other: Medium): Int {
|
||||
var result: Int
|
||||
if (sorting and SORT_BY_NAME != 0) {
|
||||
result = AlphanumComparator().compare(name.toLowerCase(), other.name.toLowerCase())
|
||||
} else if (sorting and SORT_BY_SIZE != 0) {
|
||||
result = if (size == other.size)
|
||||
0
|
||||
else if (size > other.size)
|
||||
1
|
||||
else
|
||||
-1
|
||||
} else if (sorting and SORT_BY_DATE_MODIFIED != 0) {
|
||||
result = if (modified == other.modified)
|
||||
0
|
||||
else if (modified > other.modified)
|
||||
1
|
||||
else
|
||||
-1
|
||||
} else {
|
||||
result = if (taken == other.taken)
|
||||
0
|
||||
else if (taken > other.taken)
|
||||
1
|
||||
else
|
||||
-1
|
||||
when {
|
||||
sorting and SORT_BY_NAME != 0 -> result = AlphanumericComparator().compare(name.toLowerCase(), other.name.toLowerCase())
|
||||
sorting and SORT_BY_SIZE != 0 -> result = when {
|
||||
size == other.size -> 0
|
||||
size > other.size -> 1
|
||||
else -> -1
|
||||
}
|
||||
sorting and SORT_BY_DATE_MODIFIED != 0 -> result = when {
|
||||
modified == other.modified -> 0
|
||||
modified > other.modified -> 1
|
||||
else -> -1
|
||||
}
|
||||
else -> result = when {
|
||||
taken == other.taken -> 0
|
||||
taken > other.taken -> 1
|
||||
else -> -1
|
||||
}
|
||||
}
|
||||
|
||||
if (sorting and SORT_DESCENDING != 0) {
|
||||
|
|
|
@ -14,8 +14,7 @@ class MySquareImageView : ImageView {
|
|||
constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle)
|
||||
|
||||
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
|
||||
val spec = if (isVerticalScrolling) measuredWidth else measuredHeight
|
||||
setMeasuredDimension(spec, spec)
|
||||
val spec = if (isVerticalScrolling) widthMeasureSpec else heightMeasureSpec
|
||||
super.onMeasure(spec, spec)
|
||||
}
|
||||
}
|
||||
|
|
BIN
app/src/main/res/drawable-hdpi/img_play_outline_empty.png
Normal file
BIN
app/src/main/res/drawable-hdpi/img_play_outline_empty.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.2 KiB |
BIN
app/src/main/res/drawable-xhdpi/img_play_outline_empty.png
Normal file
BIN
app/src/main/res/drawable-xhdpi/img_play_outline_empty.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.8 KiB |
BIN
app/src/main/res/drawable-xxhdpi/img_play_outline_empty.png
Normal file
BIN
app/src/main/res/drawable-xxhdpi/img_play_outline_empty.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.5 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/img_play_outline_empty.png
Normal file
BIN
app/src/main/res/drawable-xxxhdpi/img_play_outline_empty.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.7 KiB |
|
@ -10,7 +10,7 @@
|
|||
<com.simplemobiletools.commons.views.MyScalableRecyclerView
|
||||
android:id="@+id/directories_grid"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:scrollbars="none"
|
||||
app:layoutManager="android.support.v7.widget.GridLayoutManager"
|
||||
app:spanCount="@integer/directory_columns_vertical_scroll"/>
|
||||
|
|
|
@ -39,7 +39,9 @@
|
|||
android:id="@+id/dir_shadow_holder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/tmb_shadow_height"
|
||||
android:layout_alignLeft="@+id/dir_bottom_holder"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignRight="@+id/dir_bottom_holder"
|
||||
android:background="@drawable/gradient_background"/>
|
||||
|
||||
<LinearLayout
|
||||
|
@ -80,8 +82,7 @@
|
|||
android:layout_width="@dimen/sd_card_icon_size"
|
||||
android:layout_height="@dimen/sd_card_icon_size"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignRight="@+id/dir_bottom_holder"
|
||||
android:alpha="0.8"
|
||||
android:paddingBottom="@dimen/small_margin"
|
||||
android:paddingEnd="@dimen/small_margin"
|
101
app/src/main/res/layout/directory_item_list.xml
Normal file
101
app/src/main/res/layout/directory_item_list.xml
Normal file
|
@ -0,0 +1,101 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/dir_holder"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="@dimen/small_margin"
|
||||
android:paddingTop="@dimen/small_margin">
|
||||
|
||||
<com.simplemobiletools.gallery.views.MySquareImageView
|
||||
android:id="@+id/dir_thumbnail"
|
||||
android:layout_width="@dimen/list_view_folder_thumbnail_size"
|
||||
android:layout_height="@dimen/list_view_folder_thumbnail_size"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/dir_check"
|
||||
android:layout_width="@dimen/selection_check_size"
|
||||
android:layout_height="@dimen/selection_check_size"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_margin="@dimen/small_margin"
|
||||
android:background="@drawable/circle_background"
|
||||
android:padding="@dimen/tiny_margin"
|
||||
android:src="@drawable/ic_check"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dir_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toRightOf="@+id/dir_thumbnail"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:paddingLeft="6dp"
|
||||
android:paddingRight="6dp"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="@dimen/bigger_text_size"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dir_path"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignLeft="@+id/dir_name"
|
||||
android:layout_below="@+id/dir_name"
|
||||
android:layout_marginRight="@dimen/activity_margin"
|
||||
android:alpha="0.4"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:paddingLeft="6dp"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="@dimen/smaller_text_size"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/photo_cnt"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignBaseline="@+id/dir_name"
|
||||
android:layout_toRightOf="@+id/dir_name"
|
||||
android:alpha="0.4"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="@dimen/smaller_text_size"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/dir_icon_holder"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginRight="@dimen/small_margin"
|
||||
android:gravity="end"
|
||||
android:orientation="horizontal"
|
||||
android:paddingBottom="@dimen/tiny_margin">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/dir_sd_card"
|
||||
android:layout_width="@dimen/sd_card_icon_size"
|
||||
android:layout_height="@dimen/sd_card_icon_size"
|
||||
android:paddingBottom="@dimen/small_margin"
|
||||
android:src="@drawable/ic_sd_card"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/dir_pin"
|
||||
android:layout_width="@dimen/sd_card_icon_size"
|
||||
android:layout_height="@dimen/sd_card_icon_size"
|
||||
android:paddingBottom="@dimen/small_margin"
|
||||
android:src="@drawable/ic_pin"
|
||||
android:visibility="gone"/>
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dir_list_divider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_alignBottom="@+id/dir_thumbnail"
|
||||
android:layout_marginTop="2dp"
|
||||
android:layout_toRightOf="@+id/dir_thumbnail"
|
||||
android:background="@drawable/divider"/>
|
||||
|
||||
</RelativeLayout>
|
62
app/src/main/res/layout/photo_video_item_list.xml
Normal file
62
app/src/main/res/layout/photo_video_item_list.xml
Normal file
|
@ -0,0 +1,62 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/media_item_holder"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="@dimen/small_margin"
|
||||
android:paddingTop="@dimen/small_margin">
|
||||
|
||||
<com.simplemobiletools.gallery.views.MySquareImageView
|
||||
android:id="@+id/medium_thumbnail"
|
||||
android:layout_width="@dimen/list_view_folder_thumbnail_size"
|
||||
android:layout_height="@dimen/list_view_folder_thumbnail_size"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/medium_check"
|
||||
android:layout_width="@dimen/selection_check_size"
|
||||
android:layout_height="@dimen/selection_check_size"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_margin="@dimen/small_margin"
|
||||
android:background="@drawable/circle_background"
|
||||
android:padding="@dimen/tiny_margin"
|
||||
android:src="@drawable/ic_check"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/photo_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_alignBottom="@+id/medium_thumbnail"
|
||||
android:layout_alignTop="@+id/medium_thumbnail"
|
||||
android:layout_toRightOf="@+id/medium_thumbnail"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center_vertical"
|
||||
android:maxLines="3"
|
||||
android:paddingLeft="6dp"
|
||||
android:paddingRight="@dimen/normal_margin"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="@dimen/bigger_text_size"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/play_outline"
|
||||
android:layout_width="@dimen/play_outline_icon_size"
|
||||
android:layout_height="@dimen/play_outline_icon_size"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginRight="@dimen/small_margin"
|
||||
android:paddingBottom="6dp"
|
||||
android:src="@drawable/img_play_outline_empty"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dir_list_divider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_alignBottom="@+id/medium_thumbnail"
|
||||
android:layout_marginTop="2dp"
|
||||
android:layout_toRightOf="@+id/medium_thumbnail"
|
||||
android:background="@drawable/divider"/>
|
||||
|
||||
</RelativeLayout>
|
|
@ -1,6 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/cab_confirm_selection"
|
||||
android:icon="@drawable/ic_check"
|
||||
android:title="@string/confirm_selection"
|
||||
app:showAsAction="ifRoom"/>
|
||||
<item
|
||||
android:id="@+id/cab_delete"
|
||||
android:icon="@drawable/ic_delete"
|
||||
|
|
|
@ -16,6 +16,10 @@
|
|||
android:icon="@drawable/ic_filter"
|
||||
android:title="@string/filter_media"
|
||||
app:showAsAction="ifRoom"/>
|
||||
<item
|
||||
android:id="@+id/change_view_type"
|
||||
android:title="@string/change_view_type"
|
||||
app:showAsAction="never"/>
|
||||
<item
|
||||
android:id="@+id/show_all"
|
||||
android:title="@string/show_all"
|
||||
|
|
|
@ -25,6 +25,10 @@
|
|||
android:icon="@drawable/ic_camera"
|
||||
android:title="@string/open_camera"
|
||||
app:showAsAction="ifRoom"/>
|
||||
<item
|
||||
android:id="@+id/change_view_type"
|
||||
android:title="@string/change_view_type"
|
||||
app:showAsAction="never"/>
|
||||
<item
|
||||
android:id="@+id/hide_folder"
|
||||
android:title="@string/hide_folder"
|
||||
|
|
|
@ -102,6 +102,11 @@
|
|||
<string name="slideshow_ended">The slideshow ended</string>
|
||||
<string name="no_media_for_slideshow">No media for the slideshow have been found</string>
|
||||
|
||||
<!-- View types -->
|
||||
<string name="change_view_type">Change view type</string>
|
||||
<string name="grid">Grid</string>
|
||||
<string name="list">List</string>
|
||||
|
||||
<!-- Settings -->
|
||||
<string name="show_hidden_media">Show hidden media</string>
|
||||
<string name="autoplay_videos">Play videos automatically</string>
|
||||
|
|
|
@ -102,6 +102,11 @@
|
|||
<string name="slideshow_ended">The slideshow ended</string>
|
||||
<string name="no_media_for_slideshow">No media for the slideshow have been found</string>
|
||||
|
||||
<!-- View types -->
|
||||
<string name="change_view_type">Change view type</string>
|
||||
<string name="grid">Grid</string>
|
||||
<string name="list">List</string>
|
||||
|
||||
<!-- Settings -->
|
||||
<string name="show_hidden_media">Zobrazit skryté média</string>
|
||||
<string name="autoplay_videos">Automaticky přehrávat videa</string>
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<string name="no_camera_app_found">Keine Kamera-App gefunden</string>
|
||||
<string name="increase_column_count">Kacheln verkleinern</string>
|
||||
<string name="reduce_column_count">Kacheln vergrößern</string>
|
||||
<string name="change_cover_image">Cover-Bild ändern</string>
|
||||
<string name="change_cover_image">Coverbild ändern</string>
|
||||
<string name="select_photo">Auswählen</string>
|
||||
<string name="use_default">Standard</string>
|
||||
<string name="set_as">Festlegen als</string>
|
||||
|
@ -27,12 +27,12 @@
|
|||
<string name="brightness">Helligkeit</string>
|
||||
|
||||
<!-- Filter -->
|
||||
<string name="filter_media">Filter media</string>
|
||||
<string name="images">Images</string>
|
||||
<string name="filter_media">Medienfilter</string>
|
||||
<string name="images">Bilder</string>
|
||||
<string name="videos">Videos</string>
|
||||
<string name="gifs">GIFs</string>
|
||||
<string name="no_media_with_filters">No media files have been found with the selected filters.</string>
|
||||
<string name="change_filters_underlined"><u>Change filters</u></string>
|
||||
<string name="no_media_with_filters">Keine Medien für die ausgewählten Filter gefunden</string>
|
||||
<string name="change_filters_underlined"><u>Filter ändern</u></string>
|
||||
|
||||
<!-- Hide / Exclude -->
|
||||
<string name="hide_folder_description">Diese Funktion versteckt ausgewählte Ordner (auch für andere Apps), indem dort im Dateisystem eine \'.nomedia\'-Datei abgelegt wird. Dadurch werden auch deren Unterordner versteckt. Solche Ordner werden nur gezeigt, wenn die Einstellung \'Versteckte Ordner zeigen\' aktiv ist (auch andere Apps bieten üblicherweise eine solche Option). Fortfahren?</string>
|
||||
|
@ -94,14 +94,19 @@
|
|||
<string name="interval">Intervall (Sekunden):</string>
|
||||
<string name="include_photos">Bilder verwenden</string>
|
||||
<string name="include_videos">Videos verwenden</string>
|
||||
<string name="include_gifs">GIF verwenden</string>
|
||||
<string name="include_gifs">GIFs verwenden</string>
|
||||
<string name="random_order">Zufällige Reihenfolge</string>
|
||||
<string name="use_fade">Übergänge animieren</string>
|
||||
<string name="move_backwards">Rückwärts abspielen</string>
|
||||
<string name="loop_slideshow">Loop slideshow</string>
|
||||
<string name="loop_slideshow">Endlos abspielen</string>
|
||||
<string name="slideshow_ended">Diashow beendet</string>
|
||||
<string name="no_media_for_slideshow">Keine Medien für Diashow gefunden</string>
|
||||
|
||||
<!-- View types -->
|
||||
<string name="change_view_type">Change view type</string>
|
||||
<string name="grid">Grid</string>
|
||||
<string name="list">List</string>
|
||||
|
||||
<!-- Settings -->
|
||||
<string name="show_hidden_media">Versteckte Ordner zeigen</string>
|
||||
<string name="autoplay_videos">Videos automatisch abspielen</string>
|
||||
|
@ -117,8 +122,8 @@
|
|||
<string name="dark_background_at_fullscreen">Schwarzer Hintergrund im Vollbild</string>
|
||||
<string name="scroll_thumbnails_horizontally">Kacheln horizontal scrollen</string>
|
||||
<string name="hide_system_ui_at_fullscreen">Systemleisten ausblenden im Vollbild</string>
|
||||
<string name="delete_empty_folders">Delete empty folders after deleting their content</string>
|
||||
<string name="allow_video_gestures">Allow controlling video volume and brightness with vertical gestures</string>
|
||||
<string name="delete_empty_folders">Nach Löschen leere Ordner löschen</string>
|
||||
<string name="allow_video_gestures">Gesten für Videolautstärke/Helligkeit</string>
|
||||
<string name="replace_share_with_rotate">Teilen/Drehen im Vollbild-Menü vertauschen</string>
|
||||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
|
|
|
@ -102,6 +102,11 @@
|
|||
<string name="slideshow_ended">The slideshow ended</string>
|
||||
<string name="no_media_for_slideshow">No media for the slideshow have been found</string>
|
||||
|
||||
<!-- View types -->
|
||||
<string name="change_view_type">Change view type</string>
|
||||
<string name="grid">Grid</string>
|
||||
<string name="list">List</string>
|
||||
|
||||
<!-- Settings -->
|
||||
<string name="show_hidden_media">Mostrar carpetas ocultas</string>
|
||||
<string name="autoplay_videos">Reproducir vídeos automáticamente</string>
|
||||
|
|
|
@ -102,6 +102,11 @@
|
|||
<string name="slideshow_ended">Diaporama terminé</string>
|
||||
<string name="no_media_for_slideshow">Aucun média trouvé pour le diaporama</string>
|
||||
|
||||
<!-- View types -->
|
||||
<string name="change_view_type">Change view type</string>
|
||||
<string name="grid">Grid</string>
|
||||
<string name="list">List</string>
|
||||
|
||||
<!-- Settings -->
|
||||
<string name="show_hidden_media">Afficher les dossiers cachés</string>
|
||||
<string name="autoplay_videos">Lecture automatique des vidéos</string>
|
||||
|
@ -125,13 +130,13 @@
|
|||
<!-- Short description has to have less than 80 chars -->
|
||||
<string name="app_short_description">Un album pour visionner photos et vidéos sans publicité.</string>
|
||||
<string name="app_long_description">
|
||||
Un simple outil pour visionner les photos et les vidéos. Elles peuvent être triées par dates, tailles, noms dans les deux sens (alphabétique comme désalphabétique), il est possible de zoomer sur les photos. Les fichiers sont affichés sur de multiple colonnes en fonction de la taille de l\'écran, vous pouvez changer le nombre de colonnes par pincement. Elles peuvent être renommées, partagées, supprimées, copiées et déplacées. Les images peuvent en plus être tournées, rognées ou être définies comme fond d\'écran directement depuis l\'application. La galerie est aussi offerte pour l\'utiliser comme une tierce partie pour de la prévisualisation des images/vidéos, joindre aux clients mail etc. C\'est parfait pour un usage au quotidien.
|
||||
Un simple outil pour visionner les photos et les vidéos. Elles peuvent être triées par dates, tailles, noms dans les deux sens (alphabétique comme désalphabétique), il est possible de zoomer sur les photos. Les fichiers sont affichés sur de multiple colonnes en fonction de la taille de l\'écran, vous pouvez changer le nombre de colonnes par pincement. Elles peuvent être renommées, partagées, supprimées, copiées et déplacées. Les images peuvent en plus être tournées, rognées ou être définies comme fond d\'écran directement depuis l\'application.
|
||||
|
||||
La galerie est aussi offerte pour l\'utiliser comme une tierce partie pour de la prévisualisation des images/vidéos, joindre aux clients mail etc. C\'est parfait pour un usage au quotidien.
|
||||
|
||||
L\'application ne contient ni de publicité ni d\'autorisation inutile. Elle est totalement OpenSource et est aussi fournie avec un thème sombre.
|
||||
|
||||
Cette application est juste l\'une des applications d\'une plus grande suite.
|
||||
|
||||
Vous pouvez trouver les autres sur http://www.simplemobiletools.com
|
||||
Cette application est juste l\'une des applications d\'une plus grande suite. Vous pouvez trouver les autres sur http://www.simplemobiletools.com
|
||||
</string>
|
||||
|
||||
<!--
|
||||
|
|
|
@ -102,6 +102,11 @@
|
|||
<string name="slideshow_ended">The slideshow ended</string>
|
||||
<string name="no_media_for_slideshow">No media for the slideshow have been found</string>
|
||||
|
||||
<!-- View types -->
|
||||
<string name="change_view_type">Change view type</string>
|
||||
<string name="grid">Grid</string>
|
||||
<string name="list">List</string>
|
||||
|
||||
<!-- Settings -->
|
||||
<string name="show_hidden_media">Show hidden media</string>
|
||||
<string name="autoplay_videos">Play videos automatically</string>
|
||||
|
|
|
@ -27,12 +27,12 @@
|
|||
<string name="brightness">Luminosità</string>
|
||||
|
||||
<!-- Filter -->
|
||||
<string name="filter_media">Filter media</string>
|
||||
<string name="images">Images</string>
|
||||
<string name="videos">Videos</string>
|
||||
<string name="gifs">GIFs</string>
|
||||
<string name="no_media_with_filters">No media files have been found with the selected filters.</string>
|
||||
<string name="change_filters_underlined"><u>Change filters</u></string>
|
||||
<string name="filter_media">Filtra i media</string>
|
||||
<string name="images">Immagini</string>
|
||||
<string name="videos">Video</string>
|
||||
<string name="gifs">GIF</string>
|
||||
<string name="no_media_with_filters">Nessun file trovato per il filtro selezionato.</string>
|
||||
<string name="change_filters_underlined"><u>Cambia filtro</u></string>
|
||||
|
||||
<!-- Hide / Exclude -->
|
||||
<string name="hide_folder_description">Questa funzione nasconde la cartella aggiungendo un file \'.nomedia\' all\'interno, nasconderà anche tutte le sottocartelle. Puoi vederle attivando l\'opzione \'Mostra cartelle nascoste\' nelle impostazioni. Continuare?</string>
|
||||
|
@ -98,10 +98,15 @@
|
|||
<string name="random_order">Ordine sparso</string>
|
||||
<string name="use_fade">Usa animazioni a dissolvenza</string>
|
||||
<string name="move_backwards">Scorri al contrario</string>
|
||||
<string name="loop_slideshow">Loop slideshow</string>
|
||||
<string name="loop_slideshow">Ripeti presentazione</string>
|
||||
<string name="slideshow_ended">La presentazione è terminata</string>
|
||||
<string name="no_media_for_slideshow">Nessun media trovato per la presentazione</string>
|
||||
|
||||
<!-- View types -->
|
||||
<string name="change_view_type">Change view type</string>
|
||||
<string name="grid">Grid</string>
|
||||
<string name="list">List</string>
|
||||
|
||||
<!-- Settings -->
|
||||
<string name="show_hidden_media">Mostra cartelle nascoste</string>
|
||||
<string name="autoplay_videos">Riproduci video automaticamente</string>
|
||||
|
@ -117,8 +122,8 @@
|
|||
<string name="dark_background_at_fullscreen">Sfondo scuro a schermo intero</string>
|
||||
<string name="scroll_thumbnails_horizontally">Scorri miniature orizzontalmente</string>
|
||||
<string name="hide_system_ui_at_fullscreen">Nascondi UI di sistema con media a schermo intero</string>
|
||||
<string name="delete_empty_folders">Delete empty folders after deleting their content</string>
|
||||
<string name="allow_video_gestures">Allow controlling video volume and brightness with vertical gestures</string>
|
||||
<string name="delete_empty_folders">Elimina cartelle vuote dopo averne eliminato il contenuto</string>
|
||||
<string name="allow_video_gestures">Gestisci il volume e la luminosità dei video con gesti verticali</string>
|
||||
<string name="replace_share_with_rotate">Sostituisci Condividi con Ruota a schermo intero</string>
|
||||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
|
|
|
@ -4,122 +4,127 @@
|
|||
<string name="app_launcher_name">ギャラリー</string>
|
||||
<string name="edit">編集</string>
|
||||
<string name="open_camera">カメラを開く</string>
|
||||
<string name="open_with">…で開く</string>
|
||||
<string name="open_with">別のアプリで開く</string>
|
||||
<string name="no_app_found">有効なアプリが見つかりません</string>
|
||||
<string name="hidden">(非表示)</string>
|
||||
<string name="pin_folder">Pin folder</string>
|
||||
<string name="unpin_folder">Unpin folder</string>
|
||||
<string name="show_all">Show all folders content</string>
|
||||
<string name="all_folders">All media</string>
|
||||
<string name="folder_view">Switch to folder view</string>
|
||||
<string name="other_folder">Other folder</string>
|
||||
<string name="show_on_map">Show on map</string>
|
||||
<string name="unknown_location">Unknown location</string>
|
||||
<string name="no_map_application">No application with maps has been found</string>
|
||||
<string name="no_camera_app_found">No Camera app has been found</string>
|
||||
<string name="increase_column_count">Increase column count</string>
|
||||
<string name="reduce_column_count">Reduce column count</string>
|
||||
<string name="change_cover_image">Change cover image</string>
|
||||
<string name="select_photo">Select photo</string>
|
||||
<string name="use_default">Use default</string>
|
||||
<string name="set_as">Set as</string>
|
||||
<string name="volume">Volume</string>
|
||||
<string name="brightness">Brightness</string>
|
||||
<string name="pin_folder">フォルダーをピン留めする</string>
|
||||
<string name="unpin_folder">フォルダーのピン留めを外す</string>
|
||||
<string name="show_all">全てを表示</string>
|
||||
<string name="all_folders">すべてのフォルダー</string>
|
||||
<string name="folder_view">フォルダーを選択する</string>
|
||||
<string name="other_folder">その他のフォルダー</string>
|
||||
<string name="show_on_map">地図で表示</string>
|
||||
<string name="unknown_location">位置情報がありません</string>
|
||||
<string name="no_map_application">地図アプリが見つかりません</string>
|
||||
<string name="no_camera_app_found">カメラアプリが見つかりません</string>
|
||||
<string name="increase_column_count">列数を増やす</string>
|
||||
<string name="reduce_column_count">列数を減らす</string>
|
||||
<string name="change_cover_image">カバー画像を変更</string>
|
||||
<string name="select_photo">写真を選択</string>
|
||||
<string name="use_default">デフォルトに戻す</string>
|
||||
<string name="set_as">他で使う</string>
|
||||
<string name="volume">音量</string>
|
||||
<string name="brightness">明るさ</string>
|
||||
|
||||
<!-- Filter -->
|
||||
<string name="filter_media">Filter media</string>
|
||||
<string name="images">Images</string>
|
||||
<string name="videos">Videos</string>
|
||||
<string name="gifs">GIFs</string>
|
||||
<string name="no_media_with_filters">No media files have been found with the selected filters.</string>
|
||||
<string name="change_filters_underlined"><u>Change filters</u></string>
|
||||
<string name="filter_media">表示メディア種</string>
|
||||
<string name="images">画像</string>
|
||||
<string name="videos">ビデオ</string>
|
||||
<string name="gifs">GIF</string>
|
||||
<string name="no_media_with_filters">絞り込み条件に該当するメディアがありません。</string>
|
||||
<string name="change_filters_underlined"><u>絞り込み条件を変更</u></string>
|
||||
|
||||
<!-- Hide / Exclude -->
|
||||
<string name="hide_folder_description">This function hides the folder by adding a \'.nomedia\' file into it, it will hide all subfolders too. You can see them by toggling the \'Show hidden folders\' option in Settings. Continue?</string>
|
||||
<string name="exclude">Exclude</string>
|
||||
<string name="excluded_folders">Excluded folders</string>
|
||||
<string name="manage_excluded_folders">Manage excluded folders</string>
|
||||
<string name="exclude_folder_description">This will exclude the selection together with its subfolders from Simple Gallery only. You can manage excluded folders in Settings.</string>
|
||||
<string name="exclude_folder_parent">Exclude a parent instead?</string>
|
||||
<string name="excluded_activity_placeholder">Excluding folders will make them together with their subfolders hidden just in Simple Gallery, they will still be visible in other applications.\\n\\nIf you want to hide them from other apps too, use the Hide function.</string>
|
||||
<string name="remove_all">Remove all</string>
|
||||
<string name="remove_all_description">Remove all folders from the list of excluded? This will not delete the folders.</string>
|
||||
<string name="hide_folder_description">対象のフォルダーに「.nomedia」というファイルを作成し、フォルダーを非表示にします。そのフォルダー以下のすべてのサブフォルダーも、同様に非表示となります。非表示となったフォルダーを見るには、「設定」の中にある「非表示のフォルダーを表示」オプションを切り替えてください。このフォルダーを非表示にしますか?</string>
|
||||
<string name="exclude">除外する</string>
|
||||
<string name="excluded_folders">除外フォルダー</string>
|
||||
<string name="manage_excluded_folders">除外フォルダーを管理</string>
|
||||
<string name="exclude_folder_description">選択したフォルダーとそのサブフォルダーを、Simple Galleyの一覧から除外します。除外したフォルダーは「設定」で管理できます。</string>
|
||||
<string name="exclude_folder_parent">親フォルダーを選択して除外することもできます。</string>
|
||||
<string name="excluded_activity_placeholder">フォルダーを除外すると、サブフォルダーも含めSimple Galleyの一覧から除外します。他のアプリでは引き続き表示されます。\\n\\n他のアプリでも非表示にしたい場合は、「非表示」機能を使用してください。</string>
|
||||
<string name="remove_all">すべて解除</string>
|
||||
<string name="remove_all_description">除外するフォルダーの登録をすべて解除しますか? フォルダー自体は削除されません。</string>
|
||||
|
||||
<!-- Include folders -->
|
||||
<string name="include_folders">Included folders</string>
|
||||
<string name="manage_included_folders">Manage included folders</string>
|
||||
<string name="add_folder">Add folder</string>
|
||||
<string name="included_activity_placeholder">If you have some folders which contain media, but were not recognized by the app, you can add them manually here.</string>
|
||||
<string name="include_folders">追加フォルダー</string>
|
||||
<string name="manage_included_folders">追加フォルダーを管理</string>
|
||||
<string name="add_folder">フォルダーを追加</string>
|
||||
<string name="included_activity_placeholder">メディアを含んでいるフォルダーがアプリから認識されていない場合は、手動で追加できます。</string>
|
||||
|
||||
<!-- Resizing -->
|
||||
<string name="resize">Resize</string>
|
||||
<string name="resize_and_save">Resize selection and save</string>
|
||||
<string name="width">Width</string>
|
||||
<string name="height">Height</string>
|
||||
<string name="keep_aspect_ratio">Keep aspect ratio</string>
|
||||
<string name="invalid_values">Please enter a valid resolution</string>
|
||||
<string name="resize">リサイズ</string>
|
||||
<string name="resize_and_save">選択領域をリサイズして保存</string>
|
||||
<string name="width">幅</string>
|
||||
<string name="height">高さ</string>
|
||||
<string name="keep_aspect_ratio">縦横比を固定</string>
|
||||
<string name="invalid_values">解像度を正しく入力してください</string>
|
||||
|
||||
<!-- Editor -->
|
||||
<string name="editor">エディター</string>
|
||||
<string name="save">保存</string>
|
||||
<string name="rotate">回転</string>
|
||||
<string name="path">Path</string>
|
||||
<string name="path">パス</string>
|
||||
<string name="invalid_image_path">無効な画像パス</string>
|
||||
<string name="image_editing_failed">画像の編集に失敗しました</string>
|
||||
<string name="edit_image_with">画像を編集:</string>
|
||||
<string name="no_editor_found">画像エディターが見つかりません</string>
|
||||
<string name="unknown_file_location">ファイルの場所が不明です</string>
|
||||
<string name="error_saving_file">元のファイルを上書きできません</string>
|
||||
<string name="rotate_left">Rotate left</string>
|
||||
<string name="rotate_right">Rotate right</string>
|
||||
<string name="rotate_one_eighty">Rotate by 180º</string>
|
||||
<string name="flip">Flip</string>
|
||||
<string name="flip_horizontally">Flip horizontally</string>
|
||||
<string name="flip_vertically">Flip vertically</string>
|
||||
<string name="edit_with">Edit with</string>
|
||||
<string name="rotate_left">左に回転</string>
|
||||
<string name="rotate_right">右に回転</string>
|
||||
<string name="rotate_one_eighty">180º回転</string>
|
||||
<string name="flip">反転</string>
|
||||
<string name="flip_horizontally">水平方向に反転</string>
|
||||
<string name="flip_vertically">垂直方向に反転</string>
|
||||
<string name="edit_with">他のアプリで編集</string>
|
||||
|
||||
<!-- Set wallpaper -->
|
||||
<string name="simple_wallpaper">シンプル壁紙</string>
|
||||
<string name="set_as_wallpaper">壁紙として設定</string>
|
||||
<string name="set_as_wallpaper_failed">壁紙としての設定に失敗しました</string>
|
||||
<string name="set_as_wallpaper_with">壁紙として設定:</string>
|
||||
<string name="set_as_wallpaper">壁紙に設定</string>
|
||||
<string name="set_as_wallpaper_failed">壁紙の設定に失敗しました</string>
|
||||
<string name="set_as_wallpaper_with">壁紙に設定:</string>
|
||||
<string name="no_capable_app_found">対応できるアプリが見つかりません</string>
|
||||
<string name="setting_wallpaper">壁紙の設定…</string>
|
||||
<string name="setting_wallpaper">壁紙に設定中…</string>
|
||||
<string name="wallpaper_set_successfully">壁紙を正常に設定しました</string>
|
||||
<string name="portrait_aspect_ratio">Portrait aspect ratio</string>
|
||||
<string name="landscape_aspect_ratio">Landscape aspect ratio</string>
|
||||
<string name="portrait_aspect_ratio">縦向きの縦横比</string>
|
||||
<string name="landscape_aspect_ratio">横向きの縦横比</string>
|
||||
|
||||
<!-- Slideshow -->
|
||||
<string name="slideshow">Slideshow</string>
|
||||
<string name="interval">Interval (seconds):</string>
|
||||
<string name="include_photos">Include photos</string>
|
||||
<string name="include_videos">Include videos</string>
|
||||
<string name="include_gifs">Include GIFs</string>
|
||||
<string name="random_order">Random order</string>
|
||||
<string name="use_fade">Use fade animations</string>
|
||||
<string name="move_backwards">Move backwards</string>
|
||||
<string name="loop_slideshow">Loop slideshow</string>
|
||||
<string name="slideshow_ended">The slideshow ended</string>
|
||||
<string name="no_media_for_slideshow">No media for the slideshow have been found</string>
|
||||
<string name="slideshow">スライドショー</string>
|
||||
<string name="interval">間隔 (秒):</string>
|
||||
<string name="include_photos">写真を含める</string>
|
||||
<string name="include_videos">ビデオを含める</string>
|
||||
<string name="include_gifs">GIFを含める</string>
|
||||
<string name="random_order">ランダムな順序</string>
|
||||
<string name="use_fade">フェードアニメーションを使用する</string>
|
||||
<string name="move_backwards">逆方向に進む</string>
|
||||
<string name="loop_slideshow">スライドショーをリピート再生する</string>
|
||||
<string name="slideshow_ended">スライドショーが終了しました</string>
|
||||
<string name="no_media_for_slideshow">スライドショーに表示するメディアがありません</string>
|
||||
|
||||
<!-- View types -->
|
||||
<string name="change_view_type">Change view type</string>
|
||||
<string name="grid">Grid</string>
|
||||
<string name="list">List</string>
|
||||
|
||||
<!-- Settings -->
|
||||
<string name="show_hidden_media">非表示フォルダーを表示</string>
|
||||
<string name="autoplay_videos">自動的にビデオを再生</string>
|
||||
<string name="autoplay_videos">ビデオを自動再生する</string>
|
||||
<string name="toggle_filename">ファイル名の表示を切り替え</string>
|
||||
<string name="loop_videos">Loop videos</string>
|
||||
<string name="animate_gifs">Animate GIFs at thumbnails</string>
|
||||
<string name="max_brightness">Max brightness when viewing media</string>
|
||||
<string name="crop_thumbnails">Crop thumbnails into squares</string>
|
||||
<string name="screen_rotation_by">Rotate fullscreen media by</string>
|
||||
<string name="screen_rotation_system_setting">System setting</string>
|
||||
<string name="screen_rotation_device_rotation">Device rotation</string>
|
||||
<string name="screen_rotation_aspect_ratio">Aspect ratio</string>
|
||||
<string name="dark_background_at_fullscreen">Dark background at fullscreen media</string>
|
||||
<string name="scroll_thumbnails_horizontally">Scroll thumbnails horizontally</string>
|
||||
<string name="hide_system_ui_at_fullscreen">Automatically hide system UI at fullscreen media</string>
|
||||
<string name="delete_empty_folders">Delete empty folders after deleting their content</string>
|
||||
<string name="allow_video_gestures">Allow controlling video volume and brightness with vertical gestures</string>
|
||||
<string name="replace_share_with_rotate">Replace Share with Rotate at fullscreen menu</string>
|
||||
<string name="loop_videos">ビデオをリピート再生する</string>
|
||||
<string name="animate_gifs">GIF画像のサムネイルをアニメーション表示する</string>
|
||||
<string name="max_brightness">メディア再生時に明るさを最大にする</string>
|
||||
<string name="crop_thumbnails">サムネイルを正方形に切り取る</string>
|
||||
<string name="screen_rotation_by">メディア再生時のフルスクリーン表示切り替え</string>
|
||||
<string name="screen_rotation_system_setting">システム設定に従う</string>
|
||||
<string name="screen_rotation_device_rotation">端末の向きに従う</string>
|
||||
<string name="screen_rotation_aspect_ratio">メディアの縦横比に従う</string>
|
||||
<string name="dark_background_at_fullscreen">黒背景でフルスクリーン表示</string>
|
||||
<string name="scroll_thumbnails_horizontally">サムネイル画面を横方向にスクロール</string>
|
||||
<string name="hide_system_ui_at_fullscreen">フルスクリーン時にシステムUIを非表示にする</string>
|
||||
<string name="delete_empty_folders">メディアの削除後にフォルダーが空になった場合、そのフォルダーを削除する</string>
|
||||
<string name="allow_video_gestures">ビデオ再生中に、音量と明るさを縦方向のジェスチャーで変更する</string>
|
||||
<string name="replace_share_with_rotate">フルスクリーンメニューの「共有」を「回転」に置き換える</string>
|
||||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
<!-- Short description has to have less than 80 chars -->
|
||||
|
|
|
@ -57,7 +57,7 @@
|
|||
<string name="width">Szerokość</string>
|
||||
<string name="height">Wysokość</string>
|
||||
<string name="keep_aspect_ratio">Zachowaj proporcje</string>
|
||||
<string name="invalid_values">Wpisz poprawną rozdzielczość</string>
|
||||
<string name="invalid_values">Podaj poprawną rozdzielczość</string>
|
||||
|
||||
<!-- Editor -->
|
||||
<string name="editor">Edycja</string>
|
||||
|
@ -98,10 +98,15 @@
|
|||
<string name="random_order">Losowa kolejność</string>
|
||||
<string name="use_fade">Używaj płynnych przejść</string>
|
||||
<string name="move_backwards">Odwrotna kolejność</string>
|
||||
<string name="loop_slideshow">Loop slideshow</string>
|
||||
<string name="loop_slideshow">Zapętlaj</string>
|
||||
<string name="slideshow_ended">Pokaz slajdów zakończony</string>
|
||||
<string name="no_media_for_slideshow">Nie znalazłem multimediów do pokazu slajdów</string>
|
||||
|
||||
<!-- View types -->
|
||||
<string name="change_view_type">Zmień typ widoku</string>
|
||||
<string name="grid">Siatka</string>
|
||||
<string name="list">Lista</string>
|
||||
|
||||
<!-- Settings -->
|
||||
<string name="show_hidden_media">Pokazuj ukryte foldery</string>
|
||||
<string name="autoplay_videos">Odtwarzaj filmy automatycznie</string>
|
||||
|
|
|
@ -102,6 +102,11 @@
|
|||
<string name="slideshow_ended">The slideshow ended</string>
|
||||
<string name="no_media_for_slideshow">No media for the slideshow have been found</string>
|
||||
|
||||
<!-- View types -->
|
||||
<string name="change_view_type">Change view type</string>
|
||||
<string name="grid">Grid</string>
|
||||
<string name="list">List</string>
|
||||
|
||||
<!-- Settings -->
|
||||
<string name="show_hidden_media">Mostrar pastas ocultas</string>
|
||||
<string name="autoplay_videos">Reproduzir vídeos automaticamente</string>
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
<string name="images">Imagens</string>
|
||||
<string name="videos">Vídeos</string>
|
||||
<string name="gifs">GIFs</string>
|
||||
<string name="no_media_with_filters">Naõ foram encontrados ficheiros que cumpram os requisitos.</string>
|
||||
<string name="no_media_with_filters">Não foram encontrados ficheiros que cumpram os requisitos.</string>
|
||||
<string name="change_filters_underlined"><u>Alterar filtros</u></string>
|
||||
|
||||
<!-- Hide / Exclude -->
|
||||
|
@ -98,10 +98,15 @@
|
|||
<string name="random_order">Ordem aleatória</string>
|
||||
<string name="use_fade">Usar animações</string>
|
||||
<string name="move_backwards">Mover para trás</string>
|
||||
<string name="loop_slideshow">Loop slideshow</string>
|
||||
<string name="loop_slideshow">Apresentação em ciclo</string>
|
||||
<string name="slideshow_ended">Apresentação terminada</string>
|
||||
<string name="no_media_for_slideshow">Não foram encontrados ficheiros para a apresentação</string>
|
||||
|
||||
<!-- View types -->
|
||||
<string name="change_view_type">Change view type</string>
|
||||
<string name="grid">Grid</string>
|
||||
<string name="list">List</string>
|
||||
|
||||
<!-- Settings -->
|
||||
<string name="show_hidden_media">Mostrar pastas ocultas</string>
|
||||
<string name="autoplay_videos">Reproduzir vídeos automaticamente</string>
|
||||
|
|
|
@ -102,6 +102,11 @@
|
|||
<string name="slideshow_ended">Слайдшоу завершилось</string>
|
||||
<string name="no_media_for_slideshow">Никаких медиафайлов для слайдшоу не было найдено.</string>
|
||||
|
||||
<!-- View types -->
|
||||
<string name="change_view_type">Change view type</string>
|
||||
<string name="grid">Grid</string>
|
||||
<string name="list">List</string>
|
||||
|
||||
<!-- Settings -->
|
||||
<string name="show_hidden_media">Показать скрытые папки</string>
|
||||
<string name="autoplay_videos">Воспроизводить видео автоматически</string>
|
||||
|
|
|
@ -102,6 +102,11 @@
|
|||
<string name="slideshow_ended">Prezentácia skončila</string>
|
||||
<string name="no_media_for_slideshow">Pre prezentáciu sa nenašli žiadne vhodné súbory</string>
|
||||
|
||||
<!-- View types -->
|
||||
<string name="change_view_type">Zmeniť typ zobrazenia</string>
|
||||
<string name="grid">Mriežka</string>
|
||||
<string name="list">Zoznam</string>
|
||||
|
||||
<!-- Settings -->
|
||||
<string name="show_hidden_media">Zobraziť skryté médiá</string>
|
||||
<string name="autoplay_videos">Spúšťať videá automaticky</string>
|
||||
|
|
|
@ -23,16 +23,16 @@
|
|||
<string name="select_photo">Välj foto</string>
|
||||
<string name="use_default">Använd standard</string>
|
||||
<string name="set_as">Ange som</string>
|
||||
<string name="volume">Volume</string>
|
||||
<string name="brightness">Brightness</string>
|
||||
<string name="volume">Volym</string>
|
||||
<string name="brightness">Ljusstyrka</string>
|
||||
|
||||
<!-- Filter -->
|
||||
<string name="filter_media">Filter media</string>
|
||||
<string name="images">Images</string>
|
||||
<string name="videos">Videos</string>
|
||||
<string name="gifs">GIFs</string>
|
||||
<string name="no_media_with_filters">No media files have been found with the selected filters.</string>
|
||||
<string name="change_filters_underlined"><u>Change filters</u></string>
|
||||
<string name="filter_media">Filtrera media</string>
|
||||
<string name="images">Bilder</string>
|
||||
<string name="videos">Videor</string>
|
||||
<string name="gifs">GIF-bilder</string>
|
||||
<string name="no_media_with_filters">Inga mediefiler hittades med valda filter.</string>
|
||||
<string name="change_filters_underlined"><u>Ändra filter</u></string>
|
||||
|
||||
<!-- Hide / Exclude -->
|
||||
<string name="hide_folder_description">Denna funktion döljer mappen och alla dess undermappar genom att lägga till en \'.nomedia\'-fil i den. Du kan se dem genom att växla \'Visa dolda mappar\'-alternativet i Inställningar. Vill du fortsätta?</string>
|
||||
|
@ -49,7 +49,7 @@
|
|||
<string name="include_folders">Inkluderade mappar</string>
|
||||
<string name="manage_included_folders">Hantera inkluderade mappar</string>
|
||||
<string name="add_folder">Lägg till mapp</string>
|
||||
<string name="included_activity_placeholder">Om du har vissa mappar som innehåller media men som inte känns igen av appen kan du lägga till dem manuellt här.</string>
|
||||
<string name="included_activity_placeholder">Om du har vissa mappar som innehåller media men som inte känns igen av appen, kan du lägga till dem manuellt här.</string>
|
||||
|
||||
<!-- Resizing -->
|
||||
<string name="resize">Ändra storlek</string>
|
||||
|
@ -90,17 +90,22 @@
|
|||
<string name="landscape_aspect_ratio">Liggande bildförhållande</string>
|
||||
|
||||
<!-- Slideshow -->
|
||||
<string name="slideshow">Slideshow</string>
|
||||
<string name="interval">Interval (seconds):</string>
|
||||
<string name="include_photos">Include photos</string>
|
||||
<string name="include_videos">Include videos</string>
|
||||
<string name="include_gifs">Include GIFs</string>
|
||||
<string name="random_order">Random order</string>
|
||||
<string name="use_fade">Use fade animations</string>
|
||||
<string name="move_backwards">Move backwards</string>
|
||||
<string name="loop_slideshow">Loop slideshow</string>
|
||||
<string name="slideshow_ended">The slideshow ended</string>
|
||||
<string name="no_media_for_slideshow">No media for the slideshow have been found</string>
|
||||
<string name="slideshow">Bildspel</string>
|
||||
<string name="interval">Intervall (sekunder):</string>
|
||||
<string name="include_photos">Inkludera foton</string>
|
||||
<string name="include_videos">Inkludera videor</string>
|
||||
<string name="include_gifs">Inkludera GIF-bilder</string>
|
||||
<string name="random_order">Spela upp i slumpmässig ordning</string>
|
||||
<string name="use_fade">Använd toningsanimationer</string>
|
||||
<string name="move_backwards">Spela upp i omvänd ordning</string>
|
||||
<string name="loop_slideshow">Spela upp i en slinga</string>
|
||||
<string name="slideshow_ended">Bildspelet har avslutats</string>
|
||||
<string name="no_media_for_slideshow">Ingen media hittades för bildspelet</string>
|
||||
|
||||
<!-- View types -->
|
||||
<string name="change_view_type">Change view type</string>
|
||||
<string name="grid">Grid</string>
|
||||
<string name="list">List</string>
|
||||
|
||||
<!-- Settings -->
|
||||
<string name="show_hidden_media">Visa dolda mappar</string>
|
||||
|
@ -117,17 +122,17 @@
|
|||
<string name="dark_background_at_fullscreen">Mörk bakgrund när media visas i helskärmsläge</string>
|
||||
<string name="scroll_thumbnails_horizontally">Rulla horisontellt genom miniatyrer</string>
|
||||
<string name="hide_system_ui_at_fullscreen">Dölj systemanvändargränssnittet automatiskt när media visas i helskärmsläge</string>
|
||||
<string name="delete_empty_folders">Delete empty folders after deleting their content</string>
|
||||
<string name="allow_video_gestures">Allow controlling video volume and brightness with vertical gestures</string>
|
||||
<string name="replace_share_with_rotate">Replace Share with Rotate at fullscreen menu</string>
|
||||
<string name="delete_empty_folders">Ta bort tomma mappar när deras innehåll tas bort</string>
|
||||
<string name="allow_video_gestures">Tillåt styrning av videovolym och videoljusstyrka med vertikala gester</string>
|
||||
<string name="replace_share_with_rotate">Ersätt Dela med Rotera i helskärmsmenyn</string>
|
||||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
<!-- Short description has to have less than 80 chars -->
|
||||
<string name="app_short_description">Ett Galleri för att visa bilder och videos utan en massa reklam.</string>
|
||||
<string name="app_long_description">
|
||||
Ett enkelt verktyg för att visa bilder och vdeos. Objekten kan sorteras efter datum, storlek, namn både stigande och fallande, bilder kan zoomas in. Mediafiler visas i flera kolumner beroende av skärmens storlek, du kan ändra antalet kolumner genom en nyp-rörelse. De går att döpa om, dela, ta bort, kopiera, flytta. Bilder kan också beskäras, roteras och anges som bakgrundsbild direkt från appen.
|
||||
Ett enkelt verktyg för att visa bilder och videos. Objekten kan sorteras efter datum, storlek, namn både stigande och fallande, bilder kan zoomas in. Mediafiler visas i flera kolumner beroende av skärmens storlek, du kan ändra antalet kolumner genom en nyp-rörelse. De går att döpa om, dela, ta bort, kopiera, flytta. Bilder kan också beskäras, roteras och anges som bakgrundsbild direkt från appen.
|
||||
|
||||
Galleriet kan också användas av tredjeparts för förhandsgranskning av bilder / videos, bifoga bilagor i e-postklienter etc. Den är perfekt för det dagliga användandet.
|
||||
Galleriet kan också användas av tredjepartsappar för förhandsgranskning av bilder / videos, bifoga bilagor i e-postklienter etc. Den är perfekt för det dagliga användandet.
|
||||
|
||||
Innehåller ingen reklam eller onödiga behörigheter. Det är helt och hållet opensource, innehåller anpassningsbara färger.
|
||||
|
||||
|
|
|
@ -102,6 +102,11 @@
|
|||
<string name="slideshow_ended">The slideshow ended</string>
|
||||
<string name="no_media_for_slideshow">No media for the slideshow have been found</string>
|
||||
|
||||
<!-- View types -->
|
||||
<string name="change_view_type">Change view type</string>
|
||||
<string name="grid">Grid</string>
|
||||
<string name="list">List</string>
|
||||
|
||||
<!-- Settings -->
|
||||
<string name="show_hidden_media">Gizli klasörleri göster</string>
|
||||
<string name="autoplay_videos">Videoları otomatik olarak oynat</string>
|
||||
|
|
|
@ -102,6 +102,11 @@
|
|||
<string name="slideshow_ended">幻灯片结束</string>
|
||||
<string name="no_media_for_slideshow">未发现可用媒体</string>
|
||||
|
||||
<!-- View types -->
|
||||
<string name="change_view_type">Change view type</string>
|
||||
<string name="grid">Grid</string>
|
||||
<string name="list">List</string>
|
||||
|
||||
<!-- Settings -->
|
||||
<string name="show_hidden_media">显示所有</string>
|
||||
<string name="autoplay_videos">自动播放</string>
|
||||
|
|
|
@ -102,6 +102,11 @@
|
|||
<string name="slideshow_ended">投影片結束</string>
|
||||
<string name="no_media_for_slideshow">找不到投影片的媒體檔案</string>
|
||||
|
||||
<!-- View types -->
|
||||
<string name="change_view_type">Change view type</string>
|
||||
<string name="grid">Grid</string>
|
||||
<string name="list">List</string>
|
||||
|
||||
<!-- Settings -->
|
||||
<string name="show_hidden_media">顯示隱藏的媒體檔案</string>
|
||||
<string name="autoplay_videos">自動播放影片</string>
|
||||
|
|
|
@ -3,9 +3,11 @@
|
|||
<dimen name="dir_tmb_size">150dp</dimen>
|
||||
<dimen name="medium_tmb_size">100dp</dimen>
|
||||
<dimen name="sd_card_icon_size">20dp</dimen>
|
||||
<dimen name="play_outline_icon_size">22dp</dimen>
|
||||
<dimen name="selection_check_size">26dp</dimen>
|
||||
<dimen name="play_outline_size_big">150dp</dimen>
|
||||
<dimen name="timer_padding">24dp</dimen>
|
||||
<dimen name="tmb_shadow_height">50dp</dimen>
|
||||
<dimen name="video_side_slider_width">150dp</dimen>
|
||||
<dimen name="list_view_folder_thumbnail_size">72dp</dimen>
|
||||
</resources>
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
<resources>
|
||||
|
||||
<!-- Release notes -->
|
||||
<string name="release_133">
|
||||
Added fingerprint to hidden item protection\n
|
||||
Added a new List view type
|
||||
</string>
|
||||
<string name="release_127">
|
||||
Added a switch for disabling video gestures\n
|
||||
Added a switch for deleting empty folders after deleting content
|
||||
|
|
|
@ -102,6 +102,11 @@
|
|||
<string name="slideshow_ended">The slideshow ended</string>
|
||||
<string name="no_media_for_slideshow">No media for the slideshow have been found</string>
|
||||
|
||||
<!-- View types -->
|
||||
<string name="change_view_type">Change view type</string>
|
||||
<string name="grid">Grid</string>
|
||||
<string name="list">List</string>
|
||||
|
||||
<!-- Settings -->
|
||||
<string name="show_hidden_media">Show hidden media</string>
|
||||
<string name="autoplay_videos">Play videos automatically</string>
|
||||
|
|
Loading…
Reference in a new issue