add: file sorting

This commit is contained in:
hyb1996
2017-09-30 19:12:07 +08:00
parent c114148502
commit be022f1c94
15 changed files with 532 additions and 212 deletions

View File

@@ -9,8 +9,8 @@ android {
applicationId "com.stardust.scriptdroid" applicationId "com.stardust.scriptdroid"
minSdkVersion 17 minSdkVersion 17
targetSdkVersion 23 targetSdkVersion 23
versionCode 205 versionCode 206
versionName "3.0.0 Alpha6" versionName "3.0.0 Alpha7"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
multiDexEnabled true multiDexEnabled true
ndk { ndk {

View File

@@ -1,42 +0,0 @@
package com.stardust.scriptdroid.script;
import java.io.File;
/**
* Created by Stardust on 2017/1/23.
*/
public abstract class ScriptFileList {
private static ScriptFileList impl;
public static void setImpl(ScriptFileList list) {
impl = list;
}
public static ScriptFileList getImpl() {
return impl;
}
public abstract void add(ScriptFile scriptFile);
public abstract ScriptFile get(int i);
public abstract void remove(int i);
public abstract void rename(int position, String newName, boolean renameFile);
public abstract int size();
public boolean deleteFromFileSystem(int i) {
if (i < 0 || i >= size())
return false;
File file = get(i);
remove(i);
return file.delete();
}
public abstract boolean containsPath(String path);
}

View File

@@ -1,103 +0,0 @@
package com.stardust.scriptdroid.script;
import android.content.Context;
import android.content.SharedPreferences;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.stardust.pio.PFile;
import com.stardust.scriptdroid.App;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Stardust on 2017/1/23.
*/
public class SharedPrefScriptFileList extends ScriptFileList {
private static final Gson GSON = new Gson();
private static final String SP_KEY_SCRIPT_NAME = "script_name";
private static final String SP_KEY_SCRIPT_PATH = "script_path";
private static ScriptFileList instance = new SharedPrefScriptFileList(App.getApp());
private SharedPreferences mSharedPreferences;
private List<String> mScriptPath;
private List<String> mScriptName;
public static ScriptFileList getInstance() {
return instance;
}
public SharedPrefScriptFileList(Context context) {
mSharedPreferences = context.getSharedPreferences("SharedPrefScriptFileList", Context.MODE_PRIVATE);
readFromSharedPref();
}
private void readFromSharedPref() {
Type type = new TypeToken<List<String>>() {
}.getType();
mScriptName = GSON.fromJson(mSharedPreferences.getString(SP_KEY_SCRIPT_NAME, ""), type);
mScriptPath = GSON.fromJson(mSharedPreferences.getString(SP_KEY_SCRIPT_PATH, ""), type);
if (mScriptName == null || mScriptPath == null || mScriptName.size() != mScriptPath.size()) {
reset();
}
}
private void reset() {
mScriptName = new ArrayList<>();
mScriptPath = new ArrayList<>();
syncWithSharedPref();
}
@Override
public void add(ScriptFile scriptFile) {
mScriptName.add(scriptFile.getSimplifiedName());
mScriptPath.add(scriptFile.getSimplifiedPath());
syncWithSharedPref();
}
@Override
public ScriptFile get(int i) {
return new ScriptFile(mScriptPath.get(i));
}
@Override
public void remove(int i) {
mScriptName.remove(i);
mScriptPath.remove(i);
syncWithSharedPref();
}
@Override
public void rename(int position, String newName, boolean renameFile) {
mScriptName.set(position, newName);
if (renameFile) {
String newPath = PFile.renameWithoutExtensionAndReturnNewPath(mScriptPath.get(position), newName);
mScriptPath.set(position, newPath);
}
syncWithSharedPref();
}
@Override
public int size() {
return mScriptPath.size();
}
@Override
public boolean containsPath(String path) {
return mScriptPath.contains(path);
}
protected void syncWithSharedPref() {
SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.putString(SP_KEY_SCRIPT_NAME, GSON.toJson(mScriptName));
editor.putString(SP_KEY_SCRIPT_PATH, GSON.toJson(mScriptPath));
editor.apply();
}
}

View File

@@ -125,7 +125,7 @@ public class StorageFileProvider {
if (scriptFiles == null) { if (scriptFiles == null) {
return Observable.empty(); return Observable.empty();
} else { } else {
FileSorter.sort(scriptFiles); FileSorter.sort(scriptFiles, FileSorter.NAME);
mScriptFileCache.put(dir.getPath(), scriptFiles); mScriptFileCache.put(dir.getPath(), scriptFiles);
return Observable.fromArray(scriptFiles); return Observable.fromArray(scriptFiles);
} }

View File

@@ -196,6 +196,7 @@ public class CodeMirrorEditor extends FrameLayout {
public void loadFile(final File file) { public void loadFile(final File file) {
setProgress(true); setProgress(true);
// TODO: 2017/9/29 handle error
Observable.fromCallable(new Callable<String>() { Observable.fromCallable(new Callable<String>() {
@Override @Override
public String call() throws Exception { public String call() throws Exception {
@@ -346,20 +347,22 @@ public class CodeMirrorEditor extends FrameLayout {
@JavascriptInterface @JavascriptInterface
public void setStringFromJs(String text) { public void setStringFromJs(String text) {
if (mStringFromJs != null) { if (mStringFromJs == null) {
mStringFromJs.onNext(text); return;
mStringFromJs.onComplete();
mStringFromJs = null;
} }
mStringFromJs.onNext(text);
mStringFromJs.onComplete();
mStringFromJs = null;
} }
@JavascriptInterface @JavascriptInterface
public void setIntFromJs(int i) { public void setIntFromJs(int i) {
if (mIntFromJs != null) { if (mIntFromJs == null) {
mIntFromJs.onNext(i); return;
mIntFromJs.onComplete();
mIntFromJs = null;
} }
mIntFromJs.onNext(i);
mIntFromJs.onComplete();
mIntFromJs = null;
} }
@JavascriptInterface @JavascriptInterface
@@ -371,26 +374,28 @@ public class CodeMirrorEditor extends FrameLayout {
@JavascriptInterface @JavascriptInterface
public void onTextChange() { public void onTextChange() {
if (mCallback != null) { if (mCallback == null) {
mWebView.post(new Runnable() { return;
@Override
public void run() {
mCallback.onChange();
}
});
} }
mWebView.post(new Runnable() {
@Override
public void run() {
mCallback.onChange();
}
});
} }
@JavascriptInterface @JavascriptInterface
public void updateCodeCompletion(final int fromLine, final int fromCh, final int toLine, final int toCh, final String[] list) { public void updateCodeCompletion(final int fromLine, final int fromCh, final int toLine, final int toCh, final String[] list) {
if (mCallback != null) { if (mCallback == null) {
mWebView.post(new Runnable() { return;
@Override
public void run() {
mCallback.updateCodeCompletion(fromLine, fromCh, toLine, toCh, list);
}
});
} }
mWebView.post(new Runnable() {
@Override
public void run() {
mCallback.updateCodeCompletion(fromLine, fromCh, toLine, toCh, list);
}
});
} }
} }
@@ -459,7 +464,7 @@ public class CodeMirrorEditor extends FrameLayout {
@Override @Override
public void onProgressChanged(WebView view, int newProgress) { public void onProgressChanged(WebView view, int newProgress) {
mProgressBar.setVisibility(newProgress == 100 ? VISIBLE : GONE); mProgressBar.setVisibility(newProgress == 100 ? GONE : VISIBLE);
} }
} }
} }

View File

@@ -0,0 +1,105 @@
package com.stardust.scriptdroid.ui.floating;
import android.content.Context;
import android.content.Intent;
import android.support.annotation.Nullable;
import android.view.ContextThemeWrapper;
import android.view.View;
import com.stardust.enhancedfloaty.FloatyService;
import com.stardust.enhancedfloaty.ResizableFloaty;
import com.stardust.enhancedfloaty.ResizableFloatyWindow;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.script.ScriptFile;
import com.stardust.scriptdroid.ui.edit.EditActivity_;
import com.stardust.scriptdroid.ui.edit.EditorView;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import static com.stardust.scriptdroid.ui.edit.EditorView.EXTRA_NAME;
import static com.stardust.scriptdroid.ui.edit.EditorView.EXTRA_PATH;
/**
* Created by Stardust on 2017/9/29.
*/
public class EditorFloaty implements ResizableFloaty {
private Intent mIntent;
@BindView(R.id.resizer)
View mResizeIcon;
@BindView(R.id.move_cursor)
View mMoveIcon;
private ResizableFloatyWindow mWindow;
public EditorFloaty(Intent intent) {
mIntent = intent;
}
public static void floatingEdit(Context context, Intent intent) {
FloatyService.addWindow(new ResizableFloatyWindow(new EditorFloaty(intent)));
context.startService(new Intent(context, FloatyService.class));
}
public static void floatingEdit(Context context, String path) {
floatingEdit(context, null, path);
}
public static void floatingEdit(Context context, String name, String path) {
floatingEdit(context, new Intent(context, EditActivity_.class)
.putExtra(EXTRA_PATH, path)
.putExtra(EXTRA_NAME, name));
}
public static void floatingEdit(Context context, ScriptFile file) {
floatingEdit(context, file.getSimplifiedName(), file.getPath());
}
@Override
public View inflateView(FloatyService floatyService, ResizableFloatyWindow resizableFloatyWindow) {
mWindow = resizableFloatyWindow;
View v = View.inflate(new ContextThemeWrapper(floatyService, R.style.AppTheme), R.layout.floating_editor, null);
setUpViews(v);
return v;
}
private void setUpViews(View v) {
EditorView editorView = (EditorView) v.findViewById(R.id.editor_view);
editorView.handleIntent(mIntent);
ButterKnife.bind(this, v);
}
@OnClick(R.id.move_or_resize)
void showOrHideMoveAndResizeIcon() {
if (mResizeIcon.getVisibility() == View.VISIBLE) {
mResizeIcon.setVisibility(View.GONE);
mMoveIcon.setVisibility(View.GONE);
} else {
mResizeIcon.setVisibility(View.VISIBLE);
mMoveIcon.setVisibility(View.VISIBLE);
}
}
@OnClick(R.id.close)
void close() {
mWindow.close();
}
@Nullable
@Override
public View getResizerView(View view) {
return view.findViewById(R.id.resizer);
}
@Nullable
@Override
public View getMoveCursorView(View view) {
return view.findViewById(R.id.move_cursor);
}
}

View File

@@ -16,6 +16,7 @@ import com.stardust.scriptdroid.script.StorageFileProvider;
import com.stardust.scriptdroid.tool.SimpleObserver; import com.stardust.scriptdroid.tool.SimpleObserver;
import com.stardust.scriptdroid.ui.common.ScriptLoopDialog; import com.stardust.scriptdroid.ui.common.ScriptLoopDialog;
import com.stardust.scriptdroid.ui.common.ScriptOperations; import com.stardust.scriptdroid.ui.common.ScriptOperations;
import com.stardust.scriptdroid.ui.floating.EditorFloaty;
import com.stardust.scriptdroid.ui.main.FloatingActionMenu; import com.stardust.scriptdroid.ui.main.FloatingActionMenu;
import com.stardust.scriptdroid.ui.main.ViewPagerFragment; import com.stardust.scriptdroid.ui.main.ViewPagerFragment;
import com.stardust.util.BackPressedHandler; import com.stardust.util.BackPressedHandler;
@@ -56,7 +57,8 @@ public class MyScriptListFragment extends ViewPagerFragment implements BackPress
mScriptFileList.setOnScriptFileClickListener(new ScriptListView.OnScriptFileClickListener() { mScriptFileList.setOnScriptFileClickListener(new ScriptListView.OnScriptFileClickListener() {
@Override @Override
public void onScriptFileClick(View view, ScriptFile file) { public void onScriptFileClick(View view, ScriptFile file) {
Scripts.edit(file); //Scripts.edit(file);
EditorFloaty.floatingEdit(getContext(), file);
} }
}); });
} }
@@ -112,6 +114,10 @@ public class MyScriptListFragment extends ViewPagerFragment implements BackPress
mFloatingActionMenu.collapse(); mFloatingActionMenu.collapse();
return true; return true;
} }
if(mScriptFileList.canGoBack()){
mScriptFileList.goBack();
return true;
}
return false; return false;
} }

View File

@@ -7,6 +7,7 @@ import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
@@ -23,16 +24,24 @@ import com.stardust.scriptdroid.script.StorageFileProvider;
import com.stardust.scriptdroid.tool.SimpleObserver; import com.stardust.scriptdroid.tool.SimpleObserver;
import com.stardust.scriptdroid.ui.common.ScriptLoopDialog; import com.stardust.scriptdroid.ui.common.ScriptLoopDialog;
import com.stardust.scriptdroid.ui.common.ScriptOperations; import com.stardust.scriptdroid.ui.common.ScriptOperations;
import com.stardust.scriptdroid.ui.viewmodel.ScriptList;
import com.stardust.widget.BindableViewHolder; import com.stardust.widget.BindableViewHolder;
import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.Subscribe;
import java.util.ArrayList; import java.util.concurrent.Callable;
import butterknife.BindView; import butterknife.BindView;
import butterknife.ButterKnife; import butterknife.ButterKnife;
import butterknife.OnClick; import butterknife.OnClick;
import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.annotations.NonNull;
import io.reactivex.functions.Action;
import io.reactivex.functions.BiConsumer;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers; import io.reactivex.schedulers.Schedulers;
/** /**
@@ -46,14 +55,14 @@ public class ScriptListView extends SwipeRefreshLayout implements SwipeRefreshLa
void onScriptFileClick(View view, ScriptFile file); void onScriptFileClick(View view, ScriptFile file);
} }
private ScriptList mScriptList = new ScriptList();
private RecyclerView mScriptListView; private RecyclerView mScriptListView;
private ScriptListAdapter mScriptListAdapter = new ScriptListAdapter(); private ScriptListAdapter mScriptListAdapter = new ScriptListAdapter();
private ArrayList<ScriptFile> mScriptFiles = new ArrayList<>();
private ArrayList<ScriptFile> mDirectories = new ArrayList<>();
private ScriptFile mCurrentDirectory; private ScriptFile mCurrentDirectory;
private OnScriptFileClickListener mOnScriptFileClickListener; private OnScriptFileClickListener mOnScriptFileClickListener;
private ScriptFile mSelectedScriptFile; private ScriptFile mSelectedScriptFile;
private StorageFileProvider mStorageFileProvider; private StorageFileProvider mStorageFileProvider;
private boolean mDirSortMenuShowing = false;
public ScriptListView(Context context) { public ScriptListView(Context context) {
super(context); super(context);
@@ -78,6 +87,16 @@ public class ScriptListView extends SwipeRefreshLayout implements SwipeRefreshLa
mOnScriptFileClickListener = onScriptFileClickListener; mOnScriptFileClickListener = onScriptFileClickListener;
} }
public boolean canGoBack() {
return !mCurrentDirectory.equals(mStorageFileProvider.getInitialDirectory());
}
public void goBack() {
mCurrentDirectory = mCurrentDirectory.getParentFile();
loadScriptList();
}
private void init() { private void init() {
setOnRefreshListener(this); setOnRefreshListener(this);
mScriptListView = new RecyclerView(getContext()); mScriptListView = new RecyclerView(getContext());
@@ -95,7 +114,7 @@ public class ScriptListView extends SwipeRefreshLayout implements SwipeRefreshLa
@Override @Override
public int getSpanSize(int position) { public int getSpanSize(int position) {
//For directories //For directories
if (position >= 1 && position <= mDirectories.size()) { if (position >= 1 && position <= mScriptList.directoryCount()) {
return 1; return 1;
} }
//For files and category //For files and category
@@ -107,24 +126,30 @@ public class ScriptListView extends SwipeRefreshLayout implements SwipeRefreshLa
private void loadScriptList() { private void loadScriptList() {
mScriptFiles.clear(); mScriptList.clear();
mDirectories.clear();
mStorageFileProvider.getDirectoryScriptFiles(mCurrentDirectory) mStorageFileProvider.getDirectoryScriptFiles(mCurrentDirectory)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .collectInto(mScriptList, new BiConsumer<ScriptList, ScriptFile>() {
.subscribe(new SimpleObserver<ScriptFile>() {
@Override @Override
public void onNext(@io.reactivex.annotations.NonNull ScriptFile file) { public void accept(ScriptList list, ScriptFile file) throws Exception {
if (file.isFile()) { list.add(file);
mScriptFiles.add(file);
} else {
mDirectories.add(file);
}
} }
})
.observeOn(Schedulers.computation())
.doOnSuccess(new Consumer<ScriptList>() {
@Override @Override
public void onComplete() { public void accept(@NonNull ScriptList list) throws Exception {
Log.d("SSS", "before sort:" + Thread.currentThread());
list.sort();
Log.d("SSS", "after sort:" + Thread.currentThread());
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<ScriptList>() {
@Override
public void accept(@NonNull ScriptList list) throws Exception {
Log.d("SSS", "notifyDataSetChanged:" + Thread.currentThread());
mScriptList = list;
mScriptListAdapter.notifyDataSetChanged(); mScriptListAdapter.notifyDataSetChanged();
setRefreshing(false); setRefreshing(false);
} }
@@ -166,16 +191,54 @@ public class ScriptListView extends SwipeRefreshLayout implements SwipeRefreshLa
case R.id.open_by_other_apps: case R.id.open_by_other_apps:
Scripts.openByOtherApps(mSelectedScriptFile); Scripts.openByOtherApps(mSelectedScriptFile);
break; break;
case R.id.action_sort_by_date:
sort(ScriptList.SORT_TYPE_DATE, mDirSortMenuShowing);
break;
case R.id.action_sort_by_type:
sort(ScriptList.SORT_TYPE_TYPE, mDirSortMenuShowing);
break;
case R.id.action_sort_by_name:
sort(ScriptList.SORT_TYPE_NAME, mDirSortMenuShowing);
break;
case R.id.action_sort_by_size:
sort(ScriptList.SORT_TYPE_SIZE, mDirSortMenuShowing);
break;
default: default:
return false; return false;
} }
return true; return true;
} }
private void sort(final int sortType, final boolean isDir) {
setRefreshing(true);
Observable.fromCallable(new Callable<ScriptList>() {
@Override
public ScriptList call() throws Exception {
if (isDir) {
mScriptList.sortDir(sortType);
} else {
mScriptList.sortFile(sortType);
}
return mScriptList;
}
})
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<ScriptList>() {
@Override
public void accept(@NonNull ScriptList o) throws Exception {
mScriptListAdapter.notifyDataSetChanged();
setRefreshing(false);
}
});
}
@Override @Override
protected void onDetachedFromWindow() { protected void onDetachedFromWindow() {
super.onDetachedFromWindow(); super.onDetachedFromWindow();
// mStorageFileProvider.unregisterDirectoryChangeListener(this); // mStorageFileProvider.unregisterDirectoryChangeListener(this);
} }
private class ScriptListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { private class ScriptListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
@@ -202,23 +265,23 @@ public class ScriptListView extends SwipeRefreshLayout implements SwipeRefreshLa
@Override @Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
BindableViewHolder bindableViewHolder = (BindableViewHolder) holder; BindableViewHolder bindableViewHolder = (BindableViewHolder) holder;
if (position == 0 || position == mDirectories.size() + 1) { if (position == 0 || position == mScriptList.directoryCount() + 1) {
bindableViewHolder.bind(position == 0, position); bindableViewHolder.bind(position == 0, position);
return; return;
} }
if (position <= mDirectories.size()) { if (position <= mScriptList.directoryCount()) {
bindableViewHolder.bind(mDirectories.get(position - 1), position); bindableViewHolder.bind(mScriptList.getDir(position - 1), position);
return; return;
} }
bindableViewHolder.bind(mScriptFiles.get(position - mDirectories.size() - 2), position); bindableViewHolder.bind(mScriptList.getFile(position - mScriptList.directoryCount() - 2), position);
} }
@Override @Override
public int getItemViewType(int position) { public int getItemViewType(int position) {
if (position == 0 || position == mDirectories.size() + 1) { if (position == 0 || position == mScriptList.directoryCount() + 1) {
return VIEW_TYPE_CATEGORY; return VIEW_TYPE_CATEGORY;
} }
if (position <= mDirectories.size()) { if (position <= mScriptList.directoryCount()) {
return VIEW_TYPE_DIRECTORY; return VIEW_TYPE_DIRECTORY;
} }
return VIEW_TYPE_FILE; return VIEW_TYPE_FILE;
@@ -226,7 +289,7 @@ public class ScriptListView extends SwipeRefreshLayout implements SwipeRefreshLa
@Override @Override
public int getItemCount() { public int getItemCount() {
return mScriptFiles.size() + mDirectories.size() + 2; return mScriptList.count() + 2;
} }
} }
@@ -338,6 +401,11 @@ public class ScriptListView extends SwipeRefreshLayout implements SwipeRefreshLa
@BindView(R.id.sort) @BindView(R.id.sort)
ImageView mSort; ImageView mSort;
@BindView(R.id.order)
ImageView mSortOrder;
private boolean mIsDir;
CategoryViewHolder(View itemView) { CategoryViewHolder(View itemView) {
super(itemView); super(itemView);
ButterKnife.bind(this, itemView); ButterKnife.bind(this, itemView);
@@ -346,11 +414,22 @@ public class ScriptListView extends SwipeRefreshLayout implements SwipeRefreshLa
@Override @Override
public void bind(Boolean isDirCategory, int position) { public void bind(Boolean isDirCategory, int position) {
mTitle.setText(isDirCategory ? R.string.text_directory : R.string.text_file); mTitle.setText(isDirCategory ? R.string.text_directory : R.string.text_file);
mIsDir = isDirCategory;
} }
@OnClick(R.id.order) @OnClick(R.id.order)
void changeSortOrder() { void changeSortOrder() {
if (mIsDir) {
mSortOrder.setImageResource(mScriptList.isDirSortedAscending() ?
R.drawable.ic_ascending_order : R.drawable.ic_descending_order);
mScriptList.setDirSortedAscending(!mScriptList.isDirSortedAscending());
sort(mScriptList.getDirSortType(), mIsDir);
} else {
mSortOrder.setImageResource(mScriptList.isFileSortedAscending() ?
R.drawable.ic_ascending_order : R.drawable.ic_descending_order);
mScriptList.setFileSortedAscending(!mScriptList.isFileSortedAscending());
sort(mScriptList.getFileSortType(), mIsDir);
}
} }
@OnClick(R.id.sort) @OnClick(R.id.sort)
@@ -358,7 +437,9 @@ public class ScriptListView extends SwipeRefreshLayout implements SwipeRefreshLa
PopupMenu popupMenu = new PopupMenu(getContext(), mSort); PopupMenu popupMenu = new PopupMenu(getContext(), mSort);
popupMenu.inflate(R.menu.menu_sort_options); popupMenu.inflate(R.menu.menu_sort_options);
popupMenu.setOnMenuItemClickListener(ScriptListView.this); popupMenu.setOnMenuItemClickListener(ScriptListView.this);
mDirSortMenuShowing = mIsDir;
popupMenu.show(); popupMenu.show();
} }
} }
} }

View File

@@ -0,0 +1,113 @@
package com.stardust.scriptdroid.ui.viewmodel;
import com.stardust.scriptdroid.script.ScriptFile;
import com.stardust.util.FileSorter;
import java.io.File;
import java.util.ArrayList;
import java.util.Comparator;
/**
* Created by Stardust on 2017/9/30.
*/
public class ScriptList {
public static final int SORT_TYPE_NAME = 0x10;
public static final int SORT_TYPE_TYPE = 0x20;
public static final int SORT_TYPE_SIZE = 0x30;
public static final int SORT_TYPE_DATE = 0x40;
private ArrayList<ScriptFile> mScriptFiles = new ArrayList<>();
private ArrayList<ScriptFile> mDirectories = new ArrayList<>();
private int mDirSortType = SORT_TYPE_NAME;
private boolean mDirSortedAscending;
private boolean mFileSortedAscending;
private int mFileSortType = SORT_TYPE_NAME;
public boolean isDirSortedAscending() {
return mDirSortedAscending;
}
public boolean isFileSortedAscending() {
return mFileSortedAscending;
}
public int getDirSortType() {
return mDirSortType;
}
public int getFileSortType() {
return mFileSortType;
}
public void setDirSortedAscending(boolean dirSortedAscending) {
mDirSortedAscending = dirSortedAscending;
}
public void setFileSortedAscending(boolean fileSortedAscending) {
mFileSortedAscending = fileSortedAscending;
}
private Comparator<File> getComparator(int sortType) {
switch (sortType) {
case SORT_TYPE_NAME:
return FileSorter.NAME;
case SORT_TYPE_DATE:
return FileSorter.DATE;
case SORT_TYPE_SIZE:
return FileSorter.SIZE;
case SORT_TYPE_TYPE:
return FileSorter.TYPE;
}
throw new IllegalArgumentException("unknown type " + sortType);
}
public int directoryCount() {
return mDirectories.size();
}
public int fileCount() {
return mScriptFiles.size();
}
public void clear() {
mScriptFiles.clear();
mDirectories.clear();
}
public void add(ScriptFile file) {
if (file.isFile()) {
mScriptFiles.add(file);
} else {
mDirectories.add(file);
}
}
public ScriptFile getDir(int i) {
return mDirectories.get(i);
}
public ScriptFile getFile(int i) {
return mScriptFiles.get(i);
}
public int count() {
return mScriptFiles.size() + mDirectories.size();
}
public void sortDir(int sortType) {
mDirSortType = sortType;
FileSorter.sort(mDirectories, getComparator(sortType), mDirSortedAscending);
}
public void sortFile(int sortType) {
mFileSortType = sortType;
FileSorter.sort(mScriptFiles, getComparator(sortType), mFileSortedAscending);
}
public void sort() {
FileSorter.sort(mDirectories, getComparator(mDirSortType), mDirSortedAscending);
FileSorter.sort(mScriptFiles, getComparator(mFileSortType), mFileSortedAscending);
}
}

View File

@@ -59,6 +59,7 @@ public class EWebView extends FrameLayout implements SwipeRefreshLayout.OnRefres
settings.setJavaScriptEnabled(true); settings.setJavaScriptEnabled(true);
settings.setJavaScriptCanOpenWindowsAutomatically(true); settings.setJavaScriptCanOpenWindowsAutomatically(true);
settings.setDomStorageEnabled(true); settings.setDomStorageEnabled(true);
settings.setDisplayZoomControls(false);
mWebView.setWebViewClient(new MyWebViewClient()); mWebView.setWebViewClient(new MyWebViewClient());
mWebView.setWebChromeClient(new MyWebChromeClient()); mWebView.setWebChromeClient(new MyWebChromeClient());
} }

View File

@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.stardust.scriptdroid.ui.edit.EditorView_
android:id="@+id/editor_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.stardust.widget.ToolbarMenuItem
android:id="@+id/close"
android:layout_width="40dp"
android:layout_height="match_parent"
app:icon="@drawable/ic_close_white_48dp"
app:text="@string/text_close"/>
<com.stardust.widget.ToolbarMenuItem
android:id="@+id/move_or_resize"
android:layout_width="40dp"
android:layout_height="match_parent"
app:icon="@drawable/ic_settings_ethernet_white_24dp"
app:text="@string/text_adjust"/>
</LinearLayout>
<ImageView
android:id="@+id/resizer"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:background="@drawable/circle_cool_black"
android:padding="6dp"
android:scaleType="fitXY"
android:src="@drawable/ic_resizer"
android:tint="@android:color/white"
android:visibility="gone"/>
<ImageView
android:id="@+id/move_cursor"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:background="@drawable/circle_cool_black"
android:padding="5dp"
android:scaleType="fitXY"
android:src="@drawable/ic_move_cursor"
android:tint="@android:color/white"
android:visibility="gone"/>
</RelativeLayout>

View File

@@ -2,18 +2,18 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"> <menu xmlns:android="http://schemas.android.com/apk/res/android">
<item <item
android:checkable="true" android:id="@+id/action_sort_by_name"
android:title="@string/text_name"/> android:title="@string/text_name"/>
<item <item
android:checkable="true" android:id="@+id/action_sort_by_date"
android:title="@string/text_time" android:title="@string/text_time"
/> />
<item <item
android:checkable="true" android:id="@+id/action_sort_by_size"
android:title="@string/text_size" android:title="@string/text_size"
/> />
<item <item
android:checkable="true" android:id="@+id/action_sort_by_type"
android:title="@string/text_type" android:title="@string/text_type"
/> />
</menu> </menu>

View File

@@ -279,6 +279,8 @@
<string name="text_refactor">重构</string> <string name="text_refactor">重构</string>
<string name="text_select_variable">选择变量</string> <string name="text_select_variable">选择变量</string>
<string name="text_show_type">显示变量类型</string> <string name="text_show_type">显示变量类型</string>
<string name="text_close">关闭</string>
<string name="text_adjust">调整</string>
<string-array name="record_control_keys"> <string-array name="record_control_keys">

View File

@@ -2,6 +2,15 @@ package com.stardust.scriptdroid;
import org.junit.Test; import org.junit.Test;
import java.util.concurrent.Callable;
import io.reactivex.Observable;
import io.reactivex.annotations.NonNull;
import io.reactivex.functions.Action;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
/** /**
* Example local unit test, which will execute on the development machine (host). * Example local unit test, which will execute on the development machine (host).
* *
@@ -17,11 +26,33 @@ public class ExampleUnitTest {
// TODO: 2017/7/4 细节 三天 7.18 // TODO: 2017/7/4 细节 三天 7.18
// TODO: 2017/7/4 写文档 两天 7.20 // TODO: 2017/7/4 写文档 两天 7.20
// TODO: 2017/7/4 发布 3.0.0 Beta 7.22 // TODO: 2017/7/4 发布 3.0.0 Beta 7.22
// TODO: 2017/9/30 想象真是美好。
@Test @Test
public void test() { public void test() {
System.out.println("SOS".hashCode()); Observable.fromCallable(new Callable<String>() {
@Override
public String call() throws Exception {
System.out.println(Thread.currentThread());
return "";
}
})
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.newThread())
.doOnComplete(new Action() {
@Override
public void run() throws Exception {
System.out.println(Thread.currentThread());
}
})
.observeOn(Schedulers.newThread())
.subscribe(new Consumer<String>() {
@Override
public void accept(@NonNull String s) throws Exception {
System.out.println(Thread.currentThread());
}
});
} }
@Test @Test

View File

@@ -1,9 +1,14 @@
package com.stardust.util; package com.stardust.util;
import com.stardust.pio.PFile;
import java.io.File; import java.io.File;
import java.text.Collator; import java.text.Collator;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.List;
import java.util.Locale; import java.util.Locale;
/** /**
@@ -12,16 +17,72 @@ import java.util.Locale;
public class FileSorter { public class FileSorter {
public static void sort(File[] files) { public static final Comparator<File> NAME = new Comparator<File>() {
final Collator collator = Collator.getInstance(); final Collator collator = Collator.getInstance();
Arrays.sort(files, new Comparator<File>() {
@Override @Override
public int compare(File o1, File o2) { public int compare(File o1, File o2) {
if (o1.isDirectory() != o2.isDirectory()) if (o1.isDirectory() != o2.isDirectory())
return o1.isDirectory() ? Integer.MIN_VALUE : Integer.MAX_VALUE; return o1.isDirectory() ? Integer.MIN_VALUE : Integer.MAX_VALUE;
return collator.compare(o1.getName(), o2.getName()); return -collator.compare(o1.getName(), o2.getName());
} }
}); };
public static final Comparator<File> DATE = new Comparator<File>() {
@Override
public int compare(File o1, File o2) {
return o1.lastModified() == o2.lastModified() ? 0 :
o1.lastModified() > o2.lastModified() ? 1 : -1;
}
};
public static final Comparator<File> TYPE = new Comparator<File>() {
@Override
public int compare(File o1, File o2) {
return -PFile.getExtension(o1.getName()).compareTo(PFile.getExtension(o2.getName()));
}
};
public static final Comparator<File> SIZE = new Comparator<File>() {
@Override
public int compare(File o1, File o2) {
return o1.length() == o2.length() ? 0 :
o1.length() < o2.length() ? 1 : -1;
}
};
public static void sort(File[] files, final Comparator<File> comparator, boolean ascending) {
if (ascending) {
Arrays.sort(files, comparator);
} else {
Arrays.sort(files, new Comparator<File>() {
@Override
public int compare(File o1, File o2) {
return comparator.compare(o2, o1);
}
});
}
}
public static void sort(File[] files, Comparator<File> comparator) {
sort(files, comparator, true);
}
public static void sort(List<? extends File> files, final Comparator<File> comparator, boolean ascending) {
if (ascending) {
Collections.sort(files, comparator);
} else {
Collections.sort(files, new Comparator<File>() {
@Override
public int compare(File o1, File o2) {
return comparator.compare(o2, o1);
}
});
}
}
public static void sort(List<? extends File> files, Comparator<File> comparator) {
sort(files, comparator, true);
} }
} }