package com.stardust.scriptdroid.ui.edit; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.design.widget.Snackbar; import android.util.SparseArray; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Toast; 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.autojs.execution.ScriptExecution; import com.stardust.autojs.script.FileScriptSource; import com.stardust.autojs.script.JsBeautifier; import com.stardust.autojs.script.StringScriptSource; 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.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.view.ViewBinder; import com.stardust.view.ViewBinding; import com.stardust.widget.ToolbarMenuItem; import java.io.File; /** * Created by Stardust on 2017/1/29. */ public class EditActivity extends Editor920Activity { 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 static final String EXTRA_CONTENT = "Still Love Eating 17.4.5"; public static void editFile(Context context, String path) { editFile(context, null, path); } public static void editFile(Context context, String name, String path) { context.startActivity(new Intent(context, EditActivity.class) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) .putExtra("path", path) .putExtra("name", name)); } public static void editFile(Context context, ScriptFile file) { editFile(context, file.getSimplifiedName(), file.getPath()); } private String mName; private File mFile; private View mView; private EditorDelegate mEditorDelegate; private SparseArray<ToolbarMenuItem> mMenuMap; private boolean mReadOnly = false; 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); mView = View.inflate(this, R.layout.activity_edit, null); setContentView(mView); handleIntent(getIntent()); setUpUI(); setUpEditor(); registerReceiver(mOnRunFinishedReceiver, new IntentFilter(Scripts.ACTION_ON_EXECUTION_FINISHED)); } private void handleIntent(Intent intent) { String path = intent.getStringExtra("path"); mName = intent.getStringExtra("name"); mReadOnly = intent.getBooleanExtra("readOnly", false); boolean saveEnabled = intent.getBooleanExtra("saveEnabled", true); if (mReadOnly || !saveEnabled) { findViewById(R.id.save).setVisibility(View.GONE); } String content = intent.getStringExtra("content"); if (content != null) { mEditorDelegate = new EditorDelegate(0, mName, content); } else { mFile = new File(path); if (mName == null) { mName = mFile.getName(); } mEditorDelegate = new EditorDelegate(0, mFile, 0, "utf-8"); } } private void setUpUI() { ThemeColorManager.addActivityStatusBar(this); setUpToolbar(); initMenuItem(); ViewBinder.bind(this); } 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(this, editorView.getEditText())); } } private void setUpToolbar() { BaseActivity.setToolbarAsBack(this, R.id.toolbar, mName); } @ViewBinding.Click(R.id.run) private 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); } 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 FileScriptSource(mName, mFile), mFile.getParent()); } @ViewBinding.Click(R.id.undo) private void undo() { Command command = new Command(Command.CommandEnum.UNDO); mEditorDelegate.doCommand(command); } @ViewBinding.Click(R.id.redo) private void redo() { Command command = new Command(Command.CommandEnum.REDO); mEditorDelegate.doCommand(command); } @ViewBinding.Click(R.id.save) private void saveFile() { saveFile(false, null); } 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); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_console: showConsole(); return true; case R.id.action_log: showLog(); return true; case R.id.action_help: HelpCatalogueActivity.showMainCatalogue(this); return true; case R.id.action_beautify: beautifyCode(); return true; case R.id.action_open_by_other_apps: openByOtherApps(); return true; case R.id.action_force_stop: forceStop(); return true; } return super.onOptionsItemSelected(item); } private void showLog() { AutoJs.getInstance().getScriptEngineService().getGlobalConsole().show(); } private void showConsole() { if (mScriptExecution != null) { mScriptExecution.getRuntime().console.show(); } } private void forceStop() { if (mScriptExecution != null) { mScriptExecution.getEngine().forceStop(); } } private void openByOtherApps() { if (mFile != null) Scripts.openByOtherApps(mFile); } 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(); } }); } }); } @Override public void finish() { if (!mReadOnly && mEditorDelegate.isChanged()) { showExitConfirmDialog(); } else { super.finish(); } } private void showExitConfirmDialog() { new ThemeColorMaterialDialogBuilder(this) .title(R.string.text_alert) .content(R.string.edit_exit_without_save_warn) .positiveText(R.string.text_cancel) .negativeText(R.string.text_save_and_exit) .neutralText(R.string.text_exit_directly) .onNegative(new MaterialDialog.SingleButtonCallback() { @Override public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) { saveFile(true, null); EditActivity.super.finish(); } }) .onNeutral(new MaterialDialog.SingleButtonCallback() { @Override public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) { EditActivity.super.finish(); } }) .show(); } @Override public void doCommand(Command command) { mEditorDelegate.doCommand(command); } @Override protected void onDestroy() { super.onDestroy(); unregisterReceiver(mOnRunFinishedReceiver); } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { try { super.onRestoreInstanceState(savedInstanceState); } catch (RuntimeException e) { // FIXME: 2017/3/20 e.printStackTrace(); } } }