Compare commits

...

32 Commits
1.35 ... 1.36

Author SHA1 Message Date
tibbi
5f6b4516c0 updating changelog 2016-11-17 17:25:14 +01:00
tibbi
cacb419b4f update version to 1.36 2016-11-17 17:25:07 +01:00
tibbi
af970a459c refresh the folders list after copy too 2016-11-17 17:18:14 +01:00
tibbi
03d53a8436 update filepicker to 1.4.3 2016-11-17 17:14:09 +01:00
tibbi
e5f9ea9627 fix Directory and media sorting 2016-11-17 17:05:43 +01:00
tibbi
fa4cadebb4 check if new file/dir names are valid 2016-11-17 16:23:49 +01:00
tibbi
83dc85e63b simplify sendsuccess at renaming dir 2016-11-17 16:11:11 +01:00
tibbi
06f7d8d29d do not try displaying empty files 2016-11-17 15:56:50 +01:00
tibbi
db04516773 use lowercase paths at deleting folders 2016-11-17 15:55:39 +01:00
tibbi
639c3d57c6 shortening a function 2016-11-17 15:20:04 +01:00
tibbi
6a80ab4473 make sure directory name and photo cnt display properly 2016-11-17 15:09:28 +01:00
tibbi
6ee959d2a4 make sure About us is displayed properly in rtl layout 2016-11-17 15:06:01 +01:00
tibbi
f65b5013ab add delete handling 2016-11-17 15:02:59 +01:00
tibbi
18bad5106a properly store hidden folders 2016-11-17 14:14:19 +01:00
tibbi
8c57a00947 one minor style change 2016-11-17 14:00:58 +01:00
tibbi
c525a0ebc7 properly display the albums at album picker 2016-11-17 13:46:24 +01:00
tibbi
af246cdcf0 add dir copying/moving 2016-11-17 13:11:49 +01:00
tibbi
53aa8e86d7 remove fileproperties from mainactivity 2016-11-17 12:37:04 +01:00
tibbi
b759f71363 implement file properties dialog 2016-11-17 12:36:27 +01:00
tibbi
f9502638f1 update fileproperties to 1.0.5 2016-11-17 12:35:06 +01:00
tibbi
a842d4daf7 implement folder un/hiding 2016-11-17 12:02:04 +01:00
tibbi
4394e6074e display hide/unhide menu buttons when appropriate 2016-11-17 11:54:17 +01:00
tibbi
53ed959e63 show the edit cab on initial selection 2016-11-17 11:14:15 +01:00
tibbi
60596b7e5c use isActivated for selecting items 2016-11-17 11:12:58 +01:00
tibbi
06c3645bf9 allow renaming dirs 2016-11-17 11:07:00 +01:00
tibbi
cc7c6a1e24 make sure unselecting items work on all android versions 2016-11-17 10:45:52 +01:00
tibbi
258c49eeb8 allow selecting multiple directories 2016-11-17 10:35:51 +01:00
tibbi
06f345240a ditch the recyclerview parcelable state holder 2016-11-16 23:59:25 +01:00
tibbi
cd4d98d386 go to the selected directory on click 2016-11-16 23:57:27 +01:00
tibbi
6c4ec53cc1 replace directory baseadapter with recyclerview adapter 2016-11-16 23:50:46 +01:00
tibbi
613ab2bb10 add the bignerdranch multiselect library 2016-11-16 20:11:18 +01:00
tibbi
9616e914b9 convert MainActivity to kotlin, part 1 2016-11-16 20:00:58 +01:00
31 changed files with 660 additions and 764 deletions

View File

@@ -1,6 +1,13 @@
Changelog
==========
Version 1.36 *(2016-11-17)*
----------------------------
* Do not be so strict at limiting characters at file names
* Fix setting folders as un/hidden
* A lot more smaller fixes
Version 1.35 *(2016-11-15)*
----------------------------

View File

