add: tutorial tab

This commit is contained in:
hyb1996
2017-08-22 18:11:14 +08:00
parent 602b84fc92
commit 42f6802598
21 changed files with 858 additions and 305 deletions

View File

@@ -21,17 +21,17 @@ events.onKeyDown("menu", function(event){
```
### events.emitter()
## events.emitter()
返回一个新的EventEmitter。
### events.observeKey()
## events.observeKey()
启用按键监听例如音量键、Home键。
在安卓4.3以上才能使用。
### events.onKeyDown(keyName, listener)
## events.onKeyDown(keyName, listener)
* keyName \<String\> 要监听的按键名称
* listener \<Function\> 参数为一个[KeyEvent](#KeyEvent)
@@ -42,51 +42,51 @@ events.onKeyDown("menu", function(event){
* back 返回键
* menu 菜单键
### events.onKeyUp(keyName, listener)
## events.onKeyUp(keyName, listener)
* keyName \<String\> 要监听的按键名称
* listener \<Function\> 参数为一个[KeyEvent](#KeyEvent)
注册一个按键监听函数当有keyName对应的按键弹起时会调用该函数。
### events.onceKeyDown(keyName, listener)
## events.onceKeyDown(keyName, listener)
* keyName \<String\> 要监听的按键名称
* listener \<Function\> 参数为一个[KeyEvent](#KeyEvent)
注册一个按键监听函数当有keyName对应的按键被按下时会调用该函数之后会注销该按键监听。也就是listener只会被调用一次。
### events.onceKeyUp(keyName, listener)
## events.onceKeyUp(keyName, listener)
* keyName \<String\> 要监听的按键名称
* listener \<Function\> 参数为一个[KeyEvent](#KeyEvent)
注册一个按键监听函数当有keyName对应的按键弹起时会调用该函数之后会注销该按键监听。也就是listener只会被调用一次。
### events.removeAllKeyDownListeners(keyName)
## events.removeAllKeyDownListeners(keyName)
* keyName \<String\> 按键名称
删除该按键的KeyDown事件的所有监听。
### events.removeAllKeyUpListeners(keyName)
## events.removeAllKeyUpListeners(keyName)
* keyName \<String\> 按键名称
删除该按键的KeyUp事件的所有监听。
### events.observeTouch()
## events.observeTouch()
启用屏幕触摸监听。需要root权限
### events.setTouchEventTimeout(timeout)
## events.setTouchEventTimeout(timeout)
* timeout \<Number\> 两个触摸事件的最小间隔。单位毫秒。默认为10毫秒。
设置两个触摸事件分发的最小时间间隔。
例如间隔为10毫秒的话前一个触摸事件发生并被注册的监听器处理后至少要过10毫秒才能分发和处理下一个触摸事件这10毫秒之间的触摸将会被忽略。
### events.getTouchEventTimeout()
## events.getTouchEventTimeout()
返回触摸事件的最小时间间隔。
### events.onTouch(listener)
## events.onTouch(listener)
* listener \<Function\> 参数为Point的函数
注册一个触摸监听函数。相当于`on("touch", listener)`
@@ -100,11 +100,11 @@ events.onTouch(function(p){
events.loop();
```
### events.removeAllTouchListeners()
## events.removeAllTouchListeners()
删除所有事件监听函数。
### 事件: 'key'
## 事件: 'key'
* keyCode \<Number\> 键值
* event \<KeyEvent\> 事件
@@ -124,7 +124,7 @@ events.loop();
* KeyEvent.KEYCODE_VOLUME_UP 音量上键
* KeyEvent.KEYCODE_VOLUME_DOWN 音量下键
### 事件: 'key_down'
## 事件: 'key_down'
* keyCode \<Number\> 键值
* event \<KeyEvent\> 事件
@@ -138,7 +138,7 @@ events.on("key_down", function(keyCode, event){
events.loop();
```
### 事件: 'key_up'
## 事件: 'key_up'
* keyCode \<Number\> 键值
* event \<KeyEvent\> 事件
@@ -153,7 +153,7 @@ events.loop();
```
### obverseNotification()
## obverseNotification()
开启通知(包括Toast)监听。
```
events.obverseNotification();
@@ -165,12 +165,12 @@ events.onToast(function(toast){
});
```
### 事件: 'toast'
## 事件: 'toast'
* toast \<Object\>
* getText() 获取Toast的文本内容
* getPackageName() 获取发出Toast的应用包名
### 事件: 'notification'
## 事件: 'notification'
* notification \<Object\> 通知
```
@@ -184,7 +184,7 @@ events.on("notification", function(notification){
# EventEmitter
### EventEmitter.defaultMaxListeners
## EventEmitter.defaultMaxListeners
每个事件默认可以注册最多 10 个监听器。 单个 EventEmitter 实例的限制可以使用 emitter.setMaxListeners(n) 方法改变。 所有 EventEmitter 实例的默认值可以使用 EventEmitter.defaultMaxListeners 属性改变。
@@ -199,19 +199,20 @@ emitter.once('event', () => {
});
```
## EventEmitter.addListener(eventName, listener)
* eventName \<any\>
* listener \<Function\>
* eventName {any}
* listener {Function}
emitter.on(eventName, listener) 的别名。
### EventEmitter.emit(eventName\[, ...args\])
* eventName <any>
* args <any>
## EventEmitter.emit(eventName\[, ...args\])
* eventName {any}
* args {any}
按监听器的注册顺序,同步地调用每个注册到名为 eventName 事件的监听器,并传入提供的参数。
如果事件有监听器,则返回 true ,否则返回 false。
### EventEmitter.eventNames()
## EventEmitter.eventNames()
返回一个列出触发器已注册监听器的事件的数组。 数组中的值为字符串或符号。
```
@@ -225,17 +226,17 @@ myEE.on(sym, () => {});
console.log(myEE.eventNames());
// 打印: [ 'foo', 'bar', Symbol(symbol) ]
```
### EventEmitter.getMaxListeners()#
## EventEmitter.getMaxListeners()
返回 EventEmitter 当前的最大监听器限制值,该值可以通过 emitter.setMaxListeners(n) 设置或默认为 EventEmitter.defaultMaxListeners。
### EventEmitter.listenerCount(eventName)
* eventName <any> 正在被监听的事件名
## EventEmitter.listenerCount(eventName)
* eventName {any} 正在被监听的事件名
返回正在监听名为 eventName 的事件的监听器的数量。
### EventEmitter.listeners(eventName)
* eventName <any>
## EventEmitter.listeners(eventName)
* eventName {any}
返回名为 eventName 的事件的监听器数组的副本。
```
@@ -246,9 +247,9 @@ console.log(util.inspect(server.listeners('connection')));
// 打印: [ [Function] ]
```
### EventEmitter.on(eventName, listener)
* eventName <any> 事件名
* listener <Function> 回调函数
## EventEmitter.on(eventName, listener)
* eventName {any} 事件名
* listener {Function} 回调函数
添加 listener 函数到名为 eventName 的事件的监听器数组的末尾。 不会检查 listener 是否已被添加。 多次调用并传入相同的 eventName 和 listener 会导致 listener 被添加与调用多次。
```
@@ -270,9 +271,9 @@ myEE.emit('foo');
```
### EventEmitter.once(eventName, listener)#
* eventName <any> 事件名
* listener <Function> 回调函数
## EventEmitter.once(eventName, listener)#
* `eventName` {any} 事件名
* `listener` {Function} 回调函数
添加一个单次 listener 函数到名为 eventName 的事件。 下次触发 eventName 事件时,监听器会被移除,然后调用。
```
@@ -293,9 +294,9 @@ myEE.emit('foo');
// a
```
### EventEmitter.prependListener(eventName, listener)
* eventName <any> 事件名
* listener <Function> 回调函数
## EventEmitter.prependListener(eventName, listener)
* `eventName` {any} 事件名
* `listener` {Function} 回调函数
添加 listener 函数到名为 eventName 的事件的监听器数组的开头。 不会检查 listener 是否已被添加。 多次调用并传入相同的 eventName 和 listener 会导致 listener 被添加与调用多次。
```
@@ -305,9 +306,9 @@ server.prependListener('connection', (stream) => {
```
返回一个 EventEmitter 引用,可以链式调用。
### EventEmitter.prependOnceListener(eventName, listener)
* eventName <any> 事件名
* listener <Function> 回调函数
## EventEmitter.prependOnceListener(eventName, listener)
* `eventName` {any} 事件名
* `listener` {Function} 回调函数
添加一个单次 listener 函数到名为 eventName 的事件的监听器数组的开头。 下次触发 eventName 事件时,监听器会被移除,然后调用。
```
@@ -317,8 +318,8 @@ server.prependOnceListener('connection', (stream) => {
```
返回一个 EventEmitter 引用,可以链式调用。
### EventEmitter.removeAllListeners(\[eventName\])
* eventName <any>
## EventEmitter.removeAllListeners(\[eventName\])
* `eventName` {any}
移除全部或指定 eventName 的监听器。
@@ -326,9 +327,9 @@ server.prependOnceListener('connection', (stream) => {
返回一个 EventEmitter 引用,可以链式调用。
### EventEmitter.removeListener(eventName, listener)
* eventName <any>
* listener <Function>
## EventEmitter.removeListener(eventName, listener)
* `eventName` {any}
* `listener` {Function}
从名为 eventName 的事件的监听器数组中移除指定的 listener。
```
@@ -376,8 +377,8 @@ myEmitter.emit('event');
返回一个 EventEmitter 引用,可以链式调用。
### EventEmitter.setMaxListeners(n)
* n <integer>
## EventEmitter.setMaxListeners(n)
* n {number}
默认情况下,如果为特定事件添加了超过 10 个监听器,则 EventEmitter 会打印一个警告。 此限制有助于寻找内存泄露。 但是,并不是所有的事件都要被限为 10 个。 emitter.setMaxListeners() 方法允许修改指定的 EventEmitter 实例的限制。 值设为 Infinity或 0表明不限制监听器的数量。
@@ -385,29 +386,29 @@ myEmitter.emit('event');
# KeyEvent
### KeyEvent.getAction()
## KeyEvent.getAction()
返回事件的动作。包括:
* KeyEvent.ACTION_DOWN 按下事件
* KeyEvent.ACTION_UP 弹起事件
* `KeyEvent.ACTION_DOWN` 按下事件
* `KeyEvent.ACTION_UP` 弹起事件
### KeyEvent.getKeyCode()
## KeyEvent.getKeyCode()
返回按键的键值。包括:
* KeyEvent.KEYCODE_HOME 主页键
* KeyEvent.KEYCODE_BACK 返回键
* KeyEvent.KEYCODE_MENU 菜单键
* KeyEvent.KEYCODE_VOLUME_UP 音量上键
* KeyEvent.KEYCODE_VOLUME_DOWN 音量下键
* `KeyEvent.KEYCODE_HOME` 主页键
* `KeyEvent.KEYCODE_BACK` 返回键
* `KeyEvent.KEYCODE_MENU` 菜单键
* `KeyEvent.KEYCODE_VOLUME_UP` 音量上键
* `KeyEvent.KEYCODE_VOLUME_DOWN` 音量下键
### KeyEvent.getEventTime()
## KeyEvent.getEventTime()
返回事件发生的时间戳。
返回事件发生的时间戳。返回值的类型是number。
### KeyEvent.getDownTime()
## KeyEvent.getDownTime()
返回最近一次按下事件的时间戳。如果本身是按下事件则与getEventTime()相同。
### KeyEvent.keyCodeToString(keyCode)
## KeyEvent.keyCodeToString(keyCode)
把键值转换为字符串。例如KEYCODE_HOME转换为"KEYCODE_HOME"。
把键值转换为字符串。例如`KEYCODE_HOME`转换为`"KEYCODE_HOME"`

View File

@@ -26,7 +26,7 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED;
* Created by Stardust on 2017/1/23.
*/
public abstract class BaseActivity extends AppCompatActivity {
public abstract class BaseActivity extends AppCompatActivity implements BackPressedHandler.HostActivity {
protected static final int PERMISSION_REQUEST_CODE = 11186;
@@ -123,4 +123,9 @@ public abstract class BaseActivity extends AppCompatActivity {
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
@Override
public BackPressedHandler.Observer getBackPressedObserver() {
return mBackPressObserver;
}
}

View File

@@ -106,9 +106,9 @@ public class EditActivity extends Editor920Activity implements OnActivityResultD
@ViewById(R.id.content_view)
View mView;
private String mName;
private File mFile;
private EditorDelegate mEditorDelegate;
private SparseArray<ToolbarMenuItem> mMenuMap;
private EditorDelegate mEditorDelegate;
private File mFile;
private boolean mReadOnly = false;
private OnActivityResultDelegate.Mediator mActivityResultMediator = new OnActivityResultDelegate.Mediator();
private BroadcastReceiver mOnRunFinishedReceiver = new BroadcastReceiver() {

View File

@@ -0,0 +1,117 @@
package com.stardust.scriptdroid.ui.edit;
import android.content.Context;
import android.support.annotation.AttrRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;
import com.jecelyin.editor.v2.common.Command;
import com.jecelyin.editor.v2.core.widget.TextView;
import com.jecelyin.editor.v2.ui.EditorDelegate;
import com.jecelyin.editor.v2.view.EditorView;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.ui.edit.completion.InputMethodEnhanceBar;
import com.stardust.scriptdroid.ui.edit.editor920.Editor920Utils;
import org.androidannotations.annotations.EViewGroup;
import java.io.File;
/**
* Created by Stardust on 2017/8/21.
*/
@EViewGroup(R.layout.script_edit_view)
public class ScriptEditView extends FrameLayout {
private class InputMethodEnhanceBarBridge implements InputMethodEnhanceBar.EditTextBridge {
private TextView mTextView;
public InputMethodEnhanceBarBridge(TextView textView) {
mTextView = textView;
}
@Override
public void appendText(CharSequence text) {
insertText(text);
}
@Override
public void backspace(int count) {
}
@Override
public TextView getEditText() {
return mTextView;
}
}
private EditorDelegate mEditorDelegate;
private File mFile;
private boolean mReadOnly = false;
public ScriptEditView(@NonNull Context context) {
super(context);
}
public ScriptEditView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public ScriptEditView(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public boolean isReadOnly() {
return mReadOnly;
}
public void setReadOnly(boolean readOnly) {
mReadOnly = readOnly;
}
public void setFile(File file) {
mFile = file;
mEditorDelegate = new EditorDelegate(0, mFile, 0, "utf-8");
setUpEditor();
}
public void setContent(String name, String str) {
mEditorDelegate = new EditorDelegate(0, name, str);
}
public void insertText(CharSequence text) {
Command c = new Command(Command.CommandEnum.INSERT_TEXT);
c.object = text;
mEditorDelegate.doCommand(c);
}
private void setUpEditor() {
final EditorView editorView = (EditorView) findViewById(R.id.editor);
mEditorDelegate.setEditorView(editorView);
if (mFile == null)
Editor920Utils.setLang(mEditorDelegate, "JavaScript");
editorView.getEditText().setReadOnly(mReadOnly);
editorView.getEditText().setHorizontallyScrolling(true);
setUpInputMethodEnhanceBar(editorView);
}
private void setUpInputMethodEnhanceBar(final EditorView editorView) {
InputMethodEnhanceBar inputMethodEnhanceBar = (InputMethodEnhanceBar) findViewById(R.id.input_method_enhance_bar);
if (mReadOnly) {
inputMethodEnhanceBar.setVisibility(View.GONE);
} else {
inputMethodEnhanceBar.setEditTextBridge(new InputMethodEnhanceBarBridge(editorView.getEditText()));
}
}
}

View File

@@ -32,6 +32,9 @@ import com.stardust.scriptdroid.external.floatingwindow.HoverMenuManger;
import com.stardust.scriptdroid.script.ScriptFile;
import com.stardust.scriptdroid.script.StorageFileProvider;
import com.stardust.scriptdroid.ui.common.ScriptOperations;
import com.stardust.scriptdroid.ui.main.community.CommunityFragment;
import com.stardust.scriptdroid.ui.main.doc.OnlineDocsFragment;
import com.stardust.scriptdroid.ui.main.doc.OnlineDocsFragment_;
import com.stardust.scriptdroid.ui.main.script_list.MyScriptListFragment_;
import com.stardust.scriptdroid.ui.main.task.TaskManagerFragment_;
import com.stardust.util.DeveloperUtils;
@@ -62,17 +65,6 @@ public class MainActivity extends BaseActivity implements OnActivityResultDelega
public static final String MESSAGE_CLEAR_BACKGROUND_SETTINGS = "MESSAGE_CLEAR_BACKGROUND_SETTINGS";
private static final String LOG_TAG = "MainActivity";
private static final String EXTRA_ACTION = "EXTRA_ACTION";
private static final String ACTION_ON_RECORD_STOP = "ACTION_ON_RECORD_STOP";
private static final String ACTION_IMPORT_SCRIPT = "ACTION_IMPORT_SCRIPT";
private static final String ARGUMENT_SCRIPT = "ARGUMENT_SCRIPT";
private static final String ARGUMENT_PATH = "ARGUMENT_PATH";
private static final String ACTION_IMPORT_SAMPLE = "I cannot find the way back to you...Eating...17.4.29";
private static final String ARGUMENT_SAMPLE = "Take a chance on me...ok...?";
private static final String ARGUMENT_INPUT_STREAM = "17.7.12, Hi...could we start all over again...";
private static final String ACTION_ON_ROOT_RECORD_STOP = "ACTION_ON_ROOT_RECORD_STOP";
@ViewById(R.id.drawer_layout)
DrawerLayout mDrawerLayout;
@@ -183,9 +175,10 @@ public class MainActivity extends BaseActivity implements OnActivityResultDelega
private void setUpTabViewPager() {
TabLayout tabLayout = $(R.id.tab);
mPagerAdapter = new FragmentPagerAdapterBuilder(this)
.add(new MyScriptListFragment_(), R.string.text_my_script)
.add(new SampleScriptListFragment(), R.string.text_sample_script)
.add(new TaskManagerFragment_(), R.string.text_task_manage)
.add(new MyScriptListFragment_(), R.string.text_script)
.add(new OnlineDocsFragment_(), R.string.text_tutorial)
.add(new CommunityFragment(), R.string.text_community)
.add(new TaskManagerFragment_(), R.string.text_manage)
.build();
mViewPager.setAdapter(mPagerAdapter);
tabLayout.setupWithViewPager(mViewPager);

View File

@@ -0,0 +1,10 @@
package com.stardust.scriptdroid.ui.main.community;
import android.support.v4.app.Fragment;
/**
* Created by Stardust on 2017/8/22.
*/
public class CommunityFragment extends Fragment {
}

View File

@@ -0,0 +1,56 @@
package com.stardust.scriptdroid.ui.main.doc;
import android.app.Activity;
import android.content.Context;
import android.support.v4.app.Fragment;
import android.webkit.WebView;
import com.stardust.scriptdroid.R;
import com.stardust.util.BackPressedHandler;
import com.stardust.widget.EWebView;
import org.androidannotations.annotations.AfterViews;
import org.androidannotations.annotations.EFragment;
import org.androidannotations.annotations.ViewById;
/**
* Created by Stardust on 2017/8/22.
*/
@EFragment(R.layout.fragment_online_docs)
public class OnlineDocsFragment extends Fragment implements BackPressedHandler {
@ViewById(R.id.eweb_view)
EWebView mEWebView;
WebView mWebView;
@Override
public void onAttach(Context context) {
super.onAttach(context);
((BackPressedHandler.HostActivity) getActivity())
.getBackPressedObserver()
.registerHandler(this);
}
@AfterViews
void setUpViews() {
mWebView = mEWebView.getWebView();
mWebView.loadUrl("https://hyb1996.github.io/AutoJs-Docs/");
}
@Override
public void onDetach() {
super.onDetach();
((BackPressedHandler.HostActivity) getActivity())
.getBackPressedObserver()
.unregisterHandler(this);
}
@Override
public boolean onBackPressed(Activity activity) {
if (mWebView.canGoBack()) {
mWebView.goBack();
return true;
}
return false;
}
}

View File

@@ -1,30 +1,19 @@
package com.stardust.scriptdroid.ui.main.script_list;
import android.graphics.drawable.GradientDrawable;
import android.support.annotation.NonNull;
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.afollestad.materialdialogs.DialogAction;
import com.afollestad.materialdialogs.MaterialDialog;
import com.stardust.scriptdroid.script.ScriptFile;
import com.stardust.pio.PFile;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.script.ScriptFile;
import com.stardust.scriptdroid.script.Scripts;
import com.stardust.scriptdroid.script.StorageFileProvider;
import com.stardust.scriptdroid.tool.SimpleObserver;
import com.stardust.scriptdroid.ui.common.ScriptLoopDialog;
import com.stardust.widget.AutoAdapter;
import com.stardust.widget.BindableViewHolder;
import com.stardust.widget.ViewHolderSupplier;
import com.yqritc.recyclerviewflexibledivider.HorizontalDividerItemDecoration;
import com.stardust.scriptdroid.ui.edit.ScriptEditView;
import org.androidannotations.annotations.AfterViews;
import org.androidannotations.annotations.EFragment;
@@ -32,22 +21,11 @@ import org.androidannotations.annotations.ViewById;
import org.reactivestreams.Publisher;
import org.reactivestreams.Subscriber;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.concurrent.Callable;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.Optional;
import io.reactivex.Observable;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Predicate;
import io.reactivex.schedulers.Schedulers;
/**
@@ -56,76 +34,18 @@ import io.reactivex.schedulers.Schedulers;
@EFragment(R.layout.fragment_my_script_list)
public class MyScriptListFragment extends Fragment {
public static final String MESSAGE_SCRIPT_FILE_ADDED = "MESSAGE_SCRIPT_FILE_ADDED";
private static final String TAG = "MyScriptListFragment";
private static ScriptFile sCurrentDirectory = StorageFileProvider.DEFAULT_DIRECTORY;
@ViewById(R.id.script_file_list)
RecyclerView mScriptFileList;
ScriptListView mScriptFileList;
@ViewById(R.id.swipe_refresh_layout)
SwipeRefreshLayout mSwipeRefreshLayout;
private ScriptListAdapter mScriptListAdapter = new ScriptListAdapter();
private ScriptFile mSelectedScriptFile;
private ArrayList<ScriptFile> mScriptFiles = new ArrayList<>();
private ArrayList<ScriptFile> mDirectories = new ArrayList<>();
@AfterViews
void setUpViews() {
initScriptListRecyclerView();
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
loadScriptList();
}
});
}
private void initScriptListRecyclerView() {
mScriptFileList.setAdapter(mScriptListAdapter);
GridLayoutManager manager = new GridLayoutManager(getContext(), 2);
manager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
//For directories
if (position >= 1 && position <= mDirectories.size()) {
return 1;
}
//For files and category
return 2;
}
});
mScriptFileList.setLayoutManager(manager);
loadScriptList();
}
private void loadScriptList() {
mScriptFiles.clear();
mDirectories.clear();
StorageFileProvider.getDefault().getInitialDirectoryScriptFiles()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new SimpleObserver<ScriptFile>() {
@Override
public void onNext(@io.reactivex.annotations.NonNull ScriptFile file) {
if (file.isFile()) {
mScriptFiles.add(file);
} else {
mDirectories.add(file);
}
}
@Override
public void onComplete() {
mScriptListAdapter.notifyDataSetChanged();
mSwipeRefreshLayout.setRefreshing(false);
}
});
}
@@ -165,12 +85,7 @@ public class MyScriptListFragment extends Fragment {
private void onScriptFileOperated() {
mSelectedScriptFile = null;
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
mSwipeRefreshLayout.setRefreshing(false);
}
});
}
@Optional
@@ -224,123 +139,5 @@ public class MyScriptListFragment extends Fragment {
});
}
private class ScriptListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final int VIEW_TYPE_FILE = 0;
private final int VIEW_TYPE_DIRECTORY = 1;
//category是类别也即"文件", "文件夹"那两个
private final int VIEW_TYPE_CATEGORY = 2;
@Override
public RecyclerView.ViewHolder 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));
}
}
@SuppressWarnings("unchecked")
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
BindableViewHolder bindableViewHolder = (BindableViewHolder) holder;
if (position == 0 || position == mDirectories.size() + 1) {
bindableViewHolder.bind(position == 0, position);
return;
}
if (position <= mDirectories.size()) {
bindableViewHolder.bind(mDirectories.get(position - 1), position);
return;
}
bindableViewHolder.bind(mScriptFiles.get(position - mDirectories.size() - 2), position);
}
@Override
public int getItemViewType(int position) {
if (position == 0 || position == mDirectories.size() + 1) {
return VIEW_TYPE_CATEGORY;
}
if (position <= mDirectories.size()) {
return VIEW_TYPE_DIRECTORY;
}
return VIEW_TYPE_FILE;
}
@Override
public int getItemCount() {
return mScriptFiles.size() + mDirectories.size() + 2;
}
}
static class ScriptFileViewHolder extends BindableViewHolder<ScriptFile> {
private static final DateFormat DATE_FORMAT = SimpleDateFormat.getDateTimeInstance();
@BindView(R.id.name)
TextView mName;
@BindView(R.id.first_char)
TextView mFirstChar;
@BindView(R.id.desc)
TextView mDesc;
GradientDrawable mFirstCharBackground;
public ScriptFileViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
mFirstCharBackground = (GradientDrawable) mFirstChar.getBackground();
}
@Override
public void bind(ScriptFile file, int position) {
mName.setText(file.getSimplifiedName());
mDesc.setText(PFile.getHumanReadableSize(file.length()));
if (file.getType() == ScriptFile.TYPE_JAVA_SCRIPT) {
mFirstChar.setText("J");
//什么?裸写颜色代码?!不影响代码可读性和重构成本的情况下,这样子修改起来方便多啦
mFirstCharBackground.setColor(0xFF99CC99);
} else {
mFirstChar.setText("R");
mFirstCharBackground.setColor(0xFFFD999A);
}
}
}
static class DirectoryViewHolder extends BindableViewHolder<ScriptFile> {
@BindView(R.id.name)
TextView mName;
public DirectoryViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
@Override
public void bind(ScriptFile data, int position) {
mName.setText(data.getSimplifiedName());
}
}
static class CategoryViewHolder extends BindableViewHolder<Boolean> {
@BindView(R.id.title)
TextView mTitle;
public CategoryViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
@Override
public void bind(Boolean isDirCategory, int position) {
mTitle.setText(isDirCategory ? R.string.text_directory : R.string.text_file);
}
}
}

View File

@@ -0,0 +1,280 @@
package com.stardust.scriptdroid.ui.main.script_list;
import android.content.Context;
import android.graphics.drawable.GradientDrawable;
import android.support.annotation.Nullable;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.stardust.pio.PFile;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.script.ScriptFile;
import com.stardust.scriptdroid.script.Scripts;
import com.stardust.scriptdroid.script.StorageFileProvider;
import com.stardust.scriptdroid.tool.SimpleObserver;
import com.stardust.widget.BindableViewHolder;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
/**
* Created by Stardust on 2017/8/21.
*/
public class ScriptListView extends SwipeRefreshLayout implements SwipeRefreshLayout.OnRefreshListener {
public interface OnScriptFileClickListener {
void onScriptFileClick(View view, ScriptFile file);
}
private RecyclerView mScriptListView;
private ScriptListAdapter mScriptListAdapter = new ScriptListAdapter();
private ArrayList<ScriptFile> mScriptFiles = new ArrayList<>();
private ArrayList<ScriptFile> mDirectories = new ArrayList<>();
private ScriptFile mCurrentDirectory;
private OnScriptFileClickListener mOnScriptFileClickListener;
public ScriptListView(Context context) {
super(context);
init();
}
public ScriptListView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public ScriptFile getCurrentDirectory() {
return mCurrentDirectory;
}
public void setCurrentDirectory(ScriptFile currentDirectory) {
mCurrentDirectory = currentDirectory;
loadScriptList();
}
public void setOnScriptFileClickListener(OnScriptFileClickListener onScriptFileClickListener) {
mOnScriptFileClickListener = onScriptFileClickListener;
}
private void init() {
setOnRefreshListener(this);
mScriptListView = new RecyclerView(getContext());
addView(mScriptListView);
initScriptListRecyclerView();
setCurrentDirectory(StorageFileProvider.getDefault().getInitialDirectory());
}
private void initScriptListRecyclerView() {
mScriptListView.setAdapter(mScriptListAdapter);
GridLayoutManager manager = new GridLayoutManager(getContext(), 2);
manager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
//For directories
if (position >= 1 && position <= mDirectories.size()) {
return 1;
}
//For files and category
return 2;
}
});
mScriptListView.setLayoutManager(manager);
}
private void loadScriptList() {
mScriptFiles.clear();
mDirectories.clear();
StorageFileProvider.getDefault().getDirectoryScriptFiles(mCurrentDirectory)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new SimpleObserver<ScriptFile>() {
@Override
public void onNext(@io.reactivex.annotations.NonNull ScriptFile file) {
if (file.isFile()) {
mScriptFiles.add(file);
} else {
mDirectories.add(file);
}
}
@Override
public void onComplete() {
mScriptListAdapter.notifyDataSetChanged();
setRefreshing(false);
}
});
}
@Override
public void onRefresh() {
loadScriptList();
}
private class ScriptListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final int VIEW_TYPE_FILE = 0;
private final int VIEW_TYPE_DIRECTORY = 1;
//category是类别也即"文件", "文件夹"那两个
private final int VIEW_TYPE_CATEGORY = 2;
@Override
public RecyclerView.ViewHolder 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));
}
}
@SuppressWarnings("unchecked")
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
BindableViewHolder bindableViewHolder = (BindableViewHolder) holder;
if (position == 0 || position == mDirectories.size() + 1) {
bindableViewHolder.bind(position == 0, position);
return;
}
if (position <= mDirectories.size()) {
bindableViewHolder.bind(mDirectories.get(position - 1), position);
return;
}
bindableViewHolder.bind(mScriptFiles.get(position - mDirectories.size() - 2), position);
}
@Override
public int getItemViewType(int position) {
if (position == 0 || position == mDirectories.size() + 1) {
return VIEW_TYPE_CATEGORY;
}
if (position <= mDirectories.size()) {
return VIEW_TYPE_DIRECTORY;
}
return VIEW_TYPE_FILE;
}
@Override
public int getItemCount() {
return mScriptFiles.size() + mDirectories.size() + 2;
}
}
class ScriptFileViewHolder extends BindableViewHolder<ScriptFile> {
@BindView(R.id.name)
TextView mName;
@BindView(R.id.first_char)
TextView mFirstChar;
@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(PFile.getHumanReadableSize(file.length()));
if (file.getType() == ScriptFile.TYPE_JAVA_SCRIPT) {
mFirstChar.setText("J");
//什么?裸写颜色代码?!不影响代码可读性和重构成本的情况下,这样子修改起来方便多啦
mFirstCharBackground.setColor(0xFF99CC99);
} else {
mFirstChar.setText("R");
mFirstCharBackground.setColor(0xFFFD999A);
}
}
@OnClick(R.id.item)
void onItemClick() {
if(mOnScriptFileClickListener != null){
mOnScriptFileClickListener.onScriptFileClick(itemView, mScriptFile);
}
}
@OnClick(R.id.run)
void run() {
Scripts.run(mScriptFile);
}
@OnClick(R.id.edit)
void edit() {
Scripts.edit(mScriptFile);
}
@OnClick(R.id.more)
void showOptionMenu() {
}
}
class DirectoryViewHolder extends BindableViewHolder<ScriptFile> {
@BindView(R.id.name)
TextView mName;
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;
}
@OnClick(R.id.item)
void onItemClick() {
setCurrentDirectory(mScriptFile);
}
@OnClick(R.id.more)
void showOptionMenu() {
}
}
class CategoryViewHolder extends BindableViewHolder<Boolean> {
@BindView(R.id.title)
TextView mTitle;
CategoryViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
@Override
public void bind(Boolean isDirCategory, int position) {
mTitle.setText(isDirCategory ? R.string.text_directory : R.string.text_file);
}
}
}

View File

@@ -0,0 +1,86 @@
package com.stardust.widget;
import android.app.Activity;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.support.annotation.IntDef;
import android.support.annotation.Nullable;
import android.support.design.widget.AppBarLayout;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.Window;
import com.stardust.util.ViewUtil;
/**
* Created by Stardust on 2017/8/22.
*/
public class AppWithStatusBarLayout extends AppBarLayout {
public AppWithStatusBarLayout(Context context) {
super(context);
}
public AppWithStatusBarLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onWindowVisibilityChanged(int visibility) {
super.onWindowVisibilityChanged(visibility);
if (visibility == VISIBLE) {
setPadding();
}
}
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
setPadding();
}
private void setPadding() {
getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
setPadding(getPaddingLeft(), getStatusBarHeight(), getPaddingRight(), getPaddingBottom());
getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
}
private int getStatusBarHeight() {
Rect rect = new Rect();
Window window = getWindow();
if (window == null) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 24, getResources().getDisplayMetrics());
}
window.getDecorView().getWindowVisibleDisplayFrame(rect);
return rect.top;
}
@Nullable
private Window getWindow() {
return getWindowForContext(getContext());
}
@Nullable
private Window getWindowForContext(Context context) {
if (context instanceof Activity) {
return ((Activity) context).getWindow();
}
if (context instanceof ContextWrapper) {
return getWindowForContext(((ContextWrapper) context).getBaseContext());
}
return null;
}
}

View File

@@ -0,0 +1,109 @@
package com.stardust.widget;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.support.v4.widget.SwipeRefreshLayout;
import android.util.AttributeSet;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceRequest;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.FrameLayout;
import android.widget.ProgressBar;
import com.stardust.scriptdroid.R;
import org.androidannotations.annotations.ViewById;
/**
* Created by Stardust on 2017/8/22.
*/
public class EWebView extends FrameLayout implements SwipeRefreshLayout.OnRefreshListener {
private WebView mWebView;
private ProgressBar mProgressBar;
SwipeRefreshLayout mSwipeRefreshLayout;
public EWebView(Context context) {
super(context);
init();
}
public EWebView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
inflate(getContext(), R.layout.ewebview, this);
mWebView = (WebView) findViewById(R.id.web_view);
mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);
mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh_layout);
mSwipeRefreshLayout.setOnRefreshListener(this);
setUpWebView();
}
private void setUpWebView() {
WebSettings settings = mWebView.getSettings();
settings.setUseWideViewPort(true);
settings.setBuiltInZoomControls(true);
settings.setSupportZoom(true);
settings.setLoadWithOverviewMode(true);
settings.setJavaScriptEnabled(true);
mWebView.setWebViewClient(new MyWebViewClient());
mWebView.setWebChromeClient(new MyWebChromeClient());
}
public WebView getWebView() {
return mWebView;
}
@Override
public void onRefresh() {
mWebView.reload();
}
private class MyWebChromeClient extends WebChromeClient {
@Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
mProgressBar.setProgress(newProgress);
}
}
private class MyWebViewClient extends WebViewClient {
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
mProgressBar.setProgress(0);
mProgressBar.setVisibility(VISIBLE);
}
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
mProgressBar.setVisibility(GONE);
mSwipeRefreshLayout.setRefreshing(false);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
view.loadUrl(request.getUrl().toString());
return true;
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
}
}

View File

@@ -12,11 +12,10 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
<com.stardust.widget.AppWithStatusBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#5cab7d"
android:paddingTop="24px"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
@@ -34,7 +33,7 @@
app:tabGravity="fill"
app:tabIndicatorColor="@android:color/white"
app:tabMode="scrollable"/>
</android.support.design.widget.AppBarLayout>
</com.stardust.widget.AppWithStatusBarLayout>
<android.support.v4.view.ViewPager

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<WebView
android:id="@+id/web_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</android.support.v4.widget.SwipeRefreshLayout>
<ProgressBar
android:id="@+id/progress_bar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="2dp"
android:visibility="gone"/>
</merge>

View File

@@ -1,14 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
<com.stardust.scriptdroid.ui.main.script_list.ScriptListView
android:id="@+id/script_file_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</android.support.v4.widget.SwipeRefreshLayout>
</FrameLayout>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<com.stardust.widget.EWebView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/eweb_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>

View File

@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffffff"
android:orientation="vertical"
tools:showIn="@layout/activity_edit">
<com.jecelyin.editor.v2.view.EditorView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/editor"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<com.jecelyin.editor.v2.core.widget.JecEditText
android:id="@+id/edit_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffffff"
android:enabled="true"
android:gravity="start|top"
android:inputType="textMultiLine"
android:padding="5dp"
android:scrollbarThumbVertical="@android:color/transparent"
android:scrollbarTrackVertical="@null"
android:scrollbars="vertical"/>
<me.zhanghai.android.materialprogressbar.MaterialProgressBar
android:id="@+id/progress_view"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_centerHorizontal="true"
android:layout_marginTop="90dp"
android:indeterminate="true"
android:visibility="gone"/>
<com.stardust.scriptdroid.ui.edit.completion.InputMethodEnhanceBar
android:id="@+id/input_method_enhance_bar"
android:layout_width="match_parent"
android:layout_height="35dp"
android:layout_alignParentBottom="true"
android:background="#e7ebec"/>
</com.jecelyin.editor.v2.view.EditorView>
</LinearLayout>

View File

@@ -5,10 +5,10 @@
android:id="@+id/item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
android:clickable="true"
android:foreground="?selectableItemBackground"
android:paddingLeft="6dp"
android:paddingRight="6dp"
app:cardBackgroundColor="#ffffff"
app:cardElevation="1dp"
app:cardUseCompatPadding="true">
@@ -27,7 +27,7 @@
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:src="@drawable/ic_folder_yellow_100px"
android:tint="#ffde69"/>
android:tint="#ffda93"/>
<TextView
android:id="@+id/name"
@@ -44,6 +44,7 @@
<ImageView
android:id="@+id/more"
android:layout_width="52dp"
android:layout_height="20dp"
android:layout_gravity="center_vertical"

View File

@@ -11,6 +11,7 @@
android:background="#EDEEEF"/>
<LinearLayout
android:id="@+id/item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white"
@@ -59,10 +60,9 @@
android:ellipsize="end"
android:gravity="center_vertical"
android:maxLines="1"
android:text="2017年2月3日11:56"
android:textColor="#9DA0A2"
android:textSize="11sp"
tools:text="正在运行的服务"/>
tools:text="18 KB"/>
</LinearLayout>
@@ -85,6 +85,7 @@
android:tint="#A9AAAB"/>
<ImageView
android:id="@+id/edit"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
@@ -96,6 +97,7 @@
android:tint="#A9AAAB"/>
<ImageView
android:id="@+id/more"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"

View File

@@ -229,6 +229,10 @@
<string name="text_enable_observe_key">启用按键监听</string>
<string name="text_directory">文件夹</string>
<string name="text_file">文件</string>
<string name="text_tutorial">教程</string>
<string name="text_script">脚本</string>
<string name="text_community">社区</string>
<string name="text_manage">管理</string>
<string-array name="record_control_keys">