Compare commits

...

144 Commits
1.24 ... 1.32

Author SHA1 Message Date
tibbi
c480dd23ff updating changelog 2016-11-13 11:48:40 +01:00
tibbi
101b717d71 update version to 32 (1.32) 2016-11-13 11:48:35 +01:00
tibbi
04e3ea1fb2 use the extension function for checking root folders 2016-11-13 11:45:43 +01:00
tibbi
511fc5e420 update filepicker to 1.3.20 2016-11-13 11:45:33 +01:00
tibbi
e013cc02a4 do not allow renaming the root folder of a storage 2016-11-13 11:40:12 +01:00
tibbi
9b8420e9d1 check for already existing folder at renaming 2016-11-13 11:28:34 +01:00
tibbi
09231c516c display proper directory names at storage root folders 2016-11-13 11:17:01 +01:00
tibbi
4d324e491e convert myviewpager and myimageview to kotlin 2016-11-13 11:01:21 +01:00
tibbi
856913520a convert Config to Kotlin + move Utils 2016-11-13 10:58:10 +01:00
tibbi
c6779c8047 convert AboutActivity to kotlin 2016-11-13 10:50:36 +01:00
tibbi
57836b229d add filepicker and fileproperties licenses 2016-11-13 10:33:33 +01:00
tibbi
d2a8aca830 update the order of chinese strings 2016-11-13 10:20:00 +01:00
Tibor Kaputa
6b268a1c07 Merge pull request #54 from tcg2008/test-pr
simplified  chinese translation
2016-11-13 10:04:12 +01:00
tibbi
9e15c5e38d updating readme 2016-11-13 10:02:05 +01:00
tibbi
921eb4750c updating screenshots 2016-11-13 09:59:00 +01:00
tcg2008
83be878d50 test-pr 2016-11-13 16:24:08 +08:00
tibbi
5e9cc0bea8 updating changelog 2016-11-12 23:51:44 +01:00
tibbi
3c0b8bb845 update version to 31 (1.31) 2016-11-12 23:51:09 +01:00
tibbi
7d9a08d2fe add 2 proguard rules 2016-11-12 23:45:46 +01:00
tibbi
eb218f6fa6 rename intent data to resultdata 2016-11-12 23:45:40 +01:00
tibbi
8ccb0385ca move system UI toggling into extensions 2016-11-12 23:27:10 +01:00
tibbi
493ba31c5f convert PhotoVideoActivity to kotlin 2016-11-12 23:11:52 +01:00
tibbi
719c510f59 convert ViewPagerActivity to kotlin 2016-11-12 23:01:57 +01:00
tibbi
7ced072f9c update fileproperties to 1.0.3 2016-11-12 22:02:19 +01:00
tibbi
cec3e5f640 Portuguese string updates by smarquespt 2016-11-12 21:55:33 +01:00
tibbi
a6bca1ae88 renaming a string 2016-11-12 21:43:22 +01:00
tibbi
afb722ab24 let the user know if not all files have been copied/moved 2016-11-12 21:33:46 +01:00
tibbi
4f21221698 update filepicker to 1.3.19 2016-11-12 21:26:07 +01:00
tibbi
c8b927e7e1 put copy/move above Delete at media screen 2016-11-12 20:42:56 +01:00
tibbi
2465e7ae62 update filepicker to 1.3.18 2016-11-12 20:42:06 +01:00
tibbi
d2546e1a3e delete only media files at deleting a folder 2016-11-12 20:34:21 +01:00
tibbi
34d015734e add some checks to avoid displaying nonexistant files 2016-11-12 20:29:47 +01:00
tibbi
f548ed833a change copymovetask interface to inline 2016-11-12 20:11:41 +01:00
tibbi
7c3ad32dee allow copying and moving only photo and video files with the gallery 2016-11-12 19:57:18 +01:00
tibbi
cf67f52ea2 update filepicker to 1.3.17 2016-11-12 19:56:54 +01:00
tibbi
84613885ef convert Medium to kotlin + Directory updates 2016-11-12 19:26:01 +01:00
tibbi
a5deb81e58 update the copy task related things 2016-11-12 19:10:05 +01:00
tibbi
807add5579 update filepicker to 1.3.16 2016-11-12 18:54:20 +01:00
tibbi
36aaf03541 update the copy task 2016-11-12 17:52:35 +01:00
tibbi
d4855573c9 readd the Move button 2016-11-12 16:50:05 +01:00
tibbi
93b8281cfb some mediascan adjustments 2016-11-12 15:24:40 +01:00
tibbi
df5b90319f update filepicker to 1.3.15 2016-11-12 15:09:51 +01:00
tibbi
75beef4da6 using a few more extension functions 2016-11-12 12:16:50 +01:00
tibbi
c4edf3c28e replace a couple more extension functions 2016-11-12 12:12:05 +01:00
tibbi
bf94d8172c remove the local write permissions dialog related stuff 2016-11-12 12:07:07 +01:00
tibbi
9e5936b8a0 make use of some of the new extension functions 2016-11-12 12:04:38 +01:00
tibbi
42be5de0cb update filepicker to 1.3.13 2016-11-12 11:56:47 +01:00
tibbi
e3cc1b91cc rely on some extension functions from the filepicker library 2016-11-11 23:40:33 +01:00
tibbi
cb734d7c10 update filepicker to 1.3.12 2016-11-11 23:01:46 +01:00
tibbi
737d2f2a9c updating changelog 2016-11-11 00:01:28 +01:00
tibbi
293f77afe0 update version to 30 2016-11-11 00:01:22 +01:00
tibbi
4b12949a73 humanize the paths at rename dialogs 2016-11-11 00:01:08 +01:00
tibbi
48f5a33f90 remove some non translatable strings from the Portuguese file 2016-11-10 23:54:09 +01:00
tibbi
0959403628 convert a couple simple activity to kotlin, no functionality change 2016-11-10 23:19:04 +01:00
tibbi
d4c75c2107 add the actual filename visibility toggle functionality 2016-11-10 22:57:17 +01:00
tibbi
af3d247b7f use the inherited mConfig variable 2016-11-10 22:44:05 +01:00
tibbi
805f726022 add a menu item for toggling filename visibility 2016-11-10 21:39:07 +01:00
tibbi
4e9dc8e85f the background at video controls should be gradient too 2016-11-10 21:29:47 +01:00
tibbi
534ff0ab7d make the directory bottom background gradient 2016-11-10 21:27:01 +01:00
tibbi
d80a1bd185 remove the file.canWrite check 2016-11-10 21:22:02 +01:00
tibbi
3e2cfe90bc handle 3 line filenames properly 2016-11-10 20:55:28 +01:00
tibbi
8f85b5da2f do not show the permissions dialog to prekitkat devices 2016-11-10 20:50:38 +01:00
tibbi
c609072eaf display a file name at the media activity 2016-11-10 20:46:11 +01:00
Tibor Kaputa
401569043a Merge pull request #51 from LonamiWebs/master
Fixed #50 for reals
2016-11-10 20:44:07 +01:00
Lonami Exo
d6dd6210c7 Fixed #50 for reals (treeUri needs to be set at least once, always) 2016-11-10 20:41:13 +01:00
tibbi
93d4353d42 move the play outline of thumbnails to the right top corner 2016-11-10 20:23:32 +01:00
tibbi
6f2ef95b40 add a constant for displaying file names 2016-11-10 20:20:29 +01:00
tibbi
1710590639 removing a weird file creation 2016-11-10 20:06:36 +01:00
tibbi
a971b215a5 notify the user when the copy fails or succeeds 2016-11-10 20:02:06 +01:00
tibbi
dfae308cc7 Merge branch 'master' of github.com:SimpleMobileTools/Simple-Gallery 2016-11-10 18:57:34 +01:00
tibbi
8108a109dc fix #50, make sure we have SD write permission before deleting a folder 2016-11-10 18:57:09 +01:00
Tibor Kaputa
03acb74ba3 Merge pull request #49 from smarquespt/master
Portuguese update
2016-11-10 09:02:51 +01:00
Sérgio Marques
855daa4675 Portuguese update 2016-11-09 23:14:36 +00:00
tibbi
fa4c6928bd updating changelog 2016-11-09 23:41:19 +01:00
tibbi
3323ff7157 update version to 29 (1.29) 2016-11-09 23:41:14 +01:00
tibbi
96b25a43b8 make "Save as" the only saving option in the editor 2016-11-09 23:37:39 +01:00
tibbi
267317c7c2 use date_modified instead of date_taken everywhere 2016-11-09 23:20:18 +01:00
tibbi
fa14b43e3e comment out Move function for now 2016-11-09 23:02:13 +01:00
tibbi
beba22b764 refresh the directories view after copying 2016-11-09 22:58:13 +01:00
tibbi
c176959305 add a copy menu button at folder view too 2016-11-09 22:47:27 +01:00
tibbi
8487ef44c4 add a copy/move menu item to media activity 2016-11-09 22:27:13 +01:00
tibbi
d7ffc35dd0 store the real destination path in a variable 2016-11-09 21:19:46 +01:00
tibbi
d6fd4ad378 humanize the selected copy destination link too 2016-11-09 21:15:11 +01:00
tibbi
2c7d62c863 add a dialog for picking the copy destination 2016-11-09 21:10:08 +01:00
tibbi
3804f3d8f4 autoplay videos only if set so 2016-11-08 23:08:35 +01:00
tibbi
9b809790f9 create the copy dialog at viewpageractivity 2016-11-08 23:00:09 +01:00
tibbi
c6598528fd add a couple things related to file copying 2016-11-08 21:49:54 +01:00
tibbi
fbe1409862 add a pickAlbumActivity for picking copy destination 2016-11-08 20:08:39 +01:00
tibbi
10e197af95 zoom in a bit less on double tap 2016-11-08 19:09:26 +01:00
tibbi
1eb125e36d updating changelog 2016-11-08 00:05:51 +01:00
tibbi
ac7757c76e update version to 28 (1.28) 2016-11-08 00:05:20 +01:00
tibbi
f25ae4f1b7 set the default folder sorting by date, descending 2016-11-08 00:03:38 +01:00
tibbi
57048d3956 update some Spanish strings, by Felipe Criado 2016-11-08 00:01:48 +01:00
tibbi
f2e13e9cb3 fix SD card detecting 2016-11-07 23:59:08 +01:00
tibbi
1e1d0f8dc7 update filepicker to 1.3.8 2016-11-07 23:58:06 +01:00
tibbi
bebc8f808f updating changelog 2016-11-06 23:57:13 +01:00
tibbi
4c50b5bc0e update version to 27 (1.27) 2016-11-06 23:57:06 +01:00
tibbi
5cb0bb904f close #44, add "Save as" to the editor 2016-11-06 23:52:57 +01:00
tibbi
90d704cff4 add a Save as button to the editor 2016-11-06 21:52:43 +01:00
tibbi
a31533418d fix #45, display proper filename when opening an item from Downloads folder 2016-11-06 21:42:23 +01:00
tibbi
a5da407ed3 delete files from main screen more carefully, and not recursively 2016-11-06 21:32:36 +01:00
tibbi
c7408fb9fe move directory rename dialog in a separate file 2016-11-06 21:16:41 +01:00
tibbi
fc8f8c3fa7 rename RenameItemDialog to RenameFileDialog 2016-11-06 20:53:34 +01:00
tibbi
0ade1ec579 check write permissions before starting the deletion 2016-11-06 20:49:47 +01:00
tibbi
6c9c072dc9 create a helper function for displaying stupid kitkat permissions dialog 2016-11-06 20:36:55 +01:00
tibbi
c71f94d9ec handle open_documet_tree activityresult in shared simpleactivity 2016-11-06 19:53:02 +01:00
tibbi
fb59224405 convert simpleactivity to kotlin 2016-11-06 19:44:26 +01:00
tibbi
dd983c9753 handle kitkat permissions at saving edited photos 2016-11-06 19:40:03 +01:00
tibbi
84f81ed3e2 check kitkat sd permission before deleting from viewpager 2016-11-06 19:03:59 +01:00
tibbi
a70e99da34 move RenameItemDialog in a separate file 2016-11-06 18:45:33 +01:00
tibbi
7ba442e32e fix renaming files from the viewpager 2016-11-06 17:10:42 +01:00
tibbi
251ccd8078 add the filepicker 2016-11-06 16:56:17 +01:00
tibbi
32fe796d66 update the video autoplay strings 2016-11-06 16:36:37 +01:00
tibbi
3ec6bd3a94 convert utils to kotlin 2016-11-06 16:35:45 +01:00
tibbi
4f74709774 add some things related to kitkat sdcard write permissions 2016-11-06 16:26:25 +01:00
tibbi
165cff24e6 move mypageradapter to the proper folder 2016-11-06 16:09:50 +01:00
tibbi
122209fb28 convert MyPagerAdapter to kotlin 2016-11-06 16:08:48 +01:00
tibbi
def05ffbe2 convert mediaadapter to kotlin 2016-11-06 16:01:13 +01:00
tibbi
d60521411e convert directoryadapter to kotlin 2016-11-06 15:54:53 +01:00
tibbi
f0e8746bce require write_external_storage so we can modify things too 2016-11-06 15:42:56 +01:00
tibbi
3f756369f2 add a couple more path null checks 2016-11-06 15:38:34 +01:00
tibbi
657b14fdb4 add a null check at obtaining files to fix some crashes 2016-11-06 15:29:54 +01:00
tibbi
001bf403d1 move interface declaration to the bottom 2016-11-06 15:18:17 +01:00
tibbi
4153a73139 updating changelog 2016-11-03 23:29:47 +01:00
tibbi
9a58d3fedb update version to 26 (1.26) 2016-11-03 23:28:54 +01:00
tibbi
a5fc444ba3 add the properties dialog to viewpager items 2016-11-03 23:27:09 +01:00
tibbi
b3fa4bf880 add the properties dialog th the media activity 2016-11-03 23:16:47 +01:00
tibbi
97d6f2d452 implement the Properties dialog at the albums view 2016-11-03 23:12:04 +01:00
tibbi
60536bfdf6 add a properties button to directories view 2016-11-03 23:04:43 +01:00
tibbi
db2b1fedb3 updating readme 2016-11-01 19:37:49 +01:00
tibbi
0889aa76d7 updating changelog 2016-10-25 22:53:20 +02:00
tibbi
871e6d9cf1 update version to 25 (1.25) 2016-10-25 22:52:11 +02:00
tibbi
2f9c63e43b fix up directory sorting 2016-10-25 22:48:30 +02:00
tibbi
9081d1a579 load the directories asynchronously 2016-10-25 22:28:25 +02:00
tibbi
4f289b4c47 play the video at load automatically if set so, fixes #38 2016-10-25 20:50:37 +02:00
tibbi
6e0f60b770 add a toggle for autoplaying videos 2016-10-25 20:42:23 +02:00
tibbi
37bda0c72e minor refactoring 2016-10-25 20:34:09 +02:00
tibbi
07b60e0afb select Dark theme by default 2016-10-25 20:27:02 +02:00
tibbi
def5c9ce2a use white background colors if dark theme isnt selected 2016-10-25 20:26:53 +02:00
Tibor Kaputa
97cc6f4a62 Merge pull request #41 from mueller-ma/patch-1
Translated some strings to german
2016-10-25 11:12:33 +02:00
mueller-ma
fe6b65d407 Translated some strings to german 2016-10-25 11:06:58 +02:00
tibbi
b240ea6692 update gradle to 2.2.2 2016-10-22 13:46:54 +02:00
tibbi
d643cc2822 pass context instead of whole activity to scanFile 2016-10-16 19:19:40 +02:00
tibbi
34158c217c update gradle to 2.2.1 2016-10-16 16:36:22 +02:00
109 changed files with 3027 additions and 2224 deletions

View File

@@ -1,6 +1,61 @@
Changelog
==========
Version 1.32 *(2016-11-13)*
----------------------------
* Added Chinese translation
* Couple small bugfixes
Version 1.31 *(2016-11-12)*
----------------------------
* Add a Move function
* Many small improvements, mostly related to Copy/Move
Version 1.30 *(2016-11-10)*
----------------------------
* Some improvements to the Copy function
* Allow displaying filenames at the thumbnail view
* Changing the bottom shadow to gradient
Version 1.29 *(2016-11-09)*
----------------------------
* Adding an initial implementation of the Copy feature
* Sort items by date_modified instead of date_taken
* Make "Save as" the only saving option in the editor
* Autoplay videos only if selected so
Version 1.28 *(2016-11-07)*
----------------------------
* Couple file operation fixes on devices without SD card
* Set the default folder sorting by Date, descending
* Couple Spanish string corrections
Version 1.27 *(2016-11-06)*
----------------------------
* Add a "Save as" option to the editor
* Fix file operations on SD card
* Do not delete folders recursively, just the direct children
* Many other small improvements
Version 1.26 *(2016-11-03)*
----------------------------
* Add a menu item for Properties
Version 1.25 *(2016-10-25)*
----------------------------
* Change the light themes window backgrounds to white
* Change the default theme to dark
* Add an option for autoplaying videos
* Misc performance improvements
Version 1.24 *(2016-10-09)*
----------------------------

View File

@@ -3,18 +3,20 @@
A gallery for viewing photos and videos.
A simple tool usable for viewing photos and videos. Items can be sorted by date, size, name both ascending or descending, photos can be zoomed in. Media files are shown in multiple columns, depending on the size of the display. They can be renamed, shared or deleted. Images can also be cropped, rotated or set as Wallpaper directly from the app.
A simple tool usable for viewing photos and videos. Items can be sorted by date, size, name both ascending or descending, photos can be zoomed in. Media files are shown in multiple columns, depending on the size of the display. They can be renamed, shared, deleted, copied, moved. Images can also be cropped, rotated or set as Wallpaper directly from the app.
The Gallery is also offered for third party usage for previewing images / videos, adding attachments at email clients etc. It's perfect for everyday usage.
Contains no ads or unnecessary permissions. It is fully opensource, provides a Dark theme too.
This app is just one piece of a bigger series of apps. You can find the rest of them at http://www.simplemobiletools.com
<a href='https://play.google.com/store/apps/details?id=com.simplemobiletools.gallery'><img alt='Get it on Google Play' src='https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png' height=60/></a>
<a href="https://f-droid.org/app/com.simplemobiletools.gallery"><img src="https://f-droid.org/badge/get-it-on.png" alt="Get it on F-Droid" height="60"></a>
<img alt="App image" src="screenshots/app.jpg" width="250">
<img alt="App image" src="screenshots/app_2.jpg" width="250">
<img alt="App image" src="screenshots/app_3.jpg" width="250">
<img alt="App image" src="screenshots/app_5.jpg" width="250">
License
-------

View File

@@ -11,8 +11,8 @@ android {
applicationId "com.simplemobiletools.gallery"
minSdkVersion 16
targetSdkVersion 23
versionCode 24
versionName "1.24"
versionCode 32
versionName "1.32"
}
signingConfigs {
@@ -27,6 +27,10 @@ android {
}
}
packagingOptions {
exclude 'META-INF/library-compileDebugKotlin.kotlin_module'
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
@@ -42,15 +46,13 @@ dependencies {
compile 'com.davemorrissey.labs:subsampling-scale-image-view:3.5.0'
compile 'com.theartofdev.edmodo:android-image-cropper:2.3.1'
compile 'com.booking:rtlviewpager:1.0.1'
compile 'com.simplemobiletools:fileproperties:1.0.3@aar'
compile 'com.simplemobiletools:filepicker:1.3.20@aar'
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
apt 'com.jakewharton:butterknife-compiler:8.0.1'
}
repositories {
mavenCentral()
}
buildscript {
ext.kotlin_version = '1.0.3'
repositories {

View File

@@ -15,3 +15,5 @@
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
-keep class com.simplemobiletools.** { *; }
-dontwarn com.simplemobiletools.**

View File

@@ -1,105 +0,0 @@
package com.simplemobiletools.gallery;
import android.content.Context;
import android.content.SharedPreferences;
import java.util.HashSet;
import java.util.Set;
public class Config {
private SharedPreferences mPrefs;
public static Config newInstance(Context context) {
return new Config(context);
}
private Config(Context context) {
mPrefs = context.getSharedPreferences(Constants.PREFS_KEY, Context.MODE_PRIVATE);
}
public boolean getIsFirstRun() {
return mPrefs.getBoolean(Constants.IS_FIRST_RUN, true);
}
public void setIsFirstRun(boolean firstRun) {
mPrefs.edit().putBoolean(Constants.IS_FIRST_RUN, firstRun).apply();
}
public boolean getIsDarkTheme() {
return mPrefs.getBoolean(Constants.IS_DARK_THEME, false);
}
public void setIsDarkTheme(boolean isDarkTheme) {
mPrefs.edit().putBoolean(Constants.IS_DARK_THEME, isDarkTheme).apply();
}
public boolean getIsSameSorting() {
return mPrefs.getBoolean(Constants.IS_SAME_SORTING, true);
}
public void setIsSameSorting(boolean isSameSorting) {
mPrefs.edit().putBoolean(Constants.IS_SAME_SORTING, isSameSorting).apply();
}
public int getSorting() {
if (getIsSameSorting())
return getDirectorySorting();
return mPrefs.getInt(Constants.SORT_ORDER, Constants.SORT_BY_DATE | Constants.SORT_DESCENDING);
}
public void setSorting(int order) {
if (getIsSameSorting())
setDirectorySorting(order);
else
mPrefs.edit().putInt(Constants.SORT_ORDER, order).apply();
}
public int getDirectorySorting() {
return mPrefs.getInt(Constants.DIRECTORY_SORT_ORDER, Constants.SORT_BY_NAME);
}
public void setDirectorySorting(int order) {
mPrefs.edit().putInt(Constants.DIRECTORY_SORT_ORDER, order).apply();
}
public boolean getShowHiddenFolders() {
return mPrefs.getBoolean(Constants.SHOW_HIDDEN_FOLDERS, false);
}
public void setShowHiddenFolders(boolean showHiddenFolders) {
mPrefs.edit().putBoolean(Constants.SHOW_HIDDEN_FOLDERS, showHiddenFolders).apply();
}
public void addHiddenDirectory(String path) {
final Set<String> hiddenFolders = getHiddenFolders();
hiddenFolders.add(path);
mPrefs.edit().putStringSet(Constants.HIDDEN_FOLDERS, hiddenFolders).apply();
}
public void addHiddenDirectories(Set<String> paths) {
final Set<String> hiddenFolders = getHiddenFolders();
hiddenFolders.addAll(paths);
mPrefs.edit().putStringSet(Constants.HIDDEN_FOLDERS, hiddenFolders).apply();
}
public void removeHiddenDirectory(String path) {
final Set<String> hiddenFolders = getHiddenFolders();
hiddenFolders.remove(path);
mPrefs.edit().putStringSet(Constants.HIDDEN_FOLDERS, hiddenFolders).apply();
}
public void removeHiddenDirectories(Set<String> paths) {
final Set<String> hiddenFolders = getHiddenFolders();
hiddenFolders.removeAll(paths);
mPrefs.edit().putStringSet(Constants.HIDDEN_FOLDERS, hiddenFolders).apply();
}
public Set<String> getHiddenFolders() {
return mPrefs.getStringSet(Constants.HIDDEN_FOLDERS, new HashSet<String>());
}
public boolean getIsFolderHidden(String path) {
return getHiddenFolders().contains(path);
}
}

View File

@@ -17,6 +17,9 @@ public class Constants {
public static final String DIRECTORY_SORT_ORDER = "directory_sort_order";
public static final String HIDDEN_FOLDERS = "hidden_folders";
public static final String SHOW_HIDDEN_FOLDERS = "show_hidden_folders";
public static final String AUTOPLAY_VIDEOS = "autoplay_videos";
public static final String TREE_URI = "tree_uri";
public static final String DISPLAY_FILE_NAMES = "display_file_names";
// sorting
public static final int SORT_BY_NAME = 1;
@@ -24,4 +27,7 @@ public class Constants {
public static final int SORT_BY_SIZE = 4;
public static final int SORT_DESCENDING = 1024;
// global intents
public static final int OPEN_DOCUMENT_TREE = 1000;
}

View File

@@ -1,26 +0,0 @@
package com.simplemobiletools.gallery;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ImageView;
public class MyImageView extends ImageView {
public MyImageView(Context context) {
super(context);
}
public MyImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(getMeasuredWidth(), getMeasuredWidth());
}
}

View File

@@ -1,38 +0,0 @@
package com.simplemobiletools.gallery;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import com.booking.rtlviewpager.RtlViewPager;
public class MyViewPager extends RtlViewPager {
public MyViewPager(Context context) {
super(context);
}
public MyViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
try {
return super.onInterceptTouchEvent(ev);
} catch (IllegalArgumentException ex) {
ex.printStackTrace();
}
return false;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
try {
return super.onTouchEvent(ev);
} catch (IllegalArgumentException ex) {
ex.printStackTrace();
}
return false;
}
}

View File

@@ -1,153 +0,0 @@
package com.simplemobiletools.gallery;
import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.provider.MediaStore;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.ActionBar;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.Display;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.Window;
import android.webkit.MimeTypeMap;
import android.widget.Toast;
import com.simplemobiletools.gallery.models.Medium;
import java.io.File;
public class Utils {
public static String getFilename(final String path) {
return path.substring(path.lastIndexOf("/") + 1);
}
public static void showToast(Context context, int resId) {
Toast.makeText(context, context.getResources().getString(resId), Toast.LENGTH_SHORT).show();
}
public static int getActionBarHeight(Context context, Resources res) {
final TypedValue tv = new TypedValue();
int height = 0;
if (context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) {
height = TypedValue.complexToDimensionPixelSize(tv.data, res.getDisplayMetrics());
}
return height;
}
public static int getStatusBarHeight(Resources res) {
int id = res.getIdentifier("status_bar_height", "dimen", "android");
if (id > 0) {
return res.getDimensionPixelSize(id);
}
return 0;
}
public static int getNavBarHeight(Resources res) {
int id = res.getIdentifier("navigation_bar_height", "dimen", "android");
if (id > 0) {
return res.getDimensionPixelSize(id);
}
return 0;
}
public static boolean hasNavBar(Activity act) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
Display display = act.getWindowManager().getDefaultDisplay();
DisplayMetrics realDisplayMetrics = new DisplayMetrics();
display.getRealMetrics(realDisplayMetrics);
int realHeight = realDisplayMetrics.heightPixels;
int realWidth = realDisplayMetrics.widthPixels;
DisplayMetrics displayMetrics = new DisplayMetrics();
display.getMetrics(displayMetrics);
int displayHeight = displayMetrics.heightPixels;
int displayWidth = displayMetrics.widthPixels;
return (realWidth - displayWidth) > 0 || (realHeight - displayHeight) > 0;
} else {
boolean hasMenuKey = ViewConfiguration.get(act).hasPermanentMenuKey();
boolean hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
return !hasMenuKey && !hasBackKey;
}
}
public static boolean hasStoragePermission(Context cxt) {
return ContextCompat.checkSelfPermission(cxt, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
}
public static String getMimeType(String url) {
final String extension = MimeTypeMap.getFileExtensionFromUrl(url);
if (extension != null) {
return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
}
return "";
}
public static void shareMedium(Medium medium, Activity activity) {
final String shareTitle = activity.getResources().getString(R.string.share_via);
final Intent intent = new Intent();
final File file = new File(medium.getPath());
final Uri uri = Uri.fromFile(file);
intent.setAction(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_STREAM, uri);
intent.setType(getMimeType(medium));
activity.startActivity(Intent.createChooser(intent, shareTitle));
}
public static String getMimeType(Medium medium) {
if (medium.getIsVideo())
return "video/*";
else
return "image/*";
}
public static void showSystemUI(ActionBar actionbar, Window window) {
if (actionbar != null)
actionbar.show();
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}
public static void hideSystemUI(ActionBar actionbar, Window window) {
if (actionbar != null)
actionbar.hide();
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
View.SYSTEM_UI_FLAG_LOW_PROFILE |
View.SYSTEM_UI_FLAG_FULLSCREEN |
View.SYSTEM_UI_FLAG_IMMERSIVE);
}
public static String getRealPathFromURI(Context context, Uri uri) {
Cursor cursor = null;
try {
String[] projection = {MediaStore.Images.Media.DATA};
cursor = context.getContentResolver().query(uri, projection, null, null, null);
int index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(index);
} finally {
if (cursor != null) {
cursor.close();
}
}
}
}