@@ -11,8 +11,8 @@ android {
applicationId "com.simplemobiletools.gallery"
minSdkVersion 16
targetSdkVersion 23
versionCode 35
versionName "1.35"
versionCode 36
versionName "1.36"
}
signingConfigs {
@@ -44,8 +44,9 @@ dependencies {
compile 'com.davemorrissey.labs:subsampling-scale-image-view:3.6.0'
compile 'com.theartofdev.edmodo:android-image-cropper:2.3.1'
compile 'com.booking:rtlviewpager:1.0.1'
compile 'com.simplemobiletools:fileproperties:1.0.4@aar'
compile 'com.simplemobiletools:filepicker:1.4.2@aar'
compile 'com.simplemobiletools:fileproperties:1.0.5@aar'
compile 'com.simplemobiletools:filepicker:1.4.3@aar'
compile 'com.bignerdranch.android:recyclerview-multiselect:0.2'
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
apt 'com.jakewharton:butterknife-compiler:8.0.1'

View File

@@ -1,608 +0,0 @@
package com.simplemobiletools.gallery.activities;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.Color;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcelable;
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.util.SparseBooleanArray;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AdapterView;
import android.widget.GridView;
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.ChangeSortingDialog;
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.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import butterknife.BindView;
import butterknife.ButterKnife;
public class MainActivity extends SimpleActivity
implements AdapterView.OnItemClickListener, GridView.MultiChoiceModeListener, GridView.OnTouchListener,
SwipeRefreshLayout.OnRefreshListener, GetDirectoriesAsynctask.GetDirectoriesListener {
@BindView(R.id.directories_grid) GridView mGridView;
@BindView(R.id.directories_holder) SwipeRefreshLayout mSwipeRefreshLayout;
private static final int STORAGE_PERMISSION = 1;
private static final int PICK_MEDIA = 2;
private static final int PICK_WALLPAPER = 3;
private static List<Directory> mDirs;
private static Snackbar mSnackbar;
private static List<String> mToBeDeleted;
private static ActionMode mActionMode;
private static Parcelable mState;
private static boolean mIsSnackbarShown;
private static boolean mIsPickImageIntent;
private static boolean mIsPickVideoIntent;
private static boolean mIsGetImageContentIntent;
private static boolean mIsGetVideoContentIntent;
private static boolean mIsGetAnyContentIntent;
private static boolean mIsSetWallpaperIntent;
private static boolean mIsThirdPartyIntent;
private static boolean mIsGettingDirs;
private static int mSelectedItemsCnt;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
final Intent intent = getIntent();
mIsPickImageIntent = isPickImageIntent(intent);
mIsPickVideoIntent = isPickVideoIntent(intent);
mIsGetImageContentIntent = isGetImageContentIntent(intent);
mIsGetVideoContentIntent = isGetVideoContentIntent(intent);
mIsGetAnyContentIntent = isGetAnyContentIntent(intent);
mIsSetWallpaperIntent = isSetWallpaperIntent(intent);
mIsThirdPartyIntent = mIsPickImageIntent || mIsPickVideoIntent || mIsGetImageContentIntent || mIsGetVideoContentIntent ||
mIsGetAnyContentIntent || mIsSetWallpaperIntent;
mToBeDeleted = new ArrayList<>();
mSwipeRefreshLayout.setOnRefreshListener(this);
mDirs = new ArrayList<>();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
if (mIsThirdPartyIntent)
return false;
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.sort:
showSortingDialog();
return true;
case R.id.camera:
startActivity(new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA));
return true;
case R.id.settings:
startActivity(new Intent(getApplicationContext(), SettingsActivity.class));
return true;
case R.id.about:
startActivity(new Intent(getApplicationContext(), AboutActivity.class));
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
protected void onResume() {
super.onResume();
tryloadGallery();
if (mState != null && mGridView != null)
mGridView.onRestoreInstanceState(mState);
}
@Override
protected void onPause() {
super.onPause();
deleteDirs();
if (mGridView != null)
mState = mGridView.onSaveInstanceState();
}
@Override
protected void onDestroy() {
super.onDestroy();
mConfig.setFirstRun(false);
}
private void tryloadGallery() {
if (Utils.Companion.hasStoragePermission(getApplicationContext())) {
getDirectories();
} else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, STORAGE_PERMISSION);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == STORAGE_PERMISSION) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
getDirectories();
} else {
Utils.Companion.showToast(getApplicationContext(), R.string.no_permissions);
finish();
}
}
}
private void getDirectories() {
if (mIsGettingDirs)
return;
mIsGettingDirs = true;
new GetDirectoriesAsynctask(getApplicationContext(), mIsPickVideoIntent || mIsGetVideoContentIntent, mIsPickImageIntent || mIsGetImageContentIntent,
mToBeDeleted, this).execute();
}
private void showSortingDialog() {
new ChangeSortingDialog(this, true, new ChangeSortingDialog.OnChangeSortingListener() {
@Override
public void sortingChanged() {
getDirectories();
}
});
}
private void prepareForDeleting() {
Utils.Companion.showToast(this, R.string.deleting);
final SparseBooleanArray items = mGridView.getCheckedItemPositions();
final int cnt = items.size();
int deletedCnt = 0;
for (int i = 0; i < cnt; i++) {
if (items.valueAt(i)) {
final int id = items.keyAt(i);
final String path = mDirs.get(id).getPath();
mToBeDeleted.add(path);
deletedCnt++;
}
}
for (String path : mToBeDeleted) {
if (isShowingPermDialog(new File(path))) {
return;
}
}
notifyDeletion(deletedCnt);
}
private void notifyDeletion(int cnt) {
getDirectories();
final CoordinatorLayout coordinator = (CoordinatorLayout) findViewById(R.id.coordinator_layout);
final Resources res = getResources();
final String msg = res.getQuantityString(R.plurals.folders_deleted, cnt, cnt);
mSnackbar = Snackbar.make(coordinator, msg, Snackbar.LENGTH_INDEFINITE);
mSnackbar.setAction(res.getString(R.string.undo), undoDeletion);
mSnackbar.setActionTextColor(Color.WHITE);
mSnackbar.show();
mIsSnackbarShown = true;
}
private void deleteDirs() {
if (mToBeDeleted == null || mToBeDeleted.isEmpty())
return;
if (mSnackbar != null) {
mSnackbar.dismiss();
}
mIsSnackbarShown = false;
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 file : files) {
if (file.isFile() && Utils.Companion.isPhotoVideo(file)) {
updatedFiles.add(file);
deleteItem(file);
}
}
updatedFiles.add(dir);
if (dir.listFiles().length == 0)
deleteItem(dir);
}
}
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();
getDirectories();
}
};
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() {
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 String path = mDirs.get(id).getPath();
renameDir(path);
break;
}
}
}
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;
}
new RenameDirectoryDialog(this, dir, new RenameDirectoryDialog.OnRenameDirListener() {
@Override
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);
}
});
}
});
}
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 {
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);
}
});
}
private boolean isPickImageIntent(Intent intent) {
return isPickIntent(intent) && (hasImageContentData(intent) || isImageType(intent));
}
private boolean isPickVideoIntent(Intent intent) {
return isPickIntent(intent) && (hasVideoContentData(intent) || isVideoType(intent));
}
private boolean isPickIntent(Intent intent) {
return intent != null && intent.getAction() != null && intent.getAction().equals(Intent.ACTION_PICK);
}
private boolean isGetContentIntent(Intent intent) {
return intent != null && intent.getAction() != null && intent.getAction().equals(Intent.ACTION_GET_CONTENT) &&
intent.getType() != null;
}
private boolean isGetImageContentIntent(Intent intent) {
return isGetContentIntent(intent) &&
(intent.getType().startsWith("image/") || intent.getType().equals(MediaStore.Images.Media.CONTENT_TYPE));
}
private boolean isGetVideoContentIntent(Intent intent) {
return isGetContentIntent(intent) &&
(intent.getType().startsWith("video/") || intent.getType().equals(MediaStore.Video.Media.CONTENT_TYPE));
}
private boolean isGetAnyContentIntent(Intent intent) {
return isGetContentIntent(intent) && intent.getType().equals("*/*");
}
private boolean isSetWallpaperIntent(Intent intent) {
return intent != null && intent.getAction() != null && intent.getAction().equals(Intent.ACTION_SET_WALLPAPER);
}
private boolean hasImageContentData(Intent intent) {
final Uri data = intent.getData();
return data != null && data.equals(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
}
private boolean hasVideoContentData(Intent intent) {
final Uri data = intent.getData();
return data != null && data.equals(MediaStore.Video.Media.EXTERNAL_CONTENT_URI);
}
private boolean isImageType(Intent intent) {
final String type = intent.getType();
return type != null && (type.startsWith("image/") || type.equals(MediaStore.Images.Media.CONTENT_TYPE));
}
private boolean isVideoType(Intent intent) {
final String type = intent.getType();
return type != null && (type.startsWith("video/") || type.equals(MediaStore.Video.Media.CONTENT_TYPE));
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent resultData) {
if (resultCode == RESULT_OK) {
if (requestCode == PICK_MEDIA && resultData != null) {
final Intent result = new Intent();
final String path = resultData.getData().getPath();
final Uri uri = Uri.fromFile(new File(path));
if (mIsGetImageContentIntent || mIsGetVideoContentIntent || mIsGetAnyContentIntent) {
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) {
result.setData(uri);
result.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
setResult(RESULT_OK, result);
finish();
} else if (requestCode == PICK_WALLPAPER) {
setResult(RESULT_OK);
finish();
}
}
super.onActivityResult(requestCode, resultCode, resultData);
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
final Intent intent = new Intent(this, MediaActivity.class);
intent.putExtra(Constants.INSTANCE.getDIRECTORY(), mDirs.get(position).getPath());
if (mIsSetWallpaperIntent) {
intent.putExtra(Constants.INSTANCE.getSET_WALLPAPER_INTENT(), true);
startActivityForResult(intent, PICK_WALLPAPER);
} else {
intent.putExtra(Constants.INSTANCE.getGET_IMAGE_INTENT(), mIsPickImageIntent || mIsGetImageContentIntent);
intent.putExtra(Constants.INSTANCE.getGET_VIDEO_INTENT(), mIsPickVideoIntent || mIsGetVideoContentIntent);
intent.putExtra(Constants.INSTANCE.getGET_ANY_INTENT(), mIsGetAnyContentIntent);
startActivityForResult(intent, PICK_MEDIA);
}
}
@Override
public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
if (checked) {
mSelectedItemsCnt++;
} else {
mSelectedItemsCnt--;
}
if (mSelectedItemsCnt > 0) {
mode.setTitle(String.valueOf(mSelectedItemsCnt));
}
mode.invalidate();
}
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
final MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.cab_directories, menu);
mActionMode = mode;
return true;
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
menu.findItem(R.id.cab_edit).setVisible(mSelectedItemsCnt == 1);
int hiddenCnt = 0;
int unhiddenCnt = 0;
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);
if (mConfig.getIsFolderHidden(mDirs.get(id).getPath()))
hiddenCnt++;
else
unhiddenCnt++;
}
}
menu.findItem(R.id.cab_hide).setVisible(unhiddenCnt > 0);
menu.findItem(R.id.cab_unhide).setVisible(hiddenCnt > 0);
return true;
}
@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;
case R.id.cab_delete:
prepareForDeleting();
mode.finish();
return true;
case R.id.cab_hide:
hideFolders();
mode.finish();
return true;
case R.id.cab_unhide:
unhideFolders();
mode.finish();
return true;
case R.id.cab_copy_move:
displayCopyDialog();
return true;
default:
return false;
}
}
@Override
public void onDestroyActionMode(ActionMode mode) {
mSelectedItemsCnt = 0;
}
@Override
public boolean onTouch(View v, MotionEvent event) {
if (mIsSnackbarShown) {
deleteDirs();
}
return false;
}
private void hideFolders() {
mConfig.addHiddenDirectories(getSelectedPaths());
getDirectories();
}
private void unhideFolders() {
mConfig.removeHiddenDirectories(getSelectedPaths());
getDirectories();
}
private Set<String> getSelectedPaths() {
final SparseBooleanArray items = mGridView.getCheckedItemPositions();
final Set<String> selectedPaths = new HashSet<>();
final int cnt = items.size();
for (int i = 0; i < cnt; i++) {
if (items.valueAt(i)) {
final int id = items.keyAt(i);
selectedPaths.add(mDirs.get(id).getPath());
}
}
return selectedPaths;
}
private void scanCompleted(final String path) {
final File dir = new File(path);
if (dir.isDirectory()) {
getDirectories();
runOnUiThread(new Runnable() {
@Override
public void run() {
Utils.Companion.showToast(getApplicationContext(), R.string.rename_folder_ok);
}
});
}
}
@Override
public void onRefresh() {
getDirectories();
mSwipeRefreshLayout.setRefreshing(false);
}
@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

