diff --git a/CHANGELOG.md b/CHANGELOG.md index 442f658f0..5314e9911 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,73 @@ Changelog ========== +Version 2.13.0 *(2017-08-07)* +---------------------------- + + * Allow changing the screen brightness and volume at videos by vertically dragging the screen sides + * Fixed sorting of numbers in filenames + * Fixed a glitch with hidden files sometimes temporarily visible + * Unified thumbnail corner icon sizes and style + +Version 2.12.6 *(2017-08-05)* +---------------------------- + + * Added slideshow at the fullscreen view + * Replaced the foreground color of selected items with a check + * Made copy/move to SD card a lot faster + +Version 2.12.5 *(2017-08-03)* +---------------------------- + + * Updating file operation on SD card + +Version 2.12.4 *(2017-08-03)* +---------------------------- + + * Fixed SD card file operations + +Version 2.12.3 *(2017-08-02)* +---------------------------- + + * Added pattern/pin protection for showing hidden items + * Hopefully fixed unintentional SD card file deleting + +Version 2.12.2 *(2017-07-09)* +---------------------------- + + * Added a toggle for replacing Share with Rotate at fullscreen media + * Some crashfixes and translation updates + +Version 2.12.1 *(2017-07-02)* +---------------------------- + + * Couple crashfixes + +Version 2.12.0 *(2017-07-01)* +---------------------------- + + * Added a button for disabling "Temporarily show hidden" + * Updated Glide (library used for loading images) to 4.0.0 + * Made playing gifs smooth + +Version 2.11.5 *(2017-06-29)* +---------------------------- + + * Added an indicator of folders located on SD cards + * Improved the way of rotating jpg images on the internal storage by modifying the exif tags + added autosave + +Version 2.11.4 *(2017-06-26)* +---------------------------- + + * Added an option for automatically hiding the system UI at entering fullscreen mode + * Fix deleting SD card files on some devices + * Couple crashfixes + +Version 2.11.3 *(2017-06-24)* +---------------------------- + + * Added optional horizontal scrolling + Version 2.11.1 *(2017-06-19)* ---------------------------- diff --git a/app/build.gradle b/app/build.gradle index a1e12bdab..6282b5d27 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,8 +10,8 @@ android { applicationId "com.simplemobiletools.gallery" minSdkVersion 16 targetSdkVersion 23 - versionCode 111 - versionName "2.11.1" + versionCode 124 + versionName "2.13.1" } signingConfigs { @@ -29,25 +29,30 @@ android { sourceSets { main.java.srcDirs += 'src/main/kotlin' } + + lintOptions { + checkReleaseBuilds false + abortOnError false + } } dependencies { - compile 'com.simplemobiletools:commons:2.21.4' + compile 'com.simplemobiletools:commons:2.25.4' 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' compile 'com.google.code.gson:gson:2.8.0' - compile 'com.github.chrisbanes:PhotoView:1.3.1' + compile 'com.github.chrisbanes:PhotoView:2.1.2' compile 'it.sephiroth.android.exif:library:1.0.1' compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" - debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5' - releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5' - testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5' + debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.1' + releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1' + testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1' } buildscript { - ext.kotlin_version = '1.1.2-5' + ext.kotlin_version = '1.1.4-2' repositories { mavenCentral() } diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 34de0fb81..0816ea160 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -2,4 +2,4 @@ -dontwarn com.simplemobiletools.** -renamesourcefileattribute SourceFile --keepattributes SourceFile, LineNumberTable +-keepattributes SourceFile,LineNumberTable diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 8c640a923..fb8ba91aa 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -11,6 +11,7 @@ android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_launcher_name" + android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/App.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/App.kt index 9e46e19a9..4cbda3237 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/App.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/App.kt @@ -4,11 +4,14 @@ import android.app.Application import com.squareup.leakcanary.LeakCanary class App : Application() { + val USE_LEAK_CANARY = false override fun onCreate() { super.onCreate() - if (LeakCanary.isInAnalyzerProcess(this)) { - return + if (USE_LEAK_CANARY) { + if (LeakCanary.isInAnalyzerProcess(this)) { + return + } + LeakCanary.install(this) } - LeakCanary.install(this) } } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/MainActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/MainActivity.kt index 85d5bc3f6..6952c945e 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/MainActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/MainActivity.kt @@ -19,6 +19,7 @@ import android.widget.FrameLayout import com.google.gson.Gson import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.models.Release +import com.simplemobiletools.commons.views.MyScalableRecyclerView import com.simplemobiletools.gallery.BuildConfig import com.simplemobiletools.gallery.R import com.simplemobiletools.gallery.adapters.DirectoryAdapter @@ -27,7 +28,6 @@ import com.simplemobiletools.gallery.dialogs.ChangeSortingDialog import com.simplemobiletools.gallery.extensions.* import com.simplemobiletools.gallery.helpers.* import com.simplemobiletools.gallery.models.Directory -import com.simplemobiletools.gallery.views.MyScalableRecyclerView import kotlinx.android.synthetic.main.activity_main.* import java.io.* import java.util.* @@ -87,7 +87,8 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener { 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.temporarily_show_hidden).isVisible = !config.showHiddenMedia + menu.findItem(R.id.temporarily_show_hidden).isVisible = !config.shouldShowHidden + menu.findItem(R.id.stop_showing_hidden).isVisible = config.temporarilyShowHidden return true } @@ -96,7 +97,8 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener { R.id.sort -> showSortingDialog() R.id.open_camera -> launchCamera() R.id.show_all -> showAllMedia() - R.id.temporarily_show_hidden -> temporarilyShowHidden() + R.id.temporarily_show_hidden -> tryToggleTemporarilyShowHidden() + R.id.stop_showing_hidden -> tryToggleTemporarilyShowHidden() R.id.increase_column_count -> increaseColumnCount() R.id.reduce_column_count -> reduceColumnCount() R.id.settings -> launchSettings() @@ -109,16 +111,19 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener { override fun onResume() { super.onResume() if (mStoredAnimateGifs != config.animateGifs) { - directories_grid.adapter.notifyDataSetChanged() + directories_grid.adapter?.notifyDataSetChanged() } if (mStoredCropThumbnails != config.cropThumbnails) { - directories_grid.adapter.notifyDataSetChanged() + directories_grid.adapter?.notifyDataSetChanged() } if (mStoredScrollHorizontally != config.scrollHorizontally) { - (directories_grid.adapter as DirectoryAdapter).scrollVertically = !config.scrollHorizontally - directories_grid.adapter.notifyDataSetChanged() + directories_grid.adapter?.let { + (it as DirectoryAdapter).scrollVertically = !config.scrollHorizontally + it.notifyDataSetChanged() + } + setupScrollDirection() } tryloadGallery() @@ -134,7 +139,7 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener { mStoredAnimateGifs = config.animateGifs mStoredCropThumbnails = config.cropThumbnails mStoredScrollHorizontally = config.scrollHorizontally - MyScalableRecyclerView.mListener = null + directories_grid.listener = null mLastMediaHandler.removeCallbacksAndMessages(null) } @@ -205,15 +210,27 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener { finish() } - private fun temporarilyShowHidden() { - config.temporarilyShowHidden = true + private fun tryToggleTemporarilyShowHidden() { + if (config.temporarilyShowHidden) { + toggleTemporarilyShowHidden(false) + } else { + handleHiddenFolderPasswordProtection { + toggleTemporarilyShowHidden(true) + } + } + } + + private fun toggleTemporarilyShowHidden(show: Boolean) { + config.temporarilyShowHidden = show getDirectories() + invalidateOptionsMenu() } private fun checkIfColorChanged() { - if (directories_grid.adapter != null && getRecyclerAdapter().foregroundColor != config.primaryColor) { - getRecyclerAdapter().updatePrimaryColor(config.primaryColor) - directories_fastscroller.updateHandleColor() + if (directories_grid.adapter != null && getRecyclerAdapter().primaryColor != config.primaryColor) { + getRecyclerAdapter().primaryColor = config.primaryColor + directories_vertical_fastscroller.updateHandleColor() + directories_horizontal_fastscroller.updateHandleColor() } } @@ -239,8 +256,10 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener { directories_refresh_layout.layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) } + directories_grid.isDragSelectionEnabled = true + directories_grid.isZoomingEnabled = true layoutManager.spanCount = config.dirColumnCnt - MyScalableRecyclerView.mListener = object : MyScalableRecyclerView.MyScalableRecyclerViewListener { + directories_grid.listener = object : MyScalableRecyclerView.MyScalableRecyclerViewListener { override fun zoomIn() { if (layoutManager.spanCount > 1) { reduceColumnCount() @@ -268,13 +287,13 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener { private fun increaseColumnCount() { config.dirColumnCnt = ++(directories_grid.layoutManager as GridLayoutManager).spanCount invalidateOptionsMenu() - directories_grid.adapter.notifyDataSetChanged() + directories_grid.adapter?.notifyDataSetChanged() } private fun reduceColumnCount() { config.dirColumnCnt = --(directories_grid.layoutManager as GridLayoutManager).spanCount invalidateOptionsMenu() - directories_grid.adapter.notifyDataSetChanged() + directories_grid.adapter?.notifyDataSetChanged() } private fun isPickImageIntent(intent: Intent) = isPickIntent(intent) && (hasImageContentData(intent) || isImageType(intent)) @@ -373,7 +392,9 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener { mDirs = dirs - setupAdapter() + runOnUiThread { + setupAdapter() + } storeDirectories() } @@ -385,17 +406,29 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener { } private fun setupAdapter() { - val adapter = DirectoryAdapter(this, mDirs, this) { - itemClicked(it.path) - } - val currAdapter = directories_grid.adapter - if (currAdapter != null) { - (currAdapter as DirectoryAdapter).updateDirs(mDirs) + if (currAdapter == null) { + directories_grid.adapter = DirectoryAdapter(this, mDirs, this, isPickIntent(intent) || isGetAnyContentIntent(intent)) { + itemClicked(it.path) + } } else { - directories_grid.adapter = adapter + (currAdapter as DirectoryAdapter).updateDirs(mDirs) + } + setupScrollDirection() + } + + private fun setupScrollDirection() { + directories_vertical_fastscroller.isHorizontal = false + directories_vertical_fastscroller.beGoneIf(config.scrollHorizontally) + + directories_horizontal_fastscroller.isHorizontal = true + directories_horizontal_fastscroller.beVisibleIf(config.scrollHorizontally) + + if (config.scrollHorizontally) { + directories_horizontal_fastscroller.setViews(directories_grid, directories_refresh_layout) + } else { + directories_vertical_fastscroller.setViews(directories_grid, directories_refresh_layout) } - directories_fastscroller.setViews(directories_grid, directories_refresh_layout) } private fun checkLastMediaChanged() { @@ -454,6 +487,13 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener { add(Release(97, R.string.release_97)) add(Release(98, R.string.release_98)) add(Release(108, R.string.release_108)) + add(Release(112, R.string.release_112)) + add(Release(114, R.string.release_114)) + add(Release(115, R.string.release_115)) + add(Release(118, R.string.release_118)) + add(Release(119, R.string.release_119)) + add(Release(122, R.string.release_122)) + add(Release(123, R.string.release_123)) checkWhatsNew(this, BuildConfig.VERSION_CODE) } } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/MediaActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/MediaActivity.kt index 2d90e98c7..6229ffce7 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/MediaActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/MediaActivity.kt @@ -9,18 +9,19 @@ import android.os.Build import android.os.Bundle import android.os.Handler import android.support.v7.widget.GridLayoutManager -import android.util.Log import android.view.Menu import android.view.MenuItem import android.view.ViewGroup import android.widget.FrameLayout import com.bumptech.glide.Glide -import com.bumptech.glide.request.animation.GlideAnimation +import com.bumptech.glide.request.RequestOptions import com.bumptech.glide.request.target.SimpleTarget +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.extensions.* +import com.simplemobiletools.commons.views.MyScalableRecyclerView import com.simplemobiletools.gallery.R import com.simplemobiletools.gallery.adapters.MediaAdapter import com.simplemobiletools.gallery.asynctasks.GetMediaAsynctask @@ -29,7 +30,6 @@ import com.simplemobiletools.gallery.dialogs.ExcludeFolderDialog import com.simplemobiletools.gallery.extensions.* import com.simplemobiletools.gallery.helpers.* import com.simplemobiletools.gallery.models.Medium -import com.simplemobiletools.gallery.views.MyScalableRecyclerView import kotlinx.android.synthetic.main.activity_media.* import java.io.File import java.io.IOException @@ -79,16 +79,19 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener { override fun onResume() { super.onResume() if (mShowAll && mStoredAnimateGifs != config.animateGifs) { - media_grid.adapter.notifyDataSetChanged() + media_grid.adapter?.notifyDataSetChanged() } if (mStoredCropThumbnails != config.cropThumbnails) { - media_grid.adapter.notifyDataSetChanged() + media_grid.adapter?.notifyDataSetChanged() } if (mStoredScrollHorizontally != config.scrollHorizontally) { - (media_grid.adapter as MediaAdapter).scrollVertically = !config.scrollHorizontally - media_grid.adapter.notifyDataSetChanged() + media_grid.adapter?.let { + (it as MediaAdapter).scrollVertically = !config.scrollHorizontally + it.notifyDataSetChanged() + } + setupScrollDirection() } tryloadGallery() @@ -102,7 +105,7 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener { mStoredAnimateGifs = config.animateGifs mStoredCropThumbnails = config.cropThumbnails mStoredScrollHorizontally = config.scrollHorizontally - MyScalableRecyclerView.mListener = null + media_grid.listener = null mLastMediaHandler.removeCallbacksAndMessages(null) } @@ -126,9 +129,10 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener { } private fun checkIfColorChanged() { - if (media_grid.adapter != null && getRecyclerAdapter().foregroundColor != config.primaryColor) { - getRecyclerAdapter().updatePrimaryColor(config.primaryColor) - media_fastscroller.updateHandleColor() + if (media_grid.adapter != null && getRecyclerAdapter().primaryColor != config.primaryColor) { + getRecyclerAdapter().primaryColor = config.primaryColor + media_horizontal_fastscroller.updateHandleColor() + media_vertical_fastscroller.updateHandleColor() } } @@ -136,17 +140,29 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener { if (isDirEmpty()) return - val adapter = MediaAdapter(this, mMedia, this) { - itemClicked(it.path) - } - val currAdapter = media_grid.adapter - if (currAdapter != null) { - (currAdapter as MediaAdapter).updateMedia(mMedia) + if (currAdapter == null) { + media_grid.adapter = MediaAdapter(this, mMedia, this, mIsGetAnyIntent) { + itemClicked(it.path) + } } else { - media_grid.adapter = adapter + (currAdapter as MediaAdapter).updateMedia(mMedia) + } + setupScrollDirection() + } + + private fun setupScrollDirection() { + media_vertical_fastscroller.isHorizontal = false + media_vertical_fastscroller.beGoneIf(config.scrollHorizontally) + + media_horizontal_fastscroller.isHorizontal = true + media_horizontal_fastscroller.beVisibleIf(config.scrollHorizontally) + + if (config.scrollHorizontally) { + media_horizontal_fastscroller.setViews(media_grid, media_refresh_layout) + } else { + media_vertical_fastscroller.setViews(media_grid, media_refresh_layout) } - media_fastscroller.setViews(media_grid, media_refresh_layout) } private fun checkLastMediaChanged() { @@ -181,7 +197,8 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener { findItem(R.id.open_camera).isVisible = mShowAll findItem(R.id.about).isVisible = mShowAll - findItem(R.id.temporarily_show_hidden).isVisible = !config.showHiddenMedia + 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 @@ -199,7 +216,8 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener { R.id.hide_folder -> tryHideFolder() R.id.unhide_folder -> unhideFolder() R.id.exclude_folder -> tryExcludeFolder() - R.id.temporarily_show_hidden -> temporarilyShowHidden() + R.id.temporarily_show_hidden -> tryToggleTemporarilyShowHidden() + R.id.stop_showing_hidden -> tryToggleTemporarilyShowHidden() R.id.increase_column_count -> increaseColumnCount() R.id.reduce_column_count -> reduceColumnCount() R.id.settings -> launchSettings() @@ -298,9 +316,20 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener { false } - private fun temporarilyShowHidden() { - config.temporarilyShowHidden = true + private fun tryToggleTemporarilyShowHidden() { + if (config.temporarilyShowHidden) { + toggleTemporarilyShowHidden(false) + } else { + handleHiddenFolderPasswordProtection { + toggleTemporarilyShowHidden(true) + } + } + } + + private fun toggleTemporarilyShowHidden(show: Boolean) { + config.temporarilyShowHidden = show getMedia() + invalidateOptionsMenu() } private fun getRecyclerAdapter() = (media_grid.adapter as MediaAdapter) @@ -315,8 +344,10 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener { media_refresh_layout.layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) } + media_grid.isDragSelectionEnabled = true + media_grid.isZoomingEnabled = true layoutManager.spanCount = config.mediaColumnCnt - MyScalableRecyclerView.mListener = object : MyScalableRecyclerView.MyScalableRecyclerViewListener { + media_grid.listener = object : MyScalableRecyclerView.MyScalableRecyclerViewListener { override fun zoomIn() { if (layoutManager.spanCount > 1) { reduceColumnCount() @@ -344,13 +375,13 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener { private fun increaseColumnCount() { config.mediaColumnCnt = ++(media_grid.layoutManager as GridLayoutManager).spanCount invalidateOptionsMenu() - media_grid.adapter.notifyDataSetChanged() + media_grid.adapter?.notifyDataSetChanged() } private fun reduceColumnCount() { config.mediaColumnCnt = --(media_grid.layoutManager as GridLayoutManager).spanCount invalidateOptionsMenu() - media_grid.adapter.notifyDataSetChanged() + media_grid.adapter?.notifyDataSetChanged() } private fun isSetWallpaperIntent() = intent.getBooleanExtra(SET_WALLPAPER_INTENT, false) @@ -372,18 +403,22 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener { val wantedWidth = wallpaperDesiredMinimumWidth val wantedHeight = wallpaperDesiredMinimumHeight val ratio = wantedWidth.toFloat() / wantedHeight - Glide.with(this) - .load(File(path)) - .asBitmap() + + val options = RequestOptions() .override((wantedWidth * ratio).toInt(), wantedHeight) .fitCenter() + + Glide.with(this) + .asBitmap() + .load(File(path)) + .apply(options) .into(object : SimpleTarget() { - override fun onResourceReady(bitmap: Bitmap?, glideAnimation: GlideAnimation?) { + override fun onResourceReady(resource: Bitmap?, transition: Transition?) { try { - WallpaperManager.getInstance(applicationContext).setBitmap(bitmap) + WallpaperManager.getInstance(applicationContext).setBitmap(resource) setResult(Activity.RESULT_OK) - } catch (e: IOException) { - Log.e(TAG, "item click $e") + } catch (ignored: IOException) { + } finish() @@ -424,7 +459,9 @@ class MediaActivity : SimpleActivity(), MediaAdapter.MediaOperationsListener { mLastDrawnHashCode = media.hashCode() mMedia = media - setupAdapter() + runOnUiThread { + setupAdapter() + } storeFolder() } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/PhotoVideoActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/PhotoVideoActivity.kt index 0aa50ac78..96fc44b10 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/PhotoVideoActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/PhotoVideoActivity.kt @@ -31,9 +31,9 @@ open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentList private val STORAGE_PERMISSION = 1 private var mMedium: Medium? = null private var mIsFullScreen = false + private var mFragment: ViewPagerFragment? = null lateinit var mUri: Uri - lateinit var mFragment: ViewPagerFragment companion object { var mIsVideo = false @@ -76,8 +76,8 @@ open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentList if (savedInstanceState == null) { mFragment = if (mIsVideo) VideoFragment() else PhotoFragment() - mFragment.listener = this - mFragment.arguments = bundle + mFragment!!.listener = this + mFragment!!.arguments = bundle supportFragmentManager.beginTransaction().replace(R.id.fragment_holder, mFragment).commit() } @@ -98,6 +98,11 @@ open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentList } finally { cursor?.close() } + + window.decorView.setOnSystemUiVisibilityChangeListener { visibility -> + val isFullscreen = visibility and View.SYSTEM_UI_FLAG_FULLSCREEN != 0 + mFragment?.fullscreenToggled(isFullscreen) + } } override fun onResume() { @@ -158,12 +163,5 @@ open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentList } } - override fun systemUiVisibilityChanged(visibility: Int) { - if (visibility and View.SYSTEM_UI_FLAG_FULLSCREEN == 0) { - mIsFullScreen = false - showSystemUI() - } else { - mIsFullScreen = true - } - } + override fun videoEnded() = false } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/SettingsActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/SettingsActivity.kt index 0d8720b55..b5125dff1 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/SettingsActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/SettingsActivity.kt @@ -4,7 +4,10 @@ import android.content.Intent import android.content.res.Resources import android.os.Bundle 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.SHOW_ALL_TABS import com.simplemobiletools.commons.models.RadioItem import com.simplemobiletools.gallery.R import com.simplemobiletools.gallery.extensions.config @@ -35,7 +38,10 @@ class SettingsActivity : SimpleActivity() { setupDarkBackground() setupScrollHorizontally() setupScreenRotation() + setupReplaceShare() + setupPasswordProtection() setupShowMedia() + setupHideSystemUI() updateTextColors(settings_holder) } @@ -60,11 +66,21 @@ class SettingsActivity : SimpleActivity() { private fun setupShowHiddenFolders() { settings_show_hidden_folders.isChecked = config.showHiddenMedia settings_show_hidden_folders_holder.setOnClickListener { - settings_show_hidden_folders.toggle() - config.showHiddenMedia = settings_show_hidden_folders.isChecked + if (config.showHiddenMedia) { + toggleHiddenFolders() + } else { + handleHiddenFolderPasswordProtection { + toggleHiddenFolders() + } + } } } + private fun toggleHiddenFolders() { + settings_show_hidden_folders.toggle() + config.showHiddenMedia = settings_show_hidden_folders.isChecked + } + private fun setupAutoplayVideos() { settings_autoplay_videos.isChecked = config.autoplayVideos settings_autoplay_videos_holder.setOnClickListener { @@ -121,6 +137,36 @@ class SettingsActivity : SimpleActivity() { } } + private fun setupHideSystemUI() { + settings_hide_system_ui.isChecked = config.hideSystemUI + settings_hide_system_ui_holder.setOnClickListener { + settings_hide_system_ui.toggle() + config.hideSystemUI = settings_hide_system_ui.isChecked + } + } + + private fun setupReplaceShare() { + settings_replace_share.isChecked = config.replaceShare + settings_replace_share_holder.setOnClickListener { + settings_replace_share.toggle() + config.replaceShare = settings_replace_share.isChecked + } + } + + private fun setupPasswordProtection() { + settings_password_protection.isChecked = config.isPasswordProtectionOn + settings_password_protection_holder.setOnClickListener { + val tabToShow = if (config.isPasswordProtectionOn) config.protectionType else SHOW_ALL_TABS + SecurityDialog(this, config.passwordHash, tabToShow) { hash, type -> + val hasPasswordProtection = config.isPasswordProtectionOn + settings_password_protection.isChecked = !hasPasswordProtection + config.isPasswordProtectionOn = !hasPasswordProtection + config.passwordHash = if (hasPasswordProtection) "" else hash + config.protectionType = type + } + } + } + private fun setupScreenRotation() { settings_screen_rotation.text = getScreenRotationText() settings_screen_rotation_holder.setOnClickListener { diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/ViewPagerActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/ViewPagerActivity.kt index 7ac0c413a..b88493874 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/ViewPagerActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/ViewPagerActivity.kt @@ -15,13 +15,11 @@ import android.media.ExifInterface import android.net.Uri import android.os.Build import android.os.Bundle +import android.os.Handler import android.provider.MediaStore import android.support.v4.view.ViewPager import android.util.DisplayMetrics -import android.view.Menu -import android.view.MenuItem -import android.view.OrientationEventListener -import android.view.View +import android.view.* import com.simplemobiletools.commons.dialogs.ConfirmationDialog import com.simplemobiletools.commons.dialogs.PropertiesDialog import com.simplemobiletools.commons.dialogs.RenameItemDialog @@ -31,8 +29,10 @@ import com.simplemobiletools.gallery.activities.MediaActivity.Companion.mMedia import com.simplemobiletools.gallery.adapters.MyPagerAdapter import com.simplemobiletools.gallery.asynctasks.GetMediaAsynctask import com.simplemobiletools.gallery.dialogs.SaveAsDialog +import com.simplemobiletools.gallery.dialogs.SlideshowDialog 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.* import com.simplemobiletools.gallery.models.Medium @@ -49,10 +49,17 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View private var mIsFullScreen = false private var mPos = -1 private var mShowAll = false + private var mIsSlideshowActive = false private var mRotationDegrees = 0f private var mLastHandledOrientation = 0 private var mPrevHashcode = 0 + private var mSlideshowHandler = Handler() + private var mSlideshowInterval = SLIDESHOW_DEFAULT_INTERVAL + private var mSlideshowMoveBackwards = false + private var mSlideshowMedia = mutableListOf() + private var mAreSlideShowMediaVisible = false + companion object { var screenWidth = 0 var screenHeight = 0 @@ -91,8 +98,10 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View return } - if (intent.extras?.containsKey(IS_VIEW_INTENT) == true) { - config.temporarilyShowHidden = true + if (intent.extras?.containsKey(IS_VIEW_INTENT) == true && File(mPath).isHidden) { + if (!config.isPasswordProtectionOn) { + config.temporarilyShowHidden = true + } } showSystemUI() @@ -100,9 +109,17 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View mDirectory = File(mPath).parent title = mPath.getFilenameFromPath() - if (mMedia.isNotEmpty()) { - gotMedia(mMedia) - } + view_pager.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener { + override fun onGlobalLayout() { + view_pager.viewTreeObserver.removeOnGlobalLayoutListener(this) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && isDestroyed) + return + + if (mMedia.isNotEmpty()) { + gotMedia(mMedia) + } + } + }) reloadViewPager() scanPath(mPath) {} @@ -110,6 +127,17 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View if (config.darkBackground) view_pager.background = ColorDrawable(Color.BLACK) + + if (config.hideSystemUI) + fragmentClicked() + + window.decorView.setOnSystemUiVisibilityChangeListener { visibility -> + mIsFullScreen = visibility and View.SYSTEM_UI_FLAG_FULLSCREEN != 0 + view_pager.adapter?.let { + (it as MyPagerAdapter).toggleFullscreen(mIsFullScreen) + checkSystemUI() + } + } } override fun onDestroy() { @@ -163,32 +191,29 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View } else if (config.screenRotation == ROTATE_BY_SYSTEM_SETTING) { requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED } + + invalidateOptionsMenu() } override fun onPause() { super.onPause() mOrientationEventListener.disable() + stopSlideshow() } override fun onCreateOptionsMenu(menu: Menu): Boolean { menuInflater.inflate(R.menu.menu_viewpager, menu) - if (getCurrentMedium() == null) - return true + val currentMedium = getCurrentMedium() ?: return true menu.apply { - findItem(R.id.menu_set_as).isVisible = getCurrentMedium()!!.isImage() == true - findItem(R.id.menu_edit).isVisible = getCurrentMedium()!!.isImage() == true - findItem(R.id.menu_rotate).isVisible = getCurrentMedium()!!.isImage() == true + findItem(R.id.menu_share_1).isVisible = !config.replaceShare + findItem(R.id.menu_share_2).isVisible = config.replaceShare + findItem(R.id.menu_set_as).isVisible = currentMedium.isImage() + findItem(R.id.menu_edit).isVisible = currentMedium.isImage() + findItem(R.id.menu_rotate).isVisible = currentMedium.isImage() findItem(R.id.menu_save_as).isVisible = mRotationDegrees != 0f - findItem(R.id.menu_hide).isVisible = !getCurrentMedium()!!.name.startsWith('.') - findItem(R.id.menu_unhide).isVisible = getCurrentMedium()!!.name.startsWith('.') - - findItem(R.id.menu_rotate).subMenu.apply { - clearHeader() - findItem(R.id.rotate_right).icon = resources.getColoredDrawable(R.drawable.ic_rotate_right, R.color.actionbar_menu_icon) - findItem(R.id.rotate_left).icon = resources.getColoredDrawable(R.drawable.ic_rotate_left, R.color.actionbar_menu_icon) - findItem(R.id.rotate_one_eighty).icon = resources.getColoredDrawable(R.drawable.ic_rotate_one_eighty, R.color.actionbar_menu_icon) - } + findItem(R.id.menu_hide).isVisible = !currentMedium.name.startsWith('.') + findItem(R.id.menu_unhide).isVisible = currentMedium.name.startsWith('.') } return true @@ -200,39 +225,125 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View when (item.itemId) { R.id.menu_set_as -> trySetAs(getCurrentFile()) + R.id.slideshow -> initSlideshow() R.id.menu_copy_to -> copyMoveTo(true) R.id.menu_move_to -> copyMoveTo(false) R.id.menu_open_with -> openWith(getCurrentFile()) R.id.menu_hide -> toggleFileVisibility(true) R.id.menu_unhide -> toggleFileVisibility(false) - R.id.menu_share -> shareMedium(getCurrentMedium()!!) + R.id.menu_share_1 -> shareMedium(getCurrentMedium()!!) + R.id.menu_share_2 -> shareMedium(getCurrentMedium()!!) R.id.menu_delete -> askConfirmDelete() R.id.menu_rename -> renameFile() R.id.menu_edit -> openFileEditor(getCurrentFile()) R.id.menu_properties -> showProperties() - R.id.menu_save_as -> saveImageAs() R.id.show_on_map -> showOnMap() - R.id.rotate_right -> rotateImage(90f) - R.id.rotate_left -> rotateImage(-90f) - R.id.rotate_one_eighty -> rotateImage(180f) + R.id.menu_rotate -> rotateImage() + R.id.menu_save_as -> saveImageAs() R.id.settings -> launchSettings() else -> return super.onOptionsItemSelected(item) } return true } - private fun updatePagerItems() { - val pagerAdapter = MyPagerAdapter(this, supportFragmentManager, mMedia) + private fun updatePagerItems(media: MutableList) { + val pagerAdapter = MyPagerAdapter(this, supportFragmentManager, media) if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1 || !isDestroyed) { view_pager.apply { adapter = pagerAdapter + adapter!!.notifyDataSetChanged() currentItem = mPos addOnPageChangeListener(this@ViewPagerActivity) - adapter!!.notifyDataSetChanged() } } } + private fun initSlideshow() { + SlideshowDialog(this) { + startSlideshow() + } + } + + private fun startSlideshow() { + if (getMediaForSlideshow()) { + view_pager.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener { + override fun onGlobalLayout() { + view_pager.viewTreeObserver.removeOnGlobalLayoutListener(this) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && isDestroyed) + return + + hideSystemUI() + mSlideshowInterval = config.slideshowInterval + mSlideshowMoveBackwards = config.slideshowMoveBackwards + mIsSlideshowActive = true + window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) + scheduleSwipe() + } + }) + } + } + + private fun stopSlideshow() { + if (mIsSlideshowActive) { + showSystemUI() + mIsSlideshowActive = false + mSlideshowHandler.removeCallbacksAndMessages(null) + window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) + } + } + + private fun scheduleSwipe() { + mSlideshowHandler.removeCallbacksAndMessages(null) + if (mIsSlideshowActive) { + if (getCurrentMedium()!!.isImage() || getCurrentMedium()!!.isGif()) { + mSlideshowHandler.postDelayed({ + if (mIsSlideshowActive && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && !isDestroyed) { + swipeToNextMedium() + } + }, mSlideshowInterval * 1000L) + } else { + (getCurrentFragment() as? VideoFragment)!!.playVideo() + } + } + } + + private fun swipeToNextMedium() { + val before = view_pager.currentItem + view_pager.currentItem = if (mSlideshowMoveBackwards) --view_pager.currentItem else ++view_pager.currentItem + if (before == view_pager.currentItem) { + stopSlideshow() + toast(R.string.slideshow_ended) + } + } + + private fun getMediaForSlideshow(): Boolean { + mSlideshowMedia = mMedia.toMutableList() + if (!config.slideshowIncludePhotos) { + mSlideshowMedia = mSlideshowMedia.filter { !it.isImage() && !it.isGif() } as MutableList + } + + if (!config.slideshowIncludeVideos) { + mSlideshowMedia = mSlideshowMedia.filter { it.isImage() || it.isGif() } as MutableList + } + + if (config.slideshowRandomOrder) { + Collections.shuffle(mSlideshowMedia) + mPos = 0 + } else { + mPath = getCurrentPath() + mPos = getPositionInList(mSlideshowMedia) + } + + return if (mSlideshowMedia.isEmpty()) { + toast(R.string.no_media_for_slideshow) + false + } else { + updatePagerItems(mSlideshowMedia) + mAreSlideShowMediaVisible = true + true + } + } + private fun copyMoveTo(isCopyOperation: Boolean) { val files = ArrayList(1).apply { add(getCurrentFile()) } tryCopyMoveFilesTo(files, isCopyOperation) { @@ -250,12 +361,48 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View getCurrentMedium()!!.apply { name = newFileName path = it.absolutePath - mMedia[mPos] = this + getCurrentMedia()[mPos] = this } invalidateOptionsMenu() } } + private fun rotateImage() { + val currentMedium = getCurrentMedium() ?: return + if (currentMedium.isJpg() && !isPathOnSD(currentMedium.path)) { + rotateByExif() + } else { + rotateByDegrees() + } + } + + private fun rotateByExif() { + val exif = ExifInterface(getCurrentPath()) + val rotation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL) + val newRotation = getNewRotation(rotation) + exif.setAttribute(ExifInterface.TAG_ORIENTATION, newRotation) + exif.saveAttributes() + File(getCurrentPath()).setLastModified(System.currentTimeMillis()) + (getCurrentFragment() as? PhotoFragment)?.refreshBitmap() + } + + private fun getNewRotation(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) + } + supportInvalidateOptionsMenu() + } + private fun saveImageAs() { val currPath = getCurrentPath() SaveAsDialog(this, currPath) { @@ -296,19 +443,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View out.close() } - private fun rotateImage(degrees: Float) { - mRotationDegrees = (mRotationDegrees + degrees) % 360 - getCurrentFragment()?.rotateImageViewBy(mRotationDegrees) - supportInvalidateOptionsMenu() - } - - private fun getCurrentFragment(): PhotoFragment? { - val fragment = (view_pager.adapter as MyPagerAdapter).getCurrentFragment(view_pager.currentItem) - return if (fragment is PhotoFragment) - fragment - else - null - } + private fun getCurrentFragment() = (view_pager.adapter as MyPagerAdapter).getCurrentFragment(view_pager.currentItem) private fun showProperties() { if (getCurrentMedium() != null) @@ -388,7 +523,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View private fun askConfirmDelete() { ConfirmationDialog(this) { - deleteFileBg(File(mMedia[mPos].path)) { + deleteFileBg(File(getCurrentMedia()[mPos].path)) { reloadViewPager() } } @@ -405,7 +540,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View private fun renameFile() { RenameItemDialog(this, getCurrentPath()) { - mMedia[mPos].path = it + getCurrentMedia()[mPos].path = it updateActionbarTitle() } } @@ -442,21 +577,21 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View mPrevHashcode = media.hashCode() mMedia = media if (mPos == -1) { - mPos = getProperPosition() + mPos = getPositionInList(media) } else { mPos = Math.min(mPos, mMedia.size - 1) } updateActionbarTitle() - updatePagerItems() + updatePagerItems(mMedia.toMutableList()) invalidateOptionsMenu() checkOrientation() } - private fun getProperPosition(): Int { + private fun getPositionInList(items: MutableList): Int { mPos = 0 var i = 0 - for (medium in mMedia) { + for (medium in items) { if (medium.path == mPath) { return i } @@ -487,37 +622,41 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View override fun fragmentClicked() { mIsFullScreen = !mIsFullScreen + checkSystemUI() + } + + override fun videoEnded(): Boolean { + if (mIsSlideshowActive) + swipeToNextMedium() + return mIsSlideshowActive + } + + private fun checkSystemUI() { if (mIsFullScreen) { hideSystemUI() } else { + stopSlideshow() showSystemUI() } } - override fun systemUiVisibilityChanged(visibility: Int) { - if (visibility and View.SYSTEM_UI_FLAG_FULLSCREEN == 0) { - mIsFullScreen = false - showSystemUI() - } else { - mIsFullScreen = true - } - } - private fun updateActionbarTitle() { runOnUiThread { - if (mPos < mMedia.size) { - title = mMedia[mPos].path.getFilenameFromPath() + if (mPos < getCurrentMedia().size) { + title = getCurrentMedia()[mPos].path.getFilenameFromPath() } } } private fun getCurrentMedium(): Medium? { - return if (mMedia.isEmpty() || mPos == -1) + return if (getCurrentMedia().isEmpty() || mPos == -1) null else - mMedia[Math.min(mPos, mMedia.size - 1)] + getCurrentMedia()[Math.min(mPos, getCurrentMedia().size - 1)] } + private fun getCurrentMedia() = if (mAreSlideShowMediaVisible) mSlideshowMedia else mMedia + private fun getCurrentPath() = getCurrentMedium()!!.path private fun getCurrentFile() = File(getCurrentPath()) @@ -534,6 +673,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View updateActionbarTitle() mRotationDegrees = 0f supportInvalidateOptionsMenu() + scheduleSwipe() } override fun onPageScrollStateChanged(state: Int) { diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/DirectoryAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/DirectoryAdapter.kt index 02abb93f7..3ef268ecf 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/DirectoryAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/DirectoryAdapter.kt @@ -1,11 +1,10 @@ package com.simplemobiletools.gallery.adapters -import android.os.Build +import android.graphics.PorterDuff import android.support.v7.view.ActionMode import android.support.v7.widget.RecyclerView import android.util.SparseArray import android.view.* -import android.widget.FrameLayout import com.bignerdranch.android.multiselector.ModalMultiSelectorCallback import com.bignerdranch.android.multiselector.MultiSelector import com.bignerdranch.android.multiselector.SwappingHolder @@ -14,10 +13,7 @@ import com.google.gson.Gson import com.simplemobiletools.commons.dialogs.ConfirmationDialog import com.simplemobiletools.commons.dialogs.PropertiesDialog import com.simplemobiletools.commons.dialogs.RenameItemDialog -import com.simplemobiletools.commons.extensions.isAStorageRootFolder -import com.simplemobiletools.commons.extensions.isImageVideoGif -import com.simplemobiletools.commons.extensions.needsStupidWritePermissions -import com.simplemobiletools.commons.extensions.toast +import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.gallery.R import com.simplemobiletools.gallery.activities.SimpleActivity import com.simplemobiletools.gallery.dialogs.ExcludeFolderDialog @@ -26,12 +22,11 @@ import com.simplemobiletools.gallery.extensions.* 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_tmb.view.* import java.io.File import java.util.* -class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList, val listener: DirOperationsListener?, val itemClick: (Directory) -> Unit) : - RecyclerView.Adapter() { +class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList, val listener: DirOperationsListener?, val isPickIntent: Boolean, + val itemClick: (Directory) -> Unit) : RecyclerView.Adapter() { val multiSelector = MultiSelector() val config = activity.config @@ -39,50 +34,30 @@ class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList() val selectedPositions = HashSet() - var foregroundColor = 0 + var primaryColor = config.primaryColor var pinnedFolders = config.pinnedFolders var scrollVertically = !config.scrollHorizontally fun toggleItemSelection(select: Boolean, pos: Int) { - if (itemViews[pos] != null) - getProperView(itemViews[pos]!!).isSelected = select - - if (select) + if (select) { + itemViews[pos]?.dir_check?.background?.setColorFilter(primaryColor, PorterDuff.Mode.SRC_IN) selectedPositions.add(pos) - else + } else selectedPositions.remove(pos) + itemViews[pos]?.dir_check?.beVisibleIf(select) + if (selectedPositions.isEmpty()) { actMode?.finish() return } updateTitle(selectedPositions.size) - actMode?.invalidate() - } - - fun getProperView(itemView: View): View { - return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) - itemView.dir_frame - else - itemView.dir_thumbnail } fun updateTitle(cnt: Int) { actMode?.title = "$cnt / ${dirs.size}" - } - - fun updatePrimaryColor(color: Int) { - foregroundColor = color - (0..itemViews.size() - 1).mapNotNull { itemViews[it] } - .forEach { setupItemViewForeground(it) } - } - - private fun setupItemViewForeground(itemView: View) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) - (getProperView(itemView) as FrameLayout).foreground = foregroundColor.createSelector() - else - getProperView(itemView).foreground = foregroundColor.createSelector() + actMode?.invalidate() } val adapterListener = object : MyAdapterListener { @@ -90,17 +65,9 @@ class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList = selectedPositions } - init { - foregroundColor = config.primaryColor - } - val multiSelectorMode = object : ModalMultiSelectorCallback(multiSelector) { override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean { when (item.itemId) { @@ -142,8 +109,7 @@ class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList it) { + val directory = dirs[it] + folders.add(File(directory.path)) + removeFolders.add(directory) + notifyItemRemoved(it) + itemViews.put(it, null) + } } dirs.removeAll(removeFolders) @@ -362,7 +329,7 @@ class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList (Unit)) : + 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 { itemView.apply { dir_name.text = directory.name photo_cnt.text = directory.mediaCnt.toString() - dir_pin.visibility = if (isPinned) View.VISIBLE else View.GONE activity.loadImage(directory.tmb, dir_thumbnail, scrollVertically) + dir_pin.beVisibleIf(isPinned) + dir_sd_card.beVisibleIf(activity.isPathOnSD(directory.path)) setOnClickListener { viewClicked(directory) } - setOnLongClickListener { viewLongClicked(); true } + setOnLongClickListener { if (isPickIntent) viewClicked(directory) else viewLongClicked(); true } + - adapter.setupItemForeground(this) } return itemView } fun viewClicked(directory: Directory) { if (multiSelector.isSelectable) { - val isSelected = adapter.getSelectedPositions().contains(layoutPosition) - adapter.toggleItemSelectionAdapter(!isSelected, layoutPosition) + val isSelected = adapterListener.getSelectedPositions().contains(layoutPosition) + adapterListener.toggleItemSelectionAdapter(!isSelected, layoutPosition) } else { itemClick(directory) } @@ -454,7 +422,7 @@ class DirectoryAdapter(val activity: SimpleActivity, var dirs: MutableList } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/MediaAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/MediaAdapter.kt index 1f0d72042..9cbe8915e 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/MediaAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/MediaAdapter.kt @@ -1,11 +1,10 @@ package com.simplemobiletools.gallery.adapters -import android.os.Build +import android.graphics.PorterDuff import android.support.v7.view.ActionMode import android.support.v7.widget.RecyclerView import android.util.SparseArray import android.view.* -import android.widget.FrameLayout import com.bignerdranch.android.multiselector.ModalMultiSelectorCallback import com.bignerdranch.android.multiselector.MultiSelector import com.bignerdranch.android.multiselector.SwappingHolder @@ -13,18 +12,18 @@ import com.bumptech.glide.Glide import com.simplemobiletools.commons.dialogs.ConfirmationDialog import com.simplemobiletools.commons.dialogs.PropertiesDialog import com.simplemobiletools.commons.dialogs.RenameItemDialog +import com.simplemobiletools.commons.extensions.beGone 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.models.Medium import kotlinx.android.synthetic.main.photo_video_item.view.* -import kotlinx.android.synthetic.main.photo_video_tmb.view.* import java.io.File import java.util.* -class MediaAdapter(val activity: SimpleActivity, var media: MutableList, val listener: MediaOperationsListener?, val itemClick: (Medium) -> Unit) : - RecyclerView.Adapter() { +class MediaAdapter(val activity: SimpleActivity, var media: MutableList, val listener: MediaOperationsListener?, val isPickIntent: Boolean, + val itemClick: (Medium) -> Unit) : RecyclerView.Adapter() { val multiSelector = MultiSelector() val config = activity.config @@ -32,50 +31,30 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList, var actMode: ActionMode? = null var itemViews = SparseArray() val selectedPositions = HashSet() - var foregroundColor = 0 + var primaryColor = config.primaryColor var displayFilenames = config.displayFileNames var scrollVertically = !config.scrollHorizontally fun toggleItemSelection(select: Boolean, pos: Int) { - if (itemViews[pos] != null) - getProperView(itemViews[pos]!!).isSelected = select - - if (select) + if (select) { + itemViews[pos]?.medium_check?.background?.setColorFilter(primaryColor, PorterDuff.Mode.SRC_IN) selectedPositions.add(pos) - else + } else selectedPositions.remove(pos) + itemViews[pos]?.medium_check?.beVisibleIf(select) + if (selectedPositions.isEmpty()) { actMode?.finish() return } updateTitle(selectedPositions.size) - actMode?.invalidate() - } - - fun getProperView(itemView: View): View { - return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) - itemView.medium_thumbnail_holder - else - itemView.medium_thumbnail } fun updateTitle(cnt: Int) { actMode?.title = "$cnt / ${media.size}" - } - - fun updatePrimaryColor(color: Int) { - foregroundColor = color - (0..itemViews.size() - 1).mapNotNull { itemViews[it] } - .forEach { setupItemViewForeground(it) } - } - - private fun setupItemViewForeground(itemView: View) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) - (getProperView(itemView) as FrameLayout).foreground = foregroundColor.createSelector() - else - getProperView(itemView).foreground = foregroundColor.createSelector() + actMode?.invalidate() } val adapterListener = object : MyAdapterListener { @@ -83,17 +62,9 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList, toggleItemSelection(select, position) } - override fun setupItemForeground(itemView: View) { - setupItemViewForeground(itemView) - } - override fun getSelectedPositions(): HashSet = selectedPositions } - init { - foregroundColor = config.primaryColor - } - val multiSelectorMode = object : ModalMultiSelectorCallback(multiSelector) { override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean { when (item.itemId) { @@ -131,8 +102,7 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList, override fun onDestroyActionMode(actionMode: ActionMode?) { super.onDestroyActionMode(actionMode) selectedPositions.forEach { - if (itemViews[it] != null) - getProperView(itemViews[it]!!).isSelected = false + itemViews[it]?.medium_check?.beGone() } selectedPositions.clear() actMode = null @@ -218,7 +188,6 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList, notifyItemChanged(i) } updateTitle(cnt) - actMode?.invalidate() } private fun askConfirmDelete() { @@ -237,6 +206,11 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList, val files = ArrayList(selectedPositions.size) val removeMedia = ArrayList(selectedPositions.size) + if (media.size <= selectedPositions.first()) { + actMode?.finish() + return + } + activity.handleSAFDialog(File(media[selectedPositions.first()].path)) { selectedPositions.sortedDescending().forEach { val medium = media[it] @@ -271,7 +245,7 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList, 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, itemClick) + return ViewHolder(view, adapterListener, activity, multiSelectorMode, multiSelector, listener, isPickIntent, itemClick) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { @@ -336,8 +310,9 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList, } } - class ViewHolder(val view: View, val adapter: MyAdapterListener, val activity: SimpleActivity, val multiSelectorCallback: ModalMultiSelectorCallback, - val multiSelector: MultiSelector, val listener: MediaOperationsListener?, val itemClick: (Medium) -> (Unit)) : SwappingHolder(view, MultiSelector()) { + 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)) : + SwappingHolder(view, MultiSelector()) { fun bindView(medium: Medium, displayFilenames: Boolean, scrollVertically: Boolean): View { itemView.apply { play_outline.visibility = if (medium.video) View.VISIBLE else View.GONE @@ -346,17 +321,15 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList, activity.loadImage(medium.path, medium_thumbnail, scrollVertically) setOnClickListener { viewClicked(medium) } - setOnLongClickListener { viewLongClicked(); true } - - adapter.setupItemForeground(this) + setOnLongClickListener { if (isPickIntent) viewClicked(medium) else viewLongClicked(); true } } return itemView } fun viewClicked(medium: Medium) { if (multiSelector.isSelectable) { - val isSelected = adapter.getSelectedPositions().contains(layoutPosition) - adapter.toggleItemSelectionAdapter(!isSelected, layoutPosition) + val isSelected = adapterListener.getSelectedPositions().contains(layoutPosition) + adapterListener.toggleItemSelectionAdapter(!isSelected, layoutPosition) } else { itemClick(medium) } @@ -366,7 +339,7 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList, if (listener != null) { if (!multiSelector.isSelectable) { activity.startSupportActionMode(multiSelectorCallback) - adapter.toggleItemSelectionAdapter(true, layoutPosition) + adapterListener.toggleItemSelectionAdapter(true, layoutPosition) } listener.itemLongClicked(layoutPosition) @@ -374,15 +347,14 @@ class MediaAdapter(val activity: SimpleActivity, var media: MutableList, } fun stopLoad() { - Glide.clear(view.medium_thumbnail) + if (!activity.isDestroyed) + Glide.with(activity).clear(view.medium_thumbnail) } } interface MyAdapterListener { fun toggleItemSelectionAdapter(select: Boolean, position: Int) - fun setupItemForeground(itemView: View) - fun getSelectedPositions(): HashSet } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/MyPagerAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/MyPagerAdapter.kt index fbd05d975..b7e5640ad 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/MyPagerAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/adapters/MyPagerAdapter.kt @@ -5,7 +5,6 @@ import android.support.v4.app.Fragment import android.support.v4.app.FragmentManager import android.support.v4.app.FragmentStatePagerAdapter import android.support.v4.view.PagerAdapter -import android.util.SparseArray import android.view.ViewGroup import com.simplemobiletools.gallery.activities.ViewPagerActivity import com.simplemobiletools.gallery.fragments.PhotoFragment @@ -15,7 +14,7 @@ import com.simplemobiletools.gallery.helpers.MEDIUM import com.simplemobiletools.gallery.models.Medium class MyPagerAdapter(val activity: ViewPagerActivity, fm: FragmentManager, val media: MutableList) : FragmentStatePagerAdapter(fm) { - private val mFragments = SparseArray() + private val mFragments = HashMap() override fun getCount() = media.size override fun getItem(position: Int): Fragment { @@ -43,10 +42,16 @@ class MyPagerAdapter(val activity: ViewPagerActivity, fm: FragmentManager, val m return fragment } - override fun destroyItem(container: ViewGroup?, position: Int, `object`: Any?) { + override fun destroyItem(container: ViewGroup?, position: Int, any: Any?) { mFragments.remove(position) - super.destroyItem(container, position, `object`) + super.destroyItem(container, position, any) } fun getCurrentFragment(position: Int) = mFragments.get(position) + + fun toggleFullscreen(isFullscreen: Boolean) { + for ((pos, fragment) in mFragments) { + fragment.fullscreenToggled(isFullscreen) + } + } } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/asynctasks/GetDirectoriesAsynctask.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/asynctasks/GetDirectoriesAsynctask.kt index 539e78e1e..ebc8182f0 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/asynctasks/GetDirectoriesAsynctask.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/asynctasks/GetDirectoriesAsynctask.kt @@ -27,8 +27,11 @@ class GetDirectoriesAsynctask(val context: Context, val isPickVideo: Boolean, va 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) } as ArrayList + val dirs = ArrayList(directories.values + .filter { File(it.path).exists() }) + .filter { shouldFolderBeVisible(it.path, excludedPaths, includedPaths) } as ArrayList Directory.sorting = config.directorySorting dirs.sort() return movePinnedToFront(dirs) @@ -43,8 +46,8 @@ class GetDirectoriesAsynctask(val context: Context, val isPickVideo: Boolean, va cancel(true) val parentDir = File(path).parent ?: continue - if (directories.containsKey(parentDir)) { - val directory = directories[parentDir]!! + if (directories.containsKey(parentDir.toLowerCase())) { + val directory = directories[parentDir.toLowerCase()]!! val newImageCnt = directory.mediaCnt + 1 directory.mediaCnt = newImageCnt directory.addSize(size) @@ -71,17 +74,17 @@ class GetDirectoriesAsynctask(val context: Context, val isPickVideo: Boolean, va } val directory = Directory(parentDir, thumbnail, dirName, 1, dateModified, dateTaken, size) - directories.put(parentDir, directory) + directories.put(parentDir.toLowerCase(), directory) } } return directories } - private fun shouldFolderBeVisible(path: String, excludedPaths: MutableSet): Boolean { + private fun shouldFolderBeVisible(path: String, excludedPaths: MutableSet, includedPaths: MutableSet): Boolean { val file = File(path) - return if (isThisOrParentExcluded(path, excludedPaths)) + return if (isThisOrParentExcluded(path, excludedPaths, includedPaths)) { false - else if (!config.shouldShowHidden && file.isDirectory && file.canonicalFile == file.absoluteFile) { + } else if (!config.shouldShowHidden && file.isDirectory && file.canonicalFile == file.absoluteFile) { var containsNoMediaOrDot = file.containsNoMedia() || path.contains("/.") if (!containsNoMediaOrDot) { containsNoMediaOrDot = checkParentHasNoMedia(file.parentFile) @@ -105,7 +108,8 @@ class GetDirectoriesAsynctask(val context: Context, val isPickVideo: Boolean, va return false } - private fun isThisOrParentExcluded(path: String, excludedPaths: MutableSet) = excludedPaths.any { path.startsWith(it) } + private fun isThisOrParentExcluded(path: String, excludedPaths: MutableSet, includedPaths: MutableSet) = + includedPaths.none { path.startsWith(it) } && excludedPaths.any { path.startsWith(it) } private fun movePinnedToFront(dirs: ArrayList): ArrayList { val foundFolders = ArrayList() diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/ChangeSortingDialog.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/ChangeSortingDialog.kt index f6516ee9b..f7020498d 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/ChangeSortingDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/ChangeSortingDialog.kt @@ -10,14 +10,13 @@ import com.simplemobiletools.commons.helpers.* import com.simplemobiletools.gallery.R import com.simplemobiletools.gallery.activities.SimpleActivity import com.simplemobiletools.gallery.extensions.config -import com.simplemobiletools.gallery.helpers.Config import kotlinx.android.synthetic.main.dialog_change_sorting.view.* class ChangeSortingDialog(val activity: SimpleActivity, val isDirectorySorting: Boolean, showFolderCheckbox: Boolean, val path: String = "", val callback: () -> Unit) : DialogInterface.OnClickListener { private var currSorting = 0 - private var config: Config = activity.config + private var config = activity.config private var view: View init { @@ -85,6 +84,6 @@ class ChangeSortingDialog(val activity: SimpleActivity, val isDirectorySorting: config.fileSorting = sorting } } - callback.invoke() + callback() } } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/ExcludeFolderDialog.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/ExcludeFolderDialog.kt index 936433cb3..ea386870f 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/ExcludeFolderDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/ExcludeFolderDialog.kt @@ -14,7 +14,6 @@ import com.simplemobiletools.gallery.extensions.config import kotlinx.android.synthetic.main.dialog_exclude_folder.view.* class ExcludeFolderDialog(val activity: SimpleActivity, val selectedPaths: List, val callback: () -> Unit) { - var dialog: AlertDialog? = null val alternativePaths = getAlternativePathsList() var radioGroup: RadioGroup? = null @@ -46,7 +45,7 @@ class ExcludeFolderDialog(val activity: SimpleActivity, val selectedPaths: List< private fun dialogConfirmed() { val path = if (alternativePaths.isEmpty()) selectedPaths[0] else alternativePaths[radioGroup!!.checkedRadioButtonId] activity.config.addExcludedFolder(path) - callback.invoke() + callback() } private fun getAlternativePathsList(): List { diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/PickDirectoryDialog.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/PickDirectoryDialog.kt index cf384829e..39d0ca7f2 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/PickDirectoryDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/PickDirectoryDialog.kt @@ -1,9 +1,12 @@ package com.simplemobiletools.gallery.dialogs import android.support.v7.app.AlertDialog -import android.support.v7.widget.RecyclerView +import android.support.v7.widget.GridLayoutManager import android.view.LayoutInflater +import android.view.View import com.simplemobiletools.commons.dialogs.FilePickerDialog +import com.simplemobiletools.commons.extensions.beGoneIf +import com.simplemobiletools.commons.extensions.beVisibleIf import com.simplemobiletools.commons.extensions.setupDialogStuff import com.simplemobiletools.commons.extensions.toast import com.simplemobiletools.gallery.R @@ -17,12 +20,14 @@ import kotlinx.android.synthetic.main.dialog_directory_picker.view.* class PickDirectoryDialog(val activity: SimpleActivity, val sourcePath: String, val callback: (path: String) -> Unit) { var dialog: AlertDialog - var directoriesGrid: RecyclerView var shownDirectories: ArrayList = ArrayList() + var view: View = LayoutInflater.from(activity).inflate(R.layout.dialog_directory_picker, null) init { - val view = LayoutInflater.from(activity).inflate(R.layout.dialog_directory_picker, null) - directoriesGrid = view.directories_grid + (view.directories_grid.layoutManager as GridLayoutManager).apply { + orientation = if (activity.config.scrollHorizontally) GridLayoutManager.HORIZONTAL else GridLayoutManager.VERTICAL + spanCount = activity.config.dirColumnCnt + } dialog = AlertDialog.Builder(activity) .setPositiveButton(R.string.ok, null) @@ -45,7 +50,7 @@ class PickDirectoryDialog(val activity: SimpleActivity, val sourcePath: String, fun showOtherFolder() { val showHidden = activity.config.shouldShowHidden FilePickerDialog(activity, sourcePath, false, showHidden, true) { - callback.invoke(it) + callback(it) } } @@ -54,15 +59,31 @@ class PickDirectoryDialog(val activity: SimpleActivity, val sourcePath: String, return shownDirectories = directories - val adapter = DirectoryAdapter(activity, directories, null) { + val adapter = DirectoryAdapter(activity, directories, null, true) { if (it.path.trimEnd('/') == sourcePath) { activity.toast(R.string.source_and_destination_same) return@DirectoryAdapter } else { - callback.invoke(it.path) + callback(it.path) dialog.dismiss() } } - directoriesGrid.adapter = adapter + + val scrollHorizontally = activity.config.scrollHorizontally + view.apply { + directories_grid.adapter = adapter + + directories_vertical_fastscroller.isHorizontal = false + directories_vertical_fastscroller.beGoneIf(scrollHorizontally) + + directories_horizontal_fastscroller.isHorizontal = true + directories_horizontal_fastscroller.beVisibleIf(scrollHorizontally) + + if (scrollHorizontally) { + directories_horizontal_fastscroller.setViews(directories_grid) + } else { + directories_vertical_fastscroller.setViews(directories_grid) + } + } } } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/PickMediumDialog.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/PickMediumDialog.kt index 8d2bacf2b..4c57c68f1 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/PickMediumDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/PickMediumDialog.kt @@ -47,7 +47,7 @@ class PickMediumDialog(val activity: SimpleActivity, val path: String, val callb return shownMedia = media - val adapter = MediaAdapter(activity, media, null) { + val adapter = MediaAdapter(activity, media, null, true) { callback(it.path) dialog.dismiss() } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/ResizeDialog.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/ResizeDialog.kt index 0d339dcc8..c82c5fdce 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/ResizeDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/ResizeDialog.kt @@ -84,7 +84,7 @@ class ResizeDialog(val activity: SimpleActivity, val size: Point, val callback: } val newSize = Point(getViewValue(widthView), getViewValue(heightView)) - callback.invoke(newSize) + callback(newSize) dismiss() }) } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/SaveAsDialog.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/SaveAsDialog.kt index 3a5bd3320..503e0f741 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/SaveAsDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/SaveAsDialog.kt @@ -66,11 +66,11 @@ class SaveAsDialog(val activity: SimpleActivity, val path: String, val callback: if (newFile.exists()) { val title = String.format(activity.getString(R.string.file_already_exists_overwrite), newFile.name) ConfirmationDialog(activity, title) { - callback.invoke(newFile.absolutePath) + callback(newFile.absolutePath) dismiss() } } else { - callback.invoke(newFile.absolutePath) + callback(newFile.absolutePath) dismiss() } }) diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/SlideshowDialog.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/SlideshowDialog.kt new file mode 100644 index 000000000..f28d8ef62 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/dialogs/SlideshowDialog.kt @@ -0,0 +1,99 @@ +package com.simplemobiletools.gallery.dialogs + +import android.support.v7.app.AlertDialog +import android.view.LayoutInflater +import android.view.View +import android.view.WindowManager +import com.simplemobiletools.commons.extensions.hideKeyboard +import com.simplemobiletools.commons.extensions.setupDialogStuff +import com.simplemobiletools.gallery.R +import com.simplemobiletools.gallery.activities.SimpleActivity +import com.simplemobiletools.gallery.extensions.config +import com.simplemobiletools.gallery.helpers.SLIDESHOW_DEFAULT_INTERVAL +import kotlinx.android.synthetic.main.dialog_slideshow.view.* + + +class SlideshowDialog(val activity: SimpleActivity, val callback: () -> Unit) { + val dialog: AlertDialog + val view: View + + init { + view = LayoutInflater.from(activity).inflate(R.layout.dialog_slideshow, null).apply { + interval_value.setOnClickListener { + val text = interval_value.text + if (text.isNotEmpty()) { + text.replace(0, 1, text.subSequence(0, 1), 0, 1) + interval_value.selectAll() + } + } + + interval_value.setOnFocusChangeListener { v, hasFocus -> + if (!hasFocus) + activity.hideKeyboard(v) + } + + include_photos_holder.setOnClickListener { + interval_value.clearFocus() + include_photos.toggle() + } + + include_videos_holder.setOnClickListener { + interval_value.clearFocus() + include_videos.toggle() + } + + random_order_holder.setOnClickListener { + interval_value.clearFocus() + random_order.toggle() + } + + use_fade_holder.setOnClickListener { + interval_value.clearFocus() + use_fade.toggle() + } + + move_backwards_holder.setOnClickListener { + interval_value.clearFocus() + move_backwards.toggle() + } + } + setupValues() + + dialog = AlertDialog.Builder(activity) + .setPositiveButton(R.string.ok, { dialog, which -> dialogConfirmed() }) + .setNegativeButton(R.string.cancel, null) + .create().apply { + window!!.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN) + activity.setupDialogStuff(view, this) + } + } + + private fun setupValues() { + val config = activity.config + view.apply { + interval_value.setText(config.slideshowInterval.toString()) + include_photos.isChecked = config.slideshowIncludePhotos + include_videos.isChecked = config.slideshowIncludeVideos + random_order.isChecked = config.slideshowRandomOrder + use_fade.isChecked = config.slideshowUseFade + move_backwards.isChecked = config.slideshowMoveBackwards + } + } + + private fun dialogConfirmed() { + var interval = view.interval_value.text.toString() + if (interval.trim('0').isEmpty()) + interval = SLIDESHOW_DEFAULT_INTERVAL.toString() + + activity.config.apply { + slideshowInterval = interval.toInt() + slideshowIncludePhotos = view.include_photos.isChecked + slideshowIncludeVideos = view.include_videos.isChecked + slideshowRandomOrder = view.random_order.isChecked + slideshowUseFade = view.use_fade.isChecked + slideshowMoveBackwards = view.move_backwards.isChecked + } + dialog.dismiss() + callback() + } +} diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/Int.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/Int.kt deleted file mode 100644 index 064c348b6..000000000 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/Int.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.simplemobiletools.gallery.extensions - -import android.content.res.ColorStateList -import android.graphics.Color -import android.graphics.drawable.ColorDrawable -import android.graphics.drawable.RippleDrawable -import android.graphics.drawable.StateListDrawable -import android.os.Build -import com.simplemobiletools.commons.extensions.adjustAlpha - -fun Int.createSelector(): StateListDrawable { - val statelist = StateListDrawable() - val selectedDrawable = ColorDrawable(adjustAlpha(0.5f)) - statelist.addState(intArrayOf(android.R.attr.state_selected), selectedDrawable) - - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - val pressedDrawable = ColorDrawable(adjustAlpha(0.2f)) - statelist.addState(intArrayOf(android.R.attr.state_pressed), pressedDrawable) - } else { - val pressedDrawable = RippleDrawable(ColorStateList.valueOf(adjustAlpha(0.2f)), null, ColorDrawable(Color.WHITE)) - statelist.addState(intArrayOf(), pressedDrawable) - } - return statelist -} diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/activity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/activity.kt index cc9125a8e..ddb92198c 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/activity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/activity.kt @@ -15,7 +15,8 @@ import android.view.ViewConfiguration import com.bumptech.glide.Glide import com.bumptech.glide.load.DecodeFormat import com.bumptech.glide.load.engine.DiskCacheStrategy -import com.bumptech.glide.signature.StringSignature +import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions +import com.bumptech.glide.request.RequestOptions import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.simplemobiletools.commons.extensions.* @@ -194,7 +195,7 @@ fun Activity.launchCamera() { fun SimpleActivity.launchAbout() { startAboutActivity(R.string.app_name, LICENSE_KOTLIN or LICENSE_GLIDE or LICENSE_CROPPER or LICENSE_MULTISELECT or LICENSE_RTL - or LICENSE_PHOTOVIEW or LICENSE_SUBSAMPLING, BuildConfig.VERSION_NAME) + or LICENSE_PHOTOVIEW or LICENSE_SUBSAMPLING or LICENSE_PATTERN, BuildConfig.VERSION_NAME) } fun AppCompatActivity.showSystemUI() { @@ -262,8 +263,6 @@ fun SimpleActivity.toggleFileVisibility(oldFile: File, hide: Boolean, callback: } } -fun Activity.getFileSignature(path: String) = StringSignature(File(path).lastModified().toString()) - fun Activity.loadImage(path: String, target: MySquareImageView, verticalScroll: Boolean) { target.isVerticalScrolling = verticalScroll if (path.isImageFast() || path.isVideoFast()) { @@ -282,49 +281,55 @@ fun Activity.loadImage(path: String, target: MySquareImageView, verticalScroll: } fun Activity.loadPng(path: String, target: MySquareImageView) { - val builder = Glide.with(applicationContext) - .load(path) - .asBitmap() - .signature(getFileSignature(path)) - .diskCacheStrategy(DiskCacheStrategy.RESULT) + val options = RequestOptions() + .signature(path.getFileSignature()) + .diskCacheStrategy(DiskCacheStrategy.RESOURCE) .format(DecodeFormat.PREFER_ARGB_8888) - if (config.cropThumbnails) builder.centerCrop() else builder.fitCenter() - builder.into(target) + val builder = Glide.with(applicationContext) + .asBitmap() + .load(path) + + if (config.cropThumbnails) options.centerCrop() else options.fitCenter() + builder.apply(options).into(target) } fun Activity.loadJpg(path: String, target: MySquareImageView) { + val options = RequestOptions() + .signature(path.getFileSignature()) + .diskCacheStrategy(DiskCacheStrategy.RESOURCE) + val builder = Glide.with(applicationContext) .load(path) - .signature(getFileSignature(path)) - .diskCacheStrategy(DiskCacheStrategy.RESULT) - .crossFade() - if (config.cropThumbnails) builder.centerCrop() else builder.fitCenter() - builder.into(target) + if (config.cropThumbnails) options.centerCrop() else options.fitCenter() + builder.apply(options).transition(DrawableTransitionOptions.withCrossFade()).into(target) } fun Activity.loadAnimatedGif(path: String, target: MySquareImageView) { - val builder = Glide.with(applicationContext) - .load(path) - .asGif() - .signature(getFileSignature(path)) + val options = RequestOptions() + .signature(path.getFileSignature()) .diskCacheStrategy(DiskCacheStrategy.NONE) - .crossFade() - if (config.cropThumbnails) builder.centerCrop() else builder.fitCenter() - builder.into(target) + val builder = Glide.with(applicationContext) + .asGif() + .load(path) + + if (config.cropThumbnails) options.centerCrop() else options.fitCenter() + builder.apply(options).transition(DrawableTransitionOptions.withCrossFade()).into(target) } fun Activity.loadStaticGif(path: String, target: MySquareImageView) { - val builder = Glide.with(applicationContext) - .load(path) - .asBitmap() - .signature(getFileSignature(path)) - .diskCacheStrategy(DiskCacheStrategy.SOURCE) + val options = RequestOptions() + .signature(path.getFileSignature()) + .diskCacheStrategy(DiskCacheStrategy.DATA) - if (config.cropThumbnails) builder.centerCrop() else builder.fitCenter() - builder.into(target) + val builder = Glide.with(applicationContext) + .asBitmap() + .load(path) + + if (config.cropThumbnails) options.centerCrop() else options.fitCenter() + builder.apply(options).into(target) } fun Activity.getCachedDirectories(): ArrayList { diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/context.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/context.kt index ebbf2772f..2fd607c32 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/context.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/context.kt @@ -4,6 +4,7 @@ import android.content.Context import android.content.Intent import android.content.res.Configuration import android.database.Cursor +import android.media.AudioManager import android.net.Uri import android.provider.MediaStore import com.simplemobiletools.commons.extensions.* @@ -21,6 +22,7 @@ import java.io.File import java.util.* val Context.portrait get() = resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT +val Context.audioManager get() = getSystemService(Context.AUDIO_SERVICE) as AudioManager fun Context.getRealPathFromURI(uri: Uri): String? { var cursor: Cursor? = null @@ -73,6 +75,7 @@ private fun parseCursor(context: Context, cur: Cursor, isPickImage: Boolean, isP val config = context.config val showMedia = config.showMedia val showHidden = config.shouldShowHidden + val includedFolders = config.includedFolders val excludedFolders = config.excludedFolders val noMediaFolders = context.getNoMediaFolders() @@ -111,14 +114,19 @@ private fun parseCursor(context: Context, cur: Cursor, isPickImage: Boolean, isP var isExcluded = false excludedFolders.forEach { - if (path.startsWith(it)) { + if (path.startsWith("$it/")) { isExcluded = true + includedFolders.forEach { + if (path.startsWith("$it/")) { + isExcluded = false + } + } } } if (!isExcluded && !showHidden) { noMediaFolders.forEach { - if (path.startsWith(it)) { + if (path.startsWith("$it/")) { isExcluded = true } } @@ -142,7 +150,7 @@ private fun parseCursor(context: Context, cur: Cursor, isPickImage: Boolean, isP } } - config.includedFolders.filter { it.isEmpty() || it == curPath }.mapNotNull { File(it).listFiles() }.forEach { + config.includedFolders.filter { it.isNotEmpty() && (curPath.isEmpty() || it == curPath) }.mapNotNull { File(it).listFiles() }.forEach { for (file in it) { val size = file.length() if (size <= 0L) { diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/string.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/string.kt new file mode 100644 index 000000000..47837c672 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/string.kt @@ -0,0 +1,6 @@ +package com.simplemobiletools.gallery.extensions + +import com.bumptech.glide.signature.ObjectKey +import java.io.File + +fun String.getFileSignature() = ObjectKey(File(this).lastModified().toString()) diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/PhotoFragment.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/PhotoFragment.kt index 7f82ae47f..3d634a516 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/PhotoFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/PhotoFragment.kt @@ -7,15 +7,20 @@ import android.graphics.Color import android.graphics.Matrix import android.graphics.drawable.ColorDrawable import android.net.Uri +import android.os.Build import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import com.bumptech.glide.Glide import com.bumptech.glide.Priority +import com.bumptech.glide.load.DataSource import com.bumptech.glide.load.DecodeFormat import com.bumptech.glide.load.engine.DiskCacheStrategy +import com.bumptech.glide.load.engine.GlideException +import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions import com.bumptech.glide.request.RequestListener +import com.bumptech.glide.request.RequestOptions import com.bumptech.glide.request.target.Target import com.davemorrissey.labs.subscaleview.ImageSource import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView @@ -33,7 +38,6 @@ import com.simplemobiletools.gallery.helpers.MEDIUM import com.simplemobiletools.gallery.models.Medium import it.sephiroth.android.library.exif2.ExifInterface import kotlinx.android.synthetic.main.pager_photo_item.view.* -import uk.co.senab.photoview.PhotoViewAttacher import java.io.File import java.io.FileOutputStream import java.io.IOException @@ -43,7 +47,6 @@ class PhotoFragment : ViewPagerFragment() { lateinit var view: ViewGroup private var isFragmentVisible = false private var wasInit = false - private var RATIO_THRESHOLD = 0.1 override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { view = inflater.inflate(R.layout.pager_photo_item, container, false) as ViewGroup @@ -89,21 +92,16 @@ class PhotoFragment : ViewPagerFragment() { view.photo_view.apply { maximumScale = 8f mediumScale = 3f - setOnPhotoTapListener(object : PhotoViewAttacher.OnPhotoTapListener { - override fun onPhotoTap(view: View?, x: Float, y: Float) { - photoClicked() - } + setOnOutsidePhotoTapListener { + photoClicked() + } - override fun onOutsidePhotoTap() { - photoClicked() - } - }) + setOnPhotoTapListener { view, x, y -> + photoClicked() + } } loadImage() - activity.window.decorView.setOnSystemUiVisibilityChangeListener { visibility -> - listener?.systemUiVisibilityChanged(visibility) - } wasInit = true return view @@ -147,12 +145,15 @@ class PhotoFragment : ViewPagerFragment() { private fun loadImage() { if (medium.isGif()) { - Glide.with(this) - .load(medium.path) - .asGif() - .crossFade() + val options = RequestOptions() .priority(if (isFragmentVisible) Priority.IMMEDIATE else Priority.LOW) - .diskCacheStrategy(DiskCacheStrategy.SOURCE) + .diskCacheStrategy(DiskCacheStrategy.DATA) + + Glide.with(this) + .asGif() + .load(medium.path) + .transition(DrawableTransitionOptions.withCrossFade()) + .apply(options) .into(view.photo_view) } else { loadBitmap() @@ -164,31 +165,37 @@ class PhotoFragment : ViewPagerFragment() { val targetWidth = if (ViewPagerActivity.screenWidth == 0) Target.SIZE_ORIGINAL else ViewPagerActivity.screenWidth val targetHeight = if (ViewPagerActivity.screenHeight == 0) Target.SIZE_ORIGINAL else ViewPagerActivity.screenHeight - Glide.with(this) - .load(medium.path) - .asBitmap() - .signature(activity.getFileSignature(medium.path)) - .format(if (medium.isPng()) DecodeFormat.PREFER_ARGB_8888 else DecodeFormat.PREFER_RGB_565) + val options = RequestOptions() + .signature(medium.path.getFileSignature()) + .format(DecodeFormat.PREFER_ARGB_8888) .diskCacheStrategy(DiskCacheStrategy.NONE) .override(targetWidth, targetHeight) - .listener(object : RequestListener { - override fun onException(e: Exception?, model: String?, target: Target?, isFirstResource: Boolean): Boolean { + + Glide.with(this) + .asBitmap() + .load(medium.path) + .apply(options) + .listener(object : RequestListener { + override fun onLoadFailed(e: GlideException?, model: Any?, target: Target?, isFirstResource: Boolean): Boolean { return false } - override fun onResourceReady(resource: Bitmap, model: String?, target: Target?, isFromMemoryCache: Boolean, isFirstResource: Boolean): Boolean { + override fun onResourceReady(resource: Bitmap?, model: Any?, target: Target?, dataSource: DataSource?, isFirstResource: Boolean): Boolean { if (isFragmentVisible) addZoomableView() return false } }).into(view.photo_view) } else { - Glide.with(this) - .load(medium.path) - .asBitmap() - .transform(GlideRotateTransformation(context, degrees)) - .thumbnail(0.2f) + val options = RequestOptions() .diskCacheStrategy(DiskCacheStrategy.NONE) + .transform(GlideRotateTransformation(context, degrees)) + + Glide.with(this) + .asBitmap() + .load(medium.path) + .thumbnail(0.2f) + .apply(options) .into(view.photo_view) } } @@ -249,9 +256,9 @@ class PhotoFragment : ViewPagerFragment() { } } - override fun onDestroyView() { - super.onDestroyView() - Glide.clear(view.photo_view) + fun refreshBitmap() { + view.subsampling_view.beGone() + loadBitmap() } fun rotateImageViewBy(degrees: Float) { @@ -259,7 +266,14 @@ class PhotoFragment : ViewPagerFragment() { loadBitmap(degrees) } - override fun onConfigurationChanged(newConfig: Configuration?) { + override fun onDestroyView() { + super.onDestroyView() + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && !activity.isDestroyed) { + Glide.with(context).clear(view.photo_view) + } + } + + override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) loadImage() } @@ -267,4 +281,8 @@ class PhotoFragment : ViewPagerFragment() { private fun photoClicked() { listener?.fragmentClicked() } + + override fun fullscreenToggled(isFullscreen: Boolean) { + + } } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/VideoFragment.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/VideoFragment.kt index f9b3a604c..f93bc617e 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/VideoFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/VideoFragment.kt @@ -7,6 +7,7 @@ import android.net.Uri import android.os.Build import android.os.Bundle import android.os.Handler +import android.provider.Settings import android.util.DisplayMetrics import android.util.Log import android.view.* @@ -17,6 +18,8 @@ import com.simplemobiletools.commons.extensions.getFormattedDuration 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 @@ -26,6 +29,8 @@ import kotlinx.android.synthetic.main.pager_video_item.view.* import java.io.IOException class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSeekBarChangeListener { + private val CLICK_MAX_DURATION = 150 + private val SLIDE_INFO_FADE_DELAY = 1000L private var mMediaPlayer: MediaPlayer? = null private var mSurfaceView: SurfaceView? = null @@ -39,9 +44,21 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee private var mIsDragged = false private var mIsFullscreen = false private var mIsFragmentVisible = false + private var mPlayOnPrepare = false private var mCurrTime = 0 private var mDuration = 0 + private var mTouchDownX = 0f + private var mTouchDownY = 0f + private var mTouchDownTime = 0L + private var mTouchDownVolume = 0 + private var mTouchDownBrightness = -1 + private var mTempBrightness = 0 + private var mLastTouchY = 0f + + private var mSlideInfoText = "" + private var mSlideInfoFadeHandler = Handler() + lateinit var mView: View lateinit var medium: Medium @@ -60,13 +77,7 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee } mIsFullscreen = activity.window.decorView.systemUiVisibility and View.SYSTEM_UI_FLAG_FULLSCREEN == View.SYSTEM_UI_FLAG_FULLSCREEN - - activity.window.decorView.setOnSystemUiVisibilityChangeListener { visibility -> - val fullscreen = visibility and View.SYSTEM_UI_FLAG_FULLSCREEN != 0 - mIsFullscreen = fullscreen - checkFullscreen() - listener?.systemUiVisibilityChanged(visibility) - } + checkFullscreen() return mView } @@ -87,6 +98,15 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee mSurfaceHolder!!.addCallback(this) mSurfaceView!!.setOnClickListener({ toggleFullscreen() }) mView.video_holder.setOnClickListener { toggleFullscreen() } + mView.video_volume_controller.setOnTouchListener { v, event -> + handleVolumeTouched(event) + true + } + + mView.video_brightness_controller.setOnTouchListener { v, event -> + handleBrightnessTouched(event) + true + } initTimeHolder() } @@ -95,8 +115,9 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee super.setMenuVisibility(menuVisible) mIsFragmentVisible = menuVisible if (menuVisible) { - if (mSurfaceView != null) + if (mSurfaceView != null && mSurfaceHolder!!.surface.isValid) { initMediaPlayer() + } if (context?.config?.autoplayVideos == true) { playVideo() @@ -106,18 +127,135 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee } } - override fun onConfigurationChanged(newConfig: Configuration?) { + override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) setVideoSize() initTimeHolder() } private fun toggleFullscreen() { - mIsFullscreen = !mIsFullscreen - checkFullscreen() listener?.fragmentClicked() } + private fun handleVolumeTouched(event: MotionEvent) { + when (event.action) { + MotionEvent.ACTION_DOWN -> { + mTouchDownX = event.x + mTouchDownY = event.y + mLastTouchY = event.y + mTouchDownTime = System.currentTimeMillis() + mTouchDownVolume = getCurrentVolume() + mSlideInfoText = "${getString(R.string.volume)}:\n" + } + MotionEvent.ACTION_MOVE -> { + val diffX = mTouchDownX - event.x + val diffY = mTouchDownY - event.y + + if (Math.abs(diffY) > Math.abs(diffX)) { + var percent = ((diffY / ViewPagerActivity.screenHeight) * 100).toInt() * 3 + percent = Math.min(100, Math.max(-100, percent)) + + if ((percent == 100 && event.y > mLastTouchY) || (percent == -100 && event.y < mLastTouchY)) { + mTouchDownY = event.y + mTouchDownVolume = getCurrentVolume() + } + + volumePercentChanged(percent) + } + mLastTouchY = event.y + } + MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { + if (System.currentTimeMillis() - mTouchDownTime < CLICK_MAX_DURATION) { + mView.video_holder.performClick() + } + } + } + } + + private fun handleBrightnessTouched(event: MotionEvent) { + when (event.action) { + MotionEvent.ACTION_DOWN -> { + mTouchDownX = event.x + mTouchDownY = event.y + mLastTouchY = event.y + mTouchDownTime = System.currentTimeMillis() + mSlideInfoText = "${getString(R.string.brightness)}:\n" + if (mTouchDownBrightness == -1) + mTouchDownBrightness = getCurrentBrightness() + } + MotionEvent.ACTION_MOVE -> { + val diffX = mTouchDownX - event.x + val diffY = mTouchDownY - event.y + + if (Math.abs(diffY) > Math.abs(diffX)) { + var percent = ((diffY / ViewPagerActivity.screenHeight) * 100).toInt() * 3 + percent = Math.min(100, Math.max(-100, percent)) + + if ((percent == 100 && event.y > mLastTouchY) || (percent == -100 && event.y < mLastTouchY)) { + mTouchDownY = event.y + mTouchDownBrightness = mTempBrightness + } + + brightnessPercentChanged(percent) + } + mLastTouchY = event.y + } + MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { + if (System.currentTimeMillis() - mTouchDownTime < CLICK_MAX_DURATION) { + mView.video_holder.performClick() + } + mTouchDownBrightness = mTempBrightness + } + } + mView.video_holder + } + + private fun getCurrentVolume() = context.audioManager.getStreamVolume(AudioManager.STREAM_MUSIC) + + private fun getCurrentBrightness() = Settings.System.getInt(activity.contentResolver, Settings.System.SCREEN_BRIGHTNESS) + + private fun volumePercentChanged(percent: Int) { + val stream = AudioManager.STREAM_MUSIC + val maxVolume = context.audioManager.getStreamMaxVolume(stream) + val percentPerPoint = 100 / maxVolume + val addPoints = percent / percentPerPoint + val newVolume = Math.min(maxVolume, Math.max(0, mTouchDownVolume + addPoints)) + context.audioManager.setStreamVolume(stream, newVolume, 0) + + val absolutePercent = ((newVolume / maxVolume.toFloat()) * 100).toInt() + mView.slide_info.apply { + text = "$mSlideInfoText$absolutePercent%" + alpha = 1f + } + + mSlideInfoFadeHandler.removeCallbacksAndMessages(null) + mSlideInfoFadeHandler.postDelayed({ + mView.slide_info.animate().alpha(0f) + }, SLIDE_INFO_FADE_DELAY) + } + + private fun brightnessPercentChanged(percent: Int) { + val maxBrightness = 255f + var newBrightness = (mTouchDownBrightness + 2.55 * percent).toFloat() + newBrightness = Math.min(maxBrightness, Math.max(0f, newBrightness)) + mTempBrightness = newBrightness.toInt() + + val absolutePercent = ((newBrightness / maxBrightness) * 100).toInt() + mView.slide_info.apply { + text = "$mSlideInfoText$absolutePercent%" + alpha = 1f + } + + val attributes = activity.window.attributes + attributes.screenBrightness = absolutePercent / 100f + activity.window.attributes = attributes + + mSlideInfoFadeHandler.removeCallbacksAndMessages(null) + mSlideInfoFadeHandler.postDelayed({ + mView.slide_info.animate().alpha(0f) + }, SLIDE_INFO_FADE_DELAY) + } + private fun initTimeHolder() { mTimeHolder = mView.video_time_holder val res = resources @@ -201,9 +339,13 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee } } - private fun playVideo() { - mIsPlaying = true - mMediaPlayer?.start() + fun playVideo() { + if (mMediaPlayer != null) { + mIsPlaying = true + mMediaPlayer?.start() + } else { + mPlayOnPrepare = true + } mView.video_play_outline.setImageDrawable(null) activity.window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) } @@ -278,12 +420,12 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee setupTimeHolder() setProgress(mCurrTime) - if (mIsFragmentVisible && context.config.autoplayVideos) + if (mIsFragmentVisible && (context.config.autoplayVideos || mPlayOnPrepare)) playVideo() } private fun videoCompleted() { - if (context.config.loopVideos) { + if (listener?.videoEnded() == false && context.config.loopVideos) { playVideo() } else { mSeekBar!!.progress = mSeekBar!!.max @@ -366,9 +508,14 @@ class VideoFragment : ViewPagerFragment(), SurfaceHolder.Callback, SeekBar.OnSee if (!mIsPlaying) { togglePlayPause() } else { - mMediaPlayer!!.start() + mMediaPlayer?.start() } mIsDragged = false } + + override fun fullscreenToggled(isFullscreen: Boolean) { + mIsFullscreen = isFullscreen + checkFullscreen() + } } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/ViewPagerFragment.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/ViewPagerFragment.kt index bd6bc4a50..6121151ba 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/ViewPagerFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/ViewPagerFragment.kt @@ -5,9 +5,11 @@ import android.support.v4.app.Fragment abstract class ViewPagerFragment : Fragment() { var listener: FragmentListener? = null + abstract fun fullscreenToggled(isFullscreen: Boolean) + interface FragmentListener { fun fragmentClicked() - fun systemUiVisibilityChanged(visibility: Int) + fun videoEnded(): Boolean } } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/Config.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/Config.kt index b144682c4..167988674 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/Config.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/Config.kt @@ -224,4 +224,36 @@ class Config(context: Context) : BaseConfig(context) { var scrollHorizontally: Boolean get() = prefs.getBoolean(SCROLL_HORIZONTALLY, false) set(scrollHorizontally) = prefs.edit().putBoolean(SCROLL_HORIZONTALLY, scrollHorizontally).apply() + + var hideSystemUI: Boolean + get() = prefs.getBoolean(HIDE_SYSTEM_UI, false) + set(hideSystemUI) = prefs.edit().putBoolean(HIDE_SYSTEM_UI, hideSystemUI).apply() + + var replaceShare: Boolean + get() = prefs.getBoolean(REPLACE_SHARE_WITH_ROTATE, false) + set(replaceShare) = prefs.edit().putBoolean(REPLACE_SHARE_WITH_ROTATE, replaceShare).apply() + + var slideshowInterval: Int + get() = prefs.getInt(SLIDESHOW_INTERVAL, SLIDESHOW_DEFAULT_INTERVAL) + set(slideshowInterval) = prefs.edit().putInt(SLIDESHOW_INTERVAL, slideshowInterval).apply() + + var slideshowIncludePhotos: Boolean + get() = prefs.getBoolean(SLIDESHOW_INCLUDE_PHOTOS, true) + set(slideshowIncludePhotos) = prefs.edit().putBoolean(SLIDESHOW_INCLUDE_PHOTOS, slideshowIncludePhotos).apply() + + var slideshowIncludeVideos: Boolean + get() = prefs.getBoolean(SLIDESHOW_INCLUDE_VIDEOS, false) + set(slideshowIncludeVideos) = prefs.edit().putBoolean(SLIDESHOW_INCLUDE_VIDEOS, slideshowIncludeVideos).apply() + + var slideshowRandomOrder: Boolean + get() = prefs.getBoolean(SLIDESHOW_RANDOM_ORDER, false) + set(slideshowRandomOrder) = prefs.edit().putBoolean(SLIDESHOW_RANDOM_ORDER, slideshowRandomOrder).apply() + + var slideshowUseFade: Boolean + get() = prefs.getBoolean(SLIDESHOW_USE_FADE, false) + set(slideshowUseFade) = prefs.edit().putBoolean(SLIDESHOW_USE_FADE, slideshowUseFade).apply() + + var slideshowMoveBackwards: Boolean + get() = prefs.getBoolean(SLIDESHOW_MOVE_BACKWARDS, false) + set(slideshowMoveBackwards) = prefs.edit().putBoolean(SLIDESHOW_MOVE_BACKWARDS, slideshowMoveBackwards).apply() } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/Constants.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/Constants.kt index 70fe30c1b..3efd48714 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/Constants.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/Constants.kt @@ -31,6 +31,17 @@ val EXCLUDED_FOLDERS = "excluded_folders" val INCLUDED_FOLDERS = "included_folders" val ALBUM_COVERS = "album_covers" val SCROLL_HORIZONTALLY = "scroll_horizontally" +val HIDE_SYSTEM_UI = "hide_system_ui" +val REPLACE_SHARE_WITH_ROTATE = "replace_share_with_rotate" + +// slideshow +val SLIDESHOW_INTERVAL = "slideshow_interval" +val SLIDESHOW_INCLUDE_PHOTOS = "slideshow_include_photos" +val SLIDESHOW_INCLUDE_VIDEOS = "slideshow_include_videos" +val SLIDESHOW_RANDOM_ORDER = "slideshow_random_order" +val SLIDESHOW_USE_FADE = "slideshow_use_fade" +val SLIDESHOW_MOVE_BACKWARDS = "slideshow_move_backwards" +val SLIDESHOW_DEFAULT_INTERVAL = 5 val NOMEDIA = ".nomedia" diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/GlideRotateTransformation.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/GlideRotateTransformation.kt index 4e347dd9e..8a48b23f4 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/GlideRotateTransformation.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/helpers/GlideRotateTransformation.kt @@ -5,9 +5,9 @@ import android.graphics.Bitmap import android.graphics.Matrix import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool import com.bumptech.glide.load.resource.bitmap.BitmapTransformation +import java.security.MessageDigest class GlideRotateTransformation(context: Context, val rotateRotationAngle: Float) : BitmapTransformation(context) { - override fun transform(pool: BitmapPool, bitmap: Bitmap, outWidth: Int, outHeight: Int): Bitmap { if (rotateRotationAngle % 360 == 0f) return bitmap @@ -17,5 +17,6 @@ class GlideRotateTransformation(context: Context, val rotateRotationAngle: Float return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true) } - override fun getId() = "GlideRotateTransformation $rotateRotationAngle" + override fun updateDiskCacheKey(messageDigest: MessageDigest?) { + } } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/models/Directory.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/models/Directory.kt index 77cd94602..6293eba76 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/models/Directory.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/models/Directory.kt @@ -1,9 +1,6 @@ package com.simplemobiletools.gallery.models -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.commons.helpers.* import java.io.Serializable data class Directory(val path: String, val tmb: String, val name: String, var mediaCnt: Int, val modified: Long, val taken: Long, @@ -20,7 +17,7 @@ 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 = name.toLowerCase().compareTo(other.name.toLowerCase()) + result = AlphanumComparator().compare(name.toLowerCase(), other.name.toLowerCase()) } else if (sorting and SORT_BY_SIZE != 0) { result = if (size == other.size) 0 diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/models/Medium.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/models/Medium.kt index c9afe29f0..1663c60b1 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/models/Medium.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/models/Medium.kt @@ -3,10 +3,7 @@ package com.simplemobiletools.gallery.models import com.simplemobiletools.commons.extensions.getMimeType import com.simplemobiletools.commons.extensions.isGif import com.simplemobiletools.commons.extensions.isPng -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.commons.helpers.* import java.io.File import java.io.Serializable @@ -20,30 +17,32 @@ data class Medium(var name: String, var path: String, val video: Boolean, val mo fun isGif() = path.isGif() + fun isJpg() = path.endsWith(".jpg", true) || path.endsWith(".jpeg", true) + fun isImage() = !isGif() && !video fun getMimeType() = File(path).getMimeType() override fun compareTo(other: Medium): Int { - var res: Int + var result: Int if (sorting and SORT_BY_NAME != 0) { - res = name.toLowerCase().compareTo(other.name.toLowerCase()) + result = AlphanumComparator().compare(name.toLowerCase(), other.name.toLowerCase()) } else if (sorting and SORT_BY_SIZE != 0) { - res = if (size == other.size) + result = if (size == other.size) 0 else if (size > other.size) 1 else -1 } else if (sorting and SORT_BY_DATE_MODIFIED != 0) { - res = if (modified == other.modified) + result = if (modified == other.modified) 0 else if (modified > other.modified) 1 else -1 } else { - res = if (taken == other.taken) + result = if (taken == other.taken) 0 else if (taken > other.taken) 1 @@ -52,8 +51,8 @@ data class Medium(var name: String, var path: String, val video: Boolean, val mo } if (sorting and SORT_DESCENDING != 0) { - res *= -1 + result *= -1 } - return res + return result } } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/views/MyScalableRecyclerView.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/views/MyScalableRecyclerView.kt deleted file mode 100644 index 3b1a6add8..000000000 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/views/MyScalableRecyclerView.kt +++ /dev/null @@ -1,208 +0,0 @@ -package com.simplemobiletools.gallery.views - -import android.content.Context -import android.os.Handler -import android.support.v7.widget.RecyclerView -import android.util.AttributeSet -import android.view.MotionEvent -import android.view.ScaleGestureDetector -import com.simplemobiletools.gallery.R - -// drag selection is based on https://github.com/afollestad/drag-select-recyclerview -class MyScalableRecyclerView : RecyclerView { - private val AUTO_SCROLL_DELAY = 25L - - private var mScaleDetector: ScaleGestureDetector - - private var dragSelectActive = false - private var lastDraggedIndex = -1 - private var minReached = 0 - private var maxReached = 0 - private var initialSelection = 0 - - private var hotspotHeight = 0 - private var hotspotOffsetTop = 0 - private var hotspotOffsetBottom = 0 - - private var hotspotTopBoundStart = 0 - private var hotspotTopBoundEnd = 0 - private var hotspotBottomBoundStart = 0 - private var hotspotBottomBoundEnd = 0 - private var autoScrollVelocity = 0 - - private var inTopHotspot = false - private var inBottomHotspot = false - - companion object { - var mListener: MyScalableRecyclerViewListener? = null - var mCurrScaleFactor = 1.0f - var mLastUp = 0L // allow only pinch zoom, not double tap - } - - constructor(context: Context) : super(context) - - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) - - init { - hotspotHeight = context.resources.getDimensionPixelSize(R.dimen.dragselect_hotspot_height) - mScaleDetector = ScaleGestureDetector(context, GestureListener()) - } - - override fun onMeasure(widthSpec: Int, heightSpec: Int) { - super.onMeasure(widthSpec, heightSpec) - if (hotspotHeight > -1) { - hotspotTopBoundStart = hotspotOffsetTop - hotspotTopBoundEnd = hotspotOffsetTop + hotspotHeight - hotspotBottomBoundStart = measuredHeight - hotspotHeight - hotspotOffsetBottom - hotspotBottomBoundEnd = measuredHeight - hotspotOffsetBottom - } - } - - private var autoScrollHandler = Handler() - private val autoScrollRunnable = object : Runnable { - override fun run() { - if (inTopHotspot) { - scrollBy(0, -autoScrollVelocity) - autoScrollHandler.postDelayed(this, AUTO_SCROLL_DELAY) - } else if (inBottomHotspot) { - scrollBy(0, autoScrollVelocity) - autoScrollHandler.postDelayed(this, AUTO_SCROLL_DELAY) - } - } - } - - override fun dispatchTouchEvent(ev: MotionEvent): Boolean { - if (!dragSelectActive) - super.dispatchTouchEvent(ev) - - when (ev.action) { - MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { - dragSelectActive = false - inTopHotspot = false - inBottomHotspot = false - autoScrollHandler.removeCallbacks(autoScrollRunnable) - mCurrScaleFactor = 1.0f - mLastUp = System.currentTimeMillis() - return true - } - - MotionEvent.ACTION_MOVE -> { - if (dragSelectActive) { - val itemPosition = getItemPosition(ev) - if (hotspotHeight > -1) { - if (ev.y in hotspotTopBoundStart..hotspotTopBoundEnd) { - inBottomHotspot = false - if (!inTopHotspot) { - inTopHotspot = true - autoScrollHandler.removeCallbacks(autoScrollRunnable) - autoScrollHandler.postDelayed(autoScrollRunnable, AUTO_SCROLL_DELAY.toLong()) - } - - val simulatedFactor = (hotspotTopBoundEnd - hotspotTopBoundStart).toFloat() - val simulatedY = ev.y - hotspotTopBoundStart - autoScrollVelocity = (simulatedFactor - simulatedY).toInt() / 2 - } else if (ev.y in hotspotBottomBoundStart..hotspotBottomBoundEnd) { - inTopHotspot = false - if (!inBottomHotspot) { - inBottomHotspot = true - autoScrollHandler.removeCallbacks(autoScrollRunnable) - autoScrollHandler.postDelayed(autoScrollRunnable, AUTO_SCROLL_DELAY.toLong()) - } - - val simulatedY = ev.y + hotspotBottomBoundEnd - val simulatedFactor = (hotspotBottomBoundStart + hotspotBottomBoundEnd).toFloat() - autoScrollVelocity = (simulatedY - simulatedFactor).toInt() / 2 - } else if (inTopHotspot || inBottomHotspot) { - autoScrollHandler.removeCallbacks(autoScrollRunnable) - inTopHotspot = false - inBottomHotspot = false - } - } - - if (itemPosition != RecyclerView.NO_POSITION && lastDraggedIndex != itemPosition) { - lastDraggedIndex = itemPosition - if (minReached == -1) { - minReached = lastDraggedIndex - } - - if (maxReached == -1) { - maxReached = lastDraggedIndex - } - - if (lastDraggedIndex > maxReached) { - maxReached = lastDraggedIndex - } - - if (lastDraggedIndex < minReached) { - minReached = lastDraggedIndex - } - - mListener?.selectRange(initialSelection, lastDraggedIndex, minReached, maxReached) - - if (initialSelection == lastDraggedIndex) { - minReached = lastDraggedIndex - maxReached = lastDraggedIndex - } - } - - return true - } - } - } - return mScaleDetector.onTouchEvent(ev) - } - - fun setDragSelectActive(initialSelection: Int) { - if (dragSelectActive) - return - - lastDraggedIndex = -1 - minReached = -1 - maxReached = -1 - this.initialSelection = initialSelection - dragSelectActive = true - mListener?.selectItem(initialSelection) - } - - private fun getItemPosition(e: MotionEvent): Int { - val v = findChildViewUnder(e.x, e.y) ?: return RecyclerView.NO_POSITION - - if (v.tag == null || v.tag !is RecyclerView.ViewHolder) { - throw IllegalStateException("Make sure your adapter makes a call to super.onBindViewHolder(), and doesn't override itemView tags.") - } - - val holder = v.tag as RecyclerView.ViewHolder - return holder.adapterPosition - } - - - class GestureListener : ScaleGestureDetector.SimpleOnScaleGestureListener() { - private val ZOOM_IN_THRESHOLD = -0.4f - private val ZOOM_OUT_THRESHOLD = 0.15f - - override fun onScale(detector: ScaleGestureDetector): Boolean { - if (System.currentTimeMillis() - mLastUp < 1000) - return false - - val diff = mCurrScaleFactor - detector.scaleFactor - if (diff < ZOOM_IN_THRESHOLD && mCurrScaleFactor == 1.0f) { - mListener?.zoomIn() - mCurrScaleFactor = detector.scaleFactor - } else if (diff > ZOOM_OUT_THRESHOLD && mCurrScaleFactor == 1.0f) { - mListener?.zoomOut() - mCurrScaleFactor = detector.scaleFactor - } - return false - } - } - - interface MyScalableRecyclerViewListener { - fun zoomOut() - - fun zoomIn() - - fun selectItem(position: Int) - - fun selectRange(initialSelection: Int, lastDraggedIndex: Int, minReached: Int, maxReached: Int) - } -} diff --git a/app/src/main/res/drawable-hdpi/img_play_outline.png b/app/src/main/res/drawable-hdpi/img_play_outline.png index c5cf4f131..0aeace079 100644 Binary files a/app/src/main/res/drawable-hdpi/img_play_outline.png and b/app/src/main/res/drawable-hdpi/img_play_outline.png differ diff --git a/app/src/main/res/drawable-xhdpi/img_play_outline.png b/app/src/main/res/drawable-xhdpi/img_play_outline.png index 20fedaf45..d61aa4371 100644 Binary files a/app/src/main/res/drawable-xhdpi/img_play_outline.png and b/app/src/main/res/drawable-xhdpi/img_play_outline.png differ diff --git a/app/src/main/res/drawable-xxhdpi/img_play_outline.png b/app/src/main/res/drawable-xxhdpi/img_play_outline.png index 5a39e380d..a3ffa45fb 100644 Binary files a/app/src/main/res/drawable-xxhdpi/img_play_outline.png and b/app/src/main/res/drawable-xxhdpi/img_play_outline.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/img_play_outline.png b/app/src/main/res/drawable-xxxhdpi/img_play_outline.png index 54e535148..dafb99e23 100644 Binary files a/app/src/main/res/drawable-xxxhdpi/img_play_outline.png and b/app/src/main/res/drawable-xxxhdpi/img_play_outline.png differ diff --git a/app/src/main/res/drawable/black_rounded_background.xml b/app/src/main/res/drawable/black_rounded_background.xml new file mode 100644 index 000000000..edf046060 --- /dev/null +++ b/app/src/main/res/drawable/black_rounded_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/circle_background.xml b/app/src/main/res/drawable/circle_background.xml new file mode 100644 index 000000000..58f030da7 --- /dev/null +++ b/app/src/main/res/drawable/circle_background.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/app/src/main/res/drawable/circle_black_background.xml b/app/src/main/res/drawable/circle_black_background.xml new file mode 100644 index 000000000..2afe7d524 --- /dev/null +++ b/app/src/main/res/drawable/circle_black_background.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/app/src/main/res/layout-v23/directory_tmb.xml b/app/src/main/res/layout-v23/directory_tmb.xml deleted file mode 100644 index aab55c8ac..000000000 --- a/app/src/main/res/layout-v23/directory_tmb.xml +++ /dev/null @@ -1,6 +0,0 @@ - - diff --git a/app/src/main/res/layout-v23/photo_video_tmb.xml b/app/src/main/res/layout-v23/photo_video_tmb.xml deleted file mode 100644 index 5044be391..000000000 --- a/app/src/main/res/layout-v23/photo_video_tmb.xml +++ /dev/null @@ -1,6 +0,0 @@ - - diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 6fdf71aac..19fd7e7bd 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -11,7 +11,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content"> - + android:paddingStart="@dimen/normal_margin"> + + + + + + + + + diff --git a/app/src/main/res/layout/activity_media.xml b/app/src/main/res/layout/activity_media.xml index 87c46ec36..ce7f66a4c 100644 --- a/app/src/main/res/layout/activity_media.xml +++ b/app/src/main/res/layout/activity_media.xml @@ -11,7 +11,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content"> - + android:paddingStart="@dimen/normal_margin"> + + + + + + + + + diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml index 078bfe2ca..ae31ddb62 100644 --- a/app/src/main/res/layout/activity_settings.xml +++ b/app/src/main/res/layout/activity_settings.xml @@ -214,8 +214,7 @@ android:layout_height="wrap_content" android:layout_marginTop="@dimen/medium_margin" android:background="?attr/selectableItemBackground" - android:padding="@dimen/activity_margin" - android:visibility="gone"> + android:padding="@dimen/activity_margin"> + + + + + + + + + + + + + + + + + + - + android:paddingTop="@dimen/activity_margin"> + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/dialog_slideshow.xml b/app/src/main/res/layout/dialog_slideshow.xml new file mode 100644 index 000000000..d057acf77 --- /dev/null +++ b/app/src/main/res/layout/dialog_slideshow.xml @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/directory_item.xml b/app/src/main/res/layout/directory_item.xml index 63642099d..f6d296e07 100644 --- a/app/src/main/res/layout/directory_item.xml +++ b/app/src/main/res/layout/directory_item.xml @@ -6,16 +6,33 @@ android:layout_height="wrap_content" android:padding="1px"> - + + + + + + diff --git a/app/src/main/res/layout/directory_tmb.xml b/app/src/main/res/layout/directory_tmb.xml deleted file mode 100644 index f7bce5a6f..000000000 --- a/app/src/main/res/layout/directory_tmb.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - diff --git a/app/src/main/res/layout/pager_photo_item.xml b/app/src/main/res/layout/pager_photo_item.xml index 7d7cf1e82..1c4d2d76a 100644 --- a/app/src/main/res/layout/pager_photo_item.xml +++ b/app/src/main/res/layout/pager_photo_item.xml @@ -5,7 +5,7 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - diff --git a/app/src/main/res/layout/pager_video_item.xml b/app/src/main/res/layout/pager_video_item.xml index 572e96c33..3d88f52f7 100644 --- a/app/src/main/res/layout/pager_video_item.xml +++ b/app/src/main/res/layout/pager_video_item.xml @@ -12,6 +12,18 @@ android:layout_centerInParent="true" android:background="@android:color/transparent"/> + + + + + + - + + + @@ -23,11 +38,12 @@ android:id="@+id/photo_name" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_alignLeft="@+id/medium_thumbnail" android:layout_alignParentBottom="true" + android:layout_alignRight="@+id/medium_thumbnail" android:background="@drawable/gradient_background" android:gravity="bottom" android:maxLines="3" - android:minHeight="@dimen/play_outline_size" android:paddingBottom="@dimen/small_margin" android:paddingLeft="@dimen/small_margin" android:paddingRight="@dimen/small_margin" diff --git a/app/src/main/res/layout/photo_video_tmb.xml b/app/src/main/res/layout/photo_video_tmb.xml deleted file mode 100644 index 531a2533d..000000000 --- a/app/src/main/res/layout/photo_video_tmb.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - diff --git a/app/src/main/res/menu/cab_directories.xml b/app/src/main/res/menu/cab_directories.xml index 2267e4c6e..ec47b283d 100644 --- a/app/src/main/res/menu/cab_directories.xml +++ b/app/src/main/res/menu/cab_directories.xml @@ -2,9 +2,9 @@ + - diff --git a/app/src/main/res/menu/menu_main.xml b/app/src/main/res/menu/menu_main.xml index 01937ceb9..c32d48135 100644 --- a/app/src/main/res/menu/menu_main.xml +++ b/app/src/main/res/menu/menu_main.xml @@ -19,6 +19,10 @@ android:id="@+id/temporarily_show_hidden" android:title="@string/temporarily_show_hidden" app:showAsAction="never"/> + + diff --git a/app/src/main/res/menu/menu_media.xml b/app/src/main/res/menu/menu_media.xml index 8a0cc4b29..b8b9b53c5 100644 --- a/app/src/main/res/menu/menu_media.xml +++ b/app/src/main/res/menu/menu_media.xml @@ -36,6 +36,10 @@ android:id="@+id/temporarily_show_hidden" android:title="@string/temporarily_show_hidden" app:showAsAction="never"/> + - - - - - - - + + + Nebyla nalezena žádná fotografická aplikace Zvýšit počet sloupců Snížit počet sloupců - Dočasně zobrazit skryté Change cover image Select photo Use default Nastavit jako + Volume + Brightness Tato funkce skryje složku, včetně podsložek, přidáním souboru \'.nomedia\'. Zobrazíte je zvolením možnosti \'Zobrazit skryté složky\' v nastavení. Pokračovat? @@ -67,7 +68,6 @@ Překlopit Překlopit vodorovně Překlopit svisle - Zařízení nemá dostatek paměti Edit with @@ -81,6 +81,17 @@ Portrait aspect ratio Landscape aspect ratio + + Slideshow + Interval (seconds): + Include photos and GIFs + Include videos + Random order + Use fade animations + Move backwards + The slideshow ended + No media for the slideshow have been found + Zobrazit skryté média Automaticky přehrávat videa @@ -101,6 +112,8 @@ Aspect ratio Dark background at fullscreen media Scroll thumbnails horizontally + Automatically hide system UI at fullscreen media + Replace Share with Rotate at fullscreen menu diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 949a72095..ba4a39d71 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -19,11 +19,12 @@ Keine Kamera-App gefunden Kacheln verkleinern Kacheln vergrößern - Verstecktes temporär zeigen - Change cover image - Bild auswählen - Standard verwenden + Cover-Bild ändern + Auswählen + Standard Festlegen als + Lautstärke + Helligkeit 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? @@ -57,7 +58,7 @@ Pfad Ungültiger Dateipfad Bildbearbeitung fehlgeschlagen - Bild bearbeiten mit: + Bild bearbeiten mit Keine Bildeditor-App gefunden Unbekannter Dateiort Konnte Quelldatei nicht überschreiben @@ -67,20 +68,30 @@ Spiegeln Horizontal spiegeln Vertikal spiegeln - Fehler: Zuwenig Speicher - Edit with + Bearbeiten mit Schlichter Hintergrund Als Hintergrund festlegen Hintergrundbild festlegen fehlgeschlagen - Als Hintergrund festlegen mit: + Als Hintergrund festlegen mit Keine Hintergrundbild-App gefunden Hintergrund festlegen… Hintergrundbild erfolgreich festgelegt Hochformat Querformat + + Diashow + Intervall (Sekunden): + Bilder/GIFs verwenden + Videos verwenden + Zufällige Reihenfolge + Übergänge animieren + Rückwärts abspielen + Diashow beendet + Keine Medien für Diashow gefunden + Versteckte Ordner zeigen Videos automatisch abspielen @@ -92,7 +103,7 @@ Bilder, Videos und GIFs Bilder und Videos Videos in Endlosschleife spielen - Kacheln bei GIFs animieren + Kacheln von GIFs animieren Helligkeit beim Betrachten maximieren Kacheln quadratisch zuschneiden Im Vollbild ausrichten nach @@ -101,6 +112,8 @@ Seitenverhältnis Schwarzer Hintergrund im Vollbild Kacheln horizontal scrollen + Systemleisten ausblenden im Vollbild + Teilen/Drehen im Vollbild-Menü vertauschen diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index b5694df3c..b5bc78a3a 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -1,7 +1,7 @@ Simple Gallery - Gallery + Galería Editar Abrir cámara Abrir con… @@ -19,11 +19,12 @@ No se encontró aplicación de cámara Aumentar el número de columnas Reducir el número de columnas - Mostrar ocultos temporalmente - Change cover image - Select photo - Use default - Set as + Cambiar imagen de portada + Seleccionar imagen + Uso por defecto + Establecer como + Volume + Brightness Esta función oculta la carpeta agregando un archivo \'.nomedia\' en ella, y ocultará también las subcarpetas. Puede mostrarlas cambiando la opción \'Mostrar carpetas ocultas\' en los Ajustes. ¿Continuar? @@ -32,7 +33,7 @@ Gestionar carpetas excluidas Esto excluirá la selección junto con sus subcarpetas, solamente de Simple Gallery. Puede gestionar las carpetas excluidas en los Ajustes. ¿Excluir mejor la carpeta superior? - 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. + Excluir las carpetas las hará junto a sus subcarpetas ocultas sólo en Simple Gallery, estas seguirán siendo visibles en otras aplicaciones.\\n\\nSi desea ocultarlo de otras aplicaciones, utilice la función de Ocultar. Eliminar todo ¿Eliminar todas las carpetas de la lista de excluidas? Esto no borrará las carpetas. @@ -67,8 +68,7 @@ Girar Horizontalmente Verticalmente - Error: sin memoria - Edit with + Editar con Fondos de pantalla Simple Gallery @@ -81,6 +81,17 @@ Relación de aspecto tipo retrato Relación de aspecto tipo paisaje + + Slideshow + Interval (seconds): + Include photos and GIFs + Include videos + Random order + Use fade animations + Move backwards + The slideshow ended + No media for the slideshow have been found + Mostrar carpetas ocultas Reproducir vídeos automáticamente @@ -88,8 +99,8 @@ Mostrar multimedia Solo imágenes Solo vídeos - GIFs only - Images, videos, GIFs + solo GIFs + Imágenes, vídeos, GIFs Imágenes y vídeos Reproducción continua de vídeos Animar las miniaturas de GIFs @@ -100,7 +111,9 @@ Rotación del dispositivo Relación de aspecto Utilizar siempre fondo oscuro en pantalla completa - Scroll thumbnails horizontally + Desplazar miniaturas horizontalmente + Ocultar automáticamente la interfaz de usuario del sistema en medios de pantalla completa + Reemplazar Compartir con Girar en el menú de pantalla completa diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 4f32096b2..09c8d563c 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -3,7 +3,7 @@ Simple Galerie Galerie Édition - Ouvrir caméra + Ouvrir appareil photo Ouvrir avec Aucune application valide trouvée (caché) @@ -16,14 +16,15 @@ Afficher sur la carte Position inconnue Aucune application de cartes n\'a été trouvée - Aucune application d\appareil photo n\'a été trouvée + Aucune application d\\appareil photo n\'a été trouvée Augmenter le nombre de colonnes Réduire le nombre de colonnes - Afficher temporairement les fichiers masqués Change cover image - Select photo + Sélectionner une photo Use default Set as + Volume + Luminosité Cette option masque le dossier en ajoutant un fichier \'.nomedia\' à l\'intérieur, cela masquera aussi tous les sous-dossiers. Vous pouvez les voir en modifiant l\'option \'Afficher les dossiers cachés\' dans les Paramètres. Continuer ? @@ -66,9 +67,8 @@ Pivoter à 180º Retourner Retourner horizontalement - Retourner verticallement - Erreur excès de mémoire - Edit with + Retourner verticalement + Éditer avec Simple fond d\'écran @@ -76,44 +76,49 @@ Échec de la définition en tant que fond d\'écran. Définir comme fond d\'écran avec : Aucune application trouvée pour continuer cette action - Paramètre de fond d\'écran… - Fond d\'écran défini avec succès. + Paramètres de fond d\'écran… + Fond d\'écran défini avec succès Ratio aspect Portrait Ratio aspect Paysage + + Diaporama + Intervalle​ (secondes): + Inclure photos et GIFs + Inclure vidéos + Ordre aléatoire + Utiliser un fondu + Move backwards + Diaporama terminé + No media for the slideshow have been found + Afficher les dossiers cachés Lecture automatique des vidéos - Permutter la visibilité des noms de fichier + Permuter la visibilité des noms de fichier Afficher les médias Seulement les images Vidéos uniquement - GIFs only - Images, videos, GIFs + GIFs seulement + Images, vidéos, GIFs Images et vidéos Tourner en boucle les vidéos GIFs animés sur les miniatures Luminosité maximale lors de l\'affichage de media Rogner les miniatures en carrés - Pivoter les medias plen écran selon + Pivoter les medias plein écran selon Paramètres système Rotation de l\'appareil Ratio d\'aspect Dark background at fullscreen media - Scroll thumbnails horizontally + Défilement des mignatures horizontalement + Automatically hide system UI at fullscreen media + Replace Share with Rotate at fullscreen menu Un album pour visionner photos et vidéos sans publicité. - - 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 - + 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 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? @@ -67,7 +68,6 @@ Flip Flip horizontally Flip vertically - Out of memory error Edit with @@ -81,6 +81,17 @@ Portrait aspect ratio Landscape aspect ratio + + Slideshow + Interval (seconds): + Include photos and GIFs + Include videos + Random order + Use fade animations + Move backwards + The slideshow ended + No media for the slideshow have been found + Show hidden media Play videos automatically @@ -101,6 +112,8 @@ Aspect ratio Dark background at fullscreen media Scroll thumbnails horizontally + Automatically hide system UI at fullscreen media + Replace Share with Rotate at fullscreen menu diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index fa274c077..b70a13b6c 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -19,11 +19,12 @@ Nessuna app fotocamera trovata Aumenta numero colonne Riduci numero colonne - Mostra temporaneamente nascosti - Change cover image - Select photo - Use default - Set as + Cambia immagine copertina + Seleziona foto + Usa predefinita + Imposta come + Volume + Luminosità 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? @@ -67,8 +68,7 @@ Capovolgi Capovolgi orizzontalmente Capovolgi verticalmente - Errore memoria esaurita - Edit with + Modifica con Sfondo semplice @@ -81,6 +81,17 @@ Proporzioni ritratto Proporzioni panorama + + Presentazione + Intervallo (secondi): + Includi foto e GIF + Includi video + Ordine sparso + Usa animazioni a dissolvenza + Scorri al contrario + La presentazione è terminata + Nessun media trovato per la presentazione + Mostra cartelle nascoste Riproduci video automaticamente @@ -88,8 +99,8 @@ Mostra tipo di media Solo immagini Solo video - GIFs only - Images, videos, GIFs + Solo GIF + Immagini, video, GIF Immagini e video Ripeti i video Anima le GIF in miniatura @@ -100,7 +111,9 @@ Rotazione dispositivo Proporzioni Sfondo scuro a schermo intero - Scroll thumbnails horizontally + Scorri miniature orizzontalmente + Nascondi UI di sistema con media a schermo intero + Sostituisci Condividi con Ruota a schermo intero diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 67eed51b2..a1f649c3a 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -19,11 +19,12 @@ No Camera app has been found Increase column count Reduce column count - Temporarily show hidden Change cover image Select photo Use default Set as + Volume + Brightness 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? @@ -67,7 +68,6 @@ Flip Flip horizontally Flip vertically - Out of memory error Edit with @@ -81,6 +81,17 @@ Portrait aspect ratio Landscape aspect ratio + + Slideshow + Interval (seconds): + Include photos and GIFs + Include videos + Random order + Use fade animations + Move backwards + The slideshow ended + No media for the slideshow have been found + 非表示フォルダーを表示 自動的にビデオを再生 @@ -101,6 +112,8 @@ Aspect ratio Dark background at fullscreen media Scroll thumbnails horizontally + Automatically hide system UI at fullscreen media + Replace Share with Rotate at fullscreen menu diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index b8fafa6ff..81cbaaae6 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -1,13 +1,13 @@ Simple Gallery - Galeria + Simple Gallery Edytuj - Aparat + Uruchom aplikację aparatu Otwórz w Nie znaleziono danych aplikacji (ukryty) - Pin folder + Przypnij folder Wypakuj folder Pokaż wszystko Wszystkie foldery @@ -19,105 +19,115 @@ Brak aplikacji powiązanej z aparatem Zwiększ liczbę kolumn Zmniejsz liczbę kolumn - Temporarily show hidden - Change cover image - Select photo - Use default - Set as + Zmień okładkę + Wybierz obraz + Użyj domyślnej + Ustaw jako + Głośność + Jasność - Ta funkcja ukrywa folder dodając \'. \' Nomedia plik do niego, można tak ukryć wszystkie podfoldery. Można je zobaczyć poprzez przełączanie \'Pokaż ukryte foldery \' opcję w ustawieniach. Kontyntynuj? + Ta funkcja ukrywa foldery dodając do nich pusty plik .nomedia. Aby móc je zobaczyć, należy włączyć opcję \'Pokazuj ukryte foldery\' w ustawieniach. Kontyntynuować? Wyklucz - Wyklucz foldery + Wykluczone foldery Zarządzaj wykluczonymi folderami - Działa na folderach Galerii. Możesz zarządzać wykluczonymi folderami w Menu/Ustawienia. - Wykluczyć folder nadżędny ? - 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. + Działa na folderach galerii. Możesz zarządzać wykluczonymi folderami w ustawieniach aplikacji. + Wykluczyć folder nadrzędny? + Wykluczenie folderów ukryje je tylko w aplikacji Simple Gallery, w innych aplikacjach będą one wciąż widoczne.\n\nJeśli chcesz je ukryć także w innych aplikacjach, użyj funkcji ukrywania. Usuń wszystko - Usuń wszystkie foldery z listy wykluczone? To nie usuwa folderów. + Usunąć wszystkie foldery z listy wykluczonych? Foldery nie zostaną fizycznie usunięte. - Included folders - Manage included folders - Add folder - If you have some folders which contain media, but were not recognized by the app, you can add them manually here. + Dołączone foldery + Zarządzaj dołączonymi folderami + Dodaj folder + Jeśli masz jakieś foldery z multimediami, ale aplikacja ich nie wykryła, możesz je tutaj dodać ręcznie. Zmień rozmiar Zmień i zapisz - Długość + Szerokość Wysokość Zachowaj proporcje Wpisz poprawną rozdzielczość Edycja - zapisz + Zapisz Obróć Ścieżka Nieprawidłowa ścieżka - Edycja obrazu nie powiodło się + Edycja obrazu nie powiodła się Edytuj obraz w: - Nie znaleziono edytora zdjęć + Nie znalazłem edytora zdjęć Nieznana lokalizacja pliku Nie udało się zastąpić pliku Obróć w lewo Obróć w prawo - Obróć o 180o - Flip - Flip poziomo - Flip pionowo - Błąd pamięci - Edit with + Obróć o 180 stopni + Przewróć + Przewróć w poziomie + Przewróć w pionie + Edytuj w: Tapeta - Ustaw jako tapeta + Ustaw jako tapetę Ustawienie tapety nie powiodło się Ustaw jako tapetę w: Brak odpowiednich ustawień - Ustawianie tapety… - Tapeta ustawiona - Portrait aspect ratio - Landscape aspect ratio + Ustawiam tapetę… + Tapeta została ustawiona + Proporcje ekranu w trybie pionowym + Proporcje ekranu w trybie poziomym + + + Pokaz slajdów + Przedział (sekundy): + Dołączaj zdjęcia i GIFy + Dołączaj filmy + Losowa kolejność + Używaj płynnych przejść +    Odwrotna kolejność + Pokaz slajdów zakończony + Nie znalazłem multimediów do pokazu slajdów - Pokaż ukryte foldery - Odtwarzaj pliki wideo automatycznie - Włącz widoczność nazwy pliku - Wybierz co pokazywać - Tylko Zdjęcia - Tylko Filmy - GIFs only - Images, videos, GIFs - Obrazy i wideo - Pętla wideo - Animowanie GIFy z miniaturkami - Max brightness when viewing media - Crop thumbnails into squares - Rotate fullscreen media by - System setting - Device rotation - Aspect ratio - Dark background at fullscreen media - Scroll thumbnails horizontally + Pokazuj ukryte foldery + Odtwarzaj filmy automatycznie + Pokazuj / ukrywaj nazwy plików + Pokazywane typy multimediów + Tylko obrazy + Tylko filmy + Tylko GIFy + Obrazy, filmy i GIFy + Obrazy i filmy + Zapętlaj odtwarzanie filmów + Animowane miniatury GIFów + Maksymalna jasność podczas wyświetlania multimediów + Przycinaj miniatury do kwadratów + Obracaj pełnoekranowe multimedia według + Ustawień systemowych + Orientacji urządzenia + Proporcji + Czarne tło przy podglądzie pełnoekranowym + Przewijaj miniatury poziomo + Ukrywaj interfejs przy pełnoekranowym podglądzie + Zamień funkcję udostępniania na obracanie w menu pełnoekranowym - Darmowa Galeria bez reklam do przeglądania zdjęć i filmów. + Darmowa galeria bez reklam do przeglądania obrazów i filmów. - Prosta aplikacja galerii do oglądania zdjęć i filmów. Pliki mogą być sortowane według daty, rozmiaru, nazwy zarówno w porządku rosnącym lub malejącym, zdjęcia można powiększać. Pliki multimedialne są wyświetlane w wielu kolumnach w zależności od wielkości ekranu, można zmienić liczbę kolumn za pomocą gestów. Obrazy mogą być edytowane w galerii. Zdjęcia mogą być przycięte, można je obracać lub ustawić jako tapetę bezpośrednio z aplikacji. Kolor aplikacji mozna dowolnie ustawić według własnych preferencji. + Prosta aplikacja galerii do oglądania obrazów i filmów. Pliki mogą być sortowane według daty, rozmiaru i nazwy, zarówno w porządku rosnącym jak i malejącym. W zależności od wielkości ekranu wyświetlane mogą być w wielu kolumnach. Liczbę kolumn można zmieniać za pomocą gestów. Zdjęcia mogą być powiększane, przycinane, obracane lub ustawiane jako tapeta bezpośrednio z poziomu aplikacji. Kolory aplikacji można dowolnie ustawiać. - Galeria jest również oferowane do użytkowania przez osoby trzecie do podglądu zdjęć/filmów, dodawania załączników do klientów e-mail itp, Idealne nadaje się do codziennego użytku. - - Nie zawiera żadnych reklam ani niepotrzebnych uprawnień. Jest w pełni opensource. - - Ta aplikacja jest tylko jedą z większego szeregu naszych aplikacji. Można znaleźć resztę z nich w http://www.simplemobiletools.com + Aplikacja nie zawiera żadnych reklam ani niepotrzebnych uprawnień. Jest też w pełni otawrtoźrodłowa. + + Niniejsza aplikacja jest tylko częścią naszego zestawu prostych aplikacji. Znajdziecie je na stronie http://www.simplemobiletools.com. diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 9c09d69f6..ab1b9691c 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -6,7 +6,8 @@ Abrir câmera Abrir com Nenhum aplicativo encontrado -    (oculto) +     + (oculto) Fixar pasta Desfixar pasta Mostrar conteúdo de todas as pastas @@ -19,11 +20,12 @@ Nenhum aplicativo de câmera encontrado Aumentar número de colunas Reduzir número de colunas - Mostrar pastas ocultas temporariamente Trocar imagem de capa Selecionar foto Usar padrão Set as + Volume + Brightness Esta opção oculta uma pasta com a adição de um arquivo \'.nomedia\' dentro dela, e irá ocultar todas as subpastas que estejam dentro da mesma. Você poderá rever essas pastas com a opção \'Mostrar pastas ocultas\'. Continuar? @@ -67,7 +69,6 @@ Inverter Horizontalmente Verticalmente - Memória insuficiente Edit with @@ -78,8 +79,19 @@ Aplicativo não encontrado Definindo como papel de parede; Papel de parede com sucesso - Retrato - Paisagem + Retrato + Paisagem + + + Slideshow + Interval (seconds): + Include photos and GIFs + Include videos + Random order + Use fade animations + Move backwards + The slideshow ended + No media for the slideshow have been found Mostrar pastas ocultas @@ -93,7 +105,7 @@ Imagens e vídeos Reproduzir vídeos em ciclo Animação de GIFs nas miniaturas -    Brilho máximo ao visualizar mídia + Brilho máximo ao visualizar mídia Recortar miniaturas em quadrados Critério para rotação de tela Padrão do sistema @@ -101,6 +113,8 @@ Proporção da mídia Fundo de tela escuro em mídia tela cheia Rolar miniaturas horizontalmente + Automatically hide system UI at fullscreen media + Replace Share with Rotate at fullscreen menu diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 07d1e99fa..300f156b1 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -19,11 +19,12 @@ Não existe uma aplicação adequeada Aumentar número de colunas Diminuir número de colunas - Mostrar ocultas temporariamente Alterar imagem da capa Selecionar foto Predefinição - Set as + Definir como + Volume + Brilho Esta opção oculta uma pasta com a adição de um ficheiro \'.nomedia\' na pasta, e irá ocultar todas as subpastas existentes. Pode ver as pastas com a opção \'Mostrar pastas ocultas\'. Continuar? @@ -67,8 +68,7 @@ Inverter Horizontalmente Verticalmente - Memória insuficiente - Edit with + Editar com Simple Wallpaper @@ -81,6 +81,17 @@ Proporção na vertical Proporção na horizontal + + Apresentação + Intervalo (segundos): + Incluir fotos e GIFs + Incluir vídeos + Ordem aleatória + Usar animações + Mover para trás + Apresentação terminada + Não foram encontrados ficheiros para a apresentação + Mostrar pastas ocultas Reproduzir vídeos automaticamente @@ -101,6 +112,8 @@ Proporção Usar sempre um fundo escuro se em ecrã completo Deslocação horizontal de miniaturas + Ocultar interface do sistema se em ecrã completo + Substituir a opção Partilhar pela opção Rodar se em ecrã completo diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index fd09fae47..700fc831e 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -19,11 +19,12 @@ Не найдено приложения камеры Добавить 1 столбец Убрать 1 столбец - Временный показ скрытых Change cover image Select photo Use default Set as + Volume + Brightness Эта опция скрывает папку, добавляя в неё файл \'.nomedia\'; будут скрыты все подпапки. Можно показывать их, переключая \'Показать скрытые папки\' в настройках. Продолжить? @@ -67,7 +68,6 @@ Отразить По горизонтали По вертикали - Память переполнена Edit with @@ -81,6 +81,17 @@ Формат изображения Пейзажное соотношение сторон + + Slideshow + Interval (seconds): + Include photos and GIFs + Include videos + Random order + Use fade animations + Move backwards + The slideshow ended + No media for the slideshow have been found + Показать скрытые папки Воспроизводить видео автоматически @@ -101,6 +112,8 @@ Соотношение сторон Dark background at fullscreen media Scroll thumbnails horizontally + Automatically hide system UI at fullscreen media + Replace Share with Rotate at fullscreen menu diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml index 68beaf6cc..b9b0ea85c 100644 --- a/app/src/main/res/values-sk/strings.xml +++ b/app/src/main/res/values-sk/strings.xml @@ -19,11 +19,12 @@ Nenašla sa žiadna aplikácia pre fotoaparát Zvýšiť počet stĺpcov Znížiť počet stĺpcov - Dočasne zobraziť skryté Zmeniť obal albumu Zvoliť foto Použiť predvolený Nastaviť ako + Hlasitosť + Jas Táto funkcia skryje priečinok pridaním súboru \'.nomedia\', skryté budú aj podpriečinky. Môžete ich vidieť zvolením možnosti \'Zobraziť skryté priečinky\' v nastaveniach. Pokračovať? @@ -67,7 +68,6 @@ Preklopiť Preklopiť vodorovne Preklopiť zvisle - Došlo k chybe s nedostatkom pamäte Upraviť s @@ -81,6 +81,17 @@ Orientácia nastojato Orientácia naležato + + Prezentácia + Interval (sekundy): + Zahrnúť fotky a GIF súbory + Zahrnúť videá + Náhodné poradie + Používať miznúce animácie + Ísť opačným smerom + Prezentácia skončila + Pre prezentáciu sa nenašli žiadne vhodné súbory + Zobraziť skryté médiá Spúšťať videá automaticky @@ -101,6 +112,8 @@ Pomeru strán Tmavé pozadie pri médiách na celú obrazovku Prehliadať miniatúry vodorovne + Automaticky skrývať systémové lišty pri celoobrazovkových médiách + Nahradiť Zdieľanie s Otočením v celoobrazovkovom menu diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 7e3133464..68558ac8c 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -1,7 +1,7 @@ Simple Gallery - Gallery + Galleri Redigera Starta kameran Öppna med @@ -13,34 +13,35 @@ Alla mappar Byt till mappvy Andra mappar - Show on map - Unknown location - No application with maps has been found - No Camera app has been found - Increase column count - Reduce column count - Temporarily show hidden - Change cover image - Select photo - Use default - Set as + Visa på karta + Okänd plats + Ingen app med kartor hittades + Ingen Kamera-app hittades + Öka antalet kolumner + Minska antalet kolumner + Byt omslagsbild + Välj foto + Använd standard + Ange som + Volume + Brightness - 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? - Exclude - Excluded folders - Manage excluded folders - This will exclude the selection together with its subfolders from Simple Gallery only. You can manage excluded folders in Settings. - Exclude a parent instead? - 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. - Remove all - Remove all folders from the list of excluded? This will not delete the folders. + 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? + Uteslut + Uteslutna mappar + Hantera uteslutna mappar + Detta utesluter bara den markerade mappen och dess undermappar från Simple Gallery. Du kan hantera uteslutna mappar i Inställningar. + Vill du utesluta en överordnad mapp istället? + Uteslutning av mappar döljer bara dem och deras undermappar i Simple Gallery, de visas fortfarande i andra appar.\\n\\nAnvänd Dölj-funktionen om du även vill dölja dem från andra appar. + Ta bort alla + Vill du ta bort alla mappar från uteslutningslistan? Detta raderar inte mapparna. - Included folders - Manage included folders - Add folder - If you have some folders which contain media, but were not recognized by the app, you can add them manually here. + Inkluderade mappar + Hantera inkluderade mappar + Lägg till mapp + 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. Ändra storlek @@ -56,19 +57,18 @@ Rotera Sökväg Ogiltig bildsökväg - Image editing failed + Bilden kunde inte redigeras Redigera bilden med: Hittade ingen bildredigerare Okänd filplats Det gick inte att skriva över källfilen - Rotate left - Rotate right - Rotate by 180º - Flip - Flip horizontally - Flip vertically - Out of memory error - Edit with + Rotera åt vänster + Rotera åt höger + Rotera 180º + Vänd + Vänd horisontellt + Vänd vertikalt + Redigera med Bakgrundsbild @@ -78,8 +78,19 @@ Hittade ingen app som klarar av detta Inställningar för bakgrundsbild… Bakgrundsbilden är ändrad - Portrait aspect ratio - Landscape aspect ratio + Stående bildförhållande + Liggande bildförhållande + + + Slideshow + Interval (seconds): + Include photos and GIFs + Include videos + Random order + Use fade animations + Move backwards + The slideshow ended + No media for the slideshow have been found Visa dolda mappar @@ -88,19 +99,21 @@ Visa media Endast bilder Endast videos - GIFs only - Images, videos, GIFs + Bara GIF-bilder + Bilder, videor, GIF-bilder Bilder och videos Återspela videos - Animate GIFs at thumbnails - Max brightness when viewing media - Crop thumbnails into squares - Rotate fullscreen media by - System setting - Device rotation - Aspect ratio - Dark background at fullscreen media - Scroll thumbnails horizontally + Animera GIF-bilders miniatyrer + Maximal ljusstyrka när media visas + Beskär miniatyrer till kvadrater + Rotera media i helskärmsläge + Systeminställning + Enhetens rotation + Bildförhållande + Mörk bakgrund när media visas i helskärmsläge + Rulla horisontellt genom miniatyrer + Dölj systemanvändargränssnittet automatiskt när media visas i helskärmsläge + Replace Share with Rotate at fullscreen menu diff --git a/app/src/main/res/values-sw600dp/dimens.xml b/app/src/main/res/values-sw600dp/dimens.xml index 7c87748ee..595bc8570 100644 --- a/app/src/main/res/values-sw600dp/dimens.xml +++ b/app/src/main/res/values-sw600dp/dimens.xml @@ -1,9 +1,11 @@ + 150dp 120dp - 30dp - 60dp + 30dp + 38dp 230dp 32dp 60dp + 250dp diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 80f72abb2..087a7d896 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -19,11 +19,12 @@ Hiçbir Kamera uygulaması bulunamadı Sütun sayısını artır Sütun sayısını azalt - Geçici olarak gizli göster Change cover image Select photo Use default Set as + Volume + Brightness Bu işlev, klasöre\'.medya yok\'dosyası ekleyerek gizler; tüm alt klasörleri de gizler. Bunları Ayarlar\'da\'Gizli klasörleri göster\'seçeneğine basarak görebilirsiniz. Devam et? @@ -67,7 +68,6 @@ Çevir Yatay Dikey - Yetersiz bellek hatası Edit with @@ -81,6 +81,17 @@ Portrait aspect ratio Landscape aspect ratio + + Slideshow + Interval (seconds): + Include photos and GIFs + Include videos + Random order + Use fade animations + Move backwards + The slideshow ended + No media for the slideshow have been found + Gizli klasörleri göster Videoları otomatik olarak oynat @@ -101,6 +112,8 @@ En-boy oranı Dark background at fullscreen media Scroll thumbnails horizontally + Automatically hide system UI at fullscreen media + Replace Share with Rotate at fullscreen menu diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml index 11e77efc5..78a798255 100644 --- a/app/src/main/res/values-v21/styles.xml +++ b/app/src/main/res/values-v21/styles.xml @@ -3,4 +3,5 @@ + diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 3e3b6d11e..3b51081a4 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -19,11 +19,12 @@ 未找到相机应用 增加一栏 减少一栏 - 显示/隐藏缓存内容 更改封面图片 选择图片 使用默认 设置为 + Volume + Brightness 通过添加文件 \'.nomedia\' 到目录,可以防止目录及其子目录下的所有媒体被扫描。您可以通过设置中的 \'显示隐藏目录\' 选项改变设置,是否继续? @@ -67,7 +68,6 @@ 翻转 水平翻转 垂直翻转 - 内存不足 编辑方式 @@ -81,6 +81,17 @@ 纵向长宽比 横向长宽比 + + Slideshow + Interval (seconds): + Include photos and GIFs + Include videos + Random order + Use fade animations + Move backwards + The slideshow ended + No media for the slideshow have been found + 显示所有 自动播放 @@ -101,6 +112,8 @@ 根据长宽比 全屏时黑色背景 水平滚动缩略图 + Automatically hide system UI at fullscreen media + Replace Share with Rotate at fullscreen menu diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index fdd1155a7..61cc68907 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -1,50 +1,51 @@ - 簡易藝廊 - 藝廊 + 簡易相簿 + 簡易相簿 編輯 開啟相機 - 以其他應用軟體開啟 - 沒有可用的應用軟體 - (隱藏) - 鎖定資料夾 - 解除鎖定資料夾 - 顯示所有資料夾的內容 - 所有資料夾 - 切換到資料夾檢視 + 以其他應用程式開啟 + 找不到應用程式 + (隱藏) + 釘選資料夾 + 取消釘選資料夾 + 資料夾內容全部顯示 + 全部資料夾 + 切換成資料夾檢視 其他資料夾 - Show on map - Unknown location - No application with maps has been found - No Camera app has been found - Increase column count - Reduce column count - Temporarily show hidden - Change cover image - Select photo - Use default - Set as + 在地圖上顯示 + 未知的位置 + 找不到地圖程式 + 找不到相機程式 + 增加欄數 + 減少欄數 + 更換封面圖片 + 選擇相片 + 使用預設 + 設為 + 音量 + 亮度 - 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? - Exclude - Excluded folders - Manage excluded folders - This will exclude the selection together with its subfolders from Simple Gallery only. You can manage excluded folders in Settings. - Exclude a parent instead? - 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. - Remove all - Remove all folders from the list of excluded? This will not delete the folders. + 這功能藉由添加一個\'.nomedia\'檔案,來隱藏資料夾和所有子資料夾。您可以透過設定中的「顯示隱藏的資料夾」選項來查看。\n是否繼續? + 排除 + 排除資料夾 + 管理排除資料夾 + 此資料夾與子資料夾將只會都從簡易相簿中排除。您可以在設定中進行管理。 + 是否排除上層資料夾? + 「排除資料夾」只會將選擇的資料夾與子資料夾一起從簡易相簿中隱藏,他們仍會出現在其他應用程式中。\n\n如果您要在其他應用程式中也隱藏,請使用「隱藏」功能。 + 移除全部 + 是否將排除列表中的所有資料夾都移除?這不會刪除資料夾。 - Included folders - Manage included folders - Add folder - If you have some folders which contain media, but were not recognized by the app, you can add them manually here. + 包含資料夾 + 管理包含資料夾 + 增加資料夾 + 如果有些資料夾含有媒體檔案,卻沒被辨識到,您可以在此手動加入。 縮放 - 縮放選區並儲存 + 縮放所選區域並儲存 寬度 高度 保持長寬比 @@ -55,64 +56,76 @@ 儲存 旋轉 路徑 - 圖檔路徑錯誤 - 圖檔編輯失敗 - 編輯用: - 沒有可用的圖檔編輯器 - 未知檔案路徑 - 不能覆蓋源檔案 - Rotate left - Rotate right - Rotate by 180º - Flip - Flip horizontally - Flip vertically - Out of memory error - Edit with + 無效的圖片路徑 + 圖片編輯失敗 + 編輯圖片: + 找不到圖片編輯器 + 未知的檔案位置 + 無法誤蓋原始檔案 + 向左轉 + 向右轉 + 旋轉180º + 翻轉 + 水平翻轉 + 垂直翻轉 + 用其他程式編輯 簡易桌布 - 設定為桌布 - 桌布設定失敗 - 用其他應用軟體設定桌布…… - 沒有可用的應用軟體 - 正在應用軟體桌布… - 成功應用軟體桌布 - Portrait aspect ratio - Landscape aspect ratio + 設為桌布 + 設為桌布失敗 + 用其他程式設為桌布: + 找不到可用的應用程式 + 桌布設定中… + 成功設為桌布 + 直向長寬比 + 橫向長寬比 + + + 投影片 + 間隔 (秒): + 包含照片和GIF + 包含影片 + 隨機順序 + 使用淡入淡出動畫 + 反向播放 + 投影片結束 + 找不到投影片的媒體檔案 - 秀出隱藏資料夾 + 顯示隱藏的媒體檔案 自動播放影片 顯示檔案名稱 - 秀出多媒體檔案 - 僅圖片 - 僅影片 - GIFs only - Images, videos, GIFs + 顯示媒體檔案 + 只有圖片 + 只有影片 + 只有GIF + 圖片、影片、GIF 圖片和影片 - 迴圈播放影片 - Animate GIFs at thumbnails - Max brightness when viewing media - Crop thumbnails into squares - Rotate fullscreen media by - System setting - Device rotation - Aspect ratio - Dark background at fullscreen media - Scroll thumbnails horizontally + 影片循環播放 + 縮圖顯示GIF動畫 + 瀏覽時最大亮度 + 縮圖裁剪成正方形 + 全螢幕時旋轉方向 + 系統設定方向 + 裝置實際方向 + 圖片長寬比 + 全螢幕時黑背景 + 橫向滑動縮圖 + 全螢幕時自動隱藏系統介面 + 將全螢幕選單的分享取代為旋轉 - 一個沒有廣告,用來觀看照片及影片的藝廊。 + 一個用來瀏覽相片和影片,且沒有廣告的相簿。 - 一個觀看照片跟影片的簡單實用工具。項目可以根據日期、大小、名稱來進行遞增及遞減排序,照片可以縮放。媒體檔案們根據螢幕的大小呈列在多個方格中,您可以使用捏放手勢來調整一列中的方格數量。媒體檔案可以被重新命名、分享、刪除、複製以及移動。照片亦可被裁切、旋轉或是直接在應用軟體中設定為桌布。 - - 藝廊亦提供讓第三方軟體能夠用來預覽圖片/影片、添加附件於電子郵件客戶端軟體中等功能。非常適合日常使用。 - - 應用軟體不包含廣告與非必要的權限。它是完全開放原始碼的,並內建自訂顔色之使用者介面主題。 - - 這個應用軟體只是一系列應用軟體中的一小部份。您可以在 http://www.simplemobiletools.com 找到剩下的軟體。 + 一個適合用來瀏覽相片和影片的簡單工具。可以根據日期、大小、名稱來遞增或遞減排序項目,相片能被縮放。媒體檔案會依畫面大小呈現在數個欄位內,你可以使用縮放手勢來改變欄數。媒體檔案可以重新命名、分享、刪除、複製、移動;圖片還能縮放、旋轉、翻轉,或者直接設為桌布。 + + 這相簿也支援第三方應用,像是預覽圖片/影片、添加電子信箱附件...等功能,日常使用上相當適合。 + + 優點包含沒廣告,也沒非必要的權限,而且完全開放原始碼,並提供自訂顏色。 + + 這只是一個大系列應用程式的其中一項程式,你可以在這發現更多 http://www.simplemobiletools.com @color/default_dark_theme_text_color diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 4944170eb..a67c01562 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -2,11 +2,10 @@ 150dp 100dp - 20dp - 40dp + 20dp + 26dp 150dp 24dp 50dp - - 56dp + 150dp diff --git a/app/src/main/res/values/donottranslate.xml b/app/src/main/res/values/donottranslate.xml index d1487c62f..4f173fa1f 100644 --- a/app/src/main/res/values/donottranslate.xml +++ b/app/src/main/res/values/donottranslate.xml @@ -2,6 +2,16 @@ + Allow changing the screen brightness and volume at videos by vertically dragging the screen sides + Added slideshow at the fullscreen view + Added pattern/pin protection for showing hidden items + Added a toggle for replacing Share with Rotate at fullscreen media + + Added an indicator of folders located on SD cards + Improved the way of rotating jpg images on the internal storage by modifying the exif tags + added autosave + + Added an option for automatically hiding the system UI at entering fullscreen mode + Added an option for enabling horizontal scrolling Allow setting custom folder covers Allow selecting multiple items by finger dragging\n diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 26b9fc2f8..496fb5445 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -19,11 +19,12 @@ No Camera app has been found Increase column count Reduce column count - Temporarily show hidden Change cover image Select photo Use default Set as + Volume + Brightness 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? @@ -67,7 +68,6 @@ Flip Flip horizontally Flip vertically - Out of memory error Edit with @@ -81,6 +81,17 @@ Portrait aspect ratio Landscape aspect ratio + + Slideshow + Interval (seconds): + Include photos and GIFs + Include videos + Random order + Use fade animations + Move backwards + The slideshow ended + No media for the slideshow have been found + Show hidden media Play videos automatically @@ -101,6 +112,8 @@ Aspect ratio Dark background at fullscreen media Scroll thumbnails horizontally + Automatically hide system UI at fullscreen media + Replace Share with Rotate at fullscreen menu diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index f730c8f58..f7114219d 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -15,4 +15,5 @@ +