opt: communication between editor and javascript

This commit is contained in:
hyb1996
2018-02-04 19:46:59 +08:00
parent 204acdaf82
commit 464c2498db
4 changed files with 97 additions and 70 deletions

View File

@@ -1,7 +1,6 @@
package com.stardust.scriptdroid.ui.edit; package com.stardust.scriptdroid.ui.edit;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Color; import android.graphics.Color;
import android.os.Build; import android.os.Build;
import android.support.annotation.RequiresApi; import android.support.annotation.RequiresApi;
@@ -11,7 +10,6 @@ import android.util.Log;
import android.util.TypedValue; import android.util.TypedValue;
import android.view.ActionMode; import android.view.ActionMode;
import android.view.Gravity; import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo; import android.view.inputmethod.EditorInfo;
@@ -27,28 +25,22 @@ import android.webkit.WebViewClient;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.Toast; import android.widget.Toast;
import com.afollestad.materialdialogs.DialogAction;
import com.afollestad.materialdialogs.MaterialDialog;
import com.stardust.pio.PFiles; import com.stardust.pio.PFiles;
import com.stardust.scriptdroid.R; import com.stardust.scriptdroid.R;
import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder; import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder;
import com.stardust.util.ClipboardUtil; import com.stardust.util.ClipboardUtil;
import org.jdeferred.Deferred; import org.jdeferred.Deferred;
import org.jdeferred.DoneCallback;
import org.jdeferred.impl.DeferredObject; import org.jdeferred.impl.DeferredObject;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.Locale; import java.util.Locale;
import java.util.concurrent.Callable;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import io.reactivex.Observable; import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.annotations.NonNull;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers; import io.reactivex.schedulers.Schedulers;
import io.reactivex.subjects.PublishSubject; import io.reactivex.subjects.PublishSubject;
import me.zhanghai.android.materialprogressbar.MaterialProgressBar; import me.zhanghai.android.materialprogressbar.MaterialProgressBar;
@@ -76,11 +68,6 @@ public class CodeMirrorEditor extends FrameLayout {
private Callback mCallback; private Callback mCallback;
private Deferred<Void, Void, Void> mPageFinished = new DeferredObject<>(); private Deferred<Void, Void, Void> mPageFinished = new DeferredObject<>();
private PublishSubject<String> mStringFromJs;
private PublishSubject<Integer> mIntFromJs;
private String mTextFromAndroid;
public CodeMirrorEditor(Context context) { public CodeMirrorEditor(Context context) {
super(context); super(context);
init(); init();
@@ -212,41 +199,25 @@ public class CodeMirrorEditor extends FrameLayout {
} }
public void setText(final String text) { public void setText(final String text) {
mTextFromAndroid = text; int id = SharedVariables.put(text);
mPageFinished.promise().done(result -> evalJavaScript("editor.setValue(__bridge__.getStringFromAndroid());")); mPageFinished.promise().done(result -> evalJavaScript(String.format(Locale.getDefault(),
"editor.setValue(__bridge__.getStringFromAndroid(%d));", id)));
} }
public void insert(String text) { public void insert(String text) {
mTextFromAndroid = text; int id = SharedVariables.put(text);
mPageFinished.promise().done(result -> evalJavaScript("editor.replaceSelection(__bridge__.getStringFromAndroid());")); mPageFinished.promise().done(result -> evalJavaScript(String.format(Locale.getDefault(),
"editor.replaceSelection(__bridge__.getStringFromAndroid(%d));", id)));
} }
public void loadFile(final File file) {
setProgress(true);
Observable.fromCallable(() -> PFiles.read(file))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(s -> {
setText(s);
setProgress(false);
}, err -> {
err.printStackTrace();
Toast.makeText(getContext(), getContext().getString(R.string.text_cannot_read_file, file.getPath()),
Toast.LENGTH_SHORT).show();
});
}
public Observable<String> getText() { public Observable<String> getText() {
mStringFromJs = PublishSubject.create(); return evalString("editor.getValue()");
evalJavaScript("__bridge__.setStringFromJs(editor.getValue());");
return mStringFromJs;
} }
public Observable<String> getLine() { public Observable<String> getLine() {
mStringFromJs = PublishSubject.create(); return evalString("editor.getLine(editor.getCursor().line)");
evalJavaScript("__bridge__.setStringFromJs(editor.getLine(editor.getCursor().line))");
return mStringFromJs;
} }
public void deleteLine() { public void deleteLine() {
@@ -297,9 +268,10 @@ public class CodeMirrorEditor extends FrameLayout {
} }
public Observable<Integer> getLineCount() { public Observable<Integer> getLineCount() {
mIntFromJs = PublishSubject.create(); PublishSubject<Integer> publishSubject = PublishSubject.create();
evalJavaScript("__bridge__.setIntFromJs(editor.lineCount())"); int id = SharedVariables.put(publishSubject);
return mIntFromJs; evalJavaScript(String.format(Locale.getDefault(), "__bridge__.setIntFromJs(%d, editor.lineCount())", id));
return publishSubject;
} }
@@ -387,9 +359,14 @@ public class CodeMirrorEditor extends FrameLayout {
} }
public Observable<String> getSelection() { public Observable<String> getSelection() {
mStringFromJs = PublishSubject.create(); return evalString("editor.getSelection()");
evalJavaScript("__bridge__.setStringFromJs(editor.getSelection());"); }
return mStringFromJs;
private Observable<String> evalString(String expr) {
PublishSubject<String> publishSubject = PublishSubject.create();
int id = SharedVariables.put(publishSubject);
evalJavaScript(String.format(Locale.getDefault(), "__bridge__.setStringFromJs(%d, %s);", id, expr));
return publishSubject;
} }
public void replaceSelection() { public void replaceSelection() {
@@ -412,30 +389,26 @@ public class CodeMirrorEditor extends FrameLayout {
public class JavaScriptBridge { public class JavaScriptBridge {
@JavascriptInterface @JavascriptInterface
public void setStringFromJs(String text) { public void setStringFromJs(int id, String text) {
if (mStringFromJs == null) { PublishSubject<String> publishSubject = SharedVariables.remove(id);
if (publishSubject == null)
return; return;
} publishSubject.onNext(text);
mStringFromJs.onNext(text); publishSubject.onComplete();
mStringFromJs.onComplete();
mStringFromJs = null;
} }
@JavascriptInterface @JavascriptInterface
public void setIntFromJs(int i) { public void setIntFromJs(int id, int i) {
if (mIntFromJs == null) { PublishSubject<Integer> publishSubject = SharedVariables.remove(id);
if (publishSubject == null)
return; return;
} publishSubject.onNext(i);
mIntFromJs.onNext(i); publishSubject.onComplete();
mIntFromJs.onComplete();
mIntFromJs = null;
} }
@JavascriptInterface @JavascriptInterface
public String getStringFromAndroid() { public String getStringFromAndroid(int id) {
String t = mTextFromAndroid; return SharedVariables.remove(id);
mTextFromAndroid = null;
return t;
} }
@JavascriptInterface @JavascriptInterface

View File

@@ -15,6 +15,7 @@ import android.view.Gravity;
import android.view.View; import android.view.View;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.Toast;
import com.afollestad.materialdialogs.MaterialDialog; import com.afollestad.materialdialogs.MaterialDialog;
import com.stardust.autojs.engine.JavaScriptEngine; import com.stardust.autojs.engine.JavaScriptEngine;
@@ -104,6 +105,7 @@ public class EditorView extends FrameLayout implements CodeCompletionBar.OnHintC
private boolean mReadOnly = false; private boolean mReadOnly = false;
private ScriptExecution mScriptExecution; private ScriptExecution mScriptExecution;
private boolean mTextChanged = false; private boolean mTextChanged = false;
private boolean mInitialText = false;
private AutoCompletion mAutoCompletion; private AutoCompletion mAutoCompletion;
private FunctionsKeyboardHelper mFunctionsKeyboardHelper; private FunctionsKeyboardHelper mFunctionsKeyboardHelper;
private BroadcastReceiver mOnRunFinishedReceiver = new BroadcastReceiver() { private BroadcastReceiver mOnRunFinishedReceiver = new BroadcastReceiver() {
@@ -180,17 +182,39 @@ public class EditorView extends FrameLayout implements CodeCompletionBar.OnHintC
String path = intent.getStringExtra(EXTRA_PATH); String path = intent.getStringExtra(EXTRA_PATH);
String content = intent.getStringExtra(EXTRA_CONTENT); String content = intent.getStringExtra(EXTRA_CONTENT);
if (content != null) { if (content != null) {
mEditor.setText(content); setInitialText(content);
} else { } else {
mFile = new File(path); mFile = new File(path);
if (mName == null) { if (mName == null) {
mName = mFile.getName(); mName = mFile.getName();
} }
mEditor.loadFile(mFile); loadFile(mFile);
} }
} }
private void loadFile(final File file) {
mEditor.setProgress(true);
Observable.fromCallable(() -> PFiles.read(file))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(s -> {
setInitialText(s);
mEditor.setProgress(false);
}, err -> {
err.printStackTrace();
Toast.makeText(getContext(), getContext().getString(R.string.text_cannot_read_file, file.getPath()),
Toast.LENGTH_SHORT).show();
});
}
private void setInitialText(String text) {
mInitialText = true;
mTextChanged = false;
mEditor.setText(text);
}
private void setMenuItemStatus(int id, boolean enabled) { private void setMenuItemStatus(int id, boolean enabled) {
findViewById(id).setEnabled(enabled); findViewById(id).setEnabled(enabled);
} }
@@ -230,9 +254,13 @@ public class EditorView extends FrameLayout implements CodeCompletionBar.OnHintC
setTheme(PreferenceManager.getDefaultSharedPreferences(getContext()) setTheme(PreferenceManager.getDefaultSharedPreferences(getContext())
.getString(KEY_EDITOR_THEME, mEditor.getTheme())); .getString(KEY_EDITOR_THEME, mEditor.getTheme()));
mEditor.setCallback((line, cursor) -> { mEditor.setCallback((line, cursor) -> {
mTextChanged = true; if (mInitialText) {
setMenuItemStatus(R.id.save, true); mInitialText = false;
autoComplete(line, cursor); } else {
mTextChanged = true;
setMenuItemStatus(R.id.save, true);
autoComplete(line, cursor);
}
}); });

View File

@@ -0,0 +1,31 @@
package com.stardust.scriptdroid.ui.edit;
import android.util.SparseArray;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Created by Stardust on 2018/2/4.
*/
public class SharedVariables {
private static SparseArray<Object> sSharedVariables = new SparseArray<>();
private static AtomicInteger sMaxId = new AtomicInteger();
public static int put(Object value) {
int id = sMaxId.getAndIncrement();
sSharedVariables.put(id, value);
return id;
}
@SuppressWarnings("unchecked")
public static <T> T remove(int id) {
Object o = sSharedVariables.get(id);
if (o != null)
sSharedVariables.remove(id);
return (T) o;
}
}

View File

@@ -41,11 +41,6 @@ public class FloatyWindowManger {
} }
} }
public static void closeWindow(FloatyWindow window) {
window.close();
}
public static boolean isCircularMenuShowing() { public static boolean isCircularMenuShowing() {
return sCircularMenu != null && sCircularMenu.get() != null; return sCircularMenu != null && sCircularMenu.get() != null;
} }