@@ -40,35 +40,34 @@ class Config private constructor(context: Context) {
set(showHiddenFolders) = mPrefs.edit().putBoolean(SHOW_HIDDEN_FOLDERS, showHiddenFolders).apply()
fun addHiddenDirectory(path: String) {
val hiddenFolders = hiddenFolders
hiddenFolders.add(path)
mPrefs.edit().putStringSet(HIDDEN_FOLDERS, hiddenFolders).apply()
val currHiddenFolders = HashSet<String>(hiddenFolders)
currHiddenFolders.add(path)
hiddenFolders = currHiddenFolders
}
fun addHiddenDirectories(paths: Set<String>) {
val hiddenFolders = hiddenFolders
hiddenFolders.addAll(paths)
mPrefs.edit().putStringSet(HIDDEN_FOLDERS, hiddenFolders).apply()
val currHiddenFolders = HashSet<String>(hiddenFolders)
currHiddenFolders.addAll(paths)
hiddenFolders = currHiddenFolders
}
fun removeHiddenDirectory(path: String) {
val hiddenFolders = hiddenFolders
hiddenFolders.remove(path)
mPrefs.edit().putStringSet(HIDDEN_FOLDERS, hiddenFolders).apply()
val currHiddenFolders = HashSet<String>(hiddenFolders)
currHiddenFolders.remove(path)
hiddenFolders = currHiddenFolders
}
fun removeHiddenDirectories(paths: Set<String>) {
val hiddenFolders = hiddenFolders
hiddenFolders.removeAll(paths)
mPrefs.edit().putStringSet(HIDDEN_FOLDERS, hiddenFolders).apply()
val currHiddenFolders = HashSet<String>(hiddenFolders)
currHiddenFolders.removeAll(paths)
hiddenFolders = currHiddenFolders
}
val hiddenFolders: MutableSet<String>
fun getIsFolderHidden(path: String) = hiddenFolders.contains(path)
var hiddenFolders: MutableSet<String>
get() = mPrefs.getStringSet(HIDDEN_FOLDERS, HashSet<String>())
fun getIsFolderHidden(path: String): Boolean {
return hiddenFolders.contains(path)
}
set(hiddenFolders) = mPrefs.edit().remove(HIDDEN_FOLDERS).putStringSet(HIDDEN_FOLDERS, hiddenFolders).apply()
var autoplayVideos: Boolean
get() = mPrefs.getBoolean(AUTOPLAY_VIDEOS, false)

View File

@@ -97,10 +97,6 @@ class Utils {
}
}
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)

View File

@@ -0,0 +1,320 @@
package com.simplemobiletools.gallery.activities
import android.Manifest
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Color
import android.net.Uri
import android.os.Bundle
import android.provider.MediaStore
import android.support.design.widget.Snackbar
import android.support.v4.app.ActivityCompat
import android.support.v4.widget.SwipeRefreshLayout
import android.view.Menu
import android.view.MenuItem
import android.view.MotionEvent
import android.view.View
import com.simplemobiletools.filepicker.extensions.*
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.ChangeSortingDialog
import com.simplemobiletools.gallery.models.Directory
import kotlinx.android.synthetic.main.activity_main.*
import java.io.File
import java.util.*
class MainActivity : SimpleActivity(), SwipeRefreshLayout.OnRefreshListener, GetDirectoriesAsynctask.GetDirectoriesListener, View.OnTouchListener, DirectoryAdapter.DirOperationsListener {
companion object {
private val STORAGE_PERMISSION = 1
private val PICK_MEDIA = 2
private val PICK_WALLPAPER = 3
private var mSnackbar: Snackbar? = null
lateinit var mDirs: MutableList<Directory>
lateinit var mToBeDeleted: MutableList<String>
private var mIsSnackbarShown = false
private var mIsPickImageIntent = false
private var mIsPickVideoIntent = false
private var mIsGetImageContentIntent = false
private var mIsGetVideoContentIntent = false
private var mIsGetAnyContentIntent = false
private var mIsSetWallpaperIntent = false
private var mIsThirdPartyIntent = false
private var mIsGettingDirs = false
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mIsPickImageIntent = isPickImageIntent(intent)
mIsPickVideoIntent = isPickVideoIntent(intent)
mIsGetImageContentIntent = isGetImageContentIntent(intent)
mIsGetVideoContentIntent = isGetVideoContentIntent(intent)
mIsGetAnyContentIntent = isGetAnyContentIntent(intent)
mIsSetWallpaperIntent = isSetWallpaperIntent(intent)
mIsThirdPartyIntent = mIsPickImageIntent || mIsPickVideoIntent || mIsGetImageContentIntent || mIsGetVideoContentIntent ||
mIsGetAnyContentIntent || mIsSetWallpaperIntent
mToBeDeleted = ArrayList<String>()
directories_holder.setOnRefreshListener(this)
mDirs = ArrayList<Directory>()
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
if (mIsThirdPartyIntent)
return false
menuInflater.inflate(R.menu.menu_main, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.sort -> {
showSortingDialog()
true
}
R.id.camera -> {
startActivity(Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA))
true
}
R.id.settings -> {
startActivity(Intent(applicationContext, SettingsActivity::class.java))
true
}
R.id.about -> {
startActivity(Intent(applicationContext, AboutActivity::class.java))
true
}
else -> super.onOptionsItemSelected(item)
}
}
override fun onResume() {
super.onResume()
tryloadGallery()
}
override fun onPause() {
super.onPause()
deleteDirs()
}
override fun onDestroy() {
super.onDestroy()
mConfig.isFirstRun = false
}
private fun tryloadGallery() {
if (hasStoragePermission()) {
getDirectories()
} else {
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), STORAGE_PERMISSION)
}
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == STORAGE_PERMISSION) {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
getDirectories()
} else {
toast(R.string.no_permissions)
finish()
}
}
}
private fun getDirectories() {
if (mIsGettingDirs)
return
mIsGettingDirs = true
GetDirectoriesAsynctask(applicationContext, mIsPickVideoIntent || mIsGetVideoContentIntent, mIsPickImageIntent || mIsGetImageContentIntent,
mToBeDeleted, this).execute()
}
private fun showSortingDialog() {
ChangeSortingDialog(this, true, object : ChangeSortingDialog.OnChangeSortingListener {
override fun sortingChanged() {
getDirectories()
}
})
}
override fun prepareForDeleting(paths: ArrayList<String>) {
toast(R.string.deleting)
mToBeDeleted = paths
val deletedCnt = mToBeDeleted.size
if (isShowingPermDialog(File(mToBeDeleted[0])))
return
notifyDeletion(deletedCnt)
}
private fun notifyDeletion(cnt: Int) {
getDirectories()
val res = resources
val msg = res.getQuantityString(R.plurals.folders_deleted, cnt, cnt)
mSnackbar = Snackbar.make(coordinator_layout, msg, Snackbar.LENGTH_INDEFINITE)
mSnackbar!!.apply {
setAction(res.getString(R.string.undo), undoDeletion)
setActionTextColor(Color.WHITE)
show()
}
mIsSnackbarShown = true
}
private fun deleteDirs() {
if (mToBeDeleted.isEmpty())
return
mSnackbar?.dismiss()
mIsSnackbarShown = false
val updatedFiles = ArrayList<File>()
for (delPath in mToBeDeleted) {
val dir = File(delPath)
if (dir.exists()) {
val files = dir.listFiles()
files.forEach {
if (it.isFile && it.isPhotoVideo()) {
updatedFiles.add(it)
deleteItem(it)
}
}
updatedFiles.add(dir)
if (dir.listFiles().isEmpty())
deleteItem(dir)
}
}
scanFiles(updatedFiles) {}
mToBeDeleted.clear()
}
private fun deleteItem(file: File) {
if (needsStupidWritePermissions(file.absolutePath)) {
if (!isShowingPermDialog(file)) {
getFileDocument(file.absolutePath, mConfig.treeUri).delete()
}
} else {
file.delete()
}
}
private val undoDeletion = View.OnClickListener {
mSnackbar!!.dismiss()
mIsSnackbarShown = false
mToBeDeleted.clear()
getDirectories()
}
private fun isPickImageIntent(intent: Intent) = isPickIntent(intent) && (hasImageContentData(intent) || isImageType(intent))
private fun isPickVideoIntent(intent: Intent) = isPickIntent(intent) && (hasVideoContentData(intent) || isVideoType(intent))
private fun isPickIntent(intent: Intent) = intent.action == Intent.ACTION_PICK
private fun isGetContentIntent(intent: Intent) = intent.action == Intent.ACTION_GET_CONTENT && intent.type != null
private fun isGetImageContentIntent(intent: Intent) = isGetContentIntent(intent) &&
(intent.type.startsWith("image/") || intent.type == MediaStore.Images.Media.CONTENT_TYPE)
private fun isGetVideoContentIntent(intent: Intent) = isGetContentIntent(intent) &&
(intent.type.startsWith("video/") || intent.type == MediaStore.Video.Media.CONTENT_TYPE)
private fun isGetAnyContentIntent(intent: Intent) = isGetContentIntent(intent) && intent.type == "*/*"
private fun isSetWallpaperIntent(intent: Intent?) = intent?.action == Intent.ACTION_SET_WALLPAPER
private fun hasImageContentData(intent: Intent) = intent.data == MediaStore.Images.Media.EXTERNAL_CONTENT_URI
private fun hasVideoContentData(intent: Intent) = intent.data == MediaStore.Video.Media.EXTERNAL_CONTENT_URI
private fun isImageType(intent: Intent) = (intent.type?.startsWith("image/") == true || intent.type == MediaStore.Images.Media.CONTENT_TYPE)
private fun isVideoType(intent: Intent) = (intent.type?.startsWith("video/") == true || intent.type == MediaStore.Video.Media.CONTENT_TYPE)
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
if (resultCode == Activity.RESULT_OK) {
if (requestCode == PICK_MEDIA && resultData != null) {
Intent().apply {
val path = resultData.data.path
val uri = Uri.fromFile(File(path))
if (mIsGetImageContentIntent || mIsGetVideoContentIntent || mIsGetAnyContentIntent) {
val type = Utils.getMimeType(path)
setDataAndTypeAndNormalize(uri, type)
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
} else if (mIsPickImageIntent || mIsPickVideoIntent) {
data = uri
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
}
setResult(Activity.RESULT_OK, this)
}
finish()
} else if (requestCode == PICK_WALLPAPER) {
setResult(Activity.RESULT_OK)
finish()
}
}
super.onActivityResult(requestCode, resultCode, resultData)
}
fun itemClicked(path: String) {
Intent(this, MediaActivity::class.java).apply {
putExtra(Constants.DIRECTORY, path)
if (mIsSetWallpaperIntent) {
putExtra(Constants.SET_WALLPAPER_INTENT, true)
startActivityForResult(this, PICK_WALLPAPER)
} else {
putExtra(Constants.GET_IMAGE_INTENT, mIsPickImageIntent || mIsGetImageContentIntent)
putExtra(Constants.GET_VIDEO_INTENT, mIsPickVideoIntent || mIsGetVideoContentIntent)
putExtra(Constants.GET_ANY_INTENT, mIsGetAnyContentIntent)
startActivityForResult(this, PICK_MEDIA)
}
}
}
override fun onRefresh() {
getDirectories()
directories_holder.isRefreshing = false
}
override fun gotDirectories(dirs: ArrayList<Directory>) {
mIsGettingDirs = false
if (dirs.toString() == mDirs.toString()) {
return
}
mDirs = dirs
val adapter = DirectoryAdapter(this, mDirs, this) {
itemClicked(it.path)
}
directories_grid.adapter = adapter
directories_grid.setOnTouchListener(this)
}
override fun refreshItems() {
getDirectories()
}
override fun onTouch(v: View, event: MotionEvent): Boolean {
if (mIsSnackbarShown && event.action == MotionEvent.ACTION_MOVE) {
deleteDirs()
}
return false
}
}

View File

@@ -385,7 +385,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View
scanFiles(invalidFiles) {}
Medium.sorting = mConfig.sorting
Collections.sort(media)
media.sort()
var j = 0
for (medium in media) {
if (medium.path == mPath) {

View File

@@ -1,73 +1,256 @@
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 android.os.Build
import android.support.v7.view.ActionMode
import android.support.v7.widget.RecyclerView
import android.view.*
import com.bignerdranch.android.multiselector.ModalMultiSelectorCallback
import com.bignerdranch.android.multiselector.MultiSelector
import com.bignerdranch.android.multiselector.SwappingHolder
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.signature.StringSignature
import com.simplemobiletools.filepicker.asynctasks.CopyMoveTask
import com.simplemobiletools.filepicker.extensions.isAStorageRootFolder
import com.simplemobiletools.filepicker.extensions.scanPaths
import com.simplemobiletools.filepicker.extensions.toast
import com.simplemobiletools.fileproperties.dialogs.PropertiesDialog
import com.simplemobiletools.gallery.Config
import com.simplemobiletools.gallery.R
import com.simplemobiletools.gallery.activities.SimpleActivity
import com.simplemobiletools.gallery.dialogs.CopyDialog
import com.simplemobiletools.gallery.dialogs.RenameDirectoryDialog
import com.simplemobiletools.gallery.models.Directory
import kotlinx.android.synthetic.main.directory_item.view.*
import kotlinx.android.synthetic.main.directory_tmb.view.*
import java.io.File
import java.util.*
class DirectoryAdapter(private val mContext: Context, private val mDirs: MutableList<Directory>) : BaseAdapter() {
private val mInflater: LayoutInflater
class DirectoryAdapter(val activity: SimpleActivity, val dirs: MutableList<Directory>, val listener: DirOperationsListener?, val itemClick: (Directory) -> Unit) :
RecyclerView.Adapter<DirectoryAdapter.ViewHolder>() {
init {
mInflater = mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
val multiSelector = MultiSelector()
val views = ArrayList<View>()
val config = Config.newInstance(activity)
companion object {
var actMode: ActionMode? = null
fun toggleItemSelection(itemView: View, select: Boolean) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
itemView.dir_frame.isActivated = select
else
itemView.dir_thumbnail.isActivated = select
}
}
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 multiSelectorMode = object : ModalMultiSelectorCallback(multiSelector) {
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
return when (item.itemId) {
R.id.cab_properties -> {
showProperties()
true
}
R.id.cab_edit -> {
editDir()
true
}
R.id.cab_hide -> {
hideDirs()
mode.finish()
true
}
R.id.cab_unhide -> {
unhideDir()
mode.finish()
true
}
R.id.cab_copy_move -> {
displayCopyDialog()
true
}
R.id.cab_delete -> {
prepareForDeleting()
mode.finish()
true
}
else -> false
}
}
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)
override fun onCreateActionMode(actionMode: ActionMode?, menu: Menu?): Boolean {
super.onCreateActionMode(actionMode, menu)
actMode = actionMode
activity.menuInflater.inflate(R.menu.cab_directories, menu)
return true
}
return convertView
override fun onPrepareActionMode(actionMode: ActionMode?, menu: Menu): Boolean {
val menuItem = menu.findItem(R.id.cab_edit)
menuItem.isVisible = multiSelector.selectedPositions.size <= 1
var hiddenCnt = 0
var unhiddenCnt = 0
val positions = multiSelector.selectedPositions
for (i in positions) {
val path = dirs[i].path
if (config.getIsFolderHidden(path))
hiddenCnt++
else
unhiddenCnt++
}
menu.findItem(R.id.cab_hide).isVisible = unhiddenCnt > 0
menu.findItem(R.id.cab_unhide).isVisible = hiddenCnt > 0
return true
}
override fun onDestroyActionMode(actionMode: ActionMode?) {
super.onDestroyActionMode(actionMode)
views.forEach { toggleItemSelection(it, false) }
}
}
private fun formatDirectoryName(dir: Directory): String {
return dir.name
private fun showProperties() {
val selections = multiSelector.selectedPositions
if (selections.size <= 1) {
PropertiesDialog(activity, dirs[selections[0]].path, config.showHiddenFolders)
} else {
val paths = ArrayList<String>()
selections.forEach { paths.add(dirs[it].path) }
PropertiesDialog(activity, paths, config.showHiddenFolders)
}
}
override fun getCount(): Int {
return mDirs.size
private fun editDir() {
val path = dirs[multiSelector.selectedPositions[0]].path
val dir = File(path)
if (activity.isAStorageRootFolder(dir.absolutePath)) {
activity.toast(R.string.rename_folder_root)
return
}
RenameDirectoryDialog(activity, dir, object : RenameDirectoryDialog.OnRenameDirListener {
override fun onRenameDirSuccess(changedPaths: ArrayList<String>) {
activity.scanPaths(changedPaths) {
activity.runOnUiThread {
actMode?.finish()
listener?.refreshItems()
activity.toast(R.string.rename_folder_ok)
}
}
}
})
}
override fun getItem(position: Int): Any {
return mDirs[position]
private fun hideDirs() {
config.addHiddenDirectories(getSelectedPaths())
listener?.refreshItems()
}
override fun getItemId(position: Int): Long {
return 0
private fun unhideDir() {
config.removeHiddenDirectories(getSelectedPaths())
listener?.refreshItems()
}
internal class ViewHolder(view: View) {
val dirName: TextView = view.dir_name
val photoCnt: TextView = view.photo_cnt
val dirThumbnail: ImageView = view.dir_thumbnail
private fun displayCopyDialog() {
val files = ArrayList<File>()
val positions = multiSelector.selectedPositions
positions.forEach { files.add(File(dirs[it].path)) }
CopyDialog(activity, files, object : CopyMoveTask.CopyMoveListener {
override fun copySucceeded(deleted: Boolean, copiedAll: Boolean) {
if (deleted) {
activity.toast(if (copiedAll) R.string.moving_success else R.string.moving_success_partial)
} else {
activity.toast(if (copiedAll) R.string.copying_success else R.string.copying_success_partial)
}
listener?.refreshItems()
actMode?.finish()
}
override fun copyFailed() {
activity.toast(R.string.copy_move_failed)
}
})
}
private fun prepareForDeleting() {
val selections = multiSelector.selectedPositions
val paths = ArrayList<String>()
selections.forEach { paths.add(dirs[it].path.toLowerCase()) }
listener?.prepareForDeleting(paths)
}
private fun getSelectedPaths(): HashSet<String> {
val positions = multiSelector.selectedPositions
val paths = HashSet<String>()
positions.forEach { paths.add(dirs[it].path) }
return paths
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
views.add(holder.bindView(activity, multiSelectorMode, multiSelector, dirs[position]))
}
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent?.context).inflate(R.layout.directory_item, parent, false)
return ViewHolder(view, itemClick)
}
override fun getItemCount() = dirs.size
class ViewHolder(view: View, val itemClick: (Directory) -> (Unit)) : SwappingHolder(view, MultiSelector()) {
fun bindView(activity: SimpleActivity, multiSelectorCallback: ModalMultiSelectorCallback, multiSelector: MultiSelector, directory: Directory): View {
itemView.dir_name.text = directory.name
itemView.photo_cnt.text = directory.mediaCnt.toString()
val tmb = directory.thumbnail
val timestampSignature = StringSignature(directory.timestamp.toString())
if (tmb.endsWith(".gif")) {
Glide.with(activity.applicationContext).load(tmb).asGif().diskCacheStrategy(DiskCacheStrategy.NONE).signature(timestampSignature)
.placeholder(R.color.tmb_background).centerCrop().crossFade().into(itemView.dir_thumbnail)
} else {
Glide.with(activity.applicationContext).load(tmb).diskCacheStrategy(DiskCacheStrategy.RESULT).signature(timestampSignature)
.placeholder(R.color.tmb_background).centerCrop().crossFade().into(itemView.dir_thumbnail)
}
itemView.setOnClickListener { viewClicked(multiSelector, directory) }
itemView.setOnLongClickListener {
if (!multiSelector.isSelectable) {
activity.startSupportActionMode(multiSelectorCallback)
multiSelector.setSelected(this, true)
actMode?.title = multiSelector.selectedPositions.size.toString()
toggleItemSelection(itemView, true)
actMode?.invalidate()
}
true
}
return itemView
}
fun viewClicked(multiSelector: MultiSelector, directory: Directory) {
if (multiSelector.isSelectable) {
val isSelected = multiSelector.selectedPositions.contains(layoutPosition)
multiSelector.setSelected(this, !isSelected)
toggleItemSelection(itemView, !isSelected)
val selectedCnt = multiSelector.selectedPositions.size
if (selectedCnt == 0) {
actMode?.finish()
} else {
actMode?.title = selectedCnt.toString()
}
actMode?.invalidate()
} else {
itemClick(directory)
}
}
}
interface DirOperationsListener {
fun refreshItems()
fun prepareForDeleting(paths: ArrayList<String>)
}
}

View File

@@ -47,7 +47,7 @@ class GetDirectoriesAsynctask(val context: Context, val isPickVideo: Boolean, va
val file = File(fullPath)
val parentDir = file.parent
if (!file.exists()) {
if (!file.exists() || file.length() == 0L) {
invalidFiles.add(file)
continue
}
@@ -76,7 +76,7 @@ class GetDirectoriesAsynctask(val context: Context, val isPickVideo: Boolean, va
val dirs = ArrayList(directories.values)
filterDirectories(dirs)
Directory.sorting = mConfig.directorySorting
Collections.sort<Directory>(dirs)
dirs.sort()
context.scanFiles(invalidFiles) {}
return dirs
@@ -111,12 +111,7 @@ class GetDirectoriesAsynctask(val context: Context, val isPickVideo: Boolean, va
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)
}
val ignoreDirs = dirs.filter { hiddenDirs.contains(it.path) }
dirs.removeAll(ignoreDirs)
}
@@ -126,8 +121,7 @@ class GetDirectoriesAsynctask(val context: Context, val isPickVideo: Boolean, va
val dir = File(d.path)
if (dir.exists() && dir.isDirectory) {
val res = dir.list { file, filename -> filename == ".nomedia" }
if (res != null && res.size > 0)
if (res?.isNotEmpty() == true)
ignoreDirs.add(d)
}
}

View File

@@ -19,24 +19,23 @@ 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 view = LayoutInflater.from(activity).inflate(R.layout.dialog_copy_move, null)
val sourcePath = files[0].parent.trimEnd('/')
var destinationPath = ""
view.source.text = context.humanizePath(sourcePath)
view.source.text = activity.humanizePath(sourcePath)
view.destination.setOnClickListener {
PickAlbumDialog(activity, object : PickAlbumDialog.OnPickAlbumListener {
override fun onSuccess(path: String) {
destinationPath = path
view.destination.text = context.humanizePath(path)
view.destination.text = activity.humanizePath(path)
}
})
}
AlertDialog.Builder(context)
.setTitle(context.resources.getString(if (files.size == 1) R.string.copy_item else R.string.copy_items))
AlertDialog.Builder(activity)
.setTitle(activity.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)

View File

@@ -1,52 +1,41 @@
package com.simplemobiletools.gallery.dialogs
import android.app.Activity
import android.support.v7.app.AlertDialog
import android.support.v7.widget.RecyclerView
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.activities.SimpleActivity
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 kotlinx.android.synthetic.main.dialog_album_picker.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
class PickAlbumDialog(val activity: SimpleActivity, val listener: OnPickAlbumListener) : GetDirectoriesAsynctask.GetDirectoriesListener {
var dialog: AlertDialog
var directoriesGrid: RecyclerView
init {
val view = LayoutInflater.from(context).inflate(R.layout.dialog_album_picker, null)
grid = view.directories_grid
val view = LayoutInflater.from(activity).inflate(R.layout.dialog_album_picker, null)
directoriesGrid = view.directories_grid
dialog = AlertDialog.Builder(activity)
.setTitle(context.resources.getString(R.string.select_destination))
.setTitle(activity.resources.getString(R.string.select_destination))
.setView(view)
.setPositiveButton(R.string.ok, null)
.setNegativeButton(R.string.cancel, null)
.create().apply {
show()
}
.create()
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()
dialog.show()
GetDirectoriesAsynctask(activity, false, false, ArrayList<String>(), this).execute()
}
override fun gotDirectories(dirs: ArrayList<Directory>) {
this.dirs = dirs
val adapter = DirectoryAdapter(context, dirs)
grid?.adapter = adapter
grid?.onItemClickListener = this
val adapter = DirectoryAdapter(activity, dirs, null) {
listener.onSuccess(it.path)
dialog.dismiss()
}
directoriesGrid.adapter = adapter
}
interface OnPickAlbumListener {

View File

@@ -12,16 +12,14 @@ 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)
val view = LayoutInflater.from(activity).inflate(R.layout.rename_directory, null)
view.directory_name.setText(dir.name)
view.directory_path.text = "${context.humanizePath(dir.parent)}/"
view.directory_path.text = "${activity.humanizePath(dir.parent)}/"
AlertDialog.Builder(context)
.setTitle(context.resources.getString(R.string.rename_folder))
AlertDialog.Builder(activity)
.setTitle(activity.resources.getString(R.string.rename_folder))
.setView(view)
.setPositiveButton(R.string.ok, null)
.setNegativeButton(R.string.cancel, null)
@@ -30,12 +28,16 @@ class RenameDirectoryDialog(val activity: SimpleActivity, val dir: File, val lis
show()
getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener({
val newDirName = view.directory_name.value
if (newDirName.isEmpty()) {
context.toast(R.string.rename_folder_empty)
return@setOnClickListener
}
if (!newDirName.isAValidFilename()) {
context.toast(R.string.invalid_name)
return@setOnClickListener
}
val updatedFiles = ArrayList<String>()
updatedFiles.add(dir.absolutePath)
val newDir = File(dir.parent, newDirName)
@@ -65,18 +67,15 @@ class RenameDirectoryDialog(val activity: SimpleActivity, val dir: File, val lis
}
private fun sendSuccess(updatedFiles: ArrayList<String>, newDir: File) {
context.toast(R.string.renaming_folder)
activity.toast(R.string.renaming_folder)
val files = newDir.listFiles()
for (file in files) {
updatedFiles.add(file.absolutePath)
}
files.mapTo(updatedFiles) { it.absolutePath }
updatedFiles.add(newDir.absolutePath)
val changedFiles = updatedFiles.toTypedArray()
listener.onRenameDirSuccess(changedFiles)
listener.onRenameDirSuccess(updatedFiles)
}
interface OnRenameDirListener {
fun onRenameDirSuccess(changedFiles: Array<String>)
fun onRenameDirSuccess(changedPaths: ArrayList<String>)
}
}

View File

@@ -13,8 +13,7 @@ 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 view = LayoutInflater.from(activity).inflate(R.layout.rename_file, null)
val fullName = file.name
val dotAt = fullName.lastIndexOf(".")
var name = fullName
@@ -26,10 +25,10 @@ class RenameFileDialog(val activity: SimpleActivity, val file: File, val listene
}
view.file_name.setText(name)
view.file_path.text = "${context.humanizePath(file.parent)}/"
view.file_path.text = "${activity.humanizePath(file.parent)}/"
AlertDialog.Builder(context)
.setTitle(context.resources.getString(R.string.rename_file))
AlertDialog.Builder(activity)
.setTitle(activity.resources.getString(R.string.rename_file))
.setView(view)
.setPositiveButton(R.string.ok, null)
.setNegativeButton(R.string.cancel, null)
@@ -45,6 +44,11 @@ class RenameFileDialog(val activity: SimpleActivity, val file: File, val listene
return@setOnClickListener
}
if (!fileName.isAValidFilename()) {
context.toast(R.string.invalid_name)
return@setOnClickListener
}
val newFile = File(file.parent, "$fileName.$extension")
if (context.needsStupidWritePermissions(file.absolutePath)) {

View File

@@ -14,12 +14,11 @@ 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)
val view = LayoutInflater.from(activity).inflate(R.layout.dialog_save_as, null)
view.file_name.setText(path.getFilenameFromPath())
AlertDialog.Builder(context)
.setTitle(context.resources.getString(R.string.save_as))
AlertDialog.Builder(activity)
.setTitle(activity.resources.getString(R.string.save_as))
.setView(view)
.setPositiveButton(R.string.ok, null)
.setNegativeButton(R.string.cancel, null)

View File

@@ -12,7 +12,7 @@ class Directory(val path: String, val thumbnail: String, val name: String, var m
override fun compareTo(other: Directory): Int {
var res: Int
if (sorting and SORT_BY_NAME != 0) {
res = path.compareTo(other.path)
res = name.toLowerCase().compareTo(other.name.toLowerCase())
} else if (sorting and SORT_BY_DATE != 0) {
res = if (timestamp > other.timestamp) 1 else -1
} else {

View File

@@ -17,7 +17,7 @@ class Medium(val name: String, var path: String, val isVideo: Boolean, val times
override fun compareTo(other: Medium): Int {
var res: Int
if (sorting and SORT_BY_NAME != 0) {
res = path.compareTo(other.path)
res = name.toLowerCase().compareTo(other.name.toLowerCase())
} else if (sorting and SORT_BY_DATE != 0) {
res = if (timestamp > other.timestamp) 1 else -1
} else {

View File

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

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
android:id="@+id/about_scrollview"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/about_scrollview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
@@ -12,6 +12,7 @@
android:layout_height="wrap_content"
android:paddingBottom="@dimen/activity_margin"
android:paddingLeft="@dimen/activity_margin"
android:paddingRight="@dimen/activity_margin"
android:paddingTop="@dimen/activity_margin">
<TextView
@@ -89,6 +90,8 @@
android:layout_height="@dimen/social_logo"
android:layout_below="@+id/about_follow_us"
android:layout_marginLeft="@dimen/social_padding"
android:layout_marginRight="@dimen/social_padding"
android:layout_toEndOf="@+id/about_facebook"
android:layout_toRightOf="@+id/about_facebook"
android:src="@mipmap/gplus"/>

View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/coordinator_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
@@ -10,15 +11,12 @@
android:layout_width="match_parent"
android:layout_height="wrap_content">
<GridView
<android.support.v7.widget.RecyclerView
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:stretchMode="columnWidth"
android:verticalSpacing="1dp"/>
app:layoutManager="android.support.v7.widget.GridLayoutManager"
app:spanCount="@integer/columns"/>
</android.support.v4.widget.SwipeRefreshLayout>
</android.support.design.widget.CoordinatorLayout>

View File

@@ -1,12 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<GridView
<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
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"/>
app:layoutManager="android.support.v7.widget.GridLayoutManager"
app:spanCount="@integer/columns"/>

View File

@@ -3,7 +3,8 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/dir_holder"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="wrap_content"
android:padding="1px">
<include layout="@layout/directory_tmb"/>
@@ -23,6 +24,7 @@
android:id="@+id/dir_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/photo_cnt"
android:paddingBottom="@dimen/small_padding"
android:textColor="@android:color/white"/>
@@ -30,7 +32,7 @@
android:id="@+id/photo_cnt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/dir_name"
android:layout_alignParentBottom="true"
android:textColor="@android:color/white"/>
</RelativeLayout>

View File

@@ -60,6 +60,7 @@
<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>
<string name="invalid_name">Der Name enthält nicht erlaubte Zeichen</string>
<plurals name="folders_deleted">
<item quantity="one">1 Ordner gelöscht</item>

View File

@@ -60,6 +60,7 @@
<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>
<string name="invalid_name">The name contains invalid characters</string>
<plurals name="folders_deleted">
<item quantity="one">1 carpeta eliminada</item>

View File

@@ -60,6 +60,7 @@
<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>
<string name="invalid_name">Il nome contiene caratteri non validi</string>
<plurals name="folders_deleted">
<item quantity="one">1 cartella eliminata</item>

View File

@@ -60,6 +60,7 @@
<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>
<string name="invalid_name">名前に無効な文字が含まれています</string>
<plurals name="folders_deleted">
<item quantity="one">1 フォルダーを削除しました</item>

View File

@@ -0,0 +1,3 @@
<resources>
<integer name="columns">4</integer>
</resources>

View File

@@ -60,6 +60,7 @@
<string name="already_exists">Já existe um ficheiro com este nome</string>
<string name="moving_success_partial">Alguns ficheiros não foram movidos</string>
<string name="copying_success_partial">Alguns ficheiros não foram copiados</string>
<string name="invalid_name">O nome contém caracteres inválidos</string>
<plurals name="folders_deleted">
<item quantity="one">1 pasta apagada</item>

View File

@@ -60,6 +60,7 @@
<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>
<string name="invalid_name">Namnet innehåller ogiltiga tecken</string>
<plurals name="folders_deleted">
<item quantity="one">1 mapp borttagen</item>

View File

@@ -61,6 +61,7 @@
<string name="already_exists">相同的文件名已经存在</string>
<string name="moving_success_partial">相同文件不能移动</string>
<string name="copying_success_partial">相同文件不能复制</string>
<string name="invalid_name">The name contains invalid characters</string>
<plurals name="folders_deleted">
<item quantity="one">1 folder deleted</item>

View File

@@ -0,0 +1,3 @@
<resources>
<integer name="columns">2</integer>
</resources>

View File

@@ -60,6 +60,7 @@
<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>
<string name="invalid_name">The name contains invalid characters</string>
<plurals name="folders_deleted">
<item quantity="one">1 folder deleted</item>