diff --git a/.idea/dictionaries/Stardust.xml b/.idea/dictionaries/Stardust.xml
index 803965af..20a6491d 100644
--- a/.idea/dictionaries/Stardust.xml
+++ b/.idea/dictionaries/Stardust.xml
@@ -7,6 +7,7 @@
prefill
scriptable
tasker
+ uncheck
\ No newline at end of file
diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/filechooser/FileChooseListView.java b/app/src/main/java/com/stardust/scriptdroid/ui/filechooser/FileChooseListView.java
new file mode 100644
index 00000000..ddf0e0aa
--- /dev/null
+++ b/app/src/main/java/com/stardust/scriptdroid/ui/filechooser/FileChooseListView.java
@@ -0,0 +1,189 @@
+package com.stardust.scriptdroid.ui.filechooser;
+
+import android.content.Context;
+import android.graphics.drawable.GradientDrawable;
+import android.support.annotation.Nullable;
+import android.support.v4.content.res.ResourcesCompat;
+import android.support.v7.widget.SimpleItemAnimator;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.CheckBox;
+import android.widget.TextView;
+
+import com.stardust.pio.PFile;
+import com.stardust.pio.PFiles;
+import com.stardust.scriptdroid.R;
+import com.stardust.scriptdroid.model.script.ScriptFile;
+import com.stardust.scriptdroid.ui.main.scripts.ScriptListView;
+import com.stardust.widget.BindableViewHolder;
+import com.stardust.widget.CheckBoxCompat;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import butterknife.BindView;
+import butterknife.ButterKnife;
+import butterknife.OnCheckedChanged;
+import butterknife.OnClick;
+
+/**
+ * Created by Stardust on 2017/10/19.
+ */
+
+public class FileChooseListView extends ScriptListView {
+
+ private int mMaxChoice = 1;
+ private LinkedHashMap mSelectedFiles = new LinkedHashMap<>();
+ private boolean mCanChooseDir = false;
+
+ public FileChooseListView(Context context) {
+ super(context);
+ init();
+ }
+
+ public FileChooseListView(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ public void setMaxChoice(int maxChoice) {
+ mMaxChoice = maxChoice;
+ }
+
+ public void setCanChooseDir(boolean canChooseDir) {
+ mCanChooseDir = canChooseDir;
+ }
+
+ public List getSelectedFiles() {
+ ArrayList list = new ArrayList<>(mSelectedFiles.size());
+ for (Map.Entry entry : mSelectedFiles.entrySet()) {
+ list.add(entry.getKey());
+ }
+ return list;
+ }
+
+ private void init() {
+ setDirectorySpanSize(2);
+ ((SimpleItemAnimator) getScriptListView().getItemAnimator())
+ .setSupportsChangeAnimations(false);
+ }
+
+ @Override
+ protected BindableViewHolder> onCreateViewHolder(LayoutInflater inflater, ViewGroup parent, int viewType) {
+ if (viewType == VIEW_TYPE_FILE) {
+ return new ScriptFileViewHolder(inflater.inflate(R.layout.file_choose_list_file, parent, false));
+ } else if (viewType == VIEW_TYPE_DIRECTORY) {
+ return new DirectoryViewHolder(inflater.inflate(R.layout.file_choose_list_directory, parent, false));
+ } else {
+ return super.onCreateViewHolder(inflater, parent, viewType);
+ }
+ }
+
+ private void check(ScriptFile file, int position) {
+ if (mSelectedFiles.size() == mMaxChoice) {
+ Map.Entry itemToUncheck = mSelectedFiles.entrySet().iterator().next();
+ int positionOfItemToUncheck = itemToUncheck.getValue();
+ mSelectedFiles.remove(itemToUncheck.getKey());
+ getScriptListView().getAdapter().notifyItemChanged(positionOfItemToUncheck);
+ }
+ mSelectedFiles.put(file, position);
+ }
+
+
+ class ScriptFileViewHolder extends BindableViewHolder {
+
+ @BindView(R.id.name)
+ TextView mName;
+ @BindView(R.id.first_char)
+ TextView mFirstChar;
+ @BindView(R.id.checkbox)
+ CheckBoxCompat mCheckBox;
+ @BindView(R.id.desc)
+ TextView mDesc;
+ GradientDrawable mFirstCharBackground;
+
+ private ScriptFile mScriptFile;
+
+ ScriptFileViewHolder(View itemView) {
+ super(itemView);
+ ButterKnife.bind(this, itemView);
+ mFirstCharBackground = (GradientDrawable) mFirstChar.getBackground();
+ }
+
+ @Override
+ public void bind(ScriptFile file, int position) {
+ mScriptFile = file;
+ mName.setText(file.getSimplifiedName());
+ mDesc.setText(PFiles.getHumanReadableSize(file.length()));
+ mCheckBox.setChecked(mSelectedFiles.containsKey(file), false);
+ if (file.getType() == ScriptFile.TYPE_JAVA_SCRIPT) {
+ mFirstChar.setText("J");
+ mFirstCharBackground.setColor(ResourcesCompat.getColor(getResources(), R.color.color_j, getContext().getTheme()));
+ } else {
+ mFirstChar.setText("R");
+ mFirstCharBackground.setColor(ResourcesCompat.getColor(getResources(), R.color.color_r, getContext().getTheme()));
+ }
+ }
+
+ @OnClick(R.id.item)
+ void onItemClick() {
+ mCheckBox.toggle();
+ }
+
+ @OnCheckedChanged(R.id.checkbox)
+ void onCheckedChanged() {
+ if (mCheckBox.isChecked()) {
+ check(mScriptFile, getAdapterPosition());
+ } else {
+ mSelectedFiles.remove(mScriptFile);
+ }
+ }
+
+
+ }
+
+ class DirectoryViewHolder extends BindableViewHolder {
+
+ @BindView(R.id.name)
+ TextView mName;
+
+ @BindView(R.id.checkbox)
+ CheckBoxCompat mCheckBox;
+
+ private ScriptFile mScriptFile;
+
+ DirectoryViewHolder(View itemView) {
+ super(itemView);
+ ButterKnife.bind(this, itemView);
+ }
+
+ @Override
+ public void bind(ScriptFile data, int position) {
+ mName.setText(data.getSimplifiedName());
+ mScriptFile = data;
+ if (mCanChooseDir) {
+ mCheckBox.setChecked(mSelectedFiles.containsKey(data), false);
+ }
+ }
+
+ @OnClick(R.id.item)
+ void onItemClick() {
+ setCurrentDirectory(mScriptFile);
+ }
+
+ @OnCheckedChanged(R.id.checkbox)
+ void onCheckedChanged() {
+ if (mCheckBox.isChecked()) {
+ check(mScriptFile, getAdapterPosition());
+ } else {
+ mSelectedFiles.remove(mScriptFile);
+ }
+ }
+
+ }
+
+}
diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/filechooser/FileChooserDialogBuilder.java b/app/src/main/java/com/stardust/scriptdroid/ui/filechooser/FileChooserDialogBuilder.java
new file mode 100644
index 00000000..50c5e712
--- /dev/null
+++ b/app/src/main/java/com/stardust/scriptdroid/ui/filechooser/FileChooserDialogBuilder.java
@@ -0,0 +1,91 @@
+package com.stardust.scriptdroid.ui.filechooser;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+
+import com.stardust.pio.PFile;
+import com.stardust.scriptdroid.R;
+import com.stardust.scriptdroid.model.script.ScriptFile;
+import com.stardust.scriptdroid.model.script.StorageFileProvider;
+import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Created by Stardust on 2017/10/19.
+ */
+
+public class FileChooserDialogBuilder extends ThemeColorMaterialDialogBuilder {
+
+ public interface SingleChoiceCallback {
+ void onSelected(PFile file);
+ }
+
+ public interface MultiChoiceCallback {
+ void onSelected(List files);
+ }
+
+ private FileChooseListView mFileChooseListView;
+ private PFile mRootDir = StorageFileProvider.DEFAULT_DIRECTORY;
+ private MultiChoiceCallback mCallback;
+
+ public FileChooserDialogBuilder(@NonNull Context context) {
+ super(context);
+ mFileChooseListView = new FileChooseListView(context);
+ customView(mFileChooseListView, false);
+ positiveText(R.string.ok);
+ negativeText(R.string.cancel);
+ onPositive((dialog, which) -> {
+ notifySelected();
+ });
+ }
+
+ private void notifySelected() {
+ if (mCallback == null)
+ return;
+ List selectedFiles = mFileChooseListView.getSelectedFiles();
+ if (selectedFiles.isEmpty()) {
+ mCallback.onSelected(Collections.singletonList(mFileChooseListView.getCurrentDirectory()));
+ } else {
+ mCallback.onSelected(selectedFiles);
+ }
+ }
+
+ public FileChooserDialogBuilder dir(String rootDir, String initialDir) {
+ mRootDir = new PFile(rootDir);
+ mFileChooseListView.setStorageFileProvider(new StorageFileProvider(mRootDir, 10), new ScriptFile(initialDir));
+ return this;
+ }
+
+ public FileChooserDialogBuilder dir(String dir) {
+ return dir(dir, dir);
+ }
+
+
+ public FileChooserDialogBuilder chooseDir() {
+ mFileChooseListView.setCanChooseDir(true);
+ mFileChooseListView.setStorageFileProvider(new StorageFileProvider(mRootDir, 10, File::isDirectory));
+ return this;
+ }
+
+ public FileChooserDialogBuilder singleChoice(SingleChoiceCallback callback) {
+ mFileChooseListView.setMaxChoice(1);
+ mCallback = files -> callback.onSelected(files.get(0));
+ return this;
+ }
+
+
+ public FileChooserDialogBuilder multiChoice(MultiChoiceCallback callback) {
+ return multiChoice(Integer.MAX_VALUE, callback);
+ }
+
+ public FileChooserDialogBuilder multiChoice(int maxChoices, MultiChoiceCallback callback) {
+ mFileChooseListView.setMaxChoice(maxChoices);
+ mCallback = callback;
+ return this;
+ }
+
+
+}
diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/main/MainActivity.java b/app/src/main/java/com/stardust/scriptdroid/ui/main/MainActivity.java
index c8cc7e76..8f84a96f 100644
--- a/app/src/main/java/com/stardust/scriptdroid/ui/main/MainActivity.java
+++ b/app/src/main/java/com/stardust/scriptdroid/ui/main/MainActivity.java
@@ -5,6 +5,7 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
+import android.os.Environment;
import android.support.annotation.NonNull;
import android.support.annotation.RequiresApi;
import android.support.design.widget.FloatingActionButton;
@@ -16,6 +17,7 @@ import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.widget.Toolbar;
import android.view.Gravity;
import android.view.View;
+import android.widget.Toast;
import com.qq.e.comm.DownloadService;
import com.stardust.app.FragmentPagerAdapterBuilder;
@@ -27,6 +29,7 @@ import com.stardust.scriptdroid.Pref;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.autojs.AutoJs;
import com.stardust.scriptdroid.ui.common.NotAskAgainDialog;
+import com.stardust.scriptdroid.ui.filechooser.FileChooserDialogBuilder;
import com.stardust.scriptdroid.ui.floating.FloatyWindowManger;
import com.stardust.scriptdroid.model.script.StorageFileProvider;
import com.stardust.scriptdroid.ui.main.community.CommunityFragment_;
diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/main/scripts/MyScriptListFragment.java b/app/src/main/java/com/stardust/scriptdroid/ui/main/scripts/MyScriptListFragment.java
index 271af22f..80497c5e 100644
--- a/app/src/main/java/com/stardust/scriptdroid/ui/main/scripts/MyScriptListFragment.java
+++ b/app/src/main/java/com/stardust/scriptdroid/ui/main/scripts/MyScriptListFragment.java
@@ -7,6 +7,7 @@ import android.view.View;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.model.script.ScriptFile;
import com.stardust.scriptdroid.model.script.Scripts;
+import com.stardust.scriptdroid.model.script.StorageFileProvider;
import com.stardust.scriptdroid.tool.SimpleObserver;
import com.stardust.scriptdroid.ui.common.ScriptOperations;
import com.stardust.scriptdroid.ui.main.FloatingActionMenu;
@@ -38,6 +39,7 @@ public class MyScriptListFragment extends ViewPagerFragment implements BackPress
@AfterViews
void setUpViews() {
+ mScriptFileList.setStorageFileProvider(StorageFileProvider.getDefault());
mScriptFileList.setOnScriptFileClickListener(new ScriptListView.OnScriptFileClickListener() {
@Override
public void onScriptFileClick(View view, ScriptFile file) {
diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/main/scripts/ScriptListView.java b/app/src/main/java/com/stardust/scriptdroid/ui/main/scripts/ScriptListView.java
index f8555ae2..7a4e4f10 100644
--- a/app/src/main/java/com/stardust/scriptdroid/ui/main/scripts/ScriptListView.java
+++ b/app/src/main/java/com/stardust/scriptdroid/ui/main/scripts/ScriptListView.java
@@ -16,7 +16,6 @@ import android.widget.ImageView;
import android.widget.PopupMenu;
import android.widget.TextView;
-import com.stardust.pio.PFile;
import com.stardust.pio.PFiles;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.model.script.ScriptFile;
@@ -29,16 +28,11 @@ import com.stardust.widget.BindableViewHolder;
import org.greenrobot.eventbus.Subscribe;
-import java.util.concurrent.Callable;
-
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
-import io.reactivex.annotations.NonNull;
-import io.reactivex.functions.BiConsumer;
-import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;
/**
@@ -56,6 +50,11 @@ public class ScriptListView extends SwipeRefreshLayout implements SwipeRefreshLa
void OnItemOperated(ScriptFile file);
}
+ protected static final int VIEW_TYPE_FILE = 0;
+ protected static final int VIEW_TYPE_DIRECTORY = 1;
+ //category是类别,也即"文件", "文件夹"那两个
+ protected static final int VIEW_TYPE_CATEGORY = 2;
+
private static final int positionOfCategoryDir = 0;
private ScriptList mScriptList = new ScriptList();
private RecyclerView mScriptListView;
@@ -96,7 +95,16 @@ public class ScriptListView extends SwipeRefreshLayout implements SwipeRefreshLa
}
public void setStorageFileProvider(StorageFileProvider storageFileProvider) {
- mStorageFileProvider = storageFileProvider;
+ setStorageFileProvider(storageFileProvider, new ScriptFile(storageFileProvider.getInitialDirectory()));
+ }
+
+
+ public void setStorageFileProvider(StorageFileProvider fileProvider, ScriptFile currentDirectory) {
+ if (mStorageFileProvider != null)
+ mStorageFileProvider.unregisterDirectoryChangeListener(this);
+ mStorageFileProvider = fileProvider;
+ setCurrentDirectory(currentDirectory);
+ mStorageFileProvider.registerDirectoryChangeListener(this);
}
public void setOnItemOperatedListener(OnItemOperatedListener onItemOperatedListener) {
@@ -120,9 +128,6 @@ public class ScriptListView extends SwipeRefreshLayout implements SwipeRefreshLa
mScriptListView = new RecyclerView(getContext());
addView(mScriptListView);
initScriptListRecyclerView();
- mStorageFileProvider = StorageFileProvider.getDefault();
- setCurrentDirectory(new ScriptFile(mStorageFileProvider.getInitialDirectory()));
- mStorageFileProvider.registerDirectoryChangeListener(this);
}
private void initScriptListRecyclerView() {
@@ -149,12 +154,13 @@ public class ScriptListView extends SwipeRefreshLayout implements SwipeRefreshLa
}
private void loadScriptList() {
+ setRefreshing(true);
mScriptList.clear();
mStorageFileProvider.getDirectoryFiles(mCurrentDirectory)
.subscribeOn(Schedulers.io())
- .collectInto(mScriptList, (list, file) -> {
- mScriptList.add(new ScriptFile(file));
- })
+ .collectInto(mScriptList, (list, file) ->
+ mScriptList.add(new ScriptFile(file))
+ )
.observeOn(Schedulers.computation())
.doOnSuccess(ScriptList::sort)
.observeOn(AndroidSchedulers.mainThread())
@@ -178,6 +184,7 @@ public class ScriptListView extends SwipeRefreshLayout implements SwipeRefreshLa
loadScriptList();
}
+
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
@@ -229,26 +236,20 @@ public class ScriptListView extends SwipeRefreshLayout implements SwipeRefreshLa
private void sort(final int sortType, final boolean isDir) {
setRefreshing(true);
- Observable.fromCallable(new Callable() {
- @Override
- public ScriptList call() throws Exception {
- if (isDir) {
- mScriptList.sortDir(sortType);
- } else {
- mScriptList.sortFile(sortType);
- }
- return mScriptList;
+ Observable.fromCallable(() -> {
+ if (isDir) {
+ mScriptList.sortDir(sortType);
+ } else {
+ mScriptList.sortFile(sortType);
}
+ return mScriptList;
})
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
- .subscribe(new Consumer() {
- @Override
- public void accept(@NonNull ScriptList o) throws Exception {
- mScriptListAdapter.notifyDataSetChanged();
- setRefreshing(false);
- }
+ .subscribe(o -> {
+ mScriptListAdapter.notifyDataSetChanged();
+ setRefreshing(false);
});
}
@@ -259,29 +260,32 @@ public class ScriptListView extends SwipeRefreshLayout implements SwipeRefreshLa
mStorageFileProvider.unregisterDirectoryChangeListener(this);
}
- private class ScriptListAdapter extends RecyclerView.Adapter {
- private final int VIEW_TYPE_FILE = 0;
- private final int VIEW_TYPE_DIRECTORY = 1;
- //category是类别,也即"文件", "文件夹"那两个
- private final int VIEW_TYPE_CATEGORY = 2;
+ protected BindableViewHolder> onCreateViewHolder(LayoutInflater inflater, ViewGroup parent, int viewType) {
+ if (viewType == VIEW_TYPE_FILE) {
+ return new ScriptFileViewHolder(inflater.inflate(R.layout.script_file_list_file, parent, false));
+ } else if (viewType == VIEW_TYPE_DIRECTORY) {
+ return new DirectoryViewHolder(inflater.inflate(R.layout.script_file_list_directory, parent, false));
+ } else {
+ return new CategoryViewHolder(inflater.inflate(R.layout.script_file_list_category, parent, false));
+ }
+ }
+ protected RecyclerView getScriptListView() {
+ return mScriptListView;
+ }
+
+ private class ScriptListAdapter extends RecyclerView.Adapter> {
@Override
- public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ public BindableViewHolder> onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
- if (viewType == VIEW_TYPE_FILE) {
- return new ScriptFileViewHolder(inflater.inflate(R.layout.script_file_list_file, parent, false));
- } else if (viewType == VIEW_TYPE_DIRECTORY) {
- return new DirectoryViewHolder(inflater.inflate(R.layout.script_file_list_directory, parent, false));
- } else {
- return new CategoryViewHolder(inflater.inflate(R.layout.script_file_list_category, parent, false));
- }
+ return ScriptListView.this.onCreateViewHolder(inflater, parent, viewType);
}
@SuppressWarnings("unchecked")
@Override
- public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
+ public void onBindViewHolder(BindableViewHolder> holder, int position) {
int positionOfCategoryFile = positionOfCategoryFile();
BindableViewHolder bindableViewHolder = (BindableViewHolder) holder;
if (position == positionOfCategoryDir || position == positionOfCategoryFile) {
diff --git a/app/src/main/java/com/stardust/widget/CheckBoxCompat.java b/app/src/main/java/com/stardust/widget/CheckBoxCompat.java
new file mode 100644
index 00000000..7ab06388
--- /dev/null
+++ b/app/src/main/java/com/stardust/widget/CheckBoxCompat.java
@@ -0,0 +1,50 @@
+package com.stardust.widget;
+
+import android.content.Context;
+import android.support.v7.widget.AppCompatCheckBox;
+import android.util.AttributeSet;
+import android.widget.CompoundButton;
+
+/**
+ * Created by Stardust on 2017/10/19.
+ */
+
+public class CheckBoxCompat extends AppCompatCheckBox {
+ private boolean mIgnoreCheckedChange;
+
+ public CheckBoxCompat(Context context) {
+ super(context);
+ }
+
+ public CheckBoxCompat(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public CheckBoxCompat(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+
+ @Override
+ public void setOnCheckedChangeListener(final OnCheckedChangeListener listener) {
+ super.setOnCheckedChangeListener(new OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if (mIgnoreCheckedChange) {
+ return;
+ }
+ listener.onCheckedChanged(buttonView, isChecked);
+ }
+ });
+ }
+
+ public void setChecked(boolean checked, boolean notify) {
+ mIgnoreCheckedChange = !notify;
+ setChecked(checked);
+ mIgnoreCheckedChange = false;
+ }
+
+ public void toggle(boolean notify) {
+ setChecked(!isChecked(), notify);
+ }
+}
diff --git a/app/src/main/res/layout/file_choose_list_directory.xml b/app/src/main/res/layout/file_choose_list_directory.xml
new file mode 100644
index 00000000..59f4574c
--- /dev/null
+++ b/app/src/main/res/layout/file_choose_list_directory.xml
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/file_choose_list_file.xml b/app/src/main/res/layout/file_choose_list_file.xml
new file mode 100644
index 00000000..58cdefe7
--- /dev/null
+++ b/app/src/main/res/layout/file_choose_list_file.xml
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/common/src/main/java/com/stardust/pio/PFile.java b/common/src/main/java/com/stardust/pio/PFile.java
index 48642332..3b5d0e56 100644
--- a/common/src/main/java/com/stardust/pio/PFile.java
+++ b/common/src/main/java/com/stardust/pio/PFile.java
@@ -42,7 +42,11 @@ public class PFile extends File {
private void init() {
- mSimplifiedName = PFiles.getNameWithoutExtension(getName());
+ if (isDirectory()) {
+ mSimplifiedName = getName();
+ } else {
+ mSimplifiedName = PFiles.getNameWithoutExtension(getName());
+ }
mSimplifyPath = getPath();
if (mSimplifyPath.startsWith(Environment.getExternalStorageDirectory().getPath())) {
mSimplifyPath = mSimplifyPath.substring(Environment.getExternalStorageDirectory().getPath().length());