new editor!! Code mirror editor~
This commit is contained in:
@@ -9,8 +9,8 @@ import android.widget.CompoundButton;
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder;
|
||||
import com.stardust.util.HashUtils;
|
||||
|
||||
import static com.jecelyin.common.utils.StringUtils.md5;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/30.
|
||||
@@ -64,7 +64,7 @@ public class NotAskAgainDialog extends MaterialDialog {
|
||||
|
||||
private void generatePreferenceKeyIfNeeded() {
|
||||
if (mKeyRemind == null)
|
||||
mKeyRemind = md5(TextUtils.join("", Thread.currentThread().getStackTrace()));
|
||||
mKeyRemind = HashUtils.md5(TextUtils.join("", Thread.currentThread().getStackTrace()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,24 +4,15 @@ import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.jecelyin.editor.v2.common.Command;
|
||||
import com.jecelyin.editor.v2.ui.EditorDelegate;
|
||||
import com.jecelyin.editor.v2.view.EditorView;
|
||||
import com.jecelyin.editor.v2.view.menu.MenuDef;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.ui.BaseActivity;
|
||||
import com.stardust.scriptdroid.ui.edit.EditActivity;
|
||||
import com.stardust.scriptdroid.ui.edit.completion.InputMethodEnhanceBar;
|
||||
import com.stardust.scriptdroid.ui.edit.editor920.Editor920Activity;
|
||||
import com.stardust.scriptdroid.ui.edit.editor920.Editor920Utils;
|
||||
import com.stardust.theme.ThemeColorManager;
|
||||
import com.stardust.theme.ThemeColorManagerCompat;
|
||||
import com.stardust.widget.ToolbarMenuItem;
|
||||
|
||||
import org.androidannotations.annotations.AfterViews;
|
||||
import org.androidannotations.annotations.Click;
|
||||
import org.androidannotations.annotations.EActivity;
|
||||
import org.androidannotations.annotations.ViewById;
|
||||
|
||||
@@ -29,7 +20,7 @@ import org.androidannotations.annotations.ViewById;
|
||||
* Created by Stardust on 2017/4/5.
|
||||
*/
|
||||
@EActivity(R.layout.activity_tasker_script_edit)
|
||||
public class TaskerScriptEditActivity extends Editor920Activity {
|
||||
public class TaskerScriptEditActivity extends AppCompatActivity {
|
||||
|
||||
public static final int REQUEST_CODE = "Love you. Can we go back?".hashCode() >> 16;
|
||||
public static final String EXTRA_CONTENT = "Still Love Eating 17.4.5";
|
||||
@@ -41,7 +32,6 @@ public class TaskerScriptEditActivity extends Editor920Activity {
|
||||
.putExtra("title", title), REQUEST_CODE);
|
||||
}
|
||||
|
||||
private EditorDelegate mEditorDelegate;
|
||||
private String mTitle, mSummary;
|
||||
@ViewById(R.id.redo)
|
||||
ToolbarMenuItem mRedo;
|
||||
@@ -51,7 +41,7 @@ public class TaskerScriptEditActivity extends Editor920Activity {
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setTheme(R.style.EditorTheme);
|
||||
// setTheme(R.style.EditorTheme);
|
||||
handleIntent(getIntent());
|
||||
}
|
||||
|
||||
@@ -67,46 +57,18 @@ public class TaskerScriptEditActivity extends Editor920Activity {
|
||||
mTitle = intent.getStringExtra("title");
|
||||
mSummary = intent.getStringExtra("summary");
|
||||
String content = intent.getStringExtra(EXTRA_CONTENT);
|
||||
mEditorDelegate = new EditorDelegate(0, mTitle, content);
|
||||
}
|
||||
|
||||
private void setUpEditor() {
|
||||
final EditorView editorView = (EditorView) findViewById(R.id.editor);
|
||||
mEditorDelegate.setEditorView(editorView);
|
||||
Editor920Utils.setLang(mEditorDelegate, "JavaScript");
|
||||
editorView.getEditText().setHorizontallyScrolling(true);
|
||||
setUpInputMethodEnhanceBar(editorView);
|
||||
}
|
||||
|
||||
private void setUpInputMethodEnhanceBar(final EditorView editorView) {
|
||||
InputMethodEnhanceBar inputMethodEnhanceBar = (InputMethodEnhanceBar) findViewById(R.id.input_method_enhance_bar);
|
||||
inputMethodEnhanceBar.setEditTextBridge(new EditActivity.InputMethodEnhanceBarBridge(this, editorView.getEditText()));
|
||||
}
|
||||
|
||||
@Click(R.id.undo)
|
||||
void undo() {
|
||||
Command command = new Command(Command.CommandEnum.UNDO);
|
||||
mEditorDelegate.doCommand(command);
|
||||
}
|
||||
|
||||
@Click(R.id.redo)
|
||||
void redo() {
|
||||
Command command = new Command(Command.CommandEnum.REDO);
|
||||
mEditorDelegate.doCommand(command);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
setResult(RESULT_OK, new Intent().putExtra(EXTRA_CONTENT, mEditorDelegate.getText()));
|
||||
super.finish();
|
||||
}
|
||||
|
||||
public void setMenuStatus(int menuResId, int status) {
|
||||
boolean disabled = status == MenuDef.STATUS_DISABLED;
|
||||
if (menuResId == com.jecelyin.editor.v2.R.id.m_redo) {
|
||||
mRedo.setEnabled(!disabled);
|
||||
} else if (menuResId == com.jecelyin.editor.v2.R.id.m_undo) {
|
||||
mUndo.setEnabled(!disabled);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
package com.stardust.scriptdroid.ui.edit;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.webkit.JavascriptInterface;
|
||||
import android.webkit.WebChromeClient;
|
||||
import android.webkit.WebSettings;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ScrollView;
|
||||
|
||||
import com.stardust.pio.PFile;
|
||||
|
||||
import org.apache.commons.lang3.StringEscapeUtils;
|
||||
import org.jdeferred.Deferred;
|
||||
import org.jdeferred.DoneCallback;
|
||||
import org.jdeferred.impl.DeferredObject;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.subjects.PublishSubject;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/9/27.
|
||||
*/
|
||||
|
||||
public class CodeMirrorEditor extends FrameLayout {
|
||||
|
||||
|
||||
private static String[] sAvailableThemes;
|
||||
private String mTheme = "neo";
|
||||
|
||||
public interface Callback {
|
||||
void onChange();
|
||||
|
||||
void updateCodeCompletion(int fromLine, int fromCh, int toLine, int toCh, String[] list);
|
||||
}
|
||||
|
||||
private WebView mWebView;
|
||||
private JavaScriptBridge mJavaScriptBridge = new JavaScriptBridge();
|
||||
private Callback mCallback;
|
||||
private Deferred<Void, Void, Void> mPageFinished = new DeferredObject<>();
|
||||
|
||||
public CodeMirrorEditor(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public CodeMirrorEditor(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public CodeMirrorEditor(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init();
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
public CodeMirrorEditor(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
init();
|
||||
}
|
||||
|
||||
public void setCallback(Callback callback) {
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
public void beautifyCode() {
|
||||
evalJavaScript("editor.setValue(js_beautify(editor.getValue()));");
|
||||
}
|
||||
|
||||
public String[] getAvailableThemes() {
|
||||
if (sAvailableThemes == null) {
|
||||
try {
|
||||
sAvailableThemes = getResources().getAssets().list("editor/codemirror/theme");
|
||||
for (int i = 0; i < sAvailableThemes.length; i++) {
|
||||
sAvailableThemes[i] = PFile.getNameWithoutExtension(sAvailableThemes[i]);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
return sAvailableThemes;
|
||||
}
|
||||
|
||||
|
||||
public String getTheme() {
|
||||
return mTheme;
|
||||
}
|
||||
|
||||
public void setTheme(final String theme) {
|
||||
mPageFinished.promise().done(new DoneCallback<Void>() {
|
||||
@Override
|
||||
public void onDone(Void result) {
|
||||
evalJavaScript(String.format(Locale.getDefault(),
|
||||
"var e = document.createElement('link');e.setAttribute('rel', 'stylesheet');" +
|
||||
"e.setAttribute('type', 'text/css');e.setAttribute('href', '%s');" +
|
||||
"document.getElementsByTagName('head')[0].appendChild(e);",
|
||||
"codemirror/theme/" + theme + ".css"));
|
||||
evalJavaScript(String.format(Locale.getDefault(), "editor.setOption('theme', '%s');", theme));
|
||||
mTheme = theme;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private void init() {
|
||||
setupWebView();
|
||||
mWebView.loadUrl("file:///android_asset/editor/index.html");
|
||||
}
|
||||
|
||||
private void setupWebView() {
|
||||
mWebView = new WebView(getContext());
|
||||
setupWebSettings();
|
||||
mWebView.addJavascriptInterface(mJavaScriptBridge, "__bridge__");
|
||||
addView(mWebView);
|
||||
}
|
||||
|
||||
private void setupWebSettings() {
|
||||
WebSettings settings = mWebView.getSettings();
|
||||
settings.setUseWideViewPort(true);
|
||||
settings.setBuiltInZoomControls(true);
|
||||
settings.setLoadWithOverviewMode(true);
|
||||
settings.setJavaScriptEnabled(true);
|
||||
settings.setUseWideViewPort(true);
|
||||
settings.setJavaScriptCanOpenWindowsAutomatically(true);
|
||||
settings.setDomStorageEnabled(true);
|
||||
settings.setNeedInitialFocus(true);
|
||||
settings.setDisplayZoomControls(false);
|
||||
mWebView.setWebViewClient(new MyWebViewClient());
|
||||
mWebView.setWebChromeClient(new WebChromeClient());
|
||||
}
|
||||
|
||||
public void setText(final String text) {
|
||||
mPageFinished.promise().done(new DoneCallback<Void>() {
|
||||
@Override
|
||||
public void onDone(Void result) {
|
||||
String escapedString = StringEscapeUtils.escapeEcmaScript(text);
|
||||
evalJavaScript("editor.setValue('" + escapedString + "');");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Observable<String> getText() {
|
||||
mJavaScriptBridge.mText = PublishSubject.create();
|
||||
evalJavaScript("__bridge__.setText(editor.getValue());");
|
||||
return mJavaScriptBridge.mText;
|
||||
}
|
||||
|
||||
|
||||
public void undo() {
|
||||
evalJavaScript("editor.undo();");
|
||||
}
|
||||
|
||||
public void redo() {
|
||||
evalJavaScript("editor.redo();");
|
||||
}
|
||||
|
||||
private void evalJavaScript(String script) {
|
||||
mWebView.loadUrl("javascript:" + script);
|
||||
}
|
||||
|
||||
public void replace(String text, int fromLine, int fromCh, int toLine, int toCh) {
|
||||
String js = "editor.replaceRange('%s', {line: %d, ch: %d}, {line: %d, ch: %d})";
|
||||
evalJavaScript(String.format(Locale.getDefault(), js, text, fromLine, fromCh, toLine, toCh));
|
||||
}
|
||||
|
||||
public class JavaScriptBridge {
|
||||
|
||||
private PublishSubject<String> mText;
|
||||
|
||||
@JavascriptInterface
|
||||
public void setText(String text) {
|
||||
if (mText != null) {
|
||||
mText.onNext(text);
|
||||
mText.onComplete();
|
||||
mText = null;
|
||||
}
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
public void onChange() {
|
||||
if (mCallback != null) {
|
||||
mWebView.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mCallback.onChange();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
public void updateCodeCompletion(final int fromLine, final int fromCh, final int toLine, final int toCh, final String[] list) {
|
||||
if (mCallback != null) {
|
||||
mWebView.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mCallback.updateCodeCompletion(fromLine, fromCh, toLine, toCh, list);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private class MyWebViewClient extends WebViewClient {
|
||||
|
||||
private final String INIT_SCRIPT = "editor.on('change', function(){__bridge__.onChange();});";
|
||||
|
||||
@Override
|
||||
public void onPageFinished(WebView view, String url) {
|
||||
super.onPageFinished(view, url);
|
||||
mPageFinished.resolve(null);
|
||||
evalJavaScript(INIT_SCRIPT);
|
||||
// evalJavaScript("editor.setSize(" + mWebView.getMeasuredWidth() + ", " + mWebView.getMeasuredHeight() + ");");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,42 +5,33 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.util.SparseArray;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.afollestad.materialdialogs.DialogAction;
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.jecelyin.editor.v2.common.Command;
|
||||
import com.jecelyin.editor.v2.common.SaveListener;
|
||||
import com.jecelyin.editor.v2.core.widget.TextView;
|
||||
import com.jecelyin.editor.v2.ui.EditorDelegate;
|
||||
import com.jecelyin.editor.v2.view.EditorView;
|
||||
import com.jecelyin.editor.v2.view.menu.MenuDef;
|
||||
import com.stardust.app.OnActivityResultDelegate;
|
||||
import com.stardust.autojs.engine.JavaScriptEngine;
|
||||
import com.stardust.autojs.execution.ScriptExecution;
|
||||
import com.stardust.autojs.script.JavaScriptFileSource;
|
||||
import com.stardust.autojs.script.JsBeautifier;
|
||||
import com.stardust.pio.PFile;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.autojs.AutoJs;
|
||||
import com.stardust.scriptdroid.script.ScriptFile;
|
||||
import com.stardust.scriptdroid.script.Scripts;
|
||||
import com.stardust.scriptdroid.tool.JsBeautifierFactory;
|
||||
import com.stardust.scriptdroid.tool.MaterialDialogFactory;
|
||||
import com.stardust.scriptdroid.ui.BaseActivity;
|
||||
import com.stardust.scriptdroid.ui.edit.completion.CodeCompletions;
|
||||
import com.stardust.scriptdroid.ui.edit.completion.InputMethodEnhanceBar;
|
||||
import com.stardust.scriptdroid.ui.edit.editor920.Editor920Activity;
|
||||
import com.stardust.scriptdroid.ui.edit.editor920.Editor920Utils;
|
||||
import com.stardust.scriptdroid.ui.help.HelpCatalogueActivity;
|
||||
import com.stardust.theme.ThemeColorManager;
|
||||
import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder;
|
||||
import com.stardust.util.SparseArrayEntries;
|
||||
import com.stardust.widget.ToolbarMenuItem;
|
||||
|
||||
import org.androidannotations.annotations.AfterViews;
|
||||
import org.androidannotations.annotations.Click;
|
||||
@@ -48,45 +39,62 @@ import org.androidannotations.annotations.EActivity;
|
||||
import org.androidannotations.annotations.ViewById;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.functions.Consumer;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/29.
|
||||
*/
|
||||
@EActivity(R.layout.activity_edit)
|
||||
public class EditActivity extends Editor920Activity implements OnActivityResultDelegate.DelegateHost {
|
||||
|
||||
|
||||
public static class InputMethodEnhanceBarBridge implements InputMethodEnhanceBar.EditTextBridge {
|
||||
|
||||
private Editor920Activity mEditor920Activity;
|
||||
private TextView mTextView;
|
||||
|
||||
public InputMethodEnhanceBarBridge(Editor920Activity editor920Activity, TextView textView) {
|
||||
mEditor920Activity = editor920Activity;
|
||||
mTextView = textView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendText(CharSequence text) {
|
||||
mEditor920Activity.insertText(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void backspace(int count) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextView getEditText() {
|
||||
return mTextView;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public class EditActivity extends AppCompatActivity implements OnActivityResultDelegate.DelegateHost {
|
||||
|
||||
public static final String EXTRA_PATH = "Still Love Eating 17.4.5";
|
||||
private static final String EXTRA_NAME = "Still love you 17.6.29 But....(ಥ_ಥ)";
|
||||
private static final String KEY_EDITOR_THEME = "I really really really really love you dee";
|
||||
|
||||
|
||||
@ViewById(R.id.content_view)
|
||||
View mView;
|
||||
|
||||
@ViewById(R.id.editor)
|
||||
CodeMirrorEditor mEditor;
|
||||
|
||||
@ViewById(R.id.input_method_enhance_bar)
|
||||
InputMethodEnhanceBar mInputMethodEnhanceBar;
|
||||
|
||||
private String mName;
|
||||
private File mFile;
|
||||
private boolean mReadOnly = false;
|
||||
private OnActivityResultDelegate.Mediator mActivityResultMediator = new OnActivityResultDelegate.Mediator();
|
||||
private BroadcastReceiver mOnRunFinishedReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (intent.getAction().equals(Scripts.ACTION_ON_EXECUTION_FINISHED)) {
|
||||
mScriptExecution = null;
|
||||
setMenuItemStatus(R.id.run, true);
|
||||
String msg = intent.getStringExtra(Scripts.EXTRA_EXCEPTION_MESSAGE);
|
||||
if (msg != null) {
|
||||
Snackbar.make(mView, getString(R.string.text_error) + ": " + msg, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
private ScriptExecution mScriptExecution;
|
||||
private boolean mTextChanged = false;
|
||||
|
||||
public void onCreate(Bundle b) {
|
||||
super.onCreate(b);
|
||||
registerReceiver(mOnRunFinishedReceiver, new IntentFilter(Scripts.ACTION_ON_EXECUTION_FINISHED));
|
||||
}
|
||||
|
||||
public static void editFile(Context context, String path) {
|
||||
editFile(context, null, path);
|
||||
@@ -103,43 +111,13 @@ public class EditActivity extends Editor920Activity implements OnActivityResultD
|
||||
editFile(context, file.getSimplifiedName(), file.getPath());
|
||||
}
|
||||
|
||||
@ViewById(R.id.content_view)
|
||||
View mView;
|
||||
private String mName;
|
||||
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() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (intent.getAction().equals(Scripts.ACTION_ON_EXECUTION_FINISHED)) {
|
||||
mScriptExecution = null;
|
||||
setMenuStatus(R.id.run, MenuDef.STATUS_NORMAL);
|
||||
String msg = intent.getStringExtra(Scripts.EXTRA_EXCEPTION_MESSAGE);
|
||||
if (msg != null) {
|
||||
Snackbar.make(mView, getString(R.string.text_error) + ": " + msg, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
private JsBeautifier mJsBeautifier = JsBeautifierFactory.getJsBeautify();
|
||||
private ScriptExecution mScriptExecution;
|
||||
|
||||
public void onCreate(Bundle b) {
|
||||
super.onCreate(b);
|
||||
setTheme(R.style.EditorTheme);
|
||||
handleIntent(getIntent());
|
||||
registerReceiver(mOnRunFinishedReceiver, new IntentFilter(Scripts.ACTION_ON_EXECUTION_FINISHED));
|
||||
}
|
||||
|
||||
@AfterViews
|
||||
void setUpViews() {
|
||||
ThemeColorManager.addActivityStatusBar(this);
|
||||
setUpToolbar();
|
||||
initMenuItem();
|
||||
setUpEditor();
|
||||
handleIntent(getIntent());
|
||||
setMenuItemStatus(R.id.save, false);
|
||||
}
|
||||
|
||||
private void handleIntent(Intent intent) {
|
||||
@@ -152,106 +130,102 @@ public class EditActivity extends Editor920Activity implements OnActivityResultD
|
||||
}
|
||||
String content = intent.getStringExtra("content");
|
||||
if (content != null) {
|
||||
mEditorDelegate = new EditorDelegate(0, mName, content);
|
||||
mEditor.setText(content);
|
||||
} else {
|
||||
mFile = new File(path);
|
||||
if (mName == null) {
|
||||
mName = mFile.getName();
|
||||
}
|
||||
mEditorDelegate = new EditorDelegate(0, mFile, 0, "utf-8");
|
||||
mEditor.setText(PFile.read(mFile));
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
mEditor.setTheme(PreferenceManager.getDefaultSharedPreferences(EditActivity.this)
|
||||
.getString(KEY_EDITOR_THEME, mEditor.getTheme()));
|
||||
mEditor.setCallback(new CodeMirrorEditor.Callback() {
|
||||
@Override
|
||||
public void onChange() {
|
||||
mTextChanged = true;
|
||||
setMenuItemStatus(R.id.save, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateCodeCompletion(int fromLine, int fromCh, int toLine, int toCh, final String[] list) {
|
||||
mInputMethodEnhanceBar.setCodeCompletions(new CodeCompletions(
|
||||
new CodeCompletions.Pos(fromLine, fromCh),
|
||||
new CodeCompletions.Pos(toLine, toCh),
|
||||
Arrays.asList(list)
|
||||
));
|
||||
}
|
||||
});
|
||||
mInputMethodEnhanceBar.setOnHintClickListener(new InputMethodEnhanceBar.OnHintClickListener() {
|
||||
@Override
|
||||
public void onHintClick(CodeCompletions completions, int pos) {
|
||||
mEditor.replace(completions.getHints().get(pos), completions.getFrom().line, completions.getFrom().ch,
|
||||
completions.getTo().line, completions.getTo().ch);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
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(this, editorView.getEditText()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void setUpToolbar() {
|
||||
BaseActivity.setToolbarAsBack(this, R.id.toolbar, mName);
|
||||
}
|
||||
|
||||
@Click(R.id.run)
|
||||
void runAndSaveFileIFNeeded() {
|
||||
if (!mReadOnly && mEditorDelegate.isChanged()) {
|
||||
saveFile(false, new SaveListener() {
|
||||
@Override
|
||||
public void onSaved() {
|
||||
run();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
run();
|
||||
}
|
||||
}
|
||||
|
||||
private void saveFile(boolean toast, SaveListener listener) {
|
||||
Command command = new Command(Command.CommandEnum.SAVE);
|
||||
command.args = new Bundle();
|
||||
command.args.putBoolean("is_cluster", !toast);
|
||||
command.object = listener;
|
||||
mEditorDelegate.doCommand(command);
|
||||
save().observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Consumer<String>() {
|
||||
@Override
|
||||
public void accept(@io.reactivex.annotations.NonNull String s) throws Exception {
|
||||
run();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void run() {
|
||||
Snackbar.make(mView, R.string.text_start_running, Snackbar.LENGTH_SHORT).show();
|
||||
setMenuStatus(R.id.run, MenuDef.STATUS_DISABLED);
|
||||
mScriptExecution = Scripts.runWithBroadcastSender(new JavaScriptFileSource(mName, mFile), mFile.getParent());
|
||||
setMenuItemStatus(R.id.run, false);
|
||||
}
|
||||
|
||||
|
||||
@Click(R.id.undo)
|
||||
void undo() {
|
||||
Command command = new Command(Command.CommandEnum.UNDO);
|
||||
mEditorDelegate.doCommand(command);
|
||||
mEditor.undo();
|
||||
}
|
||||
|
||||
@Click(R.id.redo)
|
||||
void redo() {
|
||||
Command command = new Command(Command.CommandEnum.REDO);
|
||||
mEditorDelegate.doCommand(command);
|
||||
mEditor.redo();
|
||||
}
|
||||
|
||||
public Observable<String> save() {
|
||||
return mEditor.getText()
|
||||
.observeOn(Schedulers.io())
|
||||
.doOnNext(new Consumer<String>() {
|
||||
@Override
|
||||
public void accept(@io.reactivex.annotations.NonNull String s) throws Exception {
|
||||
PFile.write(mFile, s);
|
||||
}
|
||||
})
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.doOnNext(new Consumer<String>() {
|
||||
@Override
|
||||
public void accept(@io.reactivex.annotations.NonNull String s) throws Exception {
|
||||
mTextChanged = false;
|
||||
setMenuItemStatus(R.id.save, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Click(R.id.save)
|
||||
void saveFile() {
|
||||
saveFile(false, null);
|
||||
save().subscribe();
|
||||
}
|
||||
|
||||
private void initMenuItem() {
|
||||
mMenuMap = new SparseArrayEntries<ToolbarMenuItem>()
|
||||
.entry(com.jecelyin.editor.v2.R.id.m_redo, (ToolbarMenuItem) findViewById(R.id.redo))
|
||||
.entry(com.jecelyin.editor.v2.R.id.m_undo, (ToolbarMenuItem) findViewById(R.id.undo))
|
||||
.entry(com.jecelyin.editor.v2.R.id.m_save, (ToolbarMenuItem) findViewById(R.id.save))
|
||||
.entry(R.id.run, (ToolbarMenuItem) findViewById(R.id.run))
|
||||
.sparseArray();
|
||||
}
|
||||
|
||||
public void setMenuStatus(int menuResId, int status) {
|
||||
ToolbarMenuItem menuItem = mMenuMap.get(menuResId);
|
||||
if (menuItem == null)
|
||||
return;
|
||||
boolean disabled = status == MenuDef.STATUS_DISABLED;
|
||||
menuItem.setEnabled(!disabled);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.menu_editor, menu);
|
||||
@@ -267,8 +241,8 @@ public class EditActivity extends Editor920Activity implements OnActivityResultD
|
||||
case R.id.action_log:
|
||||
showLog();
|
||||
return true;
|
||||
case R.id.action_help:
|
||||
HelpCatalogueActivity.showMainCatalogue(this);
|
||||
case R.id.action_editor_theme:
|
||||
selectEditorTheme();
|
||||
return true;
|
||||
case R.id.action_beautify:
|
||||
beautifyCode();
|
||||
@@ -283,6 +257,10 @@ public class EditActivity extends Editor920Activity implements OnActivityResultD
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private void setMenuItemStatus(int id, boolean enabled) {
|
||||
findViewById(id).setEnabled(enabled);
|
||||
}
|
||||
|
||||
private void showLog() {
|
||||
AutoJs.getInstance().getScriptEngineService().getGlobalConsole().show();
|
||||
}
|
||||
@@ -293,6 +271,26 @@ public class EditActivity extends Editor920Activity implements OnActivityResultD
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void selectEditorTheme() {
|
||||
String[] themes = mEditor.getAvailableThemes();
|
||||
int i = Arrays.asList(themes).indexOf(mEditor.getTheme());
|
||||
new MaterialDialog.Builder(this)
|
||||
.items((CharSequence[]) themes)
|
||||
.itemsCallbackSingleChoice(i, new MaterialDialog.ListCallbackSingleChoice() {
|
||||
@Override
|
||||
public boolean onSelection(MaterialDialog dialog, View itemView, int which, CharSequence text) {
|
||||
PreferenceManager.getDefaultSharedPreferences(EditActivity.this).edit()
|
||||
.putString(KEY_EDITOR_THEME, text.toString())
|
||||
.apply();
|
||||
mEditor.setTheme(text.toString());
|
||||
return true;
|
||||
}
|
||||
})
|
||||
.show();
|
||||
}
|
||||
|
||||
|
||||
private void forceStop() {
|
||||
if (mScriptExecution != null) {
|
||||
mScriptExecution.getEngine().forceStop();
|
||||
@@ -305,43 +303,18 @@ public class EditActivity extends Editor920Activity implements OnActivityResultD
|
||||
}
|
||||
|
||||
private void beautifyCode() {
|
||||
final MaterialDialog dialog = MaterialDialogFactory.showProgress(this);
|
||||
mJsBeautifier.beautify(mEditorDelegate.getText(), new JsBeautifier.Callback() {
|
||||
@Override
|
||||
public void onSuccess(final String beautifiedCode) {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mEditorDelegate.mEditText.setText(beautifiedCode);
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onException(final Exception e) {
|
||||
e.printStackTrace();
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
dialog.dismiss();
|
||||
Toast.makeText(EditActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
mEditor.beautifyCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
if (!mReadOnly && mEditorDelegate.isChanged()) {
|
||||
if (mTextChanged) {
|
||||
showExitConfirmDialog();
|
||||
} else {
|
||||
super.finish();
|
||||
return;
|
||||
}
|
||||
super.finish();
|
||||
}
|
||||
|
||||
|
||||
private void showExitConfirmDialog() {
|
||||
new ThemeColorMaterialDialogBuilder(this)
|
||||
.title(R.string.text_alert)
|
||||
@@ -352,7 +325,7 @@ public class EditActivity extends Editor920Activity implements OnActivityResultD
|
||||
.onNegative(new MaterialDialog.SingleButtonCallback() {
|
||||
@Override
|
||||
public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
|
||||
saveFile(true, null);
|
||||
saveFile();
|
||||
EditActivity.super.finish();
|
||||
}
|
||||
})
|
||||
@@ -376,11 +349,6 @@ public class EditActivity extends Editor920Activity implements OnActivityResultD
|
||||
return mActivityResultMediator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doCommand(Command command) {
|
||||
mEditorDelegate.doCommand(command);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
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()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -6,34 +6,26 @@ import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Bundle;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.util.SparseArray;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
||||
import com.jecelyin.editor.v2.common.Command;
|
||||
import com.jecelyin.editor.v2.ui.EditorDelegate;
|
||||
import com.jecelyin.editor.v2.view.EditorView;
|
||||
import com.jecelyin.editor.v2.view.menu.MenuDef;
|
||||
import com.stardust.app.OnActivityResultDelegate;
|
||||
import com.stardust.autojs.engine.JavaScriptEngine;
|
||||
import com.stardust.autojs.execution.ScriptExecution;
|
||||
import com.stardust.autojs.script.StringScriptSource;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.autojs.AutoJs;
|
||||
import com.stardust.scriptdroid.script.Scripts;
|
||||
import com.stardust.scriptdroid.script.sample.Sample;
|
||||
import com.stardust.scriptdroid.ui.BaseActivity;
|
||||
import com.stardust.scriptdroid.ui.common.ScriptOperations;
|
||||
import com.stardust.scriptdroid.ui.edit.editor920.Editor920Activity;
|
||||
import com.stardust.scriptdroid.ui.edit.editor920.Editor920Utils;
|
||||
import com.stardust.scriptdroid.ui.help.HelpCatalogueActivity;
|
||||
import com.stardust.theme.ThemeColorManager;
|
||||
import com.stardust.util.AssetsCache;
|
||||
import com.stardust.util.SparseArrayEntries;
|
||||
import com.stardust.widget.ToolbarMenuItem;
|
||||
|
||||
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.OnClick;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
@@ -47,7 +39,7 @@ import static com.stardust.scriptdroid.script.Scripts.EXTRA_EXCEPTION_MESSAGE;
|
||||
/**
|
||||
* Created by Stardust on 2017/4/29.
|
||||
*/
|
||||
public class ViewSampleActivity extends Editor920Activity implements OnActivityResultDelegate.DelegateHost {
|
||||
public class ViewSampleActivity extends AppCompatActivity implements OnActivityResultDelegate.DelegateHost {
|
||||
|
||||
|
||||
public static void view(Context context, Sample sample) {
|
||||
@@ -59,7 +51,6 @@ public class ViewSampleActivity extends Editor920Activity implements OnActivityR
|
||||
private View mView;
|
||||
private Sample mSample;
|
||||
private ScriptExecution mScriptExecution;
|
||||
private EditorDelegate mEditorDelegate;
|
||||
private SparseArray<ToolbarMenuItem> mMenuMap;
|
||||
private OnActivityResultDelegate.Mediator mMediator = new OnActivityResultDelegate.Mediator();
|
||||
private BroadcastReceiver mOnRunFinishedReceiver = new BroadcastReceiver() {
|
||||
@@ -67,7 +58,6 @@ public class ViewSampleActivity extends Editor920Activity implements OnActivityR
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (intent.getAction().equals(ACTION_ON_EXECUTION_FINISHED)) {
|
||||
mScriptExecution = null;
|
||||
setMenuStatus(R.id.run, MenuDef.STATUS_NORMAL);
|
||||
String msg = intent.getStringExtra(EXTRA_EXCEPTION_MESSAGE);
|
||||
if (msg != null) {
|
||||
Snackbar.make(mView, getString(R.string.text_error) + ": " + msg, Snackbar.LENGTH_LONG).show();
|
||||
@@ -78,7 +68,6 @@ public class ViewSampleActivity extends Editor920Activity implements OnActivityR
|
||||
|
||||
public void onCreate(Bundle b) {
|
||||
super.onCreate(b);
|
||||
setTheme(R.style.EditorTheme);
|
||||
mView = View.inflate(this, R.layout.activity_view_sample, null);
|
||||
setContentView(mView);
|
||||
handleIntent(getIntent());
|
||||
@@ -90,7 +79,6 @@ public class ViewSampleActivity extends Editor920Activity implements OnActivityR
|
||||
private void handleIntent(Intent intent) {
|
||||
mSample = (Sample) intent.getSerializableExtra("sample");
|
||||
String content = AssetsCache.get(this, mSample.path);
|
||||
mEditorDelegate = new EditorDelegate(0, mSample.name, content);
|
||||
}
|
||||
|
||||
private void setUpUI() {
|
||||
@@ -101,11 +89,7 @@ public class ViewSampleActivity extends Editor920Activity implements OnActivityR
|
||||
}
|
||||
|
||||
private void setUpEditor() {
|
||||
final EditorView editorView = (EditorView) findViewById(R.id.editor);
|
||||
mEditorDelegate.setEditorView(editorView);
|
||||
Editor920Utils.setLang(mEditorDelegate, "JavaScript");
|
||||
editorView.getEditText().setReadOnly(true);
|
||||
editorView.getEditText().setHorizontallyScrolling(true);
|
||||
|
||||
}
|
||||
|
||||
private void setUpToolbar() {
|
||||
@@ -115,8 +99,7 @@ public class ViewSampleActivity extends Editor920Activity implements OnActivityR
|
||||
@OnClick(R.id.run)
|
||||
void run() {
|
||||
Snackbar.make(mView, R.string.text_start_running, Snackbar.LENGTH_SHORT).show();
|
||||
setMenuStatus(R.id.run, MenuDef.STATUS_DISABLED);
|
||||
mScriptExecution = Scripts.runWithBroadcastSender(new StringScriptSource(mSample.name, mEditorDelegate.getText()));
|
||||
//mScriptExecution = Scripts.runWithBroadcastSender(new StringScriptSource(mSample.name, mEditorDelegate.getText()));
|
||||
}
|
||||
|
||||
@OnClick(R.id.edit)
|
||||
@@ -143,8 +126,6 @@ public class ViewSampleActivity extends Editor920Activity implements OnActivityR
|
||||
ToolbarMenuItem menuItem = mMenuMap.get(menuResId);
|
||||
if (menuItem == null)
|
||||
return;
|
||||
boolean disabled = status == MenuDef.STATUS_DISABLED;
|
||||
menuItem.setEnabled(!disabled);
|
||||
}
|
||||
|
||||
|
||||
@@ -186,11 +167,6 @@ public class ViewSampleActivity extends Editor920Activity implements OnActivityR
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doCommand(Command command) {
|
||||
mEditorDelegate.doCommand(command);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
@@ -1,221 +0,0 @@
|
||||
package com.stardust.scriptdroid.ui.edit.completion;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.text.Editable;
|
||||
import android.text.TextUtils;
|
||||
import android.text.TextWatcher;
|
||||
|
||||
import com.stardust.scriptdroid.Pref;
|
||||
import com.jecelyin.editor.v2.core.widget.TextView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/2/17.
|
||||
*/
|
||||
// TODO: 2017/8/1 refactor
|
||||
public class CodeCompletion implements TextWatcher {
|
||||
|
||||
|
||||
public static class CodeCompletionItem implements Comparable<CodeCompletionItem> {
|
||||
String mDisplayText, mAppendText;
|
||||
|
||||
CodeCompletionItem(String displayText, String appendText) {
|
||||
mDisplayText = displayText;
|
||||
mAppendText = appendText;
|
||||
}
|
||||
|
||||
CodeCompletionItem(String text) {
|
||||
this(text, text);
|
||||
}
|
||||
|
||||
public String getAppendText() {
|
||||
return mAppendText;
|
||||
}
|
||||
|
||||
public String getDisplayText() {
|
||||
return mDisplayText;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@NonNull CodeCompletionItem o) {
|
||||
return mDisplayText.compareTo(o.mDisplayText);
|
||||
}
|
||||
}
|
||||
|
||||
interface OnCodeCompletionChangeListener {
|
||||
void OnCodeCompletionChange(@NonNull Collection<CodeCompletionItem> list1, @NonNull Collection<CodeCompletionItem> list2);
|
||||
}
|
||||
|
||||
private static final String TAG = "CodeCompletion";
|
||||
|
||||
private OnCodeCompletionChangeListener mOnCodeCompletionChangeListener;
|
||||
private TextView mEditText;
|
||||
private static final List<String> KEYWORDS = Arrays.asList("arguments", "break", "case", "catch", "class", "continue", "default", "do", "else", "eval", "export", "false", "for", "function", "if", "import", "in", "int", "new", "null", "package", "return", "switch", "this", "throw", "throws", "true", "try", "typeof", "var", "volatile", "while", "with", "Array", "Date", "hasOwnProperty", "Infinity", "isFinite", "isNaN", "isPrototypeOf", "length", "Math", "NaN", "name", "Number", "Object", "prototype", "String", "toString", "undefined", "valueOf");
|
||||
private static final int KEY_WORD_LENGTH_MAX = 15;
|
||||
|
||||
|
||||
private List<String> mGlobal = Collections.emptyList();
|
||||
private Map<String, List<String>> mVariableProperties = new HashMap<>();
|
||||
|
||||
|
||||
public CodeCompletion(OnCodeCompletionChangeListener listener) {
|
||||
mOnCodeCompletionChangeListener = listener;
|
||||
}
|
||||
|
||||
public void setEditText(TextView editText) {
|
||||
mEditText = editText;
|
||||
mEditText.addTextChangedListener(this);
|
||||
}
|
||||
|
||||
public void setGlobal(List<String> functions) {
|
||||
mGlobal = functions;
|
||||
}
|
||||
|
||||
public void setVariableProperties(Map<String, List<String>> variableProperties) {
|
||||
mVariableProperties = variableProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
int position = mEditText.getSelectionStart();
|
||||
String[] str = parseWordBefore(s, position);
|
||||
if (str != null) {
|
||||
if (str[1] != null) {
|
||||
searchCodeCompletionForVariable(str[0], str[1]);
|
||||
} else {
|
||||
searchCodeCompletionForGlobal(str[0]);
|
||||
}
|
||||
} else {
|
||||
mOnCodeCompletionChangeListener.OnCodeCompletionChange(DEFAULT_CODE_COMPLETION_LIST, Collections.<CodeCompletionItem>emptyList());
|
||||
}
|
||||
}
|
||||
|
||||
private String[] parseWordBefore(Editable s, int position) {
|
||||
if (position == 0)
|
||||
return null;
|
||||
int i;
|
||||
for (i = position - 1; i >= 0; i--) {
|
||||
if (position - i > KEY_WORD_LENGTH_MAX) {
|
||||
return null;
|
||||
}
|
||||
char c = s.charAt(i);
|
||||
if (c == '.') {
|
||||
return new String[]{parseWordBeforeDot(s, i), s.subSequence(i + 1, position).toString()};
|
||||
}
|
||||
if (!Character.isLetter(s.charAt(i))) {
|
||||
if (i < position - 1) {
|
||||
return new String[]{s.subSequence(i + 1, position).toString(), null};
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return new String[]{s.subSequence(0, position).toString(), null};
|
||||
}
|
||||
|
||||
private String parseWordBeforeDot(Editable s, int position) {
|
||||
if (position == 0)
|
||||
return null;
|
||||
int i;
|
||||
for (i = position - 1; i >= 0; i--) {
|
||||
if (position - i > KEY_WORD_LENGTH_MAX) {
|
||||
return null;
|
||||
}
|
||||
if (!Character.isLetter(s.charAt(i))) {
|
||||
if (i < position - 1) {
|
||||
return s.subSequence(i + 1, position).toString();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return s.subSequence(0, position).toString();
|
||||
}
|
||||
|
||||
|
||||
private boolean searchCodeCompletionForGlobal(String str) {
|
||||
Collection<CodeCompletionItem> c = searchWordCompletion(str);
|
||||
c.addAll(searchCodeCompletion(str, mGlobal));
|
||||
c.addAll(searchKeyWordCompletion(str));
|
||||
if (c.size() > 0) {
|
||||
mOnCodeCompletionChangeListener.OnCodeCompletionChange(c, DEFAULT_CODE_COMPLETION_LIST);
|
||||
return true;
|
||||
} else {
|
||||
mOnCodeCompletionChangeListener.OnCodeCompletionChange(DEFAULT_CODE_COMPLETION_LIST, Collections.<CodeCompletionItem>emptyList());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean searchCodeCompletionForVariable(String variable, String str) {
|
||||
List<String> properties = getPropertiesForVariable(variable);
|
||||
Collection<CodeCompletionItem> c = searchCodeCompletion(str, properties);
|
||||
if (c.isEmpty()) {
|
||||
mOnCodeCompletionChangeListener.OnCodeCompletionChange(DEFAULT_CODE_COMPLETION_LIST, Collections.<CodeCompletionItem>emptyList());
|
||||
return false;
|
||||
} else {
|
||||
mOnCodeCompletionChangeListener.OnCodeCompletionChange(c, Collections.<CodeCompletionItem>emptyList());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> getPropertiesForVariable(String str) {
|
||||
List<String> properties = mVariableProperties.get(str);
|
||||
if (properties == null)
|
||||
return Collections.emptyList();
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
||||
private Collection<CodeCompletionItem> searchWordCompletion(String str) {
|
||||
if (mEditText.getEditableText().length() < Pref.getMaxTextLengthForCodeCompletion()) {
|
||||
return searchCodeCompletion(str, Arrays.asList(splitWord(mEditText.getEditableText().toString())));
|
||||
}
|
||||
return new TreeSet<>();
|
||||
}
|
||||
|
||||
private Collection<CodeCompletionItem> searchCodeCompletion(String str, Iterable<String> words) {
|
||||
Set<CodeCompletionItem> set = new TreeSet<>();
|
||||
for (String word : words) {
|
||||
// TODO: 2017/2/18 优化 字典树
|
||||
if (word.startsWith(str) && str.length() < word.length()) {
|
||||
set.add(new CodeCompletionItem(word, word.substring(str.length())));
|
||||
}
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
private String[] splitWord(String s) {
|
||||
// TODO: 2017/2/18 优化。利用上次结果
|
||||
return s.split("[\\W]");
|
||||
}
|
||||
|
||||
private Collection<CodeCompletionItem> searchKeyWordCompletion(String str) {
|
||||
return searchCodeCompletion(str, KEYWORDS);
|
||||
}
|
||||
|
||||
private static final String[] DEFAULT_CODE_COMPLETIONS = new String[]{"=", "(", ")", ";", "{", "}", "\"", "!", "[", "]", "\\", ">", "<", ".", ", "};
|
||||
private static final List<CodeCompletionItem> DEFAULT_CODE_COMPLETION_LIST = new ArrayList<>();
|
||||
|
||||
static {
|
||||
for (String str : DEFAULT_CODE_COMPLETIONS) {
|
||||
DEFAULT_CODE_COMPLETION_LIST.add(new CodeCompletionItem(str));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.stardust.scriptdroid.ui.edit.completion;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/9/27.
|
||||
*/
|
||||
|
||||
public class CodeCompletions {
|
||||
|
||||
public static class Pos {
|
||||
public int line;
|
||||
public int ch;
|
||||
|
||||
public Pos(int line, int ch) {
|
||||
this.line = line;
|
||||
this.ch = ch;
|
||||
}
|
||||
}
|
||||
|
||||
private Pos mFrom;
|
||||
private Pos mTo;
|
||||
private List<String> mHints;
|
||||
|
||||
public CodeCompletions(Pos from, Pos to, List<String> hints) {
|
||||
mFrom = from;
|
||||
mTo = to;
|
||||
mHints = hints;
|
||||
}
|
||||
|
||||
public Pos getFrom() {
|
||||
return mFrom;
|
||||
}
|
||||
|
||||
public Pos getTo() {
|
||||
return mTo;
|
||||
}
|
||||
|
||||
public List<String> getHints() {
|
||||
return mHints;
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import com.google.gson.JsonParser;
|
||||
import com.stardust.pio.UncheckedIOException;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.tool.GsonUtils;
|
||||
import com.stardust.util.ClipboardUtil;
|
||||
import com.stardust.util.UnderuseExecutors;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -36,8 +37,38 @@ import java.util.Map;
|
||||
*/
|
||||
|
||||
// TODO: 2017/7/21 refactor
|
||||
public class InputMethodEnhanceBar extends RecyclerView implements CodeCompletion.OnCodeCompletionChangeListener {
|
||||
public class InputMethodEnhanceBar extends RecyclerView {
|
||||
|
||||
public interface OnHintClickListener {
|
||||
void onHintClick(CodeCompletions completions, int pos);
|
||||
}
|
||||
|
||||
private CodeCompletions mCodeCompletions;
|
||||
private OnHintClickListener mOnHintClickListener;
|
||||
private final OnClickListener mOnCodeCompletionItemClickListener = new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int position = getChildViewHolder(v).getAdapterPosition();
|
||||
if (position >= 0 && position < mCodeCompletions.getHints().size()) {
|
||||
if (mOnHintClickListener != null) {
|
||||
mOnHintClickListener.onHintClick(mCodeCompletions, position);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
private final OnLongClickListener mOnCodeCompletionItemLongClickListener = new OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
int position = getChildViewHolder(v).getAdapterPosition();
|
||||
if (position < 0 || position >= mCodeCompletions.getHints().size())
|
||||
return false;
|
||||
ClipboardUtil.setClip(getContext(), mCodeCompletions.getHints().get(position));
|
||||
Toast.makeText(getContext(), R.string.text_copied, Toast.LENGTH_SHORT).show();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
public InputMethodEnhanceBar(Context context) {
|
||||
super(context);
|
||||
@@ -54,74 +85,20 @@ public class InputMethodEnhanceBar extends RecyclerView implements CodeCompletio
|
||||
init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void OnCodeCompletionChange(@NonNull Collection<CodeCompletion.CodeCompletionItem> list1, @NonNull Collection<CodeCompletion.CodeCompletionItem> list2) {
|
||||
mCodeCompletionList.clear();
|
||||
mCodeCompletionList.addAll(list1);
|
||||
mCodeCompletionList.addAll(list2);
|
||||
public void setOnHintClickListener(OnHintClickListener onHintClickListener) {
|
||||
mOnHintClickListener = onHintClickListener;
|
||||
}
|
||||
|
||||
public void setCodeCompletions(CodeCompletions codeCompletions) {
|
||||
mCodeCompletions = codeCompletions;
|
||||
getAdapter().notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public interface EditTextBridge {
|
||||
void appendText(CharSequence text);
|
||||
|
||||
void backspace(int count);
|
||||
|
||||
com.jecelyin.editor.v2.core.widget.TextView getEditText();
|
||||
}
|
||||
|
||||
private static List<String> global;
|
||||
private static Map<String, List<String>> variables = new HashMap<>();
|
||||
|
||||
EditTextBridge mEditTextBridge;
|
||||
private CodeCompletion mCodeCompletion = new CodeCompletion(this);
|
||||
private List<CodeCompletion.CodeCompletionItem> mCodeCompletionList = new ArrayList<>();
|
||||
private final OnClickListener mOnCodeCompletionItemClickListener = new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int position = getChildViewHolder(v).getAdapterPosition();
|
||||
if (position >= 0 && position < mCodeCompletionList.size())
|
||||
mEditTextBridge.appendText(mCodeCompletionList.get(position).getAppendText());
|
||||
}
|
||||
};
|
||||
|
||||
private final OnLongClickListener mOnCodeCompletionItemLongClickListener = new OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
int position = getChildViewHolder(v).getAdapterPosition();
|
||||
if (position < 0 || position >= mCodeCompletionList.size())
|
||||
return false;
|
||||
((ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE)).setPrimaryClip(ClipData.newPlainText("", mCodeCompletionList.get(position).getDisplayText()));
|
||||
Toast.makeText(getContext(), R.string.text_copied, Toast.LENGTH_SHORT).show();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
private void init() {
|
||||
setAdapter(new CodeCompletionAdapter());
|
||||
setLayoutManager(new WrapContentLinearLayoutManager(getContext(), HORIZONTAL, false));
|
||||
if (global == null) {
|
||||
UnderuseExecutors.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
readCompletions(getContext(), "js/functions.json");
|
||||
mCodeCompletion.setGlobal(global);
|
||||
mCodeCompletion.setVariableProperties(variables);
|
||||
}
|
||||
});
|
||||
}else {
|
||||
mCodeCompletion.setGlobal(global);
|
||||
mCodeCompletion.setVariableProperties(variables);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void setEditTextBridge(EditTextBridge editTextBridge) {
|
||||
mEditTextBridge = editTextBridge;
|
||||
mCodeCompletion.setEditText(mEditTextBridge.getEditText());
|
||||
}
|
||||
|
||||
|
||||
private class CodeCompletionAdapter extends RecyclerView.Adapter<ViewHolder> {
|
||||
|
||||
@Override
|
||||
@@ -131,12 +108,12 @@ public class InputMethodEnhanceBar extends RecyclerView implements CodeCompletio
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ViewHolder holder, int position) {
|
||||
((TextView) holder.itemView).setText(mCodeCompletionList.get(position).getDisplayText());
|
||||
((TextView) holder.itemView).setText(mCodeCompletions.getHints().get(position));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mCodeCompletionList.size();
|
||||
return mCodeCompletions == null ? 0 : mCodeCompletions.getHints().size();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,7 +130,7 @@ public class InputMethodEnhanceBar extends RecyclerView implements CodeCompletio
|
||||
try {
|
||||
JsonParser parser = new JsonParser();
|
||||
JsonObject object = parser.parse(new InputStreamReader(context.getAssets().open(path))).getAsJsonObject();
|
||||
InputMethodEnhanceBar.global = readGlobal(object.remove("global").getAsJsonObject());
|
||||
//InputMethodEnhanceBar.global = readGlobal(object.remove("global").getAsJsonObject());
|
||||
readModules(object);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
@@ -162,7 +139,7 @@ public class InputMethodEnhanceBar extends RecyclerView implements CodeCompletio
|
||||
|
||||
private static void readModules(JsonObject object) {
|
||||
for (Map.Entry<String, JsonElement> module : object.entrySet()) {
|
||||
variables.put(module.getKey(), GsonUtils.toStringList(module.getValue()));
|
||||
//variables.put(module.getKey(), GsonUtils.toStringList(module.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
package com.stardust.scriptdroid.ui.edit.editor920;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.afollestad.materialdialogs.folderselector.FolderChooserDialog;
|
||||
import com.jecelyin.editor.v2.Pref;
|
||||
import com.jecelyin.editor.v2.common.Command;
|
||||
import com.jecelyin.editor.v2.ui.IActivity;
|
||||
import com.jecelyin.editor.v2.ui.TabManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/30.
|
||||
*/
|
||||
public abstract class Editor920Activity extends IActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
Pref.getInstance(this).setReadOnly(false);
|
||||
setPref(Pref.KEY_PREF_KEEP_BACKUP_FILE, false);
|
||||
|
||||
}
|
||||
|
||||
private void setPref(String key, Object value) {
|
||||
try {
|
||||
Field field = Pref.class.getDeclaredField("map");
|
||||
field.setAccessible(true);
|
||||
((Map) field.get(Pref.getInstance(this))).put(key, value);
|
||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startPickPathActivity(String s, String s1) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doNextCommand() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMenuStatus(int i, int i1) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doCommand(Command command) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openFile(String s, String s1, int i) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFindFolderCallback(FolderChooserDialog.FolderCallback folderCallback) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public TabManager getTabManager() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertText(CharSequence text) {
|
||||
Command c = new Command(Command.CommandEnum.INSERT_TEXT);
|
||||
c.object = text;
|
||||
doCommand(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCurrentLang() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDocumentChanged(int i) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFolderSelection(@NonNull FolderChooserDialog dialog, @NonNull File folder) {
|
||||
|
||||
}
|
||||
|
||||
protected void onDestroy() {
|
||||
try {
|
||||
super.onDestroy();
|
||||
} catch (Exception ignored) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package com.stardust.scriptdroid.ui.edit.editor920;
|
||||
|
||||
import com.jecelyin.editor.v2.ui.Document;
|
||||
import com.jecelyin.editor.v2.ui.EditorDelegate;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/4/5.
|
||||
*/
|
||||
|
||||
public class Editor920Utils {
|
||||
|
||||
public static Document getDocument(EditorDelegate editorDelegate) {
|
||||
try {
|
||||
Field field = EditorDelegate.class.getDeclaredField("document");
|
||||
field.setAccessible(true);
|
||||
return (Document) field.get(editorDelegate);
|
||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setLang(EditorDelegate editorDelegate, String name) {
|
||||
getDocument(editorDelegate).setMode(name);
|
||||
}
|
||||
}
|
||||
@@ -73,7 +73,7 @@ public class AboutActivity extends BaseActivity {
|
||||
@Click(R.id.donate)
|
||||
void showDonateMeDialog() {
|
||||
new ThemeColorMaterialDialogBuilder(this)
|
||||
.title(R.string.donate)
|
||||
.title(R.string.text_donate)
|
||||
.items("支付宝")
|
||||
.itemsCallback(new MaterialDialog.ListCallback() {
|
||||
@Override
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.stardust.theme;
|
||||
|
||||
import com.jecelyin.editor.v2.core.widget.JecEditText;
|
||||
import com.jecelyin.editor.v2.ui.EditorDelegate;
|
||||
import com.stardust.scriptdroid.*;
|
||||
import com.stardust.scriptdroid.R;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user