View File

@@ -1,136 +0,0 @@
package com.simplemobiletools.gallery;
import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Build;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.ActionBar;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.Display;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.Window;
import android.webkit.MimeTypeMap;
import android.widget.Toast;
import com.simplemobiletools.gallery.models.Medium;
import java.io.File;
public class ViewServer {
public static String getFilename(final String path) {
return path.substring(path.lastIndexOf("/") + 1);
}
public static void showToast(Context context, int resId) {
Toast.makeText(context, context.getResources().getString(resId), Toast.LENGTH_SHORT).show();
}
public static int getActionBarHeight(Context context, Resources res) {
final TypedValue tv = new TypedValue();
int height = 0;
if (context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) {
height = TypedValue.complexToDimensionPixelSize(tv.data, res.getDisplayMetrics());
}
return height;
}
public static int getStatusBarHeight(Resources res) {
int id = res.getIdentifier("status_bar_height", "dimen", "android");
if (id > 0) {
return res.getDimensionPixelSize(id);
}
return 0;
}
public static int getNavBarHeight(Resources res) {
int id = res.getIdentifier("navigation_bar_height", "dimen", "android");
if (id > 0) {
return res.getDimensionPixelSize(id);
}
return 0;
}
public static boolean hasNavBar(Activity act) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
Display display = act.getWindowManager().getDefaultDisplay();
DisplayMetrics realDisplayMetrics = new DisplayMetrics();
display.getRealMetrics(realDisplayMetrics);
int realHeight = realDisplayMetrics.heightPixels;
int realWidth = realDisplayMetrics.widthPixels;
DisplayMetrics displayMetrics = new DisplayMetrics();
display.getMetrics(displayMetrics);
int displayHeight = displayMetrics.heightPixels;
int displayWidth = displayMetrics.widthPixels;
return (realWidth - displayWidth) > 0 || (realHeight - displayHeight) > 0;
} else {
boolean hasMenuKey = ViewConfiguration.get(act).hasPermanentMenuKey();
boolean hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
return !hasMenuKey && !hasBackKey;
}
}
public static boolean hasStoragePermission(Context cxt) {
return ContextCompat.checkSelfPermission(cxt, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
}
public static String getMimeType(String url) {
final String extension = MimeTypeMap.getFileExtensionFromUrl(url);
if (extension != null) {
return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
}
return "";
}
public static void shareMedium(Medium medium, Activity activity) {
final String shareTitle = activity.getResources().getString(R.string.share_via);
final Intent intent = new Intent();
final File file = new File(medium.getPath());
final Uri uri = Uri.fromFile(file);
intent.setAction(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_STREAM, uri);
intent.setType(getMimeType(medium));
activity.startActivity(Intent.createChooser(intent, shareTitle));
}
public static String getMimeType(Medium medium) {
if (medium.getIsVideo())
return "video/*";
else
return "image/*";
}
public static void showSystemUI(ActionBar actionbar, Window window) {
if (actionbar != null)
actionbar.show();
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}
public static void hideSystemUI(ActionBar actionbar, Window window) {
if (actionbar != null)
actionbar.hide();
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
View.SYSTEM_UI_FLAG_LOW_PROFILE |
View.SYSTEM_UI_FLAG_FULLSCREEN |
View.SYSTEM_UI_FLAG_IMMERSIVE);
}
}

View File

@@ -1,110 +0,0 @@
package com.simplemobiletools.gallery.activities;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Bundle;
import android.text.Html;
import android.text.method.LinkMovementMethod;
import android.view.View;
import android.widget.TextView;
import com.simplemobiletools.gallery.BuildConfig;
import com.simplemobiletools.gallery.Config;
import com.simplemobiletools.gallery.R;
import java.util.Calendar;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class AboutActivity extends SimpleActivity {
@BindView(R.id.about_copyright) TextView mCopyright;
@BindView(R.id.about_email) TextView mEmailTV;
@BindView(R.id.about_rate_us) View mRateUs;
private static Resources mRes;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_about);
ButterKnife.bind(this);
mRes = getResources();
setupEmail();
setupCopyright();
setupRateUs();
}
private void setupEmail() {
final String email = mRes.getString(R.string.email);
final String appName = mRes.getString(R.string.app_name);
final String href = "<a href=\"mailto:" + email + "?subject=" + appName + "\">" + email + "</a>";
mEmailTV.setText(Html.fromHtml(href));
mEmailTV.setMovementMethod(LinkMovementMethod.getInstance());
}
private void setupCopyright() {
final String versionName = BuildConfig.VERSION_NAME;
final int year = Calendar.getInstance().get(Calendar.YEAR);
final String copyrightText = String.format(mRes.getString(R.string.copyright), versionName, year);
mCopyright.setText(copyrightText);
}
private void setupRateUs() {
if (Config.newInstance(getApplicationContext()).getIsFirstRun()) {
mRateUs.setVisibility(View.GONE);
}
}
@OnClick(R.id.about_invite)
public void inviteFriend() {
final Intent intent = new Intent();
final String text = String.format(getString(R.string.share_text), getString(R.string.app_name), getStoreUrl());
intent.setAction(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.app_name));
intent.putExtra(Intent.EXTRA_TEXT, text);
intent.setType("text/plain");
startActivity(Intent.createChooser(intent, getString(R.string.invite_via)));
}
@OnClick(R.id.about_rate_us)
public void rateUsClicked() {
final Uri uri = Uri.parse("market://details?id=" + getPackageName());
try {
startActivity(new Intent(Intent.ACTION_VIEW, uri));
} catch (ActivityNotFoundException ignored) {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(getStoreUrl())));
}
}
@OnClick(R.id.about_license)
public void licenseClicked() {
final Intent intent = new Intent(getApplicationContext(), LicenseActivity.class);
startActivity(intent);
}
@OnClick(R.id.about_facebook)
public void facebookClicked() {
String link = "https://www.facebook.com/simplemobiletools";
try {
getPackageManager().getPackageInfo("com.facebook.katana", 0);
link = "fb://page/150270895341774";
} catch (Exception ignored) {
}
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(link)));
}
@OnClick(R.id.about_gplus)
public void googlePlusClicked() {
final String link = "https://plus.google.com/communities/104880861558693868382";
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(link)));
}
private String getStoreUrl() {
return "https://play.google.com/store/apps/details?id=" + getPackageName();
}
}

View File

@@ -1,46 +0,0 @@
package com.simplemobiletools.gallery.activities;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import com.simplemobiletools.gallery.R;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class LicenseActivity extends SimpleActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_license);
ButterKnife.bind(this);
}
@OnClick(R.id.license_butterknife_title)
public void butterKnifeClicked() {
openUrl(R.string.butterknife_url);
}
@OnClick(R.id.license_photoview_title)
public void photoViewClicked() {
openUrl(R.string.photoview_url);
}
@OnClick(R.id.license_glide_title)
public void glideClicked() {
openUrl(R.string.glide_url);
}
@OnClick(R.id.license_cropper_title)
public void cropperClicked() {
openUrl(R.string.cropper_url);
}
private void openUrl(int id) {
final String url = getResources().getString(id);
final Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(browserIntent);
}
}

View File

@@ -4,7 +4,6 @@ import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Color;
import android.media.MediaScannerConnection;
import android.net.Uri;
@@ -14,8 +13,8 @@ import android.provider.MediaStore;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.Snackbar;
import android.support.v4.app.ActivityCompat;
import android.support.v4.provider.DocumentFile;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AlertDialog;
import android.util.SparseBooleanArray;
import android.view.ActionMode;
import android.view.Menu;
@@ -24,26 +23,27 @@ import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.GridView;
import android.widget.TextView;
import com.simplemobiletools.gallery.Config;
import com.simplemobiletools.filepicker.asynctasks.CopyMoveTask;
import com.simplemobiletools.fileproperties.dialogs.PropertiesDialog;
import com.simplemobiletools.gallery.Constants;
import com.simplemobiletools.gallery.R;
import com.simplemobiletools.gallery.Utils;
import com.simplemobiletools.gallery.adapters.DirectoryAdapter;
import com.simplemobiletools.gallery.asynctasks.GetDirectoriesAsynctask;
import com.simplemobiletools.gallery.dialogs.ChangeSorting;
import com.simplemobiletools.gallery.dialogs.CopyDialog;
import com.simplemobiletools.gallery.dialogs.RenameDirectoryDialog;
import com.simplemobiletools.gallery.models.Directory;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import butterknife.BindView;
@@ -51,7 +51,7 @@ import butterknife.ButterKnife;
public class MainActivity extends SimpleActivity
implements AdapterView.OnItemClickListener, GridView.MultiChoiceModeListener, GridView.OnTouchListener,
SwipeRefreshLayout.OnRefreshListener, ChangeSorting.ChangeDialogListener {
SwipeRefreshLayout.OnRefreshListener, ChangeSorting.ChangeDialogListener, GetDirectoriesAsynctask.GetDirectoriesListener {
@BindView(R.id.directories_grid) GridView mGridView;
@BindView(R.id.directories_holder) SwipeRefreshLayout mSwipeRefreshLayout;
@@ -73,6 +73,7 @@ public class MainActivity extends SimpleActivity
private static boolean mIsGetAnyContentIntent;
private static boolean mIsSetWallpaperIntent;
private static boolean mIsThirdPartyIntent;
private static boolean mIsGettingDirs;
private static int mSelectedItemsCnt;
@Override
@@ -144,14 +145,14 @@ public class MainActivity extends SimpleActivity
@Override
protected void onDestroy() {
super.onDestroy();
Config.newInstance(getApplicationContext()).setIsFirstRun(false);
mConfig.setFirstRun(false);
}
private void tryloadGallery() {
if (Utils.hasStoragePermission(getApplicationContext())) {
initializeGallery();
if (Utils.Companion.hasStoragePermission(getApplicationContext())) {
getDirectories();
} else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, STORAGE_PERMISSION);
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, STORAGE_PERMISSION);
}
}
@@ -161,139 +162,21 @@ public class MainActivity extends SimpleActivity
if (requestCode == STORAGE_PERMISSION) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
initializeGallery();
getDirectories();
} else {
Utils.showToast(getApplicationContext(), R.string.no_permissions);
Utils.Companion.showToast(getApplicationContext(), R.string.no_permissions);
finish();
}
}
}
private void initializeGallery() {
final List<Directory> newDirs = getDirectories();
if (newDirs.toString().equals(mDirs.toString())) {
private void getDirectories() {
if (mIsGettingDirs)
return;
}
mDirs = newDirs;
final DirectoryAdapter adapter = new DirectoryAdapter(this, mDirs);
mGridView.setAdapter(adapter);
mGridView.setOnItemClickListener(this);
mGridView.setMultiChoiceModeListener(this);
mGridView.setOnTouchListener(this);
}
private List<Directory> getDirectories() {
final Map<String, Directory> directories = new LinkedHashMap<>();
final List<String> invalidFiles = new ArrayList<>();
for (int i = 0; i < 2; i++) {
if ((mIsPickVideoIntent || mIsGetVideoContentIntent) && i == 0)
continue;
Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
if (i == 1) {
if (mIsPickImageIntent || mIsGetImageContentIntent)
continue;
uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
}
final String[] columns = {MediaStore.Images.Media.DATA, MediaStore.Images.Media.DATE_TAKEN};
final String order = getSortOrder();
final Cursor cursor = getContentResolver().query(uri, columns, null, null, order);
if (cursor != null && cursor.moveToFirst()) {
final int pathIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA);
do {
final String fullPath = cursor.getString(pathIndex);
final File file = new File(fullPath);
final String parentDir = file.getParent();
if (!file.exists()) {
invalidFiles.add(file.getAbsolutePath());
continue;
}
final int dateIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATE_TAKEN);
final long timestamp = cursor.getLong(dateIndex);
if (directories.containsKey(parentDir)) {
final Directory directory = directories.get(parentDir);
final int newImageCnt = directory.getMediaCnt() + 1;
directory.setMediaCnt(newImageCnt);
directory.addSize(file.length());
} else if (!mToBeDeleted.contains(parentDir)) {
String dirName = Utils.getFilename(parentDir);
if (mConfig.getIsFolderHidden(parentDir)) {
dirName += " " + getResources().getString(R.string.hidden);
}
directories.put(parentDir, new Directory(parentDir, fullPath, dirName, 1, timestamp, file.length()));
}
} while (cursor.moveToNext());
cursor.close();
}
}
final List<Directory> dirs = new ArrayList<>(directories.values());
filterDirectories(dirs);
Directory.mSorting = mConfig.getDirectorySorting();
Collections.sort(dirs);
final String[] invalids = invalidFiles.toArray(new String[invalidFiles.size()]);
MediaScannerConnection.scanFile(getApplicationContext(), invalids, null, null);
return dirs;
}
private void filterDirectories(List<Directory> dirs) {
if (!mConfig.getShowHiddenFolders())
removeHiddenFolders(dirs);
removeNoMediaFolders(dirs);
}
private void removeHiddenFolders(List<Directory> dirs) {
final Set<String> hiddenDirs = mConfig.getHiddenFolders();
final List<Directory> ignoreDirs = new ArrayList<>();
for (Directory d : dirs) {
if (hiddenDirs.contains(d.getPath()))
ignoreDirs.add(d);
}
dirs.removeAll(ignoreDirs);
}
private void removeNoMediaFolders(List<Directory> dirs) {
final List<Directory> ignoreDirs = new ArrayList<>();
for (final Directory d : dirs) {
final File dir = new File(d.getPath());
if (dir.exists() && dir.isDirectory()) {
final String[] res = dir.list(new FilenameFilter() {
@Override
public boolean accept(File file, String filename) {
return filename.equals(".nomedia");
}
});
if (res.length > 0)
ignoreDirs.add(d);
}
}
dirs.removeAll(ignoreDirs);
}
// sort the files at querying too, just to get the correct thumbnail
private String getSortOrder() {
final int sorting = mConfig.getDirectorySorting();
String sortBy = MediaStore.Images.Media.DATE_TAKEN;
if ((sorting & Constants.SORT_BY_NAME) != 0) {
sortBy = MediaStore.Images.Media.DATA;
}
if ((sorting & Constants.SORT_DESCENDING) != 0) {
sortBy += " DESC";
}
return sortBy;
mIsGettingDirs = true;
new GetDirectoriesAsynctask(getApplicationContext(), mIsPickVideoIntent || mIsGetVideoContentIntent, mIsPickImageIntent || mIsGetImageContentIntent,
mToBeDeleted, this).execute();
}
private void showSortingDialog() {
@@ -301,7 +184,7 @@ public class MainActivity extends SimpleActivity
}
private void prepareForDeleting() {
Utils.showToast(this, R.string.deleting);
Utils.Companion.showToast(this, R.string.deleting);
final SparseBooleanArray items = mGridView.getCheckedItemPositions();
final int cnt = items.size();
int deletedCnt = 0;
@@ -314,11 +197,17 @@ public class MainActivity extends SimpleActivity
}
}
for (String path : mToBeDeleted) {
if (isShowingPermDialog(new File(path))) {
return;
}
}
notifyDeletion(deletedCnt);
}
private void notifyDeletion(int cnt) {
mDirs = getDirectories();
getDirectories();
final CoordinatorLayout coordinator = (CoordinatorLayout) findViewById(R.id.coordinator_layout);
final Resources res = getResources();
@@ -328,7 +217,6 @@ public class MainActivity extends SimpleActivity
mSnackbar.setActionTextColor(Color.WHITE);
mSnackbar.show();
mIsSnackbarShown = true;
updateGridView();
}
private void deleteDirs() {
@@ -341,39 +229,64 @@ public class MainActivity extends SimpleActivity
mIsSnackbarShown = false;
final List<String> updatedFiles = new ArrayList<>();
final ArrayList<File> updatedFiles = new ArrayList<>();
for (String delPath : mToBeDeleted) {
final File dir = new File(delPath);
if (dir.exists()) {
final File[] files = dir.listFiles();
for (File f : files) {
updatedFiles.add(f.getAbsolutePath());
f.delete();
for (File file : files) {
if (file.isFile() && Utils.Companion.isPhotoVideo(file)) {
updatedFiles.add(file);
deleteItem(file);
}
}
updatedFiles.add(dir.getAbsolutePath());
dir.delete();
updatedFiles.add(dir);
if (dir.listFiles().length == 0)
deleteItem(dir);
}
}
final String[] deletedPaths = updatedFiles.toArray(new String[updatedFiles.size()]);
MediaScannerConnection.scanFile(this, deletedPaths, null, null);
Utils.Companion.scanFiles(getApplicationContext(), updatedFiles);
mToBeDeleted.clear();
}
private void deleteItem(File file) {
if (Utils.Companion.needsStupidWritePermissions(this, file.getAbsolutePath())) {
if (!isShowingPermDialog(file)) {
final DocumentFile document = Utils.Companion.getFileDocument(this, file.getAbsolutePath(), mConfig.getTreeUri());
document.delete();
}
} else {
file.delete();
}
}
private View.OnClickListener undoDeletion = new View.OnClickListener() {
@Override
public void onClick(View v) {
mSnackbar.dismiss();
mIsSnackbarShown = false;
mToBeDeleted.clear();
mDirs = getDirectories();
updateGridView();
getDirectories();
}
};
private void updateGridView() {
final DirectoryAdapter adapter = (DirectoryAdapter) mGridView.getAdapter();
adapter.updateItems(mDirs);
private void showProperties() {
final SparseBooleanArray items = mGridView.getCheckedItemPositions();
if (items.size() == 1) {
new PropertiesDialog(this, (String) getSelectedPaths().toArray()[0], false);
} else {
final List<String> paths = new ArrayList<>(items.size());
final int cnt = items.size();
for (int i = 0; i < cnt; i++) {
if (items.valueAt(i)) {
final int id = items.keyAt(i);
paths.add(mDirs.get(id).getPath());
}
}
new PropertiesDialog(this, paths, false);
}
}
private void editDirectory() {
@@ -391,59 +304,53 @@ public class MainActivity extends SimpleActivity
private void renameDir(final String path) {
final File dir = new File(path);
if (Utils.Companion.isAStorageRootFolder(this, path)) {
Utils.Companion.showToast(this, R.string.rename_folder_root);
return;
}
final View renameDirView = getLayoutInflater().inflate(R.layout.rename_directory, null);
final EditText dirNameET = (EditText) renameDirView.findViewById(R.id.directory_name);
dirNameET.setText(dir.getName());
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(getResources().getString(R.string.rename_folder));
builder.setView(renameDirView);
final TextView dirPath = (TextView) renameDirView.findViewById(R.id.directory_path);
dirPath.setText(dir.getParent() + "/");
builder.setPositiveButton(R.string.ok, null);
builder.setNegativeButton(R.string.cancel, null);
final AlertDialog alertDialog = builder.create();
alertDialog.show();
alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() {
new RenameDirectoryDialog(this, dir, new RenameDirectoryDialog.OnRenameDirListener() {
@Override
public void onClick(View v) {
final String newDirName = dirNameET.getText().toString().trim();
if (newDirName.isEmpty()) {
Utils.showToast(getApplicationContext(), R.string.rename_folder_empty);
return;
}
final List<String> updatedFiles = new ArrayList<>();
updatedFiles.add(dir.getAbsolutePath());
final File newDir = new File(dir.getParent(), newDirName);
if (dir.renameTo(newDir)) {
Utils.showToast(getApplicationContext(), R.string.renaming_folder);
alertDialog.dismiss();
mActionMode.finish();
final File[] files = newDir.listFiles();
for (File f : files) {
updatedFiles.add(f.getAbsolutePath());
public void onRenameDirSuccess(@NotNull String[] changedFiles) {
mActionMode.finish();
MediaScannerConnection.scanFile(getApplicationContext(), changedFiles, null, new MediaScannerConnection.OnScanCompletedListener() {
@Override
public void onScanCompleted(String path, Uri uri) {
scanCompleted(path);
}
});
}
});
}
updatedFiles.add(newDir.getAbsolutePath());
final String[] changedFiles = updatedFiles.toArray(new String[updatedFiles.size()]);
MediaScannerConnection
.scanFile(getApplicationContext(), changedFiles, null, new MediaScannerConnection.OnScanCompletedListener() {
@Override
public void onScanCompleted(String path, Uri uri) {
scanCompleted(path);
}
});
private void displayCopyDialog() {
final ArrayList<File> files = new ArrayList<>();
final SparseBooleanArray items = mGridView.getCheckedItemPositions();
final int cnt = items.size();
for (int i = 0; i < cnt; i++) {
if (items.valueAt(i)) {
final int id = items.keyAt(i);
final File dir = new File(mDirs.get(id).getPath());
files.addAll(Arrays.asList(dir.listFiles()));
}
}
new CopyDialog(this, files, new CopyMoveTask.CopyMoveListener() {
@Override
public void copySucceeded(boolean deleted, boolean copiedAll) {
int msgId;
if (deleted) {
getDirectories();
msgId = copiedAll ? R.string.moving_success : R.string.moving_success_partial;
} else {
Utils.showToast(getApplicationContext(), R.string.rename_folder_error);
msgId = copiedAll ? R.string.copying_success : R.string.copying_success_partial;
}
Utils.Companion.showToast(getApplicationContext(), msgId);
}
@Override
public void copyFailed() {
Utils.Companion.showToast(getApplicationContext(), R.string.copy_move_failed);
}
});
}
@@ -504,14 +411,14 @@ public class MainActivity extends SimpleActivity
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
protected void onActivityResult(int requestCode, int resultCode, Intent resultData) {
if (resultCode == RESULT_OK) {
if (requestCode == PICK_MEDIA && data != null) {
if (requestCode == PICK_MEDIA && resultData != null) {
final Intent result = new Intent();
final String path = data.getData().getPath();
final String path = resultData.getData().getPath();
final Uri uri = Uri.fromFile(new File(path));
if (mIsGetImageContentIntent || mIsGetVideoContentIntent || mIsGetAnyContentIntent) {
final String type = Utils.getMimeType(path);
final String type = Utils.Companion.getMimeType(path);
result.setDataAndTypeAndNormalize(uri, type);
result.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
} else if (mIsPickImageIntent || mIsPickVideoIntent) {
@@ -526,7 +433,7 @@ public class MainActivity extends SimpleActivity
finish();
}
}
super.onActivityResult(requestCode, resultCode, data);
super.onActivityResult(requestCode, resultCode, resultData);
}
@Override
@@ -563,7 +470,7 @@ public class MainActivity extends SimpleActivity
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
final MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.directories_cab, menu);
inflater.inflate(R.menu.cab_directories, menu);
mActionMode = mode;
return true;
}
@@ -595,6 +502,9 @@ public class MainActivity extends SimpleActivity
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.cab_properties:
showProperties();
return true;
case R.id.cab_edit:
editDirectory();
return true;
@@ -610,6 +520,9 @@ public class MainActivity extends SimpleActivity
unhideFolders();
mode.finish();
return true;
case R.id.cab_copy_move:
displayCopyDialog();
return true;
default:
return false;
}
@@ -631,12 +544,12 @@ public class MainActivity extends SimpleActivity
private void hideFolders() {
mConfig.addHiddenDirectories(getSelectedPaths());
initializeGallery();
getDirectories();
}
private void unhideFolders() {
mConfig.removeHiddenDirectories(getSelectedPaths());
initializeGallery();
getDirectories();
}
private Set<String> getSelectedPaths() {
@@ -655,14 +568,12 @@ public class MainActivity extends SimpleActivity
private void scanCompleted(final String path) {
final File dir = new File(path);
if (dir.isDirectory()) {
mDirs = getDirectories();
getDirectories();
runOnUiThread(new Runnable() {
@Override
public void run() {
updateGridView();
mGridView.requestLayout();
Utils.showToast(getApplicationContext(), R.string.rename_folder_ok);
Utils.Companion.showToast(getApplicationContext(), R.string.rename_folder_ok);
}
});
}
@@ -670,12 +581,28 @@ public class MainActivity extends SimpleActivity
@Override
public void onRefresh() {
initializeGallery();
getDirectories();
mSwipeRefreshLayout.setRefreshing(false);
}
@Override
public void dialogClosed() {
initializeGallery();
public void sortingDialogClosed() {
getDirectories();
}
@Override
public void gotDirectories(@NotNull ArrayList<Directory> dirs) {
mIsGettingDirs = false;
if (dirs.toString().equals(mDirs.toString())) {
return;
}
mDirs = dirs;
final DirectoryAdapter adapter = new DirectoryAdapter(this, mDirs);
mGridView.setAdapter(adapter);
mGridView.setOnItemClickListener(this);
mGridView.setMultiChoiceModeListener(this);
mGridView.setOnTouchListener(this);
mGridView.setChoiceMode(GridView.CHOICE_MODE_MULTIPLE_MODAL);
}
}

View File

@@ -13,6 +13,7 @@ import android.os.Parcelable;
import android.provider.MediaStore;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.Snackbar;
import android.support.v4.provider.DocumentFile;
import android.support.v4.widget.SwipeRefreshLayout;
import android.util.Log;
import android.util.SparseBooleanArray;
@@ -28,11 +29,14 @@ import android.widget.GridView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.animation.GlideAnimation;
import com.bumptech.glide.request.target.SimpleTarget;
import com.simplemobiletools.filepicker.asynctasks.CopyMoveTask;
import com.simplemobiletools.fileproperties.dialogs.PropertiesDialog;
import com.simplemobiletools.gallery.Constants;
import com.simplemobiletools.gallery.R;
import com.simplemobiletools.gallery.Utils;
import com.simplemobiletools.gallery.adapters.MediaAdapter;
import com.simplemobiletools.gallery.dialogs.ChangeSorting;
import com.simplemobiletools.gallery.dialogs.CopyDialog;
import com.simplemobiletools.gallery.models.Medium;
import java.io.File;
@@ -99,7 +103,7 @@ public class MediaActivity extends SimpleActivity
}
private void tryloadGallery() {
if (Utils.hasStoragePermission(getApplicationContext())) {
if (Utils.Companion.hasStoragePermission(getApplicationContext())) {
initializeGallery();
} else {
finish();
@@ -123,7 +127,7 @@ public class MediaActivity extends SimpleActivity
mGridView.setOnTouchListener(this);
mIsSnackbarShown = false;
final String dirName = Utils.getFilename(mPath);
final String dirName = Utils.Companion.getFilename(this, mPath);
setTitle(dirName);
}
@@ -144,6 +148,9 @@ public class MediaActivity extends SimpleActivity
case R.id.sort:
showSortingDialog();
return true;
case R.id.toggle_filename:
toggleFilenameVisibility();
return true;
case R.id.hide_folder:
hideDirectory();
return true;
@@ -155,17 +162,9 @@ public class MediaActivity extends SimpleActivity
}
}
private void rescanDirectory(File dir) {
final File[] files = dir.listFiles();
final String[] paths = new String[files.length];
final int cnt = dir.listFiles().length;
for (int i = 0; i < cnt; i++) {
paths[i] = files[i].getPath();
if (files[i].isDirectory()) {
rescanDirectory(files[i]);
}
}
MediaScannerConnection.scanFile(getApplicationContext(), paths, null, null);
private void toggleFilenameVisibility() {
mConfig.setDisplayFileNames(!mConfig.getDisplayFileNames());
((MediaAdapter)mGridView.getAdapter()).updateDisplayFilenames(mConfig.getDisplayFileNames());
}
private void showSortingDialog() {
@@ -195,7 +194,7 @@ public class MediaActivity extends SimpleActivity
private List<Medium> getMedia() {
final List<Medium> media = new ArrayList<>();
final List<String> invalidFiles = new ArrayList<>();
final ArrayList<File> invalidFiles = new ArrayList<>();
for (int i = 0; i < 2; i++) {
if (mIsGetVideoIntent && i == 0)
continue;
@@ -209,34 +208,37 @@ public class MediaActivity extends SimpleActivity
}
final String where = MediaStore.Images.Media.DATA + " like ? ";
final String[] args = new String[]{mPath + "%"};
final String[] columns = {MediaStore.Images.Media.DATA, MediaStore.Images.Media.DATE_TAKEN};
final String[] columns = {MediaStore.Images.Media.DATA, MediaStore.Images.Media.DATE_MODIFIED};
final Cursor cursor = getContentResolver().query(uri, columns, where, args, null);
final String pattern = Pattern.quote(mPath) + "/[^/]*";
if (cursor != null && cursor.moveToFirst()) {
final int pathIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA);
do {
final String curPath = cursor.getString(pathIndex);
if (curPath.matches(pattern) && !mToBeDeleted.contains(curPath)) {
final File file = new File(curPath);
if (file.exists()) {
final int dateIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATE_TAKEN);
final long timestamp = cursor.getLong(dateIndex);
media.add(new Medium(curPath, (i == 1), timestamp, file.length()));
} else {
invalidFiles.add(file.getAbsolutePath());
if (cursor != null) {
if (cursor.moveToFirst()) {
final int pathIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA);
do {
final String curPath = cursor.getString(pathIndex);
if (curPath == null)
continue;
if (curPath.matches(pattern) && !mToBeDeleted.contains(curPath)) {
final File file = new File(curPath);
if (file.exists()) {
final int dateIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATE_MODIFIED);
final long timestamp = cursor.getLong(dateIndex);
media.add(new Medium(file.getName(), curPath, (i == 1), timestamp, file.length()));
} else {
invalidFiles.add(file);
}
}
}
} while (cursor.moveToNext());
} while (cursor.moveToNext());
}
cursor.close();
}
}
Medium.mSorting = mConfig.getSorting();
Medium.Companion.setSorting(mConfig.getSorting());
Collections.sort(media);
final String[] invalids = invalidFiles.toArray(new String[invalidFiles.size()]);
MediaScannerConnection.scanFile(getApplicationContext(), invalids, null, null);
Utils.Companion.scanFiles(getApplicationContext(), invalidFiles);
return media;
}
@@ -253,7 +255,7 @@ public class MediaActivity extends SimpleActivity
private void shareMedia() {
final List<Medium> selectedMedia = getSelectedMedia();
if (selectedMedia.size() <= 1) {
Utils.shareMedium(selectedMedia.get(0), this);
Utils.Companion.shareMedium(selectedMedia.get(0), this);
} else {
shareMedia(selectedMedia);
}
@@ -288,7 +290,10 @@ public class MediaActivity extends SimpleActivity
}
private void prepareForDeleting() {
Utils.showToast(this, R.string.deleting);
if (isShowingPermDialog(new File(mPath)))
return;
Utils.Companion.showToast(this, R.string.deleting);
final SparseBooleanArray items = mGridView.getCheckedItemPositions();
final int cnt = items.size();
int deletedCnt = 0;
@@ -331,23 +336,38 @@ public class MediaActivity extends SimpleActivity
}
mIsSnackbarShown = false;
boolean wereFilesDeleted = false;
for (String delPath : mToBeDeleted) {
final File file = new File(delPath);
if (file.exists())
file.delete();
}
if (file.exists()) {
if (Utils.Companion.needsStupidWritePermissions(this, delPath)) {
if (isShowingPermDialog(file))
return;
final String[] deletedPaths = mToBeDeleted.toArray(new String[mToBeDeleted.size()]);
MediaScannerConnection.scanFile(this, deletedPaths, null, new MediaScannerConnection.OnScanCompletedListener() {
@Override
public void onScanCompleted(String path, Uri uri) {
if (mMedia != null && mMedia.isEmpty()) {
finish();
final DocumentFile document = Utils.Companion.getFileDocument(this, delPath, mConfig.getTreeUri());
if (document.delete()) {
wereFilesDeleted = true;
}
} else {
if (file.delete())
wereFilesDeleted = true;
}
}
});
mToBeDeleted.clear();
}
if (wereFilesDeleted) {
final String[] deletedPaths = mToBeDeleted.toArray(new String[mToBeDeleted.size()]);
MediaScannerConnection.scanFile(getApplicationContext(), deletedPaths, null, new MediaScannerConnection.OnScanCompletedListener() {
@Override
public void onScanCompleted(String path, Uri uri) {
if (mMedia != null && mMedia.isEmpty()) {
finish();
}
}
});
mToBeDeleted.clear();
}
}
private View.OnClickListener undoDeletion = new View.OnClickListener() {
@@ -368,15 +388,60 @@ public class MediaActivity extends SimpleActivity
}
}
private void showProperties() {
final List<Medium> selectedMedia = getSelectedMedia();
if (selectedMedia.size() == 1) {
new PropertiesDialog(this, selectedMedia.get(0).getPath(), false);
} else {
final List<String> paths = new ArrayList<>(selectedMedia.size());
for (Medium medium : selectedMedia) {
paths.add(medium.getPath());
}
new PropertiesDialog(this, paths, false);
}
}
private boolean isSetWallpaperIntent() {
return getIntent().getBooleanExtra(Constants.SET_WALLPAPER_INTENT, false);
}
private void displayCopyDialog() {
final ArrayList<File> files = new ArrayList<>();
final SparseBooleanArray items = mGridView.getCheckedItemPositions();
final int cnt = items.size();
for (int i = 0; i < cnt; i++) {
if (items.valueAt(i)) {
final int id = items.keyAt(i);
files.add(new File(mMedia.get(id).getPath()));
}
}
new CopyDialog(this, files, new CopyMoveTask.CopyMoveListener() {
@Override
public void copySucceeded(boolean deleted, boolean copiedAll) {
int msgId;
if (deleted) {
refreshDir();
msgId = copiedAll ? R.string.moving_success : R.string.moving_success_partial;
} else {
msgId = copiedAll? R.string.copying_success : R.string.copying_success_partial;
}
Utils.Companion.showToast(getApplicationContext(), msgId);
}
@Override
public void copyFailed() {
Utils.Companion.showToast(getApplicationContext(), R.string.copy_move_failed);
}
});
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
final String curItemPath = mMedia.get(position).getPath();
if (isSetWallpaperIntent()) {
Utils.showToast(this, R.string.setting_wallpaper);
Utils.Companion.showToast(this, R.string.setting_wallpaper);
final int wantedWidth = getWallpaperDesiredMinimumWidth();
final int wantedHeight = getWallpaperDesiredMinimumHeight();
@@ -439,6 +504,9 @@ public class MediaActivity extends SimpleActivity
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.cab_properties:
showProperties();
return true;
case R.id.cab_share:
shareMedia();
return true;
@@ -446,6 +514,9 @@ public class MediaActivity extends SimpleActivity
prepareForDeleting();
mode.finish();
return true;
case R.id.cab_copy_move:
displayCopyDialog();
return true;
default:
return false;
}
@@ -467,16 +538,20 @@ public class MediaActivity extends SimpleActivity
@Override
public void onRefresh() {
refreshDir();
}
private void refreshDir() {
final File dir = new File(mPath);
if (dir.isDirectory()) {
rescanDirectory(dir);
Utils.Companion.scanPath(getApplicationContext(), mPath);
}
initializeGallery();
mSwipeRefreshLayout.setRefreshing(false);
}
@Override
public void dialogClosed() {
public void sortingDialogClosed() {
initializeGallery();
}
}

View File

@@ -1,12 +0,0 @@
package com.simplemobiletools.gallery.activities;
import android.os.Bundle;
public class PhotoActivity extends PhotoVideoActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
mIsVideo = false;
super.onCreate(savedInstanceState);
}
}

View File

@@ -1,107 +0,0 @@
package com.simplemobiletools.gallery.activities;
import android.content.Intent;
import android.content.res.Configuration;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.ActionBar;
import android.view.Menu;
import android.view.MenuItem;
import com.simplemobiletools.gallery.Constants;
import com.simplemobiletools.gallery.R;
import com.simplemobiletools.gallery.Utils;
import com.simplemobiletools.gallery.fragments.PhotoFragment;
import com.simplemobiletools.gallery.fragments.VideoFragment;
import com.simplemobiletools.gallery.fragments.ViewPagerFragment;
import com.simplemobiletools.gallery.models.Medium;
import java.io.File;
public class PhotoVideoActivity extends SimpleActivity implements ViewPagerFragment.FragmentClickListener {
private static ActionBar mActionbar;
private static Uri mUri;
private static ViewPagerFragment mFragment;
private static boolean mIsFullScreen;
protected static boolean mIsVideo;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_holder);
mUri = getIntent().getData();
if (mUri == null)
return;
mActionbar = getSupportActionBar();
mIsFullScreen = true;
hideSystemUI();
final Bundle bundle = new Bundle();
final File file = new File(mUri.toString());
final Medium medium = new Medium(mUri.toString(), mIsVideo, 0, file.length());
bundle.putSerializable(Constants.MEDIUM, medium);
if (savedInstanceState == null) {
mFragment = (mIsVideo ? new VideoFragment() : new PhotoFragment());
mFragment.setListener(this);
mFragment.setArguments(bundle);
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_holder, mFragment).commit();
}
hideSystemUI();
setTitle(Utils.getFilename(mUri.toString()));
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mFragment.updateItem();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.photo_video_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_share:
shareMedium();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void shareMedium() {
final String shareTitle = getResources().getString(R.string.share_via);
final Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_STREAM, mUri);
sendIntent.setType(mIsVideo ? "video/*" : "image/*");
startActivity(Intent.createChooser(sendIntent, shareTitle));
}
@Override
public void fragmentClicked() {
mIsFullScreen = !mIsFullScreen;
if (mIsFullScreen) {
hideSystemUI();
} else {
showSystemUI();
}
}
private void hideSystemUI() {
Utils.hideSystemUI(mActionbar, getWindow());
}
private void showSystemUI() {
Utils.showSystemUI(mActionbar, getWindow());
}
}

View File

@@ -1,67 +0,0 @@
package com.simplemobiletools.gallery.activities;
import android.os.Bundle;
import android.support.v4.app.TaskStackBuilder;
import android.support.v7.widget.SwitchCompat;
import com.simplemobiletools.gallery.Config;
import com.simplemobiletools.gallery.R;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class SettingsActivity extends SimpleActivity {
@BindView(R.id.settings_dark_theme) SwitchCompat mDarkThemeSwitch;
@BindView(R.id.settings_same_sorting) SwitchCompat mSameSortingSwitch;
@BindView(R.id.settings_show_hidden_folders) SwitchCompat mShowHiddenFoldersSwitch;
private static Config mConfig;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
mConfig = Config.newInstance(getApplicationContext());
ButterKnife.bind(this);
setupDarkTheme();
setupSameSorting();
setupShowHiddenFolders();
}
private void setupDarkTheme() {
mDarkThemeSwitch.setChecked(mConfig.getIsDarkTheme());
}
private void setupSameSorting() {
mSameSortingSwitch.setChecked(mConfig.getIsSameSorting());
}
private void setupShowHiddenFolders() {
mShowHiddenFoldersSwitch.setChecked(mConfig.getShowHiddenFolders());
}
@OnClick(R.id.settings_dark_theme_holder)
public void handleDarkTheme() {
mDarkThemeSwitch.setChecked(!mDarkThemeSwitch.isChecked());
mConfig.setIsDarkTheme(mDarkThemeSwitch.isChecked());
restartActivity();
}
@OnClick(R.id.settings_same_sorting_holder)
public void handleSameSorting() {
mSameSortingSwitch.setChecked(!mSameSortingSwitch.isChecked());
mConfig.setIsSameSorting(mSameSortingSwitch.isChecked());
}
@OnClick(R.id.settings_show_hidden_folders_holder)
public void handleShowHiddenFolders() {
mShowHiddenFoldersSwitch.setChecked(!mShowHiddenFoldersSwitch.isChecked());
mConfig.setShowHiddenFolders(mShowHiddenFoldersSwitch.isChecked());
}
private void restartActivity() {
TaskStackBuilder.create(getApplicationContext()).addNextIntentWithParentStack(getIntent()).startActivities();
}
}

View File

@@ -1,35 +0,0 @@
package com.simplemobiletools.gallery.activities;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.MenuItem;
import com.simplemobiletools.gallery.Config;
import com.simplemobiletools.gallery.R;
public class SimpleActivity extends AppCompatActivity {
protected Config mConfig;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
mConfig = Config.newInstance(getApplicationContext());
int theme = mConfig.getIsDarkTheme() ? R.style.AppTheme_Dark : R.style.AppTheme;
if (this instanceof ViewPagerActivity || this instanceof PhotoActivity || this instanceof VideoActivity) {
theme = mConfig.getIsDarkTheme() ? R.style.FullScreenTheme_Dark : R.style.FullScreenTheme;
}
setTheme(theme);
super.onCreate(savedInstanceState);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
finish();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}

View File

@@ -1,12 +0,0 @@
package com.simplemobiletools.gallery.activities;
import android.os.Bundle;
public class VideoActivity extends PhotoVideoActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
mIsVideo = true;
super.onCreate(savedInstanceState);
}
}

View File

@@ -1,507 +0,0 @@
package com.simplemobiletools.gallery.activities;
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.Cursor;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.v4.view.ViewPager;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AlertDialog;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.widget.EditText;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.simplemobiletools.gallery.Constants;
import com.simplemobiletools.gallery.MyViewPager;
import com.simplemobiletools.gallery.R;
import com.simplemobiletools.gallery.Utils;
import com.simplemobiletools.gallery.adapters.MyPagerAdapter;
import com.simplemobiletools.gallery.fragments.ViewPagerFragment;
import com.simplemobiletools.gallery.models.Medium;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class ViewPagerActivity extends SimpleActivity
implements ViewPager.OnPageChangeListener, View.OnSystemUiVisibilityChangeListener, ViewPager.OnTouchListener,
ViewPagerFragment.FragmentClickListener {
@BindView(R.id.undo_delete) View mUndoBtn;
@BindView(R.id.view_pager) MyViewPager mPager;
private static final int EDIT_IMAGE = 1;
private static final int SET_WALLPAPER = 2;
private static ActionBar mActionbar;
private static List<Medium> mMedia;
private static String mPath;
private static String mDirectory;
private static String mToBeDeleted;
private static String mBeingDeleted;
private static boolean mIsFullScreen;
private static boolean mIsUndoShown;
private static int mPos;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_medium);
ButterKnife.bind(this);
if (!Utils.hasStoragePermission(getApplicationContext())) {
finish();
return;
}
final Uri uri = getIntent().getData();
if (uri != null) {
Cursor cursor = null;
try {
final String[] proj = {MediaStore.Images.Media.DATA};
cursor = getContentResolver().query(uri, proj, null, null, null);
if (cursor != null) {
final int dataIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
mPath = cursor.getString(dataIndex);
}
} finally {
if (cursor != null) {
cursor.close();
}
}
} else {
mPath = getIntent().getStringExtra(Constants.MEDIUM);
}
if (mPath == null || mPath.isEmpty()) {
Utils.showToast(getApplicationContext(), R.string.unknown_error);
finish();
return;
}
mPos = 0;
mIsFullScreen = true;
mActionbar = getSupportActionBar();
mToBeDeleted = "";
mBeingDeleted = "";
hideSystemUI();
MediaScannerConnection.scanFile(this, new String[]{mPath}, null, null);
addUndoMargin();
mDirectory = new File(mPath).getParent();
mMedia = getMedia();
if (isDirEmpty())
return;
final MyPagerAdapter adapter = new MyPagerAdapter(this, getSupportFragmentManager(), mMedia);
mPager.setAdapter(adapter);
mPager.setCurrentItem(mPos);
mPager.addOnPageChangeListener(this);
mPager.setOnTouchListener(this);
getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(this);
updateActionbarTitle();
}
@Override
protected void onResume() {
super.onResume();
if (!Utils.hasStoragePermission(getApplicationContext())) {
finish();
}
}
@OnClick(R.id.undo_delete)
public void undoDeletion() {
mIsUndoShown = false;
mToBeDeleted = "";
mBeingDeleted = "";
mUndoBtn.setVisibility(View.GONE);
reloadViewPager();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.viewpager_menu, menu);
menu.findItem(R.id.menu_set_as_wallpaper).setVisible(getCurrentMedium().isImage());
menu.findItem(R.id.menu_edit).setVisible(getCurrentMedium().isImage());
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
deleteFile();
switch (item.getItemId()) {
case R.id.menu_set_as_wallpaper:
setAsWallpaper();
return true;
case R.id.menu_open_with:
openWith();
return true;
case R.id.menu_share:
shareMedium();
return true;
case R.id.menu_delete:
notifyDeletion();
return true;
case R.id.menu_rename:
editMedium();
return true;
case R.id.menu_edit:
openEditor();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
final MyPagerAdapter adapter = (MyPagerAdapter) mPager.getAdapter();
adapter.updateItems(mPos);
}
private void openEditor() {
final Intent intent = new Intent(Intent.ACTION_EDIT);
intent.setDataAndType(Uri.fromFile(getCurrentFile()), "image/*");
final Intent chooser = Intent.createChooser(intent, getString(R.string.edit_image_with));
if (intent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(chooser, EDIT_IMAGE);
} else {
Utils.showToast(getApplicationContext(), R.string.no_editor_found);
}
}
private void setAsWallpaper() {
final Intent intent = new Intent(Intent.ACTION_ATTACH_DATA);
intent.setDataAndType(Uri.fromFile(getCurrentFile()), "image/jpeg");
final Intent chooser = Intent.createChooser(intent, getString(R.string.set_as_wallpaper_with));
if (intent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(chooser, SET_WALLPAPER);
} else {
Utils.showToast(getApplicationContext(), R.string.no_wallpaper_setter_found);
}
}
private void openWith() {
final Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(getCurrentFile()), Utils.getMimeType(getCurrentMedium()));
final Intent chooser = Intent.createChooser(intent, getString(R.string.open_with));
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(chooser);
} else {
Utils.showToast(getApplicationContext(), R.string.no_app_found);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == EDIT_IMAGE) {
if (resultCode == RESULT_OK && data != null) {
final MyPagerAdapter adapter = (MyPagerAdapter) mPager.getAdapter();
adapter.updateItems(mPos);
}
} else if (requestCode == SET_WALLPAPER) {
if (resultCode == RESULT_OK) {
Utils.showToast(getApplicationContext(), R.string.wallpaper_set_successfully);
}
}
super.onActivityResult(requestCode, resultCode, data);
}
private void shareMedium() {
final Medium medium = getCurrentMedium();
Utils.shareMedium(medium, this);
}
private void notifyDeletion() {
mToBeDeleted = getCurrentFile().getAbsolutePath();
if (mMedia.size() <= 1) {
deleteFile();
} else {
Utils.showToast(this, R.string.file_deleted);
mUndoBtn.setVisibility(View.VISIBLE);
mIsUndoShown = true;
reloadViewPager();
}
}
private void deleteFile() {
if (mToBeDeleted.isEmpty())
return;
mIsUndoShown = false;
mBeingDeleted = "";
final File file = new File(mToBeDeleted);
if (file.delete()) {
mBeingDeleted = mToBeDeleted;
final String[] deletedPath = new String[]{mToBeDeleted};
MediaScannerConnection.scanFile(this, deletedPath, null, new MediaScannerConnection.OnScanCompletedListener() {
@Override
public void onScanCompleted(String path, Uri uri) {
scanCompleted();
}
});
}
mToBeDeleted = "";
mUndoBtn.setVisibility(View.GONE);
}
private boolean isDirEmpty() {
if (mMedia.size() <= 0) {
deleteDirectoryIfEmpty();
finish();
return true;
}
return false;
}
private void editMedium() {
final File file = getCurrentFile();
final String fullName = file.getName();
final int dotAt = fullName.lastIndexOf(".");
if (dotAt <= 0)
return;
final String name = fullName.substring(0, dotAt);
final String extension = fullName.substring(dotAt + 1, fullName.length());
final View renameFileView = getLayoutInflater().inflate(R.layout.rename_file, null);
final EditText fileNameET = (EditText) renameFileView.findViewById(R.id.file_name);
fileNameET.setText(name);
final EditText extensionET = (EditText) renameFileView.findViewById(R.id.extension);
extensionET.setText(extension);
final TextView filePath = (TextView) renameFileView.findViewById(R.id.file_path);
filePath.setText(file.getParent() + "/");
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(getResources().getString(R.string.rename_file));
builder.setView(renameFileView);
builder.setPositiveButton(R.string.ok, null);
builder.setNegativeButton(R.string.cancel, null);
final AlertDialog alertDialog = builder.create();
alertDialog.show();
alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final String fileName = fileNameET.getText().toString().trim();
final String extension = extensionET.getText().toString().trim();
if (fileName.isEmpty() || extension.isEmpty()) {
Utils.showToast(getApplicationContext(), R.string.rename_file_empty);
return;
}
final File newFile = new File(file.getParent(), fileName + "." + extension);
if (file.renameTo(newFile)) {
final int currItem = mPager.getCurrentItem();
mMedia.set(currItem, new Medium(newFile.getAbsolutePath(), mMedia.get(currItem).getIsVideo(), 0, file.length()));
final String[] changedFiles = {file.getAbsolutePath(), newFile.getAbsolutePath()};
MediaScannerConnection.scanFile(getApplicationContext(), changedFiles, null, null);
updateActionbarTitle();
alertDialog.dismiss();
} else {
Utils.showToast(getApplicationContext(), R.string.rename_file_error);
}
}
});
}
private void reloadViewPager() {
final MyPagerAdapter adapter = (MyPagerAdapter) mPager.getAdapter();
final int curPos = mPager.getCurrentItem();
mMedia = getMedia();
if (isDirEmpty())
return;
mPager.setAdapter(null);
adapter.updateItems(mMedia);
mPager.setAdapter(adapter);
final int newPos = Math.min(curPos, adapter.getCount());
mPager.setCurrentItem(newPos);
updateActionbarTitle();
}
private void deleteDirectoryIfEmpty() {
final File file = new File(mDirectory);
if (file.isDirectory() && file.listFiles().length == 0) {
file.delete();
}
final String[] toBeDeleted = new String[]{mDirectory};
MediaScannerConnection.scanFile(getApplicationContext(), toBeDeleted, null, null);
}
private List<Medium> getMedia() {
final List<Medium> media = new ArrayList<>();
for (int i = 0; i < 2; i++) {
Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
if (i == 1) {
uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
}
final String where = MediaStore.Images.Media.DATA + " like ? ";
final String[] args = new String[]{mDirectory + "%"};
final String[] columns = {MediaStore.Images.Media.DATA, MediaStore.Images.Media.DATE_TAKEN, MediaStore.Images.Media.SIZE};
final Cursor cursor = getContentResolver().query(uri, columns, where, args, null);
final String pattern = Pattern.quote(mDirectory) + "/[^/]*";
if (cursor != null && cursor.moveToFirst()) {
final int pathIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA);
do {
final String curPath = cursor.getString(pathIndex);
if (curPath.matches(pattern) && !curPath.equals(mToBeDeleted) && !curPath.equals(mBeingDeleted)) {
final int dateIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATE_TAKEN);
final long timestamp = cursor.getLong(dateIndex);
final int sizeIndex = cursor.getColumnIndex(MediaStore.Images.Media.SIZE);
final long size = cursor.getLong(sizeIndex);
media.add(new Medium(curPath, i == 1, timestamp, size));
}
} while (cursor.moveToNext());
cursor.close();
}
}
Medium.mSorting = mConfig.getSorting();
Collections.sort(media);
int j = 0;
for (Medium medium : media) {
if (medium.getPath().equals(mPath)) {
mPos = j;
break;
}
j++;
}
return media;
}
@Override
public void fragmentClicked() {
deleteFile();
mIsFullScreen = !mIsFullScreen;
if (mIsFullScreen) {
hideSystemUI();
} else {
showSystemUI();
}
}
private void hideSystemUI() {
Utils.hideSystemUI(mActionbar, getWindow());
}
private void showSystemUI() {
Utils.showSystemUI(mActionbar, getWindow());
}
private void updateActionbarTitle() {
setTitle(Utils.getFilename(mMedia.get(mPager.getCurrentItem()).getPath()));
}
private Medium getCurrentMedium() {
if (mPos >= mMedia.size())
mPos = mMedia.size() - 1;
return mMedia.get(mPos);
}
private File getCurrentFile() {
return new File(getCurrentMedium().getPath());
}
private void addUndoMargin() {
final Resources res = getResources();
final RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) mUndoBtn.getLayoutParams();
final int topMargin = Utils.getStatusBarHeight(res) + Utils.getActionBarHeight(getApplicationContext(), res);
int rightMargin = params.rightMargin;
if (getResources().getConfiguration().orientation != Configuration.ORIENTATION_PORTRAIT) {
rightMargin += Utils.getNavBarHeight(res);
}
params.setMargins(params.leftMargin, topMargin, rightMargin, params.bottomMargin);
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
updateActionbarTitle();
mPos = position;
supportInvalidateOptionsMenu();
}
@Override
public void onPageScrollStateChanged(int state) {
if (state == ViewPager.SCROLL_STATE_DRAGGING) {
final MyPagerAdapter adapter = (MyPagerAdapter) mPager.getAdapter();
adapter.itemDragged(mPos);
}
}
@Override
public void onSystemUiVisibilityChange(int visibility) {
if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
mIsFullScreen = false;
}
final MyPagerAdapter adapter = (MyPagerAdapter) mPager.getAdapter();
adapter.updateUiVisibility(mIsFullScreen, mPos);
}
private void scanCompleted() {
mBeingDeleted = "";
runOnUiThread(new Runnable() {
@Override
public void run() {
if (mMedia != null && mMedia.size() <= 1) {
reloadViewPager();
}
}
});
}
@Override
public boolean onTouch(View v, MotionEvent event) {
if (mIsUndoShown) {
deleteFile();
}
return false;
}
@Override
protected void onPause() {
super.onPause();
deleteFile();
}
}

View File

@@ -1,90 +0,0 @@
package com.simplemobiletools.gallery.adapters;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.signature.StringSignature;
import com.simplemobiletools.gallery.R;
import com.simplemobiletools.gallery.models.Directory;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
public class DirectoryAdapter extends BaseAdapter {
private final Context mContext;
private final List<Directory> mDirs;
private final LayoutInflater mInflater;
public DirectoryAdapter(Context context, List<Directory> dirs) {
mContext = context;
mDirs = dirs;
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.directory_item, parent, false);
viewHolder = new ViewHolder(convertView);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
final Directory dir = mDirs.get(position);
viewHolder.dirName.setText(dir.getName());
viewHolder.photoCnt.setText(String.valueOf(dir.getMediaCnt()));
final String tmb = dir.getThumbnail();
final StringSignature timestampSignature = new StringSignature(String.valueOf(dir.getTimestamp()));
if (tmb.endsWith(".gif")) {
Glide.with(mContext).load(tmb).asGif().diskCacheStrategy(DiskCacheStrategy.NONE).signature(timestampSignature)
.placeholder(R.color.tmb_background).centerCrop().crossFade().into(viewHolder.dirThumbnail);
} else {
Glide.with(mContext).load(tmb).diskCacheStrategy(DiskCacheStrategy.RESULT).signature(timestampSignature)
.placeholder(R.color.tmb_background).centerCrop().crossFade().into(viewHolder.dirThumbnail);
}
return convertView;
}
@Override
public int getCount() {
return mDirs.size();
}
@Override
public Object getItem(int position) {
return mDirs.get(position);
}
@Override
public long getItemId(int position) {
return 0;
}
public void updateItems(List<Directory> newDirs) {
mDirs.clear();
mDirs.addAll(newDirs);
notifyDataSetChanged();
}
static class ViewHolder {
@BindView(R.id.dir_name) TextView dirName;
@BindView(R.id.photo_cnt) TextView photoCnt;
@BindView(R.id.dir_thumbnail) ImageView dirThumbnail;
public ViewHolder(View view) {
ButterKnife.bind(this, view);
}
}
}

View File

@@ -1,91 +0,0 @@
package com.simplemobiletools.gallery.adapters;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.signature.StringSignature;
import com.simplemobiletools.gallery.R;
import com.simplemobiletools.gallery.models.Medium;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
public class MediaAdapter extends BaseAdapter {
private final Context mContext;
private final List<Medium> mMedia;
private final LayoutInflater mInflater;
public MediaAdapter(Context context, List<Medium> media) {
mContext = context;
mMedia = media;
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final Medium medium = mMedia.get(position);
ViewHolder viewHolder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.photo_video_item, parent, false);
viewHolder = new ViewHolder(convertView);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
if (medium.getIsVideo()) {
viewHolder.playOutline.setVisibility(View.VISIBLE);
} else {
viewHolder.playOutline.setVisibility(View.GONE);
}
final String path = medium.getPath();
final StringSignature timestampSignature = new StringSignature(String.valueOf(medium.getTimestamp()));
if (medium.isGif()) {
Glide.with(mContext).load(path).asGif().diskCacheStrategy(DiskCacheStrategy.NONE).signature(timestampSignature).into(viewHolder.photoThumbnail);
} else {
Glide.with(mContext).load(path).diskCacheStrategy(DiskCacheStrategy.NONE).signature(timestampSignature)
.placeholder(R.color.tmb_background).centerCrop().crossFade().into(viewHolder.photoThumbnail);
}
return convertView;
}
@Override
public int getCount() {
return mMedia.size();
}
@Override
public Object getItem(int position) {
return mMedia.get(position);
}
@Override
public long getItemId(int position) {
return 0;
}
public void updateItems(List<Medium> newPhotos) {
mMedia.clear();
mMedia.addAll(newPhotos);
notifyDataSetChanged();
}
static class ViewHolder {
@BindView(R.id.medium_thumbnail) ImageView photoThumbnail;
@BindView(R.id.play_outline) View playOutline;
public ViewHolder(View view) {
ButterKnife.bind(this, view);
}
}
}

View File

@@ -1,84 +0,0 @@
package com.simplemobiletools.gallery.adapters;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import com.simplemobiletools.gallery.Constants;
import com.simplemobiletools.gallery.activities.ViewPagerActivity;
import com.simplemobiletools.gallery.fragments.PhotoFragment;
import com.simplemobiletools.gallery.fragments.VideoFragment;
import com.simplemobiletools.gallery.fragments.ViewPagerFragment;
import com.simplemobiletools.gallery.models.Medium;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class MyPagerAdapter extends FragmentStatePagerAdapter {
private final List<Medium> mMedia;
private final Map<Integer, ViewPagerFragment> mFragments;
private final ViewPagerActivity mActivity;
public MyPagerAdapter(ViewPagerActivity act, FragmentManager fm, List<Medium> media) {
super(fm);
mActivity = act;
mMedia = media;
mFragments = new HashMap<>();
}
@Override
public int getCount() {
return mMedia.size();
}
@Override
public Fragment getItem(int position) {
final Medium medium = mMedia.get(position);
final Bundle bundle = new Bundle();
bundle.putSerializable(Constants.MEDIUM, medium);
ViewPagerFragment fragment;
if (medium.getIsVideo()) {
fragment = new VideoFragment();
} else {
fragment = new PhotoFragment();
}
mFragments.put(position, fragment);
fragment.setArguments(bundle);
fragment.setListener(mActivity);
return fragment;
}
public void itemDragged(int pos) {
if (mFragments.get(pos) != null) {
mFragments.get(pos).itemDragged();
}
}
public void updateUiVisibility(boolean isFullscreen, int pos) {
for (int i = -1; i <= 1; i++) {
final ViewPagerFragment fragment = mFragments.get(pos + i);
if (fragment != null) {
fragment.systemUiVisibilityChanged(isFullscreen);
}
}
}
public void updateItems(int pos) {
for (int i = -1; i <= 1; i++) {
final ViewPagerFragment fragment = mFragments.get(pos + i);
if (fragment != null) {
fragment.updateItem();
}
}
}
public void updateItems(List<Medium> newPaths) {
mMedia.clear();
mMedia.addAll(newPaths);
notifyDataSetChanged();
}
}

View File

@@ -24,7 +24,7 @@ public class ChangeSorting extends AlertDialog.Builder implements DialogInterfac
mIsDirectorySorting = isDirectorySorting;
mListener = (ChangeDialogListener) act;
mConfig = Config.newInstance(getContext());
mConfig = Config.Companion.newInstance(getContext());
mHolder = act.getLayoutInflater().inflate(R.layout.change_sorting, null);
final AlertDialog.Builder builder = new AlertDialog.Builder(act);
@@ -90,10 +90,10 @@ public class ChangeSorting extends AlertDialog.Builder implements DialogInterfac
mConfig.setSorting(sorting);
}
}
mListener.dialogClosed();
mListener.sortingDialogClosed();
}
public interface ChangeDialogListener {
void dialogClosed();
void sortingDialogClosed();
}
}

View File

@@ -26,7 +26,7 @@ public class PhotoFragment extends ViewPagerFragment implements View.OnClickList
mMedium = (Medium) getArguments().getSerializable(Constants.MEDIUM);
if (mMedium.getPath().startsWith("content://"))
mMedium.setPath(Utils.getRealPathFromURI(getContext(), Uri.parse(mMedium.getPath())));
mMedium.setPath(Utils.Companion.getRealPathFromURI(getContext(), Uri.parse(mMedium.getPath())));
if (mMedium == null)
return view;
@@ -39,6 +39,7 @@ public class PhotoFragment extends ViewPagerFragment implements View.OnClickList
Glide.with(getContext()).load(mMedium.getPath()).asGif().diskCacheStrategy(DiskCacheStrategy.NONE).into(imageView);
imageView.setOnClickListener(this);
} else {
mSubsamplingView.setDoubleTapZoomScale(1.2f);
mSubsamplingView.setOrientation(SubsamplingScaleImageView.ORIENTATION_USE_EXIF);
mSubsamplingView.setImage(ImageSource.uri(mMedium.getPath()));
mSubsamplingView.setMaxScale(4f);

View File

@@ -23,6 +23,7 @@ import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
import com.simplemobiletools.gallery.Config;
import com.simplemobiletools.gallery.Constants;
import com.simplemobiletools.gallery.R;
import com.simplemobiletools.gallery.Utils;
@@ -52,6 +53,7 @@ public class VideoFragment extends ViewPagerFragment
private boolean mIsPlaying;
private boolean mIsDragged;
private boolean mIsFullscreen;
private boolean mIsFragmentVisible;
private int mCurrTime;
private int mDuration;
@@ -87,6 +89,17 @@ public class VideoFragment extends ViewPagerFragment
initTimeHolder();
}
@Override
public void setMenuVisibility(boolean menuVisible) {
super.setMenuVisibility(menuVisible);
mIsFragmentVisible = menuVisible;
if (menuVisible) {
if (getContext() != null && Config.Companion.newInstance(getContext()).getAutoplayVideos()) {
playVideo();
}
}
}
public void itemDragged() {
pauseVideo();
}
@@ -108,13 +121,13 @@ public class VideoFragment extends ViewPagerFragment
private void initTimeHolder() {
mTimeHolder = mView.findViewById(R.id.video_time_holder);
final Resources res = getResources();
final int height = Utils.getNavBarHeight(res);
final int height = Utils.Companion.getNavBarHeight(res);
final int left = mTimeHolder.getPaddingLeft();
final int top = mTimeHolder.getPaddingTop();
int right = (int) getResources().getDimension(R.dimen.timer_padding);
int bottom = 0;
if (Utils.hasNavBar(getActivity())) {
if (Utils.Companion.hasNavBar(getActivity())) {
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
bottom += height;
} else {
@@ -190,34 +203,38 @@ public class VideoFragment extends ViewPagerFragment
mTimeHolder.startAnimation(animation);
}
private void pauseVideo() {
if (mIsPlaying) {
togglePlayPause();
}
}
private void togglePlayPause() {
if (getActivity() == null)
if (getActivity() == null || !isAdded())
return;
mIsPlaying = !mIsPlaying;
if (mIsPlaying) {
if (mMediaPlayer != null) {
mMediaPlayer.start();
}
mPlayOutline.setImageDrawable(null);
getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
playVideo();
} else {
if (mMediaPlayer != null) {
mMediaPlayer.pause();
}
mPlayOutline.setImageDrawable(getResources().getDrawable(R.mipmap.play_outline_big));
getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
pauseVideo();
}
}
private void playVideo() {
mIsPlaying = true;
if (mMediaPlayer != null) {
mMediaPlayer.start();
}
mPlayOutline.setImageDrawable(null);
getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
private void pauseVideo() {
mIsPlaying = false;
if (mMediaPlayer != null) {
mMediaPlayer.pause();
}
mPlayOutline.setImageDrawable(getResources().getDrawable(R.mipmap.play_outline_big));
getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
private void initMediaPlayer() {
if (mMediaPlayer != null)
return;
@@ -251,6 +268,7 @@ public class VideoFragment extends ViewPagerFragment
public void onPause() {
super.onPause();
pauseVideo();
mIsFragmentVisible = false;
}
@Override
@@ -390,5 +408,8 @@ public class VideoFragment extends ViewPagerFragment
addPreviewImage();
setupTimeHolder();
setProgress(mCurrTime);
if (mIsFragmentVisible && Config.Companion.newInstance(getContext()).getAutoplayVideos())
playVideo();
}
}

View File

@@ -1,82 +0,0 @@
package com.simplemobiletools.gallery.models;
import com.simplemobiletools.gallery.Constants;
public class Directory implements Comparable {
private final String mPath;
private final String mThumbnail;
private final String mName;
private final long mTimestamp;
private int mMediaCnt;
private long mSize;
public static int mSorting;
public Directory(String path, String thumbnail, String name, int mediaCnt, long timestamp, long size) {
mPath = path;
mThumbnail = thumbnail;
mName = name;
mMediaCnt = mediaCnt;
mTimestamp = timestamp;
mSize = size;
}
public String getPath() {
return mPath;
}
public String getThumbnail() {
return mThumbnail;
}
public String getName() {
return mName;
}
public int getMediaCnt() {
return mMediaCnt;
}
public void setMediaCnt(int cnt) {
mMediaCnt = cnt;
}
public long getTimestamp() {
return mTimestamp;
}
public long getSize() {
return mSize;
}
public void addSize(long bytes) {
mSize += bytes;
}
@Override
public int compareTo(Object object) {
final Directory directory = (Directory) object;
int res;
if ((mSorting & Constants.SORT_BY_NAME) != 0) {
res = mPath.compareTo(directory.getPath());
} else if ((mSorting & Constants.SORT_BY_DATE) != 0) {
res = (mTimestamp > directory.getTimestamp()) ? 1 : -1;
} else {
res = (mSize > directory.getSize()) ? 1 : -1;
}
if ((mSorting & Constants.SORT_DESCENDING) != 0) {
res *= -1;
}
return res;
}
@Override
public String toString() {
return "Directory {" +
"path=" + getPath() +
", thumbnail=" + getThumbnail() +
", name=" + getName() +
", timestamp=" + getTimestamp() +
", mediaCnt=" + getMediaCnt() + "}";
}
}

View File

@@ -1,76 +0,0 @@
package com.simplemobiletools.gallery.models;
import com.simplemobiletools.gallery.Constants;
import java.io.Serializable;
public class Medium implements Serializable, Comparable {
private static final long serialVersionUID = -6543139465975455L;
private final boolean mIsVideo;
private final long mTimestamp;
private final long mSize;
public static int mSorting;
private String mPath;
public Medium(String path, boolean isVideo, long timestamp, long size) {
mPath = path;
mIsVideo = isVideo;
mTimestamp = timestamp;
mSize = size;
}
public void setPath(String path) {
mPath = path;
}
public String getPath() {
return mPath;
}
public boolean getIsVideo() {
return mIsVideo;
}
public long getTimestamp() {
return mTimestamp;
}
public long getSize() {
return mSize;
}
public boolean isGif() {
return getPath().toLowerCase().endsWith(".gif");
}
public boolean isImage() {
return !isGif() && !getIsVideo();
}
@Override
public int compareTo(Object object) {
final Medium medium = (Medium) object;
int res;
if ((mSorting & Constants.SORT_BY_NAME) != 0) {
res = mPath.compareTo(medium.getPath());
} else if ((mSorting & Constants.SORT_BY_DATE) != 0) {
res = (mTimestamp > medium.getTimestamp()) ? 1 : -1;
} else {
res = (mSize > medium.getSize()) ? 1 : -1;
}
if ((mSorting & Constants.SORT_DESCENDING) != 0) {
res *= -1;
}
return res;
}
@Override
public String toString() {
return "Medium {" +
"isVideo=" + getIsVideo() +
", timestamp=" + getTimestamp() +
", size=" + getSize() +
", path=" + getPath() + "}";
}
}

View File

@@ -0,0 +1,86 @@
package com.simplemobiletools.gallery
import android.content.Context
import android.content.SharedPreferences
import java.util.*
class Config private constructor(context: Context) {
private val mPrefs: SharedPreferences
companion object {
fun newInstance(context: Context): Config {
return Config(context)
}
}
init {
mPrefs = context.getSharedPreferences(Constants.PREFS_KEY, Context.MODE_PRIVATE)
}
var isFirstRun: Boolean
get() = mPrefs.getBoolean(Constants.IS_FIRST_RUN, true)
set(isFirstRun) = mPrefs.edit().putBoolean(Constants.IS_FIRST_RUN, isFirstRun).apply()
var isDarkTheme: Boolean
get() = mPrefs.getBoolean(Constants.IS_DARK_THEME, true)
set(isDarkTheme) = mPrefs.edit().putBoolean(Constants.IS_DARK_THEME, isDarkTheme).apply()
var isSameSorting: Boolean
get() = mPrefs.getBoolean(Constants.IS_SAME_SORTING, true)
set(isSameSorting) = mPrefs.edit().putBoolean(Constants.IS_SAME_SORTING, isSameSorting).apply()
var sorting: Int
get() = if (isSameSorting) directorySorting else mPrefs.getInt(Constants.SORT_ORDER, Constants.SORT_BY_DATE or Constants.SORT_DESCENDING)
set(order) = if (isSameSorting) directorySorting = order else mPrefs.edit().putInt(Constants.SORT_ORDER, order).apply()
var directorySorting: Int
get() = mPrefs.getInt(Constants.DIRECTORY_SORT_ORDER, Constants.SORT_BY_DATE or Constants.SORT_DESCENDING)
set(order) = mPrefs.edit().putInt(Constants.DIRECTORY_SORT_ORDER, order).apply()
var showHiddenFolders: Boolean
get() = mPrefs.getBoolean(Constants.SHOW_HIDDEN_FOLDERS, false)
set(showHiddenFolders) = mPrefs.edit().putBoolean(Constants.SHOW_HIDDEN_FOLDERS, showHiddenFolders).apply()
fun addHiddenDirectory(path: String) {
val hiddenFolders = hiddenFolders
hiddenFolders.add(path)
mPrefs.edit().putStringSet(Constants.HIDDEN_FOLDERS, hiddenFolders).apply()
}
fun addHiddenDirectories(paths: Set<String>) {
val hiddenFolders = hiddenFolders
hiddenFolders.addAll(paths)
mPrefs.edit().putStringSet(Constants.HIDDEN_FOLDERS, hiddenFolders).apply()
}
fun removeHiddenDirectory(path: String) {
val hiddenFolders = hiddenFolders
hiddenFolders.remove(path)
mPrefs.edit().putStringSet(Constants.HIDDEN_FOLDERS, hiddenFolders).apply()
}
fun removeHiddenDirectories(paths: Set<String>) {
val hiddenFolders = hiddenFolders
hiddenFolders.removeAll(paths)
mPrefs.edit().putStringSet(Constants.HIDDEN_FOLDERS, hiddenFolders).apply()
}
val hiddenFolders: MutableSet<String>
get() = mPrefs.getStringSet(Constants.HIDDEN_FOLDERS, HashSet<String>())
fun getIsFolderHidden(path: String): Boolean {
return hiddenFolders.contains(path)
}
var autoplayVideos: Boolean
get() = mPrefs.getBoolean(Constants.AUTOPLAY_VIDEOS, false)
set(autoplay) = mPrefs.edit().putBoolean(Constants.AUTOPLAY_VIDEOS, autoplay).apply()
var treeUri: String
get() = mPrefs.getString(Constants.TREE_URI, "")
set(uri) = mPrefs.edit().putString(Constants.TREE_URI, uri).apply()
var displayFileNames: Boolean
get() = mPrefs.getBoolean(Constants.DISPLAY_FILE_NAMES, false)
set(display) = mPrefs.edit().putBoolean(Constants.DISPLAY_FILE_NAMES, display).apply()
}

View File

@@ -0,0 +1,126 @@
package com.simplemobiletools.gallery
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.res.Resources
import android.database.Cursor
import android.net.Uri
import android.os.Build
import android.provider.MediaStore
import android.util.DisplayMetrics
import android.util.TypedValue
import android.view.KeyCharacterMap
import android.view.KeyEvent
import android.view.ViewConfiguration
import android.webkit.MimeTypeMap
import com.simplemobiletools.filepicker.extensions.*
import com.simplemobiletools.gallery.models.Medium
import java.io.File
import java.util.*
class Utils {
companion object {
fun getFilename(context: Context, path: String): String {
val humanized = context.humanizePath(path)
return humanized.substring(humanized.lastIndexOf("/") + 1)
}
fun showToast(context: Context, resId: Int) = context.toast(resId)
fun getActionBarHeight(context: Context, res: Resources): Int {
val tv = TypedValue()
var height = 0
if (context.theme.resolveAttribute(android.R.attr.actionBarSize, tv, true)) {
height = TypedValue.complexToDimensionPixelSize(tv.data, res.displayMetrics)
}
return height
}
fun getStatusBarHeight(res: Resources): Int {
val id = res.getIdentifier("status_bar_height", "dimen", "android")
return if (id > 0) {
res.getDimensionPixelSize(id)
} else
0
}
fun getNavBarHeight(res: Resources): Int {
val id = res.getIdentifier("navigation_bar_height", "dimen", "android")
return if (id > 0) {
res.getDimensionPixelSize(id)
} else
0
}
fun hasNavBar(act: Activity): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
val display = act.windowManager.defaultDisplay
val realDisplayMetrics = DisplayMetrics()
display.getRealMetrics(realDisplayMetrics)
val realHeight = realDisplayMetrics.heightPixels
val realWidth = realDisplayMetrics.widthPixels
val displayMetrics = DisplayMetrics()
display.getMetrics(displayMetrics)
val displayHeight = displayMetrics.heightPixels
val displayWidth = displayMetrics.widthPixels
realWidth - displayWidth > 0 || realHeight - displayHeight > 0
} else {
val hasMenuKey = ViewConfiguration.get(act).hasPermanentMenuKey()
val hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK)
!hasMenuKey && !hasBackKey
}
}
fun hasStoragePermission(context: Context) = context.hasStoragePermission()
fun getMimeType(url: String): String {
val extension = MimeTypeMap.getFileExtensionFromUrl(url)
return if (extension != null) {
MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension)
} else
""
}
fun shareMedium(medium: Medium, activity: Activity) {
val shareTitle = activity.resources.getString(R.string.share_via)
val intent = Intent()
val file = File(medium.path)
val uri = Uri.fromFile(file)
intent.action = Intent.ACTION_SEND
intent.putExtra(Intent.EXTRA_STREAM, uri)
intent.type = medium.getMimeType()
activity.startActivity(Intent.createChooser(intent, shareTitle))
}
fun getRealPathFromURI(context: Context, uri: Uri): String? {
var cursor: Cursor? = null
try {
val projection = arrayOf(MediaStore.Images.Media.DATA)
cursor = context.contentResolver.query(uri, projection, null, null, null)
val index = cursor!!.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
cursor.moveToFirst()
return cursor.getString(index)
} finally {
cursor?.close()
}
}
fun isAStorageRootFolder(context: Context, path: String) = context.isAStorageRootFolder(path)
fun isPhotoVideo(file: File) = file.isPhotoVideo()
fun needsStupidWritePermissions(context: Context, path: String) = context.needsStupidWritePermissions(path)
fun getFileDocument(context: Context, path: String, treeUri: String) = context.getFileDocument(path, treeUri)
fun scanPath(context: Context, path: String) = context.scanPath(path) {}
fun scanFiles(context: Context, files: ArrayList<File>) = context.scanFiles(files) {}
}
}

View File

@@ -0,0 +1,100 @@
package com.simplemobiletools.gallery.activities
import android.content.ActivityNotFoundException
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.text.Html
import android.text.method.LinkMovementMethod
import android.view.View
import com.simplemobiletools.gallery.BuildConfig
import com.simplemobiletools.gallery.R
import kotlinx.android.synthetic.main.activity_about.*
import java.util.*
class AboutActivity : SimpleActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_about)
setupEmail()
setupCopyright()
setupRateUs()
setupInvite()
setupLicense()
setupFacebook()
setupGPlus()
}
private fun setupEmail() {
val email = getString(R.string.email)
val appName = getString(R.string.app_name)
val href = "<a href=\"mailto:$email?subject=$appName\">$email</a>"
about_email.text = Html.fromHtml(href)
about_email.movementMethod = LinkMovementMethod.getInstance()
}
private fun setupCopyright() {
val versionName = BuildConfig.VERSION_NAME
val year = Calendar.getInstance().get(Calendar.YEAR)
val copyrightText = String.format(getString(R.string.copyright), versionName, year)
about_copyright.text = copyrightText
}
private fun setupRateUs() {
if (mConfig.isFirstRun) {
about_rate_us.visibility = View.GONE
} else {
about_rate_us.setOnClickListener {
val uri = Uri.parse("market://details?id=$packageName")
try {
startActivity(Intent(Intent.ACTION_VIEW, uri))
} catch (ignored: ActivityNotFoundException) {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(getStoreUrl())))
}
}
}
}
fun setupInvite() {
about_invite.setOnClickListener {
val text = String.format(getString(R.string.share_text), getString(R.string.app_name), getStoreUrl())
Intent().apply {
action = Intent.ACTION_SEND
putExtra(Intent.EXTRA_SUBJECT, getString(R.string.app_name))
putExtra(Intent.EXTRA_TEXT, text)
type = "text/plain"
startActivity(Intent.createChooser(this, getString(R.string.invite_via)))
}
}
}
fun setupLicense() {
about_license.setOnClickListener {
val intent = Intent(applicationContext, LicenseActivity::class.java)
startActivity(intent)
}
}
fun setupFacebook() {
about_facebook.setOnClickListener {
var link = "https://www.facebook.com/simplemobiletools"
try {
packageManager.getPackageInfo("com.facebook.katana", 0)
link = "fb://page/150270895341774"
} catch (ignored: Exception) {
}
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(link)))
}
}
fun setupGPlus() {
about_gplus.setOnClickListener {
val link = "https://plus.google.com/communities/104880861558693868382"
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(link)))
}
}
private fun getStoreUrl() = "https://play.google.com/store/apps/details?id=$packageName"
}

View File

@@ -2,23 +2,28 @@ package com.simplemobiletools.gallery.activities
import android.app.Activity
import android.graphics.Bitmap
import android.media.MediaScannerConnection
import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import com.simplemobiletools.filepicker.extensions.getFileDocument
import com.simplemobiletools.filepicker.extensions.needsStupidWritePermissions
import com.simplemobiletools.filepicker.extensions.scanPath
import com.simplemobiletools.filepicker.extensions.toast
import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.Utils
import com.simplemobiletools.gallery.extensions.toast
import com.simplemobiletools.gallery.dialogs.SaveAsDialog
import com.theartofdev.edmodo.cropper.CropImageView
import kotlinx.android.synthetic.main.activity_edit.*
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.io.OutputStream
class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener {
val TAG: String = EditActivity::class.java.simpleName
lateinit var uri: Uri
override fun onCreate(savedInstanceState: Bundle?) {
@@ -51,27 +56,39 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.save -> {
return when (item.itemId) {
R.id.save_as -> {
crop_image_view.getCroppedImageAsync()
return true
true
}
R.id.rotate -> {
crop_image_view.rotateImage(90)
return true
true
}
else -> super.onOptionsItemSelected(item)
}
return super.onOptionsItemSelected(item)
}
override fun onCropImageComplete(view: CropImageView, result: CropImageView.CropResult) {
if (result.error == null) {
if (uri.scheme == "file") {
saveBitmapToFile(result.bitmap, uri.path)
SaveAsDialog(this, uri.path, object : SaveAsDialog.OnSaveAsListener {
override fun onSaveAsSuccess(filename: String) {
val parent = File(uri.path).parent
val path = File(parent, filename).absolutePath
saveBitmapToFile(result.bitmap, path)
}
})
} else if (uri.scheme == "content") {
val newPath = Utils.getRealPathFromURI(applicationContext, uri) ?: ""
if (!newPath.isEmpty()) {
saveBitmapToFile(result.bitmap, newPath)
SaveAsDialog(this, newPath, object : SaveAsDialog.OnSaveAsListener {
override fun onSaveAsSuccess(filename: String) {
val parent = File(uri.path).parent
val path = File(parent, filename).absolutePath
saveBitmapToFile(result.bitmap, path)
}
})
} else {
toast(R.string.image_editing_failed)
finish()
@@ -87,19 +104,26 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
private fun saveBitmapToFile(bitmap: Bitmap, path: String) {
val file = File(path)
if (!file.exists()) {
toast(R.string.error_saving_file)
finish()
return
}
var out: FileOutputStream? = null
var out: OutputStream? = null
try {
out = FileOutputStream(file)
if (needsStupidWritePermissions(path)) {
if (isShowingPermDialog(file))
return
var document = getFileDocument(path, mConfig.treeUri)
if (!file.exists()) {
document = document.createFile("", file.name)
}
out = contentResolver.openOutputStream(document.uri)
} else {
out = FileOutputStream(file)
}
bitmap.compress(getCompressionFormat(file), 90, out)
setResult(Activity.RESULT_OK, intent)
} catch (e: Exception) {
Log.e(TAG, "Crop compressing failed $e")
Log.e(TAG, "Crop compressing failed $path $e")
toast(R.string.image_editing_failed)
finish()
} finally {
@@ -110,10 +134,14 @@ class EditActivity : SimpleActivity(), CropImageView.OnCropImageCompleteListener
}
}
MediaScannerConnection.scanFile(applicationContext, arrayOf(path), null, { path: String, uri: Uri ->
scanPath(path) {
setResult(Activity.RESULT_OK, intent)
runOnUiThread {
toast(R.string.file_saved)
}
finish()
})
}
}
private fun getCompressionFormat(file: File): Bitmap.CompressFormat {

View File

@@ -0,0 +1,27 @@
package com.simplemobiletools.gallery.activities
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import com.simplemobiletools.gallery.R
import kotlinx.android.synthetic.main.activity_license.*
class LicenseActivity : SimpleActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_license)
license_butterknife_title.setOnClickListener { openUrl(R.string.butterknife_url) }
license_photoview_title.setOnClickListener { openUrl(R.string.photoview_url) }
license_glide_title.setOnClickListener { openUrl(R.string.glide_url) }
license_cropper_title.setOnClickListener { openUrl(R.string.cropper_url) }
license_filepicker_title.setOnClickListener { openUrl(R.string.filepicker_url) }
license_fileproperties_title.setOnClickListener { openUrl(R.string.fileproperties_url) }
}
private fun openUrl(id: Int) {
val url = resources.getString(id)
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
startActivity(browserIntent)
}
}

View File

@@ -0,0 +1,11 @@
package com.simplemobiletools.gallery.activities
import android.os.Bundle
class PhotoActivity : PhotoVideoActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
PhotoVideoActivity.mIsVideo = false
super.onCreate(savedInstanceState)
}
}

View File

@@ -0,0 +1,100 @@
package com.simplemobiletools.gallery.activities
import android.content.Intent
import android.content.res.Configuration
import android.net.Uri
import android.os.Bundle
import android.provider.MediaStore
import android.view.Menu
import android.view.MenuItem
import com.simplemobiletools.filepicker.extensions.getFilenameFromPath
import com.simplemobiletools.gallery.Constants
import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.fragments.PhotoFragment
import com.simplemobiletools.gallery.fragments.VideoFragment
import com.simplemobiletools.gallery.fragments.ViewPagerFragment
import com.simplemobiletools.gallery.models.Medium
import java.io.File
open class PhotoVideoActivity : SimpleActivity(), ViewPagerFragment.FragmentClickListener {
companion object {
private var mUri: Uri? = null
private var mFragment: ViewPagerFragment? = null
private var mIsFullScreen = false
var mIsVideo = false
}
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.fragment_holder)
mUri = intent.data ?: return
mIsFullScreen = true
val bundle = Bundle()
val file = File(mUri!!.toString())
val medium = Medium(file.name, mUri!!.toString(), mIsVideo, 0, file.length())
bundle.putSerializable(Constants.MEDIUM, medium)
if (savedInstanceState == null) {
mFragment = if (mIsVideo) VideoFragment() else PhotoFragment()
mFragment!!.setListener(this)
mFragment!!.arguments = bundle
supportFragmentManager.beginTransaction().replace(R.id.fragment_holder, mFragment).commit()
}
hideUI()
if (mUri!!.scheme == "content") {
val proj = arrayOf(MediaStore.Images.Media.TITLE)
val cursor = contentResolver.query(mUri!!, proj, null, null, null)
if (cursor != null && cursor.count != 0) {
val columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.TITLE)
cursor.moveToFirst()
title = cursor.getString(columnIndex)
}
cursor?.close()
} else {
title = mUri!!.toString().getFilenameFromPath()
}
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
mFragment!!.updateItem()
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.photo_video_menu, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.menu_share -> {
shareMedium()
true
}
else -> super.onOptionsItemSelected(item)
}
}
private fun shareMedium() {
val shareTitle = resources.getString(R.string.share_via)
Intent().apply {
action = Intent.ACTION_SEND
putExtra(Intent.EXTRA_STREAM, mUri)
type = if (mIsVideo) "video/*" else "image/*"
startActivity(Intent.createChooser(this, shareTitle))
}
}
override fun fragmentClicked() {
mIsFullScreen = !mIsFullScreen
if (mIsFullScreen) {
hideUI()
} else {
showUI()
}
}
}

View File

@@ -8,8 +8,8 @@ import android.net.Uri
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import com.simplemobiletools.filepicker.extensions.toast
import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.extensions.toast
import com.theartofdev.edmodo.cropper.CropImageView
import kotlinx.android.synthetic.main.activity_edit.*
@@ -87,14 +87,14 @@ class SetWallpaperActivity : SimpleActivity(), CropImageView.OnCropImageComplete
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
if (requestCode == PICK_IMAGE) {
if (resultCode == Activity.RESULT_OK && data != null) {
handleImage(data)
if (resultCode == Activity.RESULT_OK && resultData != null) {
handleImage(resultData)
} else {
finish()
}
}
super.onActivityResult(requestCode, resultCode, data)
super.onActivityResult(requestCode, resultCode, resultData)
}
}

View File

@@ -0,0 +1,54 @@
package com.simplemobiletools.gallery.activities
import android.os.Bundle
import android.support.v4.app.TaskStackBuilder
import com.simplemobiletools.gallery.R
import kotlinx.android.synthetic.main.activity_settings.*
class SettingsActivity : SimpleActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_settings)
setupDarkTheme()
setupSameSorting()
setupShowHiddenFolders()
setupAutoplayVideos()
}
private fun setupDarkTheme() {
settings_dark_theme.isChecked = mConfig.isDarkTheme
settings_dark_theme_holder.setOnClickListener {
settings_dark_theme.toggle()
mConfig.isDarkTheme = settings_dark_theme.isChecked
restartActivity()
}
}
private fun setupSameSorting() {
settings_same_sorting.isChecked = mConfig.isSameSorting
settings_same_sorting_holder.setOnClickListener {
settings_same_sorting.toggle()
mConfig.isSameSorting = settings_same_sorting.isChecked
}
}
private fun setupShowHiddenFolders() {
settings_show_hidden_folders.isChecked = mConfig.showHiddenFolders
settings_show_hidden_folders_holder.setOnClickListener {
settings_show_hidden_folders.toggle()
mConfig.showHiddenFolders = settings_show_hidden_folders.isChecked
}
}
private fun setupAutoplayVideos() {
settings_autoplay_videos_holder.setOnClickListener {
settings_autoplay_videos.toggle()
mConfig.autoplayVideos = settings_autoplay_videos.isChecked
}
}
private fun restartActivity() {
TaskStackBuilder.create(applicationContext).addNextIntentWithParentStack(intent).startActivities()
}
}

View File

@@ -0,0 +1,62 @@
package com.simplemobiletools.gallery.activities
import android.annotation.TargetApi
import android.app.Activity
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.view.MenuItem
import com.simplemobiletools.filepicker.extensions.isShowingWritePermissions
import com.simplemobiletools.gallery.Config
import com.simplemobiletools.gallery.Constants
import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.extensions.hideSystemUI
import com.simplemobiletools.gallery.extensions.showSystemUI
import java.io.File
open class SimpleActivity : AppCompatActivity() {
lateinit var mConfig: Config
override fun onCreate(savedInstanceState: Bundle?) {
mConfig = Config.newInstance(applicationContext)
var theme = if (mConfig.isDarkTheme) R.style.AppTheme_Dark else R.style.AppTheme
if (this is ViewPagerActivity || this is PhotoActivity || this is VideoActivity) {
theme = if (mConfig.isDarkTheme) R.style.FullScreenTheme_Dark else R.style.FullScreenTheme
}
setTheme(theme)
super.onCreate(savedInstanceState)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
android.R.id.home -> {
finish()
true
}
else -> super.onOptionsItemSelected(item)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
super.onActivityResult(requestCode, resultCode, resultData)
if (requestCode == Constants.OPEN_DOCUMENT_TREE && resultCode == Activity.RESULT_OK && resultData != null) {
saveTreeUri(resultData)
}
}
@TargetApi(Build.VERSION_CODES.KITKAT)
fun saveTreeUri(resultData: Intent) {
val treeUri = resultData.data
mConfig.treeUri = treeUri.toString()
val takeFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
contentResolver.takePersistableUriPermission(treeUri, takeFlags)
}
fun isShowingPermDialog(file: File) = isShowingWritePermissions(file, mConfig.treeUri, Constants.OPEN_DOCUMENT_TREE)
fun hideUI() = hideSystemUI(supportActionBar, window)
fun showUI() = showSystemUI(supportActionBar, window)
}

View File

@@ -0,0 +1,11 @@
package com.simplemobiletools.gallery.activities
import android.os.Bundle
class VideoActivity : PhotoVideoActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
PhotoVideoActivity.mIsVideo = true
super.onCreate(savedInstanceState)
}
}

View File

@@ -0,0 +1,463 @@
package com.simplemobiletools.gallery.activities
import android.app.Activity
import android.content.Intent
import android.content.res.Configuration
import android.database.Cursor
import android.net.Uri
import android.os.Bundle
import android.provider.MediaStore
import android.support.v4.view.ViewPager
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.widget.RelativeLayout
import com.simplemobiletools.filepicker.asynctasks.CopyMoveTask
import com.simplemobiletools.filepicker.extensions.*
import com.simplemobiletools.fileproperties.dialogs.PropertiesDialog
import com.simplemobiletools.gallery.Constants
import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.Utils
import com.simplemobiletools.gallery.adapters.MyPagerAdapter
import com.simplemobiletools.gallery.dialogs.CopyDialog
import com.simplemobiletools.gallery.dialogs.RenameFileDialog
import com.simplemobiletools.gallery.fragments.ViewPagerFragment
import com.simplemobiletools.gallery.models.Medium
import kotlinx.android.synthetic.main.activity_medium.*
import java.io.File
import java.util.*
import java.util.regex.Pattern
class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View.OnSystemUiVisibilityChangeListener, ViewPagerFragment.FragmentClickListener {
private var mMedia: MutableList<Medium>? = null
private var mPath = ""
private var mDirectory = ""
private var mToBeDeleted = ""
private var mBeingDeleted = ""
private var mIsFullScreen = false
private var mIsUndoShown = false
private var mPos = 0
companion object {
private val EDIT_IMAGE = 1
private val SET_WALLPAPER = 2
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_medium)
if (!hasStoragePermission()) {
finish()
return
}
val uri = intent.data
if (uri != null) {
var cursor: Cursor? = null
try {
val proj = arrayOf(MediaStore.Images.Media.DATA)
cursor = contentResolver.query(uri, proj, null, null, null)
if (cursor != null) {
val dataIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
cursor.moveToFirst()
mPath = cursor.getString(dataIndex)
}
} finally {
cursor?.close()
}
} else {
mPath = intent.getStringExtra(Constants.MEDIUM)
}
if (mPath.isEmpty()) {
toast(R.string.unknown_error)
finish()
return
}
mPos = 0
mIsFullScreen = true
mToBeDeleted = ""
mBeingDeleted = ""
hideUI()
scanPath(mPath) {}
addUndoMargin()
mDirectory = File(mPath).parent
mMedia = getMedia()
if (isDirEmpty())
return
val pagerAdapter = MyPagerAdapter(this, supportFragmentManager, mMedia!!)
view_pager.apply {
adapter = pagerAdapter
currentItem = mPos
addOnPageChangeListener(this@ViewPagerActivity)
}
window.decorView.setOnSystemUiVisibilityChangeListener(this)
updateActionbarTitle()
undo_delete.setOnClickListener { undoDeletion() }
}
override fun onResume() {
super.onResume()
if (!hasStoragePermission()) {
finish()
}
}
fun undoDeletion() {
mIsUndoShown = false
mToBeDeleted = ""
mBeingDeleted = ""
undo_delete.visibility = View.GONE
reloadViewPager()
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.viewpager_menu, menu)
menu.findItem(R.id.menu_set_as_wallpaper).isVisible = getCurrentMedium().isImage
menu.findItem(R.id.menu_edit).isVisible = getCurrentMedium().isImage
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
deleteFile()
return when (item.itemId) {
R.id.menu_set_as_wallpaper -> {
setAsWallpaper()
true
}
R.id.menu_copy_move -> {
displayCopyDialog()
true
}
R.id.menu_open_with -> {
openWith()
true
}
R.id.menu_share -> {
shareMedium()
true
}
R.id.menu_delete -> {
notifyDeletion()
true
}
R.id.menu_rename -> {
editMedium()
true
}
R.id.menu_edit -> {
openEditor()
true
}
R.id.menu_properties -> {
showProperties()
true
}
else -> super.onOptionsItemSelected(item)
}
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
val adapter = view_pager.adapter as MyPagerAdapter
adapter.updateItems(mPos)
}
private fun displayCopyDialog() {
val files = ArrayList<File>()
files.add(getCurrentFile())
CopyDialog(this, files, object : CopyMoveTask.CopyMoveListener {
override fun copySucceeded(deleted: Boolean, copiedAll: Boolean) {
if (deleted) {
reloadViewPager()
toast(if (copiedAll) R.string.moving_success else R.string.moving_success_partial)
} else {
toast(if (copiedAll) R.string.copying_success else R.string.copying_success_partial)
}
}
override fun copyFailed() {
toast(R.string.copy_move_failed)
}
})
}
private fun openEditor() {
val intent = Intent(Intent.ACTION_EDIT)
intent.setDataAndType(Uri.fromFile(getCurrentFile()), "image/*")
val chooser = Intent.createChooser(intent, getString(R.string.edit_image_with))
if (intent.resolveActivity(packageManager) != null) {
startActivityForResult(chooser, EDIT_IMAGE)
} else {
toast(R.string.no_editor_found)
}
}
private fun setAsWallpaper() {
val intent = Intent(Intent.ACTION_ATTACH_DATA)
intent.setDataAndType(Uri.fromFile(getCurrentFile()), "image/jpeg")
val chooser = Intent.createChooser(intent, getString(R.string.set_as_wallpaper_with))
if (intent.resolveActivity(packageManager) != null) {
startActivityForResult(chooser, SET_WALLPAPER)
} else {
toast(R.string.no_wallpaper_setter_found)
}
}
private fun openWith() {
val intent = Intent(Intent.ACTION_VIEW)
intent.setDataAndType(Uri.fromFile(getCurrentFile()), getCurrentMedium().getMimeType())
val chooser = Intent.createChooser(intent, getString(R.string.open_with))
if (intent.resolveActivity(packageManager) != null) {
startActivity(chooser)
} else {
toast(R.string.no_app_found)
}
}
private fun showProperties() {
PropertiesDialog(this, getCurrentFile().absolutePath, false)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
if (requestCode == EDIT_IMAGE) {
if (resultCode == Activity.RESULT_OK && resultData != null) {
val adapter = view_pager.adapter as MyPagerAdapter
adapter.updateItems(mPos)
}
} else if (requestCode == SET_WALLPAPER) {
if (resultCode == Activity.RESULT_OK) {
toast(R.string.wallpaper_set_successfully)
}
}
super.onActivityResult(requestCode, resultCode, resultData)
}
private fun shareMedium() {
Utils.shareMedium(getCurrentMedium(), this)
}
private fun notifyDeletion() {
if (isShowingPermDialog(File(mPath)))
return
mToBeDeleted = getCurrentFile().absolutePath
if (mMedia!!.size <= 1) {
deleteFile()
} else {
toast(R.string.file_deleted)
undo_delete.visibility = View.VISIBLE
mIsUndoShown = true
reloadViewPager()
}
}
private fun deleteFile() {
if (mToBeDeleted.isEmpty())
return
mIsUndoShown = false
mBeingDeleted = ""
var mWasFileDeleted = false
val file = File(mToBeDeleted)
if (needsStupidWritePermissions(mToBeDeleted)) {
if (!isShowingPermDialog(file)) {
val document = getFileDocument(mToBeDeleted, mConfig.treeUri)
if (document.canWrite()) {
mWasFileDeleted = document.delete()
}
}
} else {
mWasFileDeleted = file.delete()
}
if (mWasFileDeleted) {
mBeingDeleted = mToBeDeleted
scanPath(mToBeDeleted) { scanCompleted() }
}
mToBeDeleted = ""
undo_delete.visibility = View.GONE
}
private fun isDirEmpty(): Boolean {
return if (mMedia!!.size <= 0) {
deleteDirectoryIfEmpty()
finish()
true
} else
false
}
private fun editMedium() {
RenameFileDialog(this, getCurrentFile(), object : RenameFileDialog.OnRenameFileListener {
override fun onRenameFileSuccess(newFile: File) {
mMedia!![view_pager.currentItem].path = newFile.absolutePath
updateActionbarTitle()
}
})
}
private fun reloadViewPager() {
val adapter = view_pager.adapter as MyPagerAdapter
val curPos = view_pager.currentItem
mMedia = getMedia()
if (isDirEmpty())
return
view_pager.adapter = null
adapter.updateItems(mMedia!!)
view_pager.adapter = adapter
val newPos = Math.min(curPos, adapter.count)
view_pager.currentItem = newPos
updateActionbarTitle()
}
private fun deleteDirectoryIfEmpty() {
val file = File(mDirectory)
if (file.isDirectory && file.listFiles().size == 0) {
file.delete()
}
scanPath(mDirectory) {}
}
private fun getMedia(): MutableList<Medium> {
val media = ArrayList<Medium>()
val invalidFiles = ArrayList<File>()
for (i in 0..1) {
var uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
if (i == 1) {
uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
}
val where = "${MediaStore.Images.Media.DATA} like ? "
val args = arrayOf("$mDirectory%")
val columns = arrayOf(MediaStore.Images.Media.DATA, MediaStore.Images.Media.DATE_MODIFIED, MediaStore.Images.Media.SIZE)
val cursor = contentResolver.query(uri, columns, where, args, null)
val pattern = "${Pattern.quote(mDirectory)}/[^/]*"
if (cursor?.moveToFirst() == true) {
val pathIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA)
do {
val curPath = cursor.getString(pathIndex) ?: continue
val file = File(curPath)
if (!file.exists()) {
invalidFiles.add(file)
continue
}
if (curPath.matches(pattern.toRegex()) && curPath != mToBeDeleted && curPath != mBeingDeleted) {
val dateIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATE_MODIFIED)
val timestamp = cursor.getLong(dateIndex)
val sizeIndex = cursor.getColumnIndex(MediaStore.Images.Media.SIZE)
val size = cursor.getLong(sizeIndex)
media.add(Medium(file.name, curPath, i == 1, timestamp, size))
}
} while (cursor.moveToNext())
}
cursor?.close()
}
scanFiles(invalidFiles) {}
Medium.sorting = mConfig.sorting
Collections.sort(media)
var j = 0
for (medium in media) {
if (medium.path == mPath) {
mPos = j
break
}
j++
}
return media
}
override fun fragmentClicked() {
deleteFile()
mIsFullScreen = !mIsFullScreen
if (mIsFullScreen) {
hideUI()
} else {
showUI()
}
}
private fun updateActionbarTitle() {
title = mMedia!![view_pager.currentItem].path.getFilenameFromPath()
}
private fun getCurrentMedium(): Medium {
if (mPos >= mMedia!!.size)
mPos = mMedia!!.size - 1
return mMedia!![mPos]
}
private fun getCurrentFile() = File(getCurrentMedium().path)
private fun addUndoMargin() {
val res = resources
val params = undo_delete.layoutParams as RelativeLayout.LayoutParams
val topMargin = Utils.getStatusBarHeight(res) + Utils.getActionBarHeight(applicationContext, res)
var rightMargin = params.rightMargin
if (res.configuration.orientation != Configuration.ORIENTATION_PORTRAIT) {
rightMargin += Utils.getNavBarHeight(res)
}
params.setMargins(params.leftMargin, topMargin, rightMargin, params.bottomMargin)
}
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
}
override fun onPageSelected(position: Int) {
updateActionbarTitle()
mPos = position
supportInvalidateOptionsMenu()
}
override fun onPageScrollStateChanged(state: Int) {
if (state == ViewPager.SCROLL_STATE_DRAGGING) {
val adapter = view_pager.adapter as MyPagerAdapter
adapter.itemDragged(mPos)
}
}
override fun onSystemUiVisibilityChange(visibility: Int) {
if (visibility and View.SYSTEM_UI_FLAG_FULLSCREEN == 0) {
mIsFullScreen = false
}
val adapter = view_pager.adapter as MyPagerAdapter
adapter.updateUiVisibility(mIsFullScreen, mPos)
}
private fun scanCompleted() {
mBeingDeleted = ""
runOnUiThread {
if (mMedia != null && mMedia!!.size <= 1) {
reloadViewPager()
}
}
}
override fun onPause() {
super.onPause()
deleteFile()
}
}

View File

@@ -0,0 +1,73 @@
package com.simplemobiletools.gallery.adapters
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.ImageView
import android.widget.TextView
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.signature.StringSignature
import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.models.Directory
import kotlinx.android.synthetic.main.directory_item.view.*
import kotlinx.android.synthetic.main.directory_tmb.view.*
class DirectoryAdapter(private val mContext: Context, private val mDirs: MutableList<Directory>) : BaseAdapter() {
private val mInflater: LayoutInflater
init {
mInflater = mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
}
override fun getView(position: Int, view: View?, parent: ViewGroup): View {
var convertView = view
val viewHolder: ViewHolder
if (convertView == null) {
convertView = mInflater.inflate(R.layout.directory_item, parent, false)
viewHolder = ViewHolder(convertView)
convertView!!.tag = viewHolder
} else {
viewHolder = convertView.tag as ViewHolder
}
val dir = mDirs[position]
viewHolder.dirName.text = formatDirectoryName(dir)
viewHolder.photoCnt.text = dir.mediaCnt.toString()
val tmb = dir.thumbnail
val timestampSignature = StringSignature(dir.timestamp.toString())
if (tmb.endsWith(".gif")) {
Glide.with(mContext).load(tmb).asGif().diskCacheStrategy(DiskCacheStrategy.NONE).signature(timestampSignature)
.placeholder(R.color.tmb_background).centerCrop().crossFade().into(viewHolder.dirThumbnail)
} else {
Glide.with(mContext).load(tmb).diskCacheStrategy(DiskCacheStrategy.RESULT).signature(timestampSignature)
.placeholder(R.color.tmb_background).centerCrop().crossFade().into(viewHolder.dirThumbnail)
}
return convertView
}
private fun formatDirectoryName(dir: Directory): String {
return dir.name
}
override fun getCount(): Int {
return mDirs.size
}
override fun getItem(position: Int): Any {
return mDirs[position]
}
override fun getItemId(position: Int): Long {
return 0
}
internal class ViewHolder(view: View) {
val dirName: TextView = view.dir_name
val photoCnt: TextView = view.photo_cnt
val dirThumbnail: ImageView = view.dir_thumbnail
}
}

View File

@@ -0,0 +1,86 @@
package com.simplemobiletools.gallery.adapters
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.ImageView
import android.widget.TextView
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.signature.StringSignature
import com.simplemobiletools.gallery.Config
import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.extensions.beVisibleIf
import com.simplemobiletools.gallery.models.Medium
import kotlinx.android.synthetic.main.photo_video_item.view.*
import kotlinx.android.synthetic.main.photo_video_tmb.view.*
class MediaAdapter(private val context: Context, private val media: MutableList<Medium>) : BaseAdapter() {
private val mInflater: LayoutInflater
var displayFilenames = false
init {
mInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
displayFilenames = Config.newInstance(context).displayFileNames
}
override fun getView(position: Int, view: View?, parent: ViewGroup): View {
var convertView = view
val medium = media[position]
val viewHolder: ViewHolder
if (convertView == null) {
convertView = mInflater.inflate(R.layout.photo_video_item, parent, false)
viewHolder = ViewHolder(convertView)
convertView!!.tag = viewHolder
} else {
viewHolder = convertView.tag as ViewHolder
}
viewHolder.playOutline.visibility = if (medium.isVideo) View.VISIBLE else View.GONE
viewHolder.fileName.beVisibleIf(displayFilenames)
if (displayFilenames)
viewHolder.fileName.text = medium.name
val path = medium.path
val timestampSignature = StringSignature(medium.timestamp.toString())
if (medium.isGif) {
Glide.with(context).load(path).asGif().diskCacheStrategy(DiskCacheStrategy.NONE).signature(timestampSignature).into(viewHolder.photoThumbnail)
} else {
Glide.with(context).load(path).diskCacheStrategy(DiskCacheStrategy.NONE).signature(timestampSignature)
.placeholder(R.color.tmb_background).centerCrop().crossFade().into(viewHolder.photoThumbnail)
}
return convertView
}
fun updateDisplayFilenames(display: Boolean) {
displayFilenames = display
notifyDataSetChanged()
}
override fun getCount(): Int {
return media.size
}
override fun getItem(position: Int): Any {
return media[position]
}
override fun getItemId(position: Int): Long {
return 0
}
fun updateItems(newPhotos: List<Medium>) {
media.clear()
media.addAll(newPhotos)
notifyDataSetChanged()
}
internal class ViewHolder(view: View) {
val photoThumbnail: ImageView = view.medium_thumbnail
val playOutline: View = view.play_outline
val fileName: TextView = view.file_name
}
}

View File

@@ -0,0 +1,67 @@
package com.simplemobiletools.gallery.adapters
import android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v4.app.FragmentManager
import android.support.v4.app.FragmentStatePagerAdapter
import android.util.SparseArray
import com.simplemobiletools.gallery.Constants
import com.simplemobiletools.gallery.activities.ViewPagerActivity
import com.simplemobiletools.gallery.fragments.PhotoFragment
import com.simplemobiletools.gallery.fragments.VideoFragment
import com.simplemobiletools.gallery.fragments.ViewPagerFragment
import com.simplemobiletools.gallery.models.Medium
class MyPagerAdapter(val activity: ViewPagerActivity, fm: FragmentManager, val media: MutableList<Medium>) : FragmentStatePagerAdapter(fm) {
private val mFragments: SparseArray<ViewPagerFragment>
init {
mFragments = SparseArray<ViewPagerFragment>()
}
override fun getCount(): Int {
return media.size
}
override fun getItem(position: Int): Fragment {
val medium = media[position]
val bundle = Bundle()
bundle.putSerializable(Constants.MEDIUM, medium)
val fragment: ViewPagerFragment
if (medium.isVideo) {
fragment = VideoFragment()
} else {
fragment = PhotoFragment()
}
mFragments.put(position, fragment)
fragment.arguments = bundle
fragment.setListener(activity)
return fragment
}
fun itemDragged(pos: Int) {
mFragments[pos]?.itemDragged()
}
fun updateUiVisibility(isFullscreen: Boolean, pos: Int) {
for (i in -1..1) {
val fragment = mFragments[pos + i]
fragment?.systemUiVisibilityChanged(isFullscreen)
}
}
fun updateItems(pos: Int) {
for (i in -1..1) {
val fragment = mFragments[pos + i]
fragment?.updateItem()
}
}
fun updateItems(newPaths: List<Medium>) {
media.clear()
media.addAll(newPaths)
notifyDataSetChanged()
}
}

View File

@@ -0,0 +1,144 @@
package com.simplemobiletools.gallery.asynctasks
import android.content.Context
import android.os.AsyncTask
import android.provider.MediaStore
import com.simplemobiletools.filepicker.extensions.scanFiles
import com.simplemobiletools.gallery.Config
import com.simplemobiletools.gallery.Constants
import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.Utils
import com.simplemobiletools.gallery.models.Directory
import java.io.File
import java.lang.ref.WeakReference
import java.util.*
class GetDirectoriesAsynctask(val context: Context, val isPickVideo: Boolean, val isPickImage: Boolean,
val mToBeDeleted: List<String>, val listener: GetDirectoriesListener) : AsyncTask<Void, Void, ArrayList<Directory>>() {
lateinit var mConfig: Config
lateinit var mListener: WeakReference<GetDirectoriesListener>
override fun onPreExecute() {
super.onPreExecute()
mConfig = Config.newInstance(context)
mListener = WeakReference(listener)
}
override fun doInBackground(vararg params: Void): ArrayList<Directory> {
val directories = LinkedHashMap<String, Directory>()
val invalidFiles = ArrayList<File>()
for (i in 0..1) {
if ((isPickVideo) && i == 0)
continue
var uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
if (i == 1) {
if (isPickImage)
continue
uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
}
val columns = arrayOf(MediaStore.Images.Media.DATA, MediaStore.Images.Media.DATE_MODIFIED)
val order = getSortOrder()
val cursor = context.contentResolver.query(uri, columns, null, null, order)
if (cursor != null) {
if (cursor.moveToFirst()) {
val pathIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA)
do {
val fullPath: String = cursor.getString(pathIndex) ?: continue
val file = File(fullPath)
val parentDir = file.parent
if (!file.exists()) {
invalidFiles.add(file)
continue
}
val dateIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATE_MODIFIED)
val timestamp = cursor.getLong(dateIndex)
if (directories.containsKey(parentDir)) {
val directory: Directory = directories[parentDir]!!
val newImageCnt = directory.mediaCnt + 1
directory.mediaCnt = newImageCnt
directory.addSize(file.length())
} else if (!mToBeDeleted.contains(parentDir)) {
var dirName = Utils.getFilename(context, parentDir)
if (mConfig.getIsFolderHidden(parentDir)) {
dirName += " ${context.resources.getString(R.string.hidden)}"
}
directories.put(parentDir, Directory(parentDir, fullPath, dirName, 1, timestamp, file.length()))
}
} while (cursor.moveToNext())
}
cursor.close()
}
}
val dirs = ArrayList(directories.values)
filterDirectories(dirs)
Directory.sorting = mConfig.directorySorting
Collections.sort<Directory>(dirs)
context.scanFiles(invalidFiles) {}
return dirs
}
override fun onPostExecute(dirs: ArrayList<Directory>) {
super.onPostExecute(dirs)
val listener = mListener.get()
listener?.gotDirectories(dirs)
}
// sort the files at querying too, just to get the correct thumbnail
private fun getSortOrder(): String {
val sorting = mConfig.directorySorting
var sortBy = MediaStore.Images.Media.DATE_MODIFIED
if (sorting and Constants.SORT_BY_NAME != 0) {
sortBy = MediaStore.Images.Media.DATA
}
if (sorting and Constants.SORT_DESCENDING != 0) {
sortBy += " DESC"
}
return sortBy
}
private fun filterDirectories(dirs: MutableList<Directory>) {
if (!mConfig.showHiddenFolders)
removeHiddenFolders(dirs)
removeNoMediaFolders(dirs)
}
private fun removeHiddenFolders(dirs: MutableList<Directory>) {
val hiddenDirs = mConfig.hiddenFolders
val ignoreDirs = ArrayList<Directory>()
for (dir in dirs) {
if (hiddenDirs.contains(dir.path))
ignoreDirs.add(dir)
}
dirs.removeAll(ignoreDirs)
}
private fun removeNoMediaFolders(dirs: MutableList<Directory>) {
val ignoreDirs = ArrayList<Directory>()
for (d in dirs) {
val dir = File(d.path)
if (dir.exists() && dir.isDirectory) {
val res = dir.list { file, filename -> filename == ".nomedia" }
if (res != null && res.size > 0)
ignoreDirs.add(d)
}
}
dirs.removeAll(ignoreDirs)
}
interface GetDirectoriesListener {
fun gotDirectories(dirs: ArrayList<Directory>)
}
}

View File

@@ -0,0 +1,104 @@
package com.simplemobiletools.gallery.dialogs
import android.support.v4.util.Pair
import android.support.v7.app.AlertDialog
import android.view.LayoutInflater
import android.view.WindowManager
import com.simplemobiletools.filepicker.asynctasks.CopyMoveTask
import com.simplemobiletools.filepicker.extensions.humanizePath
import com.simplemobiletools.filepicker.extensions.isPathOnSD
import com.simplemobiletools.filepicker.extensions.scanFiles
import com.simplemobiletools.filepicker.extensions.toast
import com.simplemobiletools.gallery.Config
import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.activities.SimpleActivity
import kotlinx.android.synthetic.main.dialog_copy_move.view.*
import java.io.File
import java.util.*
class CopyDialog(val activity: SimpleActivity, val files: ArrayList<File>, val copyMoveListener: CopyMoveTask.CopyMoveListener) {
init {
val context = activity
val view = LayoutInflater.from(context).inflate(R.layout.dialog_copy_move, null)
val sourcePath = files[0].parent.trimEnd('/')
var destinationPath = ""
view.source.text = context.humanizePath(sourcePath)
view.destination.setOnClickListener {
PickAlbumDialog(activity, object : PickAlbumDialog.OnPickAlbumListener {
override fun onSuccess(path: String) {
destinationPath = path
view.destination.text = context.humanizePath(path)
}
})
}
AlertDialog.Builder(context)
.setTitle(context.resources.getString(if (files.size == 1) R.string.copy_item else R.string.copy_items))
.setView(view)
.setPositiveButton(R.string.ok, null)
.setNegativeButton(R.string.cancel, null)
.create().apply {
window!!.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE)
show()
getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener({
if (destinationPath == context.resources.getString(R.string.select_destination) || destinationPath.isEmpty()) {
context.toast(R.string.please_select_destination)
return@setOnClickListener
}
if (view.source.text.trimEnd('/') == destinationPath.trimEnd('/')) {
context.toast(R.string.source_and_destination_same)
return@setOnClickListener
}
val destinationDir = File(destinationPath)
if (!destinationDir.exists()) {
context.toast(R.string.invalid_destination)
return@setOnClickListener
}
if (files.size == 1) {
val newFile = File(files[0].path)
if (File(destinationPath, newFile.name).exists()) {
context.toast(R.string.already_exists)
return@setOnClickListener
}
}
if (activity.isShowingPermDialog(destinationDir)) {
return@setOnClickListener
}
val config = Config.newInstance(context)
if (view.dialog_radio_group.checkedRadioButtonId == R.id.dialog_radio_copy) {
context.toast(R.string.copying)
val pair = Pair<ArrayList<File>, File>(files, destinationDir)
CopyMoveTask(context, false, config.treeUri, true, copyMoveListener).execute(pair)
dismiss()
} else {
if (context.isPathOnSD(sourcePath) || context.isPathOnSD(destinationPath)) {
context.toast(R.string.moving)
val pair = Pair<ArrayList<File>, File>(files, destinationDir)
CopyMoveTask(context, true, config.treeUri, true, copyMoveListener).execute(pair)
dismiss()
} else {
val updatedFiles = ArrayList<File>(files.size * 2)
updatedFiles.addAll(files)
for (file in files) {
val destination = File(destinationDir, file.name)
if (file.renameTo(destination))
updatedFiles.add(destination)
}
context.scanFiles(updatedFiles) {}
dismiss()
copyMoveListener.copySucceeded(true, files.size * 2 == updatedFiles.size)
}
}
})
}
}
}

View File

@@ -0,0 +1,55 @@
package com.simplemobiletools.gallery.dialogs
import android.app.Activity
import android.support.v7.app.AlertDialog
import android.view.LayoutInflater
import android.view.View
import android.widget.AdapterView
import android.widget.GridView
import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.adapters.DirectoryAdapter
import com.simplemobiletools.gallery.asynctasks.GetDirectoriesAsynctask
import com.simplemobiletools.gallery.models.Directory
import kotlinx.android.synthetic.main.activity_main.view.*
import java.util.*
class PickAlbumDialog(val activity: Activity, val listener: OnPickAlbumListener) : AdapterView.OnItemClickListener, GetDirectoriesAsynctask.GetDirectoriesListener {
val context = activity.applicationContext
var grid: GridView? = null
var dirs = ArrayList<Directory>()
var dialog: AlertDialog? = null
init {
val view = LayoutInflater.from(context).inflate(R.layout.dialog_album_picker, null)
grid = view.directories_grid
dialog = AlertDialog.Builder(activity)
.setTitle(context.resources.getString(R.string.select_destination))
.setView(view)
.setPositiveButton(R.string.ok, null)
.setNegativeButton(R.string.cancel, null)
.create().apply {
show()
}
GetDirectoriesAsynctask(context, false, false, ArrayList<String>(), this).execute()
}
override fun onItemClick(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
listener.onSuccess(dirs[position].path)
dialog?.dismiss()
}
override fun gotDirectories(dirs: ArrayList<Directory>) {
this.dirs = dirs
val adapter = DirectoryAdapter(context, dirs)
grid?.adapter = adapter
grid?.onItemClickListener = this
}
interface OnPickAlbumListener {
fun onSuccess(path: String)
}
}

View File

@@ -0,0 +1,82 @@
package com.simplemobiletools.gallery.dialogs
import android.support.v7.app.AlertDialog
import android.view.LayoutInflater
import android.view.WindowManager
import com.simplemobiletools.filepicker.extensions.*
import com.simplemobiletools.gallery.Config
import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.activities.SimpleActivity
import kotlinx.android.synthetic.main.rename_directory.view.*
import java.io.File
import java.util.*
class RenameDirectoryDialog(val activity: SimpleActivity, val dir: File, val listener: OnRenameDirListener) {
val context = activity
init {
val view = LayoutInflater.from(context).inflate(R.layout.rename_directory, null)
view.directory_name.setText(dir.name)
view.directory_path.text = "${context.humanizePath(dir.parent)}/"
AlertDialog.Builder(context)
.setTitle(context.resources.getString(R.string.rename_folder))
.setView(view)
.setPositiveButton(R.string.ok, null)
.setNegativeButton(R.string.cancel, null)
.create().apply {
window!!.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE)
show()
getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener({
val newDirName = view.directory_name.value
if (newDirName.isEmpty()) {
context.toast(R.string.rename_folder_empty)
return@setOnClickListener
}
val updatedFiles = ArrayList<String>()
updatedFiles.add(dir.absolutePath)
val newDir = File(dir.parent, newDirName)
if (newDir.exists()) {
context.toast(R.string.rename_folder_exists)
return@setOnClickListener
}
if (context.needsStupidWritePermissions(dir.absolutePath)) {
if (activity.isShowingPermDialog(dir))
return@setOnClickListener
val document = context.getFileDocument(dir.absolutePath, Config.newInstance(context).treeUri)
if (document.canWrite())
document.renameTo(newDirName)
sendSuccess(updatedFiles, newDir)
dismiss()
} else if (dir.renameTo(newDir)) {
sendSuccess(updatedFiles, newDir)
dismiss()
} else {
context.toast(R.string.rename_folder_error)
}
})
}
}
private fun sendSuccess(updatedFiles: ArrayList<String>, newDir: File) {
context.toast(R.string.renaming_folder)
val files = newDir.listFiles()
for (file in files) {
updatedFiles.add(file.absolutePath)
}
updatedFiles.add(newDir.absolutePath)
val changedFiles = updatedFiles.toTypedArray()
listener.onRenameDirSuccess(changedFiles)
}
interface OnRenameDirListener {
fun onRenameDirSuccess(changedFiles: Array<String>)
}
}

View File

@@ -0,0 +1,78 @@
package com.simplemobiletools.gallery.dialogs
import android.support.v7.app.AlertDialog
import android.view.LayoutInflater
import android.view.WindowManager
import com.simplemobiletools.filepicker.extensions.*
import com.simplemobiletools.gallery.Config
import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.activities.SimpleActivity
import kotlinx.android.synthetic.main.rename_file.view.*
import java.io.File
class RenameFileDialog(val activity: SimpleActivity, val file: File, val listener: OnRenameFileListener) {
init {
val context = activity
val view = LayoutInflater.from(context).inflate(R.layout.rename_file, null)
val fullName = file.name
val dotAt = fullName.lastIndexOf(".")
var name = fullName
if (dotAt > 0) {
name = fullName.substring(0, dotAt)
val extension = fullName.substring(dotAt + 1)
view.file_extension.setText(extension)
}
view.file_name.setText(name)
view.file_path.text = "${context.humanizePath(file.parent)}/"
AlertDialog.Builder(context)
.setTitle(context.resources.getString(R.string.rename_file))
.setView(view)
.setPositiveButton(R.string.ok, null)
.setNegativeButton(R.string.cancel, null)
.create().apply {
window!!.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE)
show()
getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener({
val fileName = view.file_name.value
val extension = view.file_extension.value
if (fileName.isEmpty() || extension.isEmpty()) {
context.toast(R.string.filename_cannot_be_empty)
return@setOnClickListener
}
val newFile = File(file.parent, "$fileName.$extension")
if (context.needsStupidWritePermissions(file.absolutePath)) {
if (activity.isShowingPermDialog(file))
return@setOnClickListener
val document = context.getFileDocument(file.absolutePath, Config.newInstance(context).treeUri)
if (document.canWrite())
document.renameTo(newFile.name)
sendSuccess(file, newFile)
dismiss()
} else if (file.renameTo(newFile)) {
sendSuccess(file, newFile)
dismiss()
} else {
context.toast(R.string.rename_file_error)
}
})
}
}
private fun sendSuccess(currFile: File, newFile: File) {
val changedFiles = arrayListOf(currFile, newFile)
activity.scanFiles(changedFiles) {}
listener.onRenameFileSuccess(newFile)
}
interface OnRenameFileListener {
fun onRenameFileSuccess(newFile: File)
}
}

View File

@@ -0,0 +1,51 @@
package com.simplemobiletools.gallery.dialogs
import android.app.Activity
import android.support.v7.app.AlertDialog
import android.view.LayoutInflater
import android.view.WindowManager
import com.simplemobiletools.filepicker.extensions.getFilenameFromPath
import com.simplemobiletools.filepicker.extensions.isAValidFilename
import com.simplemobiletools.filepicker.extensions.toast
import com.simplemobiletools.filepicker.extensions.value
import com.simplemobiletools.gallery.R
import kotlinx.android.synthetic.main.rename_file.view.*
class SaveAsDialog(val activity: Activity, val path: String, val listener: OnSaveAsListener) {
init {
val context = activity
val view = LayoutInflater.from(context).inflate(R.layout.dialog_save_as, null)
view.file_name.setText(path.getFilenameFromPath())
AlertDialog.Builder(context)
.setTitle(context.resources.getString(R.string.save_as))
.setView(view)
.setPositiveButton(R.string.ok, null)
.setNegativeButton(R.string.cancel, null)
.create().apply {
window!!.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE)
show()
getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener({
val filename = view.file_name.value
if (filename.isEmpty()) {
context.toast(R.string.filename_cannot_be_empty)
return@setOnClickListener
}
if (!filename.isAValidFilename()) {
context.toast(R.string.filename_invalid_characters)
return@setOnClickListener
}
listener.onSaveAsSuccess(filename)
dismiss()
})
}
}
interface OnSaveAsListener {
fun onSaveAsSuccess(filename: String)
}
}

View File

@@ -0,0 +1,23 @@
package com.simplemobiletools.gallery.extensions
import android.app.Activity
import android.support.v7.app.ActionBar
import android.view.View
import android.view.Window
fun Activity.showSystemUI(actionbar: ActionBar?, window: Window) {
actionbar?.show()
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
}
fun Activity.hideSystemUI(actionbar: ActionBar?, window: Window) {
actionbar?.hide()
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
View.SYSTEM_UI_FLAG_LOW_PROFILE or
View.SYSTEM_UI_FLAG_FULLSCREEN or
View.SYSTEM_UI_FLAG_IMMERSIVE
}

View File

@@ -1,8 +0,0 @@
package com.simplemobiletools.gallery.extensions
import android.content.Context
import android.widget.Toast
fun Context.toast(msg: String, duration: Int = Toast.LENGTH_SHORT) = Toast.makeText(this, msg, duration).show()
fun Context.toast(msgId: Int, duration: Int = Toast.LENGTH_SHORT) = Toast.makeText(this, resources.getString(msgId), duration).show()

View File

@@ -0,0 +1,5 @@
package com.simplemobiletools.gallery.extensions
import android.view.View
fun View.beVisibleIf(beVisible: Boolean) = if (beVisible) visibility = View.VISIBLE else visibility = View.GONE

View File

@@ -0,0 +1,31 @@
package com.simplemobiletools.gallery.models
import com.simplemobiletools.gallery.Constants
class Directory(val path: String, val thumbnail: String, val name: String, var mediaCnt: Int, val timestamp: Long, var size: Long) : Comparable<Directory> {
fun addSize(bytes: Long) {
size += bytes
}
override fun compareTo(other: Directory): Int {
var res: Int
if (sorting and Constants.SORT_BY_NAME != 0) {
res = path.compareTo(other.path)
} else if (sorting and Constants.SORT_BY_DATE != 0) {
res = if (timestamp > other.timestamp) 1 else -1
} else {
res = if (size > other.size) 1 else -1
}
if (sorting and Constants.SORT_DESCENDING != 0) {
res *= -1
}
return res
}
override fun toString() = "Directory {path=$path, thumbnail=$thumbnail, name=$name, mediaCnt=$mediaCnt, timestamp=$timestamp, size $size}"
companion object {
var sorting: Int = 0
}
}

View File

@@ -0,0 +1,38 @@
package com.simplemobiletools.gallery.models
import com.simplemobiletools.gallery.Constants
import java.io.Serializable
class Medium(val name: String, var path: String, val isVideo: Boolean, val timestamp: Long, val size: Long) : Serializable, Comparable<Medium> {
val isGif: Boolean
get() = path.toLowerCase().endsWith(".gif")
val isImage: Boolean
get() = !isGif && !isVideo
fun getMimeType() = if (isVideo) "video/*" else "image/*"
override fun compareTo(other: Medium): Int {
var res: Int
if (sorting and Constants.SORT_BY_NAME != 0) {
res = path.compareTo(other.path)
} else if (sorting and Constants.SORT_BY_DATE != 0) {
res = if (timestamp > other.timestamp) 1 else -1
} else {
res = if (size > other.size) 1 else -1
}
if (sorting and Constants.SORT_DESCENDING != 0) {
res *= -1
}
return res
}
override fun toString() = "Medium {name=$name, path=$path, isVideo=$isVideo, timestamp=$timestamp, size=$size}"
companion object {
private val serialVersionUID = -6543139465975455L
var sorting: Int = 0
}
}

View File

@@ -0,0 +1,22 @@
package com.simplemobiletools.gallery.views
import android.content.Context
import android.util.AttributeSet
import android.widget.ImageView
class MyImageView : ImageView {
constructor(context: Context) : super(context) {
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
}
constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
setMeasuredDimension(measuredWidth, measuredWidth)
}
}

View File

@@ -0,0 +1,36 @@
package com.simplemobiletools.gallery.views
import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import com.booking.rtlviewpager.RtlViewPager
class MyViewPager : RtlViewPager {
constructor(context: Context) : super(context) {
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
}
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
try {
return super.onInterceptTouchEvent(ev)
} catch (ex: IllegalArgumentException) {
ex.printStackTrace()
}
return false
}
override fun onTouchEvent(ev: MotionEvent): Boolean {
try {
return super.onTouchEvent(ev)
} catch (ex: IllegalArgumentException) {
ex.printStackTrace()
}
return false
}
}

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:angle="90"
android:endColor="@android:color/transparent"
android:startColor="#BB000000"/>
</shape>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<com.simplemobiletools.gallery.MyImageView
<com.simplemobiletools.gallery.views.MyImageView
android:id="@+id/dir_thumbnail"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<com.simplemobiletools.gallery.MyImageView
<com.simplemobiletools.gallery.views.MyImageView
android:id="@+id/medium_thumbnail"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"

View File

@@ -4,8 +4,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/coordinator_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black">
android:layout_height="match_parent">
<com.theartofdev.edmodo.cropper.CropImageView
android:id="@+id/crop_image_view"

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
android:id="@+id/license_holder"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/license_holder"
android:layout_width="match_parent"
android:layout_height="match_parent">
@@ -73,5 +73,32 @@
android:layout_height="wrap_content"
android:text="@string/cropper_text"/>
<TextView
android:id="@+id/license_filepicker_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/activity_margin"
android:text="@string/filepicker_title"
android:textColor="@color/colorPrimary"/>
<TextView
android:id="@+id/license_filepicker_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/filepicker_text"/>
<TextView
android:id="@+id/license_fileproperties_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/activity_margin"
android:text="@string/fileproperties_title"
android:textColor="@color/colorPrimary"/>
<TextView
android:id="@+id/license_fileproperties_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/fileproperties_text"/>
</LinearLayout>
</ScrollView>

View File

@@ -1,10 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
android:id="@+id/coordinator_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/coordinator_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black">
android:layout_height="match_parent">
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/directories_holder"
@@ -15,7 +14,6 @@
android:id="@+id/directories_grid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:choiceMode="multipleChoiceModal"
android:columnWidth="@dimen/dir_tmb_size"
android:horizontalSpacing="1dp"
android:numColumns="auto_fit"

View File

@@ -1,10 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
android:id="@+id/coordinator_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/coordinator_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black">
android:layout_height="match_parent">
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/media_holder"

View File

@@ -1,12 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:id="@+id/fragment_holder"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment_holder"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black">
android:layout_height="match_parent">
<com.simplemobiletools.gallery.MyViewPager
<com.simplemobiletools.gallery.views.MyViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

View File

@@ -4,8 +4,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/coordinator_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black">
android:layout_height="match_parent">
<com.theartofdev.edmodo.cropper.CropImageView
android:id="@+id/crop_image_view"

View File

@@ -94,5 +94,33 @@
android:clickable="false"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/settings_autoplay_videos_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/settings_padding"
android:background="?attr/selectableItemBackground"
android:padding="@dimen/activity_margin">
<TextView
android:id="@+id/settings_autoplay_videos_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:paddingLeft="@dimen/settings_padding"
android:paddingStart="@dimen/settings_padding"
android:text="@string/autoplay_videos"/>
<android.support.v7.widget.SwitchCompat
android:id="@+id/settings_autoplay_videos"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:background="@null"
android:clickable="false"/>
</RelativeLayout>
</LinearLayout>
</ScrollView>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<GridView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/directories_grid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:columnWidth="@dimen/dir_tmb_size"
android:horizontalSpacing="1dp"
android:numColumns="auto_fit"
android:paddingTop="@dimen/activity_margin"
android:stretchMode="columnWidth"
android:verticalSpacing="1dp"/>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/dialog_holder"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingLeft="@dimen/activity_margin"
android:paddingRight="@dimen/activity_margin"
android:paddingTop="@dimen/activity_margin">
<TextView
android:id="@+id/source_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/source"
android:textSize="@dimen/details_text_size"/>
<TextView
android:id="@+id/source"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/activity_margin"
android:layout_marginLeft="@dimen/activity_margin"
android:paddingRight="@dimen/small_padding"
android:paddingTop="@dimen/small_padding"/>
<TextView
android:id="@+id/destination_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/destination"
android:textSize="@dimen/details_text_size"/>
<TextView
android:id="@+id/destination"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/activity_margin"
android:layout_marginLeft="@dimen/activity_margin"
android:paddingBottom="@dimen/small_padding"
android:paddingRight="@dimen/small_padding"
android:paddingTop="@dimen/small_padding"
android:text="@string/select_destination"/>
<RadioGroup
android:id="@+id/dialog_radio_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:checkedButton="@+id/dialog_radio_copy">
<RadioButton
android:id="@+id/dialog_radio_copy"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/medium_padding"
android:text="@string/copy"/>
<RadioButton
android:id="@+id/dialog_radio_move"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/move"/>
</RadioGroup>
</LinearLayout>

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/save_as_holder"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="@dimen/activity_margin">
<EditText
android:id="@+id/file_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/activity_margin"
android:singleLine="true"/>
</LinearLayout>

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:id="@+id/dir_holder"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/dir_holder"
android:layout_width="match_parent"
android:layout_height="match_parent">
@@ -12,7 +12,8 @@
android:layout_width="match_parent"
android:layout_height="@dimen/tmb_shadow_height"
android:layout_alignParentBottom="true"
android:background="@color/actionbar_grey"
android:background="@drawable/gradient_background"
android:gravity="bottom"
android:paddingBottom="@dimen/small_padding"
android:paddingLeft="@dimen/medium_padding"
android:paddingRight="@dimen/medium_padding"

View File

@@ -7,7 +7,7 @@
android:layout_height="match_parent"
android:foreground="@drawable/selector">
<com.simplemobiletools.gallery.MyImageView
<com.simplemobiletools.gallery.views.MyImageView
android:id="@+id/dir_thumbnail"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

View File

@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
android:id="@+id/fragment_holder"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment_holder"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black"/>
android:layout_height="match_parent"/>

View File

@@ -1,13 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:id="@+id/photo_holder"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/photo_holder"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
android:id="@+id/photo_view"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/photo_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

View File

@@ -2,8 +2,7 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/video_holder"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black">
android:layout_height="match_parent">
<SurfaceView
android:id="@+id/video_surface"
@@ -25,7 +24,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="@color/actionbar_grey"
android:background="@drawable/gradient_background"
android:paddingLeft="@dimen/timer_padding"
android:paddingRight="@dimen/timer_padding">

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:id="@+id/media_item_holder"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/media_item_holder"
android:layout_width="match_parent"
android:layout_height="match_parent">
@@ -11,9 +11,24 @@
android:id="@+id/play_outline"
android:layout_width="@dimen/play_outline_size"
android:layout_height="@dimen/play_outline_size"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:src="@mipmap/play_outline"
android:visibility="gone"/>
<TextView
android:id="@+id/file_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="@drawable/gradient_background"
android:gravity="bottom"
android:maxLines="3"
android:minHeight="@dimen/play_outline_size"
android:paddingBottom="@dimen/small_padding"
android:paddingLeft="@dimen/small_padding"
android:paddingRight="@dimen/small_padding"
android:textColor="@android:color/white"
android:textSize="@dimen/details_text_size"/>
</RelativeLayout>

View File

@@ -2,13 +2,13 @@
<merge>
<FrameLayout
android:id="@+id/medium_thumbnail_holder"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/medium_thumbnail_holder"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:foreground="@drawable/selector">
<com.simplemobiletools.gallery.MyImageView
<com.simplemobiletools.gallery.views.MyImageView
android:id="@+id/medium_thumbnail"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:id="@+id/rename_directory_holder"
xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rename_directory_holder"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:id="@+id/rename_file_holder"
xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rename_file_holder"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
@@ -19,13 +19,13 @@
android:singleLine="true"/>
<TextView
android:id="@+id/extension_label"
android:id="@+id/file_extension_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/extension"/>
<EditText
android:id="@+id/extension"
android:id="@+id/file_extension"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/activity_margin"

View File

@@ -1,6 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/cab_properties"
android:icon="@mipmap/info"
android:title="@string/properties"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/cab_edit"
android:icon="@mipmap/rename"
@@ -16,6 +21,10 @@
android:icon="@mipmap/unhide"
android:title="@string/unhide_folder"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/cab_copy_move"
android:title="@string/copy_move"
app:showAsAction="never"/>
<item
android:id="@+id/cab_delete"
android:icon="@mipmap/delete"

View File

@@ -1,11 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/cab_properties"
android:icon="@mipmap/info"
android:title="@string/properties"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/cab_share"
android:icon="@mipmap/share"
android:title="@string/share"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/cab_copy_move"
android:title="@string/copy_move"
app:showAsAction="never"/>
<item
android:id="@+id/cab_delete"
android:icon="@mipmap/delete"

View File

@@ -7,8 +7,8 @@
android:title="@string/rotate"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/save"
android:id="@+id/save_as"
android:icon="@mipmap/check"
android:title="@string/save"
android:title="@string/save_as"
app:showAsAction="ifRoom"/>
</menu>

View File

@@ -6,6 +6,11 @@
android:icon="@mipmap/sort"
android:title="@string/sort_by"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/toggle_filename"
android:icon="@mipmap/toggle_filename"
android:title="@string/toggle_filename"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/hide_folder"
android:title="@string/hide_folder"

View File

@@ -1,6 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_copy_move"
android:title="@string/copy_move"
app:showAsAction="never"/>
<item
android:id="@+id/menu_set_as_wallpaper"
android:title="@string/set_as_wallpaper"
@@ -24,6 +28,11 @@
android:icon="@mipmap/rename"
android:title="@string/rename"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/menu_properties"
android:icon="@mipmap/info"
android:title="@string/properties"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/menu_delete"
android:icon="@mipmap/delete"

Binary file not shown.

After

Width:  |  Height:  |  Size: 755 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 433 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 322 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 516 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 293 B

View File

@@ -1,22 +1,26 @@
<resources>
<string name="app_name">Simple Gallery</string>
<string name="app_launcher_name">Gallery</string>
<string name="app_name">Schlichte Galerie</string>
<string name="app_launcher_name">Galerie</string>
<string name="share_via">Teilen via</string>
<string name="no_permissions">Ohne Zugriff auf deinen Speicher gibt es hier nicht viel zu tun</string>
<string name="delete">Löschen</string>
<string name="deleting">Lösche</string>
<string name="rename">Rename</string>
<string name="edit">Edit</string>
<string name="rename">Umbenennen</string>
<string name="edit">Bearbeiten</string>
<string name="undo">Rückgängig</string>
<string name="share">Teilen</string>
<string name="properties">Eigenschaften</string>
<string name="rename_file">Datei umbenennen</string>
<string name="rename_folder">Ordner umbenennen</string>
<string name="rename_file_error">Konnte die Datei nicht umbenennen</string>
<string name="rename_file_empty">Dateiname darf nicht leer sein</string>
<string name="rename_folder_error">Konnte den Ordner nicht umbenennen</string>
<string name="rename_folder_empty">Ordnername darf nicht leer sein</string>
<string name="rename_folder_exists">A folder with that name already exists</string>
<string name="rename_folder_root">Cannot rename the root folder of a storage</string>
<string name="rename_folder_ok">Ordner erfolgreich umbenannt</string>
<string name="renaming_folder">Benenne Ordner um</string>
<string name="filename_cannot_be_empty">Dateiname darf nicht leer sein</string>
<string name="filename_invalid_characters">Filename contains invalid characters</string>
<string name="extension">Dateiendung</string>
<string name="file_deleted">Datei gelöscht</string>
<string name="open_camera">Kamera öffnen</string>
@@ -29,11 +33,33 @@
<string name="descending">Absteigend</string>
<string name="ok">OK</string>
<string name="cancel">Abbrechen</string>
<string name="open_with">Open with</string>
<string name="no_app_found">No valid app found</string>
<string name="hide_folder">Hide folder</string>
<string name="unhide_folder">Unhide folder</string>
<string name="hidden">(hidden)</string>
<string name="open_with">Öffnen mit</string>
<string name="no_app_found">Keine zulässige App gefunden</string>
<string name="hide_folder">Ordner verstecken</string>
<string name="unhide_folder">Ordner sichtbar machen</string>
<string name="hidden">(versteckt)</string>
<string name="save_as">Save as</string>
<string name="file_saved">File saved successfully</string>
<string name="copy">Kopieren</string>
<string name="move">Verschieben</string>
<string name="copy_move">Kopieren/Verschieben</string>
<string name="copy_item">Datei/Ordner kopieren</string>
<string name="copy_items">Dateien/Ordner kopieren</string>
<string name="source">Quelle</string>
<string name="destination">Ziel</string>
<string name="select_destination">Ziel auswählen</string>
<string name="invalid_destination">Konnte nicht an ausgewähltes Ziel schreiben</string>
<string name="please_select_destination">Bitte wähle ein Ziel</string>
<string name="source_and_destination_same">Source and destination cannot be the same</string>
<string name="copy_failed">Konnte die Datei nicht kopieren</string>
<string name="copying">Kopiere&#8230;</string>
<string name="copying_success">Files copied successfully</string>
<string name="copy_move_failed">An error occurred</string>
<string name="moving">Moving&#8230;</string>
<string name="moving_success">Files moved successfully</string>
<string name="already_exists">A file with that name already exists</string>
<string name="moving_success_partial">Some files could not be moved</string>
<string name="copying_success_partial">Some files could not be copied</string>
<plurals name="folders_deleted">
<item quantity="one">1 Ordner gelöscht</item>
@@ -47,23 +73,23 @@
<!-- Editor -->
<string name="editor">Editor</string>
<string name="save">Save</string>
<string name="rotate">Rotate</string>
<string name="invalid_image_path">Invalid image path</string>
<string name="image_editing_failed">Image editing failed</string>
<string name="edit_image_with">Edit image with:</string>
<string name="no_editor_found">No image editor found</string>
<string name="unknown_file_location">Unknown file location</string>
<string name="error_saving_file">Could not overwrite the source file</string>
<string name="save">Speichern</string>
<string name="rotate">Drehen</string>
<string name="invalid_image_path">Ungültiger Dateipfad</string>
<string name="image_editing_failed">Bildbearbeitung fehlgeschlagen</string>
<string name="edit_image_with">Bearbeite Bild mit:</string>
<string name="no_editor_found">Kein Bildeditor gefunden</string>
<string name="unknown_file_location">Unbekannter Dateiort</string>
<string name="error_saving_file">Konnte Quelldatei nicht überschreiben</string>
<!-- Set wallpaper -->
<string name="simple_wallpaper">Simple Wallpaper</string>
<string name="set_as_wallpaper">Als Hintergrundbild setzen</string>
<string name="set_as_wallpaper">Als Hintergrundbild festlegen</string>
<string name="set_as_wallpaper_failed">Setzen des Hintergrundbildes fehlgeschlagen</string>
<string name="set_as_wallpaper_with">Set as wallpaper with:</string>
<string name="no_wallpaper_setter_found">No app capable of it has been found</string>
<string name="set_as_wallpaper_with">Als Hintergrundbild festlegen mit:</string>
<string name="no_wallpaper_setter_found">Keine passende App gefunden</string>
<string name="setting_wallpaper">Setze Hintergrundbild&#8230;</string>
<string name="wallpaper_set_successfully">Wallpaper set successfully</string>
<string name="wallpaper_set_successfully">Hintergrundbild erfolgreich festgelegt</string>
<!-- About -->
<string name="about">Über</string>
@@ -79,15 +105,19 @@
<!-- Settings -->
<string name="settings">Einstellungen</string>
<string name="dark_theme">Dunkles Thema</string>
<string name="dark_theme">Dunkles Design</string>
<string name="same_sorting">Selbe Sortierung für Dateien und Ordner</string>
<string name="show_hidden_folders">Show hidden folders</string>
<string name="show_hidden_folders">Zeige versteckte Ordner</string>
<string name="autoplay_videos">Play videos automatically</string>
<string name="toggle_filename">Toggle filename visibility</string>
<!-- License -->
<string name="notice">Diese App nutzt die folgenden Drittanbieterbilbiotheken, die mein Leben einfacher machen. Danke.</string>
<string name="third_party_licences">Drittanbieterlizenzen</string>
<string name="butterknife_title"><u>Butter Knife (view injector)</u></string>
<string name="photoview_title"><u>PhotoView (zoomable imageviews)</u></string>
<string name="glide_title"><u>Glide (image loading and caching)</u></string>
<string name="butterknife_title"><u>Butter Knife (View Injector)</u></string>
<string name="photoview_title"><u>PhotoView (Zoomable Imageviews)</u></string>
<string name="glide_title"><u>Glide (Bilder laden und zwischenspeichern)</u></string>
<string name="cropper_title"><u>Android Image Cropper</u></string>
<string name="filepicker_title"><u>Simple File Picker (filepicker dialog)</u></string>
<string name="fileproperties_title"><u>Simple File Properties (properties dialog)</u></string>
</resources>

View File

@@ -5,18 +5,22 @@
<string name="no_permissions">No hay mucho que hacer en una galería sin acceso al almacenamiento</string>
<string name="delete">Eliminar</string>
<string name="deleting">Eliminando</string>
<string name="rename">Rename</string>
<string name="rename">Renombrar</string>
<string name="edit">Edit</string>
<string name="undo">Deshacer</string>
<string name="share">Compartir</string>
<string name="properties">Propiedades</string>
<string name="rename_file">Renombrar archivo</string>
<string name="rename_folder">Renombrar carpeta</string>
<string name="rename_file_error">No se pudo renombrar el archivo</string>
<string name="rename_file_empty">El nombre de archivo no puede estar vacío</string>
<string name="rename_folder_error">No se pudo renombrar la carpeta</string>
<string name="rename_folder_empty">El nombre de carpeta no puede estar vacío</string>
<string name="rename_folder_exists">A folder with that name already exists</string>
<string name="rename_folder_root">Cannot rename the root folder of a storage</string>
<string name="rename_folder_ok">Carpeta renombrada correctamente</string>
<string name="renaming_folder">Renombrando carpeta</string>
<string name="filename_cannot_be_empty">El nombre de archivo no puede estar vacío</string>
<string name="filename_invalid_characters">Filename contains invalid characters</string>
<string name="extension">Extensión</string>
<string name="file_deleted">Archivo eliminado</string>
<string name="open_camera">Abrir cámara</string>
@@ -29,11 +33,33 @@
<string name="descending">Descendente</string>
<string name="ok">Aceptar</string>
<string name="cancel">Cancelar</string>
<string name="open_with">Open with</string>
<string name="open_with">Abrir con&#8230;</string>
<string name="no_app_found">No valid app found</string>
<string name="hide_folder">Hide folder</string>
<string name="hide_folder">Ocultar carpeta</string>
<string name="unhide_folder">Unhide folder</string>
<string name="hidden">(hidden)</string>
<string name="save_as">Salvar como</string>
<string name="file_saved">Archivo guardado con éxito</string>
<string name="copy">Copy</string>
<string name="move">Move</string>
<string name="copy_move">Copy/Move</string>
<string name="copy_item">Copy item</string>
<string name="copy_items">Copy items</string>
<string name="source">Source</string>
<string name="destination">Destination</string>
<string name="select_destination">Select destination</string>
<string name="invalid_destination">Could not write to the selected destination</string>
<string name="please_select_destination">Please select a destination</string>
<string name="source_and_destination_same">Source and destination cannot be the same</string>
<string name="copy_failed">Could not copy the files</string>
<string name="copying">Copying&#8230;</string>
<string name="copying_success">Files copied successfully</string>
<string name="copy_move_failed">An error occurred</string>
<string name="moving">Moving&#8230;</string>
<string name="moving_success">Files moved successfully</string>
<string name="already_exists">A file with that name already exists</string>
<string name="moving_success_partial">Some files could not be moved</string>
<string name="copying_success_partial">Some files could not be copied</string>
<plurals name="folders_deleted">
<item quantity="one">1 carpeta eliminada</item>
@@ -51,7 +77,7 @@
<string name="rotate">Rotate</string>
<string name="invalid_image_path">Invalid image path</string>
<string name="image_editing_failed">Image editing failed</string>
<string name="edit_image_with">Edit image with:</string>
<string name="edit_image_with">Editar image usando:</string>
<string name="no_editor_found">No image editor found</string>
<string name="unknown_file_location">Unknown file location</string>
<string name="error_saving_file">Could not overwrite the source file</string>
@@ -81,7 +107,9 @@
<string name="settings">Ajustes</string>
<string name="dark_theme">Tema oscuro</string>
<string name="same_sorting">Ordenar del mismo modo los archivos y las carpetas</string>
<string name="show_hidden_folders">Show hidden folders</string>
<string name="show_hidden_folders">Mostrar carpetas ocultas</string>
<string name="autoplay_videos">Reproducir vídeos automáticamente</string>
<string name="toggle_filename">Toggle filename visibility</string>
<!-- License -->
<string name="notice">Esta aplicación usa las siguientes bibliotecas de terceros que hacen mi vida más fácil. Gracias.</string>
@@ -90,4 +118,6 @@
<string name="photoview_title"><u>PhotoView (zoomable imageviews)</u></string>
<string name="glide_title"><u>Glide (image loading and caching)</u></string>
<string name="cropper_title"><u>Android Image Cropper</u></string>
<string name="filepicker_title"><u>Simple File Picker (filepicker dialog)</u></string>
<string name="fileproperties_title"><u>Simple File Properties (properties dialog)</u></string>
</resources>

View File

@@ -9,14 +9,18 @@
<string name="edit">Edit</string>
<string name="undo">Annulla</string>
<string name="share">Condividi</string>
<string name="properties">Proprietà</string>
<string name="rename_file">Rinomina file</string>
<string name="rename_folder">Rinomina cartella</string>
<string name="rename_file_error">Impossibile rinominare il file</string>
<string name="rename_file_empty">Il nome del file non deve essere vuoto</string>
<string name="rename_folder_error">Impossibile rinominare la cartella</string>
<string name="rename_folder_empty">Il nome della cartella non deve essere vuoto</string>
<string name="rename_folder_exists">A folder with that name already exists</string>
<string name="rename_folder_root">Cannot rename the root folder of a storage</string>
<string name="rename_folder_ok">Cartella rinominata correttamente</string>
<string name="renaming_folder">Rinominazione cartella</string>
<string name="filename_cannot_be_empty">Il nome del file non deve essere vuoto</string>
<string name="filename_invalid_characters">Filename contains invalid characters</string>
<string name="extension">Estensione</string>
<string name="file_deleted">File eliminato</string>
<string name="open_camera">Apri fotocamera</string>
@@ -34,6 +38,28 @@
<string name="hide_folder">Hide folder</string>
<string name="unhide_folder">Unhide folder</string>
<string name="hidden">(hidden)</string>
<string name="save_as">Save as</string>
<string name="file_saved">File saved successfully</string>
<string name="copy">Copia</string>
<string name="move">Sposta</string>
<string name="copy_move">Copia/Sposta</string>
<string name="copy_item">Copia elemento</string>
<string name="copy_items">Copia elementi</string>
<string name="source">Fonte</string>
<string name="destination">Destinazione</string>
<string name="select_destination">Seleziona destinazione</string>
<string name="invalid_destination">Impossibile scrivere nella destinazione selezionata</string>
<string name="please_select_destination">Seleziona una destinazione</string>
<string name="source_and_destination_same">Source and destination cannot be the same</string>
<string name="copy_failed">Impossibile copiare i file</string>
<string name="copying">Copia in corso&#8230;</string>
<string name="copying_success">Files copied successfully</string>
<string name="copy_move_failed">An error occurred</string>
<string name="moving">Moving&#8230;</string>
<string name="moving_success">Files moved successfully</string>
<string name="already_exists">A file with that name already exists</string>
<string name="moving_success_partial">Some files could not be moved</string>
<string name="copying_success_partial">Some files could not be copied</string>
<plurals name="folders_deleted">
<item quantity="one">1 cartella eliminata</item>
@@ -82,6 +108,8 @@
<string name="dark_theme">Tema scuro</string>
<string name="same_sorting">Same sorting for files and folders</string>
<string name="show_hidden_folders">Show hidden folders</string>
<string name="autoplay_videos">Play videos automatically</string>
<string name="toggle_filename">Toggle filename visibility</string>
<!-- License -->
<string name="notice">Questa app usa le seguenti librerie di terze parti per semplificarmi la vita. Grazie.</string>
@@ -90,4 +118,6 @@
<string name="photoview_title"><u>PhotoView (zoomable imageviews)</u></string>
<string name="glide_title"><u>Glide (image loading and caching)</u></string>
<string name="cropper_title"><u>Android Image Cropper</u></string>
<string name="filepicker_title"><u>Simple File Picker (filepicker dialog)</u></string>
<string name="fileproperties_title"><u>Simple File Properties (properties dialog)</u></string>
</resources>

View File

@@ -9,14 +9,18 @@
<string name="edit">Edit</string>
<string name="undo">元に戻す</string>
<string name="share">共有</string>
<string name="properties">Properties</string>
<string name="rename_file">ファイルの名前を変更</string>
<string name="rename_folder">フォルダーの名前を変更</string>
<string name="rename_file_error">ファイルの名前を変更できませんでした</string>
<string name="rename_file_empty">ファイル名は空にできません</string>
<string name="rename_folder_error">フォルダーの名前を変更できませんでした</string>
<string name="rename_folder_empty">フォルダー名は空にできません</string>
<string name="rename_folder_exists">A folder with that name already exists</string>
<string name="rename_folder_root">Cannot rename the root folder of a storage</string>
<string name="rename_folder_ok">フォルダーの名前を正常に変更しました</string>
<string name="renaming_folder">フォルダーの名前を変更中</string>
<string name="filename_cannot_be_empty">ファイル名は空にできません</string>
<string name="filename_invalid_characters">Filename contains invalid characters</string>
<string name="extension">拡張</string>
<string name="file_deleted">ファイルを削除しました</string>
<string name="open_camera">カメラを開く</string>
@@ -34,6 +38,28 @@
<string name="hide_folder">Hide folder</string>
<string name="unhide_folder">Unhide folder</string>
<string name="hidden">(hidden)</string>
<string name="save_as">Save as</string>
<string name="file_saved">File saved successfully</string>
<string name="copy">コピー</string>
<string name="move">移動</string>
<string name="copy_move">Copy/Move</string>
<string name="copy_item">アイテムをコピー</string>
<string name="copy_items">アイテムをコピー</string>
<string name="source"></string>
<string name="destination"></string>
<string name="select_destination">宛先を選択</string>
<string name="invalid_destination">選択した宛先に書き込みできませんでした</string>
<string name="please_select_destination">宛先を選択してください</string>
<string name="source_and_destination_same">Source and destination cannot be the same</string>
<string name="copy_failed">ファイルをコピーできませんでした</string>
<string name="copying">コピー中&#8230;</string>
<string name="copying_success">Files copied successfully</string>
<string name="copy_move_failed">An error occurred</string>
<string name="moving">Moving&#8230;</string>
<string name="moving_success">Files moved successfully</string>
<string name="already_exists">A file with that name already exists</string>
<string name="moving_success_partial">Some files could not be moved</string>
<string name="copying_success_partial">Some files could not be copied</string>
<plurals name="folders_deleted">
<item quantity="one">1 フォルダーを削除しました</item>
@@ -82,6 +108,8 @@
<string name="dark_theme">ダークテーマ</string>
<string name="same_sorting">Same sorting for files and folders</string>
<string name="show_hidden_folders">Show hidden folders</string>
<string name="autoplay_videos">Play videos automatically</string>
<string name="toggle_filename">Toggle filename visibility</string>
<!-- License -->
<string name="notice">このアプリは、私の人生を容易にするために、次のサードパーティのライブラリーを使用しています。 ありがとうございます。</string>
@@ -90,4 +118,6 @@
<string name="photoview_title"><u>PhotoView (ズーム可能イメージビュー)</u></string>
<string name="glide_title"><u>Glide (イメージ ローディングとキャッシング)</u></string>
<string name="cropper_title"><u>Android Image Cropper</u></string>
<string name="filepicker_title"><u>Simple File Picker (filepicker dialog)</u></string>
<string name="fileproperties_title"><u>Simple File Properties (properties dialog)</u></string>
</resources>

View File

@@ -3,22 +3,26 @@
<string name="app_launcher_name">Galeria</string>
<string name="share_via">Partilhar via</string>
<string name="no_permissions">É necessário o acesso ao armazenamento para a galeria ter utilidade</string>
<string name="delete">Eliminar</string>
<string name="deleting">A eliminar</string>
<string name="rename">Rename</string>
<string name="edit">Edit</string>
<string name="delete">Apagar</string>
<string name="deleting">A apagar</string>
<string name="rename">Renomear</string>
<string name="edit">Editar</string>
<string name="undo">Desfazer</string>
<string name="share">Partilhar</string>
<string name="properties">Propriedades</string>
<string name="rename_file">Renomear ficheiro</string>
<string name="rename_folder">Renomear pasta</string>
<string name="rename_file_error">Não foi possível renomear o ficheiro</string>
<string name="rename_file_empty">O nome do ficheiro não pode ficar em branco</string>
<string name="rename_folder_error">Não foi possível renomear a pasta</string>
<string name="rename_folder_empty">O nome da pasta não pode ficar em branco</string>
<string name="rename_folder_empty">O nome da pasta não pode estar vazio</string>
<string name="rename_folder_exists">A folder with that name already exists</string>
<string name="rename_folder_root">Cannot rename the root folder of a storage</string>
<string name="rename_folder_ok">A pasta foi renomeada com sucesso</string>
<string name="renaming_folder">A renomear pasta</string>
<string name="filename_cannot_be_empty">O nome do ficheiro não pode estar vazio</string>
<string name="filename_invalid_characters">O nome do ficheiro contém caracteres inválidos</string>
<string name="extension">Extensão</string>
<string name="file_deleted">Ficheiro eliminado</string>
<string name="file_deleted">Ficheiro apagado</string>
<string name="open_camera">Abrir câmara</string>
<string name="unknown_error">Ocorreu um erro desconhecido</string>
<string name="sort_by">Ordenar por</string>
@@ -29,65 +33,91 @@
<string name="descending">Descendente</string>
<string name="ok">OK</string>
<string name="cancel">Cancelar</string>
<string name="open_with">Open with</string>
<string name="no_app_found">No valid app found</string>
<string name="hide_folder">Hide folder</string>
<string name="unhide_folder">Unhide folder</string>
<string name="hidden">(hidden)</string>
<string name="open_with">Abrir com</string>
<string name="no_app_found">Nenhuma aplicação encontrada</string>
<string name="hide_folder">Ocultar pasta</string>
<string name="unhide_folder">Mostrar pasta</string>
<string name="hidden">(oculta)</string>
<string name="save_as">Guardar como</string>
<string name="file_saved">Ficheiro guardado com sucesso</string>
<string name="copy">Copiar</string>
<string name="move">Mover</string>
<string name="copy_move">Copiar/mover para</string>
<string name="copy_item">Copiar item</string>
<string name="copy_items">Copiar itens</string>
<string name="source">Origem</string>
<string name="destination">Destino</string>
<string name="select_destination">Selecione o destino</string>
<string name="invalid_destination">Não foi possível escrever no destino selecionado</string>
<string name="please_select_destination">Por favor selecione um destino</string>
<string name="source_and_destination_same">A origem e o destino não podem ser iguais</string>
<string name="copy_failed">Não foi possível copiar os ficheiros</string>
<string name="copying">A copiar&#8230;</string>
<string name="copying_success">Ficheiros copiados com sucesso</string>
<string name="copy_move_failed">Ocorreu um erro ao copiar</string>
<string name="moving">Moving&#8230;</string>
<string name="moving_success">Files moved successfully</string>
<string name="already_exists">Já existe um ficheiro com este nome</string>
<string name="moving_success_partial">Some files could not be moved</string>
<string name="copying_success_partial">Some files could not be copied</string>
<plurals name="folders_deleted">
<item quantity="one">1 pasta eliminada</item>
<item quantity="other">%1$d pastas eliminadas</item>
<item quantity="one">1 pasta apagada</item>
<item quantity="other">%1$d pastas apagadas</item>
</plurals>
<plurals name="files_deleted">
<item quantity="one">1 ficheiro eliminado</item>
<item quantity="other">%1$d ficheiros eliminados</item>
<item quantity="one">1 ficheiro apagado</item>
<item quantity="other">%1$d ficheiros apagadas</item>
</plurals>
<!-- Editor -->
<string name="editor">Editor</string>
<string name="save">Save</string>
<string name="rotate">Rotate</string>
<string name="invalid_image_path">Invalid image path</string>
<string name="image_editing_failed">Image editing failed</string>
<string name="edit_image_with">Edit image with:</string>
<string name="no_editor_found">No image editor found</string>
<string name="unknown_file_location">Unknown file location</string>
<string name="error_saving_file">Could not overwrite the source file</string>
<string name="save">Guardar</string>
<string name="rotate">Rodar</string>
<string name="invalid_image_path">Caminho inválido</string>
<string name="image_editing_failed">Falha de edição de imagem</string>
<string name="edit_image_with">Editar imagem com:</string>
<string name="no_editor_found">Editor não encontrado</string>
<string name="unknown_file_location">Localização desconhecida</string>
<string name="error_saving_file">Não foi possível substituir o ficheiro original</string>
<!-- Set wallpaper -->
<string name="simple_wallpaper">Simple Wallpaper</string>
<string name="set_as_wallpaper">Definir como fundo de ecrã</string>
<string name="set_as_wallpaper">Definir como fundo do ecrã</string>
<string name="set_as_wallpaper_failed">Falha ao definir como fundo de ecrã</string>
<string name="set_as_wallpaper_with">Set as wallpaper with:</string>
<string name="no_wallpaper_setter_found">No app capable of it has been found</string>
<string name="set_as_wallpaper_with">Definir como fundo com:</string>
<string name="no_wallpaper_setter_found">Aplicação não encontrada</string>
<string name="setting_wallpaper">A definir como fundo de ecrã&#8230;</string>
<string name="wallpaper_set_successfully">Wallpaper set successfully</string>
<string name="wallpaper_set_successfully">Fundo definido com sucesso</string>
<!-- About -->
<string name="about">Sobre</string>
<string name="website">Mais aplicações simples e código de fonte em:\nhttp://simplemobiletools.com</string>
<string name="about">Acerca</string>
<string name="website">Mais aplicações Simple e código fonte em:\nhttp://simplemobiletools.com</string>
<string name="email_label">Envie os seus comentários ou sugestões para:</string>
<string name="third_party_licences_underlined"><u>Licenças de terceiros</u></string>
<string name="invite_friends_underlined"><u>Convidar amigos</u></string>
<string name="share_text">Olá, experimente %1$s em %2$s</string>
<string name="share_text">Olá, experimenta %1$s em %2$s</string>
<string name="invite_via">Convidar via</string>
<string name="rate_us_underlined"><u>Classifique-nos na Play Store</u></string>
<string name="rate_us_underlined"><u>Avalie-nos na Play Store</u></string>
<string name="follow_us">Siga-nos:</string>
<string name="copyright">v %1$s\nCopyright © Simple Mobile Tools %2$d</string>
<string name="copyright">V %1$s\nCopyright © Simple Mobile Tools %2$d</string>
<!-- Settings -->
<string name="settings">Definições</string>
<string name="dark_theme">Tema escuro</string>
<string name="same_sorting">A mesma ordenação para ficheiros e pastas</string>
<string name="show_hidden_folders">Show hidden folders</string>
<string name="same_sorting">Mesma ordenação para ficheiros e pastas</string>
<string name="show_hidden_folders">Mostrar pastas ocultas</string>
<string name="autoplay_videos">Reproduzir vídeos automaticamente</string>
<string name="toggle_filename">Toggle filename visibility</string>
<!-- License -->
<string name="notice">Esta aplicação usa as seguintes bibliotecas de terceiros para facilitar a minha vida. Obrigado.</string>
<string name="third_party_licences">Licenças de terceiros</string>
<string name="butterknife_title"><u>Butter Knife (injetor de \"views\")</u></string>
<string name="photoview_title"><u>PhotoView (\"imageviews\" ampliáveis)</u></string>
<string name="butterknife_title"><u>Butter Knife (injetor de vistas)</u></string>
<string name="photoview_title"><u>PhotoView (ampliação de imagens)</u></string>
<string name="glide_title"><u>Glide (carregamento e cache de imagens)</u></string>
<string name="cropper_title"><u>Android Image Cropper</u></string>
<string name="filepicker_title"><u>Simple File Picker (filepicker dialog)</u></string>
<string name="fileproperties_title"><u>Simple File Properties (properties dialog)</u></string>
</resources>

View File

@@ -9,14 +9,18 @@
<string name="edit">Edit</string>
<string name="undo">Ångra</string>
<string name="share">Dela</string>
<string name="properties">Properties</string>
<string name="rename_file">Döp om fil</string>
<string name="rename_folder">Döp om mapp</string>
<string name="rename_file_error">Det gick inte att döpa om filen</string>
<string name="rename_file_empty">Du måste ange ett filnamn</string>
<string name="rename_folder_error">Det gick inte att döpa om mappen</string>
<string name="rename_folder_empty">Du måste ange ett mappnamn</string>
<string name="rename_folder_exists">A folder with that name already exists</string>
<string name="rename_folder_root">Cannot rename the root folder of a storage</string>
<string name="rename_folder_ok">Mappen döptes om</string>
<string name="renaming_folder">Döper om mappen</string>
<string name="filename_cannot_be_empty">Du måste ange ett filnamn</string>
<string name="filename_invalid_characters">Filename contains invalid characters</string>
<string name="extension">Filändelse</string>
<string name="file_deleted">Fil borttagen</string>
<string name="open_camera">Starta kameran</string>
@@ -34,6 +38,28 @@
<string name="hide_folder">Hide folder</string>
<string name="unhide_folder">Unhide folder</string>
<string name="hidden">(hidden)</string>
<string name="save_as">Save as</string>
<string name="file_saved">File saved successfully</string>
<string name="copy">Kopiera</string>
<string name="move">Flytta</string>
<string name="copy_move">Copy/Move</string>
<string name="copy_item">Kopiera objekt</string>
<string name="copy_items">Kopiera objekt</string>
<string name="source">Källa</string>
<string name="destination">Mål</string>
<string name="select_destination">Välj mål</string>
<string name="invalid_destination">Det gick inte att skriva till målet</string>
<string name="please_select_destination">Please select a destination</string>
<string name="source_and_destination_same">Source and destination cannot be the same</string>
<string name="copy_failed">Kunde inte kopiera filen</string>
<string name="copying">Kopierar&#8230;</string>
<string name="copying_success">Files copied successfully</string>
<string name="copy_move_failed">An error occurred</string>
<string name="moving">Moving&#8230;</string>
<string name="moving_success">Files moved successfully</string>
<string name="already_exists">A file with that name already exists</string>
<string name="moving_success_partial">Some files could not be moved</string>
<string name="copying_success_partial">Some files could not be copied</string>
<plurals name="folders_deleted">
<item quantity="one">1 mapp borttagen</item>
@@ -82,6 +108,8 @@
<string name="dark_theme">Mörkt tema</string>
<string name="same_sorting">Same sorting for files and folders</string>
<string name="show_hidden_folders">Show hidden folders</string>
<string name="autoplay_videos">Play videos automatically</string>
<string name="toggle_filename">Toggle filename visibility</string>
<!-- License -->
<string name="notice">Denna app använder följande tredjepartsbibliotek för att göra mitt liv enklare. Tack.</string>
@@ -90,4 +118,6 @@
<string name="photoview_title"><u>PhotoView (zoomable imageviews)</u></string>
<string name="glide_title"><u>Glide (image loading and caching)</u></string>
<string name="cropper_title"><u>Android Image Cropper</u></string>
<string name="filepicker_title"><u>Simple File Picker (filepicker dialog)</u></string>
<string name="fileproperties_title"><u>Simple File Properties (properties dialog)</u></string>
</resources>

View File

@@ -0,0 +1,124 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">相册</string>
<string name="app_launcher_name">相册</string>
<string name="share_via">分享到</string>
<string name="no_permissions">需要访问储存权限</string>
<string name="delete">删除</string>
<string name="deleting">删除中</string>
<string name="rename">重命名</string>
<string name="edit">编辑</string>
<string name="undo">撤销</string>
<string name="share">分享</string>
<string name="properties">信息</string>
<string name="rename_file">重命名文件</string>
<string name="rename_file_error">文件不能重命名</string>
<string name="rename_folder">重命名文件夹</string>
<string name="rename_folder_empty">文件夹名不能为空</string>
<string name="rename_folder_exists">A folder with that name already exists</string>
<string name="rename_folder_root">Cannot rename the root folder of a storage</string>
<string name="rename_folder_error">文件夹不能重命名</string>
<string name="rename_folder_ok">文件夹重命名成功</string>
<string name="renaming_folder">重命名中..</string>
<string name="filename_cannot_be_empty">文件名不能为空</string>
<string name="filename_invalid_characters">文件名包含非法字符</string>
<string name="extension">扩展名</string>
<string name="file_deleted">文件删除成功</string>
<string name="open_camera">打开相机</string>
<string name="unknown_error">未知错误</string>
<string name="sort_by">排序方式</string>
<string name="name">名称</string>
<string name="size">大小</string>
<string name="date">日期</string>
<string name="ascending">递增</string>
<string name="descending">递减</string>
<string name="ok">确认</string>
<string name="cancel">取消</string>
<string name="open_with">打开方式</string>
<string name="no_app_found">没有可用的软件</string>
<string name="hide_folder">隐藏文件夹</string>
<string name="unhide_folder">显示文件夹</string>
<string name="hidden">(隐藏)</string>
<string name="save_as">保存</string>
<string name="file_saved">文件保存成功</string>
<string name="copy">复制</string>
<string name="move">移动</string>
<string name="copy_move">复制/移动</string>
<string name="copy_item">复制</string>
<string name="copy_items">复制多个</string>
<string name="source">原路径</string>
<string name="destination">目标</string>
<string name="select_destination">选择目标</string>
<string name="invalid_destination">不能写入选中目标</string>
<string name="please_select_destination">请选择先目标</string>
<string name="source_and_destination_same">原路径和目标不能相同</string>
<string name="copy_failed">不能复制文件</string>
<string name="copying">正在复制&#8230;</string>
<string name="copying_success">复制成功</string>
<string name="copy_move_failed">操作失败</string>
<string name="moving">移动中&#8230;</string>
<string name="moving_success">文件移动成功</string>
<string name="already_exists">相同的文件名已经存在</string>
<string name="moving_success_partial">相同文件不能移动</string>
<string name="copying_success_partial">相同文件不能复制</string>
<plurals name="folders_deleted">
<item quantity="one">1 folder deleted</item>
<item quantity="other">%1$d folders deleted</item>
</plurals>
<plurals name="files_deleted">
<item quantity="one">1 file deleted</item>
<item quantity="other">%1$d files deleted</item>
</plurals>
<!-- Editor -->
<string name="editor">编辑器</string>
<string name="save">保存</string>
<string name="rotate">旋转</string>
<string name="invalid_image_path">错误图片路径</string>
<string name="image_editing_failed">图像编辑失败</string>
<string name="edit_image_with">编辑方式:</string>
<string name="no_editor_found">没有可用的图片编辑器</string>
<string name="unknown_file_location">未知文件路径</string>
<string name="error_saving_file">不能覆盖源文件</string>
<!-- Set wallpaper -->
<string name="simple_wallpaper">Simple Wallpaper</string>
<string name="set_as_wallpaper">设为壁纸</string>
<string name="set_as_wallpaper_failed">壁纸设置失败</string>
<string name="set_as_wallpaper_with">设为壁纸..</string>
<string name="no_wallpaper_setter_found">没有可用的软件</string>
<string name="setting_wallpaper">壁纸应用中&#8230;</string>
<string name="wallpaper_set_successfully">壁纸应用成功</string>
<!-- About -->
<string name="about">关于</string>
<string name="website">更多软件请访问: http://simplemobiletools.com</string>
<string name="email_label">反馈您的意见到:</string>
<string name="third_party_licences_underlined"><u>开放源代码</u></string>
<string name="invite_friends_underlined"><u>分享给好友</u></string>
<string name="share_text">Hey, come check out %1$s at %2$s</string>
<string name="invite_via">分享到</string>
<string name="rate_us_underlined"><u>为我们打分</u></string>
<string name="follow_us">关注我们:</string>
<string name="copyright">v %1$s Copyright © Simple Mobile Tools %2$d</string>
<!-- Settings -->
<string name="settings">设置</string>
<string name="dark_theme">暗主题</string>
<string name="same_sorting">全局排序</string>
<string name="show_hidden_folders">显示所有</string>
<string name="autoplay_videos">自动播放</string>
<string name="toggle_filename">显示文件名</string>
<!-- License -->
<string name="notice">This app uses the following third party libraries to make my life easier. Thank you.</string>
<string name="third_party_licences">开放源代码</string>
<string name="butterknife_title"><u>Butter Knife (view injector)</u></string>
<string name="photoview_title"><u>PhotoView (zoomable imageviews)</u></string>
<string name="glide_title"><u>Glide (image loading and caching)</u></string>
<string name="cropper_title"><u>Android Image Cropper</u></string>
<string name="filepicker_title"><u>Simple File Picker (filepicker dialog)</u></string>
<string name="fileproperties_title"><u>Simple File Properties (properties dialog)</u></string>
</resources>

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