complete the new floating window

This commit is contained in:
hyb1996 2017-10-18 22:46:36 +08:00
parent a478278135
commit d95b85cb2e
26 changed files with 242 additions and 670 deletions

View File

@ -124,7 +124,7 @@ dependencies {
compile 'com.yqritc:recyclerview-flexibledivider:1.4.0'
compile 'com.wang.avi:library:2.1.3'
compile 'org.apache.commons:commons-lang3:3.5'
compile 'com.github.hyb1996:FloatingCircularActionMenu:0.0.1'
compile 'com.github.hyb1996:FloatingCircularActionMenu:0.0.2'
// RxJava
compile "io.reactivex.rxjava2:rxjava:2.1.0"
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'

View File

@ -19,7 +19,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:name=".App"
android:allowBackup="false"
android:icon="@drawable/autojs_material"
android:icon="@drawable/autojs_logo"
android:label="@string/_app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme"

View File

@ -28,7 +28,7 @@ public class OperationDialogBuilder extends MaterialDialog.Builder {
private RecyclerView mOperations;
private ArrayList<Integer> mIds = new ArrayList<>();
private ArrayList<Integer> mIcons = new ArrayList<>();
private ArrayList<Integer> mTexts = new ArrayList<>();
private ArrayList<String> mTexts = new ArrayList<>();
private Object mOnItemClickTarget;
public OperationDialogBuilder(@NonNull Context context) {
@ -61,9 +61,13 @@ public class OperationDialogBuilder extends MaterialDialog.Builder {
}
public OperationDialogBuilder item(int id, int iconRes, int textRes) {
return item(id, iconRes, getContext().getString(textRes));
}
public OperationDialogBuilder item(int id, int iconRes, String text) {
mIds.add(id);
mIcons.add(iconRes);
mTexts.add(textRes);
mTexts.add(text);
return this;
}

View File

@ -122,7 +122,9 @@ public class Pref {
}
public static boolean isRecordWithRootEnabled() {
return def().getBoolean(getString(R.string.key_record_with_root), false);
//always return true after version 3.0.0
//record without root has been deprecated
return true;
}
public static boolean isRecordToastEnabled() {

View File

@ -7,14 +7,14 @@ import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.external.CommonUtils;
import com.stardust.scriptdroid.script.ScriptFile;
import com.stardust.scriptdroid.script.StorageFileProvider;
import com.stardust.scriptdroid.ui.BaseActivity;
import com.stardust.scriptdroid.ui.main.scripts.ScriptListRecyclerView;
import com.stardust.scriptdroid.ui.main.scripts.ScriptListWithProgressBarView;
import com.stardust.scriptdroid.ui.main.scripts.ScriptListView;
import com.twofortyfouram.locale.sdk.client.ui.activity.AbstractAppCompatPluginActivity;
import org.androidannotations.annotations.AfterViews;
@ -43,13 +43,12 @@ public class TaskPrefEditActivity extends AbstractAppCompatPluginActivity {
private void initScriptListRecyclerView() {
mStorageFileProvider = StorageFileProvider.getExternalStorageProvider();
ScriptListWithProgressBarView scriptList = (ScriptListWithProgressBarView) findViewById(R.id.script_list);
scriptList.setScriptFileOperationEnabled(false);
scriptList.setStorageScriptProvider(mStorageFileProvider);
ScriptListView scriptList = (ScriptListView) findViewById(R.id.script_list);
scriptList.setStorageFileProvider(mStorageFileProvider);
scriptList.setCurrentDirectory(StorageFileProvider.DEFAULT_DIRECTORY);
scriptList.setOnItemClickListener(new ScriptListRecyclerView.OnScriptFileClickListener() {
scriptList.setOnScriptFileClickListener(new ScriptListView.OnScriptFileClickListener() {
@Override
public void onClick(ScriptFile file, int position) {
public void onScriptFileClick(View view, ScriptFile file) {
mSelectedScriptFilePath = file.getPath();
finish();
}

View File

@ -6,13 +6,13 @@ import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.script.ScriptFile;
import com.stardust.scriptdroid.script.StorageFileProvider;
import com.stardust.scriptdroid.ui.BaseActivity;
import com.stardust.scriptdroid.ui.main.scripts.ScriptListRecyclerView;
import com.stardust.scriptdroid.ui.main.scripts.ScriptListWithProgressBarView;
import com.stardust.scriptdroid.ui.main.scripts.ScriptListView;
import org.androidannotations.annotations.AfterViews;
import org.androidannotations.annotations.EActivity;
@ -43,13 +43,12 @@ public class ScriptWidgetSettingsActivity extends BaseActivity {
private void initScriptListRecyclerView() {
mStorageFileProvider = StorageFileProvider.getExternalStorageProvider();
ScriptListWithProgressBarView scriptList = (ScriptListWithProgressBarView) findViewById(R.id.script_list);
scriptList.setScriptFileOperationEnabled(false);
scriptList.setStorageScriptProvider(mStorageFileProvider);
ScriptListView scriptList = (ScriptListView) findViewById(R.id.script_list);
scriptList.setStorageFileProvider(mStorageFileProvider);
scriptList.setCurrentDirectory(StorageFileProvider.DEFAULT_DIRECTORY);
scriptList.setOnItemClickListener(new ScriptListRecyclerView.OnScriptFileClickListener() {
scriptList.setOnScriptFileClickListener(new ScriptListView.OnScriptFileClickListener() {
@Override
public void onClick(ScriptFile file, int position) {
public void onScriptFileClick(View view, ScriptFile file) {
mSelectedScriptFilePath = file.getPath();
finish();
}

View File

@ -9,6 +9,7 @@ import android.widget.Toast;
import com.afollestad.materialdialogs.DialogAction;
import com.afollestad.materialdialogs.MaterialDialog;
import com.stardust.app.DialogUtils;
import com.stardust.scriptdroid.App;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.script.ScriptFile;
@ -73,7 +74,7 @@ public class ScriptLoopDialog {
}
public void show() {
mDialog.show();
DialogUtils.showDialog(mDialog);
}
}

View File

@ -1,11 +1,16 @@
package com.stardust.scriptdroid.ui.floating;
import android.content.Context;
import android.text.TextUtils;
import android.view.ContextThemeWrapper;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;
import com.afollestad.materialdialogs.MaterialDialog;
import com.stardust.app.DialogUtils;
import com.stardust.app.OperationDialogBuilder;
import com.stardust.autojs.core.record.Recorder;
import com.stardust.enhancedfloaty.FloatyService;
import com.stardust.floatingcircularactionmenu.CircularActionMenu;
import com.stardust.floatingcircularactionmenu.CircularActionMenuFloatingWindow;
@ -13,37 +18,66 @@ import com.stardust.floatingcircularactionmenu.CircularActionMenuFloaty;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.accessibility.AccessibilityService;
import com.stardust.scriptdroid.autojs.AutoJs;
import com.stardust.scriptdroid.autojs.record.GlobalRecorder;
import com.stardust.scriptdroid.script.ScriptFile;
import com.stardust.scriptdroid.tool.AccessibilityServiceTool;
import com.stardust.scriptdroid.ui.floating.layoutinspector.LayoutBoundsFloatyWindow;
import com.stardust.scriptdroid.ui.floating.layoutinspector.LayoutHierarchyFloatyWindow;
import com.stardust.scriptdroid.ui.floating.layoutinspector.LayoutHierarchyView;
import com.stardust.scriptdroid.ui.main.scripts.ScriptListView;
import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder;
import com.stardust.util.ClipboardUtil;
import com.stardust.view.accessibility.LayoutInspector;
import org.androidannotations.annotations.Click;
import org.greenrobot.eventbus.EventBus;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.Optional;
/**
* Created by Stardust on 2017/10/18.
*/
public class CircularMenu {
public class CircularMenu implements Recorder.OnStateChangedListener {
public static class StateChangeEvent {
private int currentState;
private int previousState;
private static final int STATE_NORMAL = 0;
private static final int STATE_RECORDING = 1;
public StateChangeEvent(int currentState, int previousState) {
this.currentState = currentState;
this.previousState = previousState;
}
public int getCurrentState() {
return currentState;
}
public int getPreviousState() {
return previousState;
}
}
public static final int STATE_CLOSED = -1;
public static final int STATE_NORMAL = 0;
public static final int STATE_RECORDING = 1;
CircularActionMenuFloatingWindow mWindow;
private int mState;
private ImageView mActionViewIcon;
private Context mContext;
private GlobalRecorder mRecorder;
private MaterialDialog mSettingsDialog;
private String mRunningPackage, mRunningActivity;
public CircularMenu(Context context) {
mContext = context;
mContext = new ContextThemeWrapper(context, R.style.AppTheme);
initFloaty();
setupListeners();
FloatyService.addWindow(mWindow);
mRecorder = GlobalRecorder.getSingleton(context);
mRecorder.addOnStateChangedListener(this);
}
private void setupListeners() {
@ -60,7 +94,6 @@ public class CircularMenu {
}
}
});
}
@ -81,32 +114,59 @@ public class CircularMenu {
return menu;
}
});
mWindow.setKeepToSideHiddenWidthRadio(0.2f);
FloatyService.addWindow(mWindow);
}
@Optional
@OnClick(R.id.script_list)
void showScriptList() {
mWindow.collapse();
ScriptListView listView = new ScriptListView(mContext);
listView.setDirectorySpanSize(2);
final MaterialDialog dialog = new ThemeColorMaterialDialogBuilder(mContext)
.title(R.string.text_run_script)
.customView(listView, false)
.positiveText(R.string.cancel)
.build();
listView.setOnItemOperatedListener(new ScriptListView.OnItemOperatedListener() {
@Override
public void OnItemOperated(ScriptFile file) {
dialog.dismiss();
}
});
DialogUtils.showDialog(dialog);
}
@Optional
@OnClick(R.id.record)
void startRecord() {
mWindow.collapse();
mState = STATE_RECORDING;
mActionViewIcon.setImageResource(R.drawable.ic_ali_record);
mActionViewIcon.setBackgroundResource(R.drawable.circle_red);
mActionViewIcon.setPadding(28, 28, 28, 28);
mRecorder.start();
}
private void setState(int state) {
int previousState = mState;
mState = state;
mActionViewIcon.setImageResource(mState == STATE_RECORDING ? R.drawable.ic_ali_record :
R.drawable.autojs_logo);
mActionViewIcon.setBackgroundResource(mState == STATE_RECORDING ? R.drawable.circle_red :
0);
if (state == STATE_RECORDING) {
mActionViewIcon.setPadding(28, 28, 28, 28);
} else {
mActionViewIcon.setPadding(0, 0, 0, 0);
}
EventBus.getDefault().post(new StateChangeEvent(mState, previousState));
}
private void stopRecord() {
mWindow.collapse();
mState = STATE_NORMAL;
mActionViewIcon.setImageResource(R.drawable.autojs_logo);
mActionViewIcon.setBackground(null);
mActionViewIcon.setPadding(0, 0, 0, 0);
mRecorder.stop();
}
@Optional
@OnClick(R.id.layout_bounds)
void showLayoutBounds() {
mWindow.collapse();
@ -119,6 +179,7 @@ public class CircularMenu {
FloatyService.addWindow(window);
}
@Optional
@OnClick(R.id.layout_hierarchy)
void showLayoutHierarchy() {
mWindow.collapse();
@ -131,12 +192,6 @@ public class CircularMenu {
FloatyService.addWindow(window);
}
@OnClick(R.id.settings)
void settings() {
mWindow.collapse();
}
private boolean ensureCapture() {
LayoutInspector inspector = AutoJs.getInstance().getLayoutInspector();
if (inspector.isDumping()) {
@ -155,7 +210,88 @@ public class CircularMenu {
}
@Optional
@OnClick(R.id.settings)
void settings() {
mWindow.collapse();
mRunningPackage = AutoJs.getInstance().getInfoProvider().getLatestPackage();
mRunningActivity = AutoJs.getInstance().getInfoProvider().getLatestActivity();
mSettingsDialog = new OperationDialogBuilder(mContext)
.item(R.id.accessibility_service, R.drawable.ic_service_green, R.string.text_accessibility_settings)
.item(R.id.package_name, R.drawable.ic_ali_app,
mContext.getString(R.string.text_current_package) + mRunningPackage)
.item(R.id.class_name, R.drawable.ic_ali_android,
mContext.getString(R.string.text_current_activity) + mRunningActivity)
.item(R.id.exit, R.drawable.ic_close_white_48dp, R.string.text_exit_floating_window)
.bindItemClick(this)
.title(R.string.text_more)
.build();
DialogUtils.showDialog(mSettingsDialog);
}
@Optional
@OnClick(R.id.accessibility_service)
void enableAccessibilityService() {
dismissSettingsDialog();
AccessibilityServiceTool.enableAccessibilityService();
}
private void dismissSettingsDialog() {
if (mSettingsDialog == null)
return;
mSettingsDialog.dismiss();
mSettingsDialog = null;
}
@Optional
@OnClick(R.id.package_name)
void copyPackageName() {
dismissSettingsDialog();
if (TextUtils.isEmpty(mRunningPackage))
return;
ClipboardUtil.setClip(mContext, mRunningPackage);
Toast.makeText(mContext, R.string.text_already_copy_to_clip, Toast.LENGTH_SHORT).show();
}
@Optional
@OnClick(R.id.package_name)
void copyActivityName() {
dismissSettingsDialog();
if (TextUtils.isEmpty(mRunningActivity))
return;
ClipboardUtil.setClip(mContext, mRunningActivity);
Toast.makeText(mContext, R.string.text_already_copy_to_clip, Toast.LENGTH_SHORT).show();
}
@Optional
@OnClick(R.id.exit)
public void close() {
dismissSettingsDialog();
mWindow.close();
mRecorder.removeOnStateChangedListener(this);
EventBus.getDefault().post(new StateChangeEvent(STATE_CLOSED, mState));
mState = STATE_CLOSED;
}
@Override
public void onStart() {
setState(STATE_RECORDING);
}
@Override
public void onStop() {
setState(STATE_NORMAL);
}
@Override
public void onPause() {
}
@Override
public void onResume() {
}
}

View File

@ -7,11 +7,9 @@ import android.view.ContextThemeWrapper;
import android.view.View;
import com.stardust.enhancedfloaty.FloatyService;
import com.stardust.enhancedfloaty.FloatyWindow;
import com.stardust.enhancedfloaty.ResizableFloaty;
import com.stardust.enhancedfloaty.ResizableFloatyWindow;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.external.floatingwindow.FloatyWindowManger;
import com.stardust.scriptdroid.script.ScriptFile;
import com.stardust.scriptdroid.ui.edit.EditActivity_;
import com.stardust.scriptdroid.ui.edit.EditorView;

View File

@ -1,4 +1,4 @@
package com.stardust.scriptdroid.external.floatingwindow;
package com.stardust.scriptdroid.ui.floating;
import android.content.Context;
import android.content.Intent;
@ -10,6 +10,7 @@ import com.stardust.enhancedfloaty.util.FloatingWindowPermissionUtil;
import com.stardust.scriptdroid.App;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.ui.floating.CircularMenu;
import com.stardust.util.IntentUtil;
import java.lang.ref.WeakReference;
@ -61,9 +62,14 @@ public class FloatyWindowManger {
}
public static void showCircularMenu() {
App.getApp().startService(new Intent(App.getApp(), FloatyService.class));
CircularMenu menu = new CircularMenu(App.getApp());
sCircularMenu = new WeakReference<>(menu);
if (!SettingsCompat.canDrawOverlays(App.getApp())) {
Toast.makeText(App.getApp(), R.string.text_no_floating_window_permission, Toast.LENGTH_SHORT).show();
manageDrawOverlays(App.getApp());
} else {
App.getApp().startService(new Intent(App.getApp(), FloatyService.class));
CircularMenu menu = new CircularMenu(App.getApp());
sCircularMenu = new WeakReference<>(menu);
}
}
public static void hideCircularMenu() {

View File

@ -26,9 +26,8 @@ import com.stardust.scriptdroid.BuildConfig;
import com.stardust.scriptdroid.Pref;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.autojs.AutoJs;
import com.stardust.scriptdroid.external.floatingwindow.FloatyWindowManger;
import com.stardust.scriptdroid.ui.floating.FloatyWindowManger;
import com.stardust.scriptdroid.script.StorageFileProvider;
import com.stardust.scriptdroid.ui.floating.CircularMenu;
import com.stardust.scriptdroid.ui.main.community.CommunityFragment_;
import com.stardust.scriptdroid.ui.main.doc.OnlineDocsFragment_;
import com.stardust.scriptdroid.ui.main.scripts.MyScriptListFragment_;

View File

@ -14,7 +14,8 @@ import com.afollestad.materialdialogs.MaterialDialog;
import com.stardust.scriptdroid.App;
import com.stardust.scriptdroid.Pref;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.external.floatingwindow.FloatyWindowManger;
import com.stardust.scriptdroid.ui.floating.CircularMenu;
import com.stardust.scriptdroid.ui.floating.FloatyWindowManger;
import com.stardust.scriptdroid.network.NodeBB;
import com.stardust.scriptdroid.network.VersionService;
import com.stardust.scriptdroid.network.api.UserApi;
@ -35,6 +36,7 @@ import org.androidannotations.annotations.AfterViews;
import org.androidannotations.annotations.Click;
import org.androidannotations.annotations.EFragment;
import org.androidannotations.annotations.ViewById;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import java.util.concurrent.Callable;
@ -91,6 +93,7 @@ public class DrawerFragment extends android.support.v4.app.Fragment {
}
})
.subscribe();
EventBus.getDefault().register(this);
}
@Override
@ -286,6 +289,11 @@ public class DrawerFragment extends android.support.v4.app.Fragment {
});
}
@Subscribe
void onCircularMenuStateChange(CircularMenu.StateChangeEvent event) {
mFloatingWindowItem.getSwitchCompat().setChecked(event.getCurrentState() != CircularMenu.STATE_CLOSED);
}
private void syncSwitchState() {
mAccessibilityServiceItem.getSwitchCompat().setChecked(
@ -326,6 +334,7 @@ public class DrawerFragment extends android.support.v4.app.Fragment {
public void onDestroy() {
super.onDestroy();
mConnectionStateDisposable.dispose();
EventBus.getDefault().unregister(this);
}
}

View File

@ -1,63 +0,0 @@
package com.stardust.scriptdroid.ui.main.scripts;
import android.content.Context;
import android.support.annotation.NonNull;
import com.afollestad.materialdialogs.MaterialDialog;
import com.stardust.scriptdroid.script.ScriptFile;
import com.stardust.scriptdroid.script.StorageFileProvider;
/**
* Created by Stardust on 2017/4/3.
*/
public class ScriptFileChooserDialogBuilder extends MaterialDialog.Builder {
public interface FileCallback {
void onFileSelection(MaterialDialog dialog, ScriptFile file);
}
private ScriptListWithProgressBarView mScriptListWithProgressBarView;
private StorageFileProvider mStorageFileProvider;
private FileCallback mFileCallback;
public ScriptFileChooserDialogBuilder(@NonNull Context context) {
super(context);
mScriptListWithProgressBarView = new ScriptListWithProgressBarView(context);
mScriptListWithProgressBarView.setMinimumHeight(800);
mScriptListWithProgressBarView.setScriptFileOperationEnabled(false);
}
public ScriptFileChooserDialogBuilder fileCallback(final FileCallback fileCallback) {
mFileCallback = fileCallback;
return this;
}
public ScriptFileChooserDialogBuilder initialPath(String initialPath) {
mStorageFileProvider = new StorageFileProvider(initialPath, 5);
return this;
}
public ScriptFileChooserDialogBuilder scriptProvider(StorageFileProvider storageFileProvider) {
mStorageFileProvider = storageFileProvider;
return this;
}
public MaterialDialog build() {
if (mStorageFileProvider != null) {
mScriptListWithProgressBarView.setStorageScriptProvider(mStorageFileProvider);
}
customView(mScriptListWithProgressBarView, false);
final MaterialDialog dialog = super.build();
if (mFileCallback != null) {
mScriptListWithProgressBarView.setOnItemClickListener(new ScriptListRecyclerView.OnScriptFileClickListener() {
@Override
public void onClick(ScriptFile file, int position) {
mFileCallback.onFileSelection(dialog, file);
}
});
}
return dialog;
}
}

View File

@ -1,426 +0,0 @@
package com.stardust.scriptdroid.ui.main.scripts;
import android.content.Context;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.workground.WrapContentLinearLayoutManager;
import com.stardust.scriptdroid.script.ScriptFile;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.script.Scripts;
import com.stardust.scriptdroid.script.StorageFileProvider;
import com.stardust.util.ViewUtils;
import com.stardust.widget.ViewHolderMutableAdapter;
import com.stardust.widget.ViewHolderSupplier;
import com.yqritc.recyclerviewflexibledivider.HorizontalDividerItemDecoration;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.util.List;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.annotations.NonNull;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;
/**
* Created by Stardust on 2017/3/27.
*/
public class ScriptListRecyclerView extends RecyclerView {
public interface OnScriptFileClickListener {
void onClick(ScriptFile file, int position);
}
public interface OnScriptFileLongClickListener {
void onLongClick(ScriptFile file, int position);
}
public interface FileProcessListener {
void onFilesListing();
void onFileListed();
}
public interface OnCurrentDirectoryChangeListener {
void onChange(ScriptFile oldDir, ScriptFile newDir);
}
public static final int VIEW_TYPE_DIRECTORY = 1;
public static final int VIEW_TYPE_FILE = 2;
public static class ViewHolder extends RecyclerView.ViewHolder {
TextView name;
public ViewHolder(View itemView) {
super(itemView);
name = (TextView) itemView.findViewById(R.id.name);
}
public void bind(ScriptFile file) {
if (file.isDirectory()) {
name.setText(file.getName());
} else {
name.setText(file.getSimplifiedName());
}
}
}
private OnScriptFileClickListener mOnItemClickListener;
private OnScriptFileLongClickListener mOnItemLongClickListener;
private final OnClickListener mOnItemClickListenerProxy = new OnClickListener() {
@Override
public void onClick(View v) {
int position = getChildViewHolder(v).getAdapterPosition();
if (mCanGoBack && position == 0) {
goBack();
return;
}
ScriptFile file = mAdapter.getScriptFileAt(position);
if (file == null)
return;
if (file.isDirectory()) {
setCurrentDirectory(file, true);
} else if (mOnItemClickListener != null) {
mOnItemClickListener.onClick(file, position);
}
}
};
private final OnLongClickListener mOnItemLongClickListenerProxy = new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
if (mOnItemLongClickListener != null) {
int position = getChildViewHolder(v).getAdapterPosition();
ScriptFile file = mAdapter.getScriptFileAt(position);
if (file == null)
return false;
mOnItemLongClickListener.onLongClick(file, position);
return true;
}
return false;
}
};
private OnClickListener mOnRunClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
View item = ViewUtils.findParentById(v, R.id.item);
if (item == null)
return;
int position = getChildViewHolder(item).getAdapterPosition();
ScriptFile file = mAdapter.getScriptFileAt(position);
if (file == null)
return;
Scripts.run(file);
}
};
private final ViewHolderSupplier<ViewHolder> mDefaultViewHolderSupplier = new ViewHolderSupplier<ViewHolder>() {
@Override
public ViewHolder createViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case VIEW_TYPE_FILE:
return new FileViewHolder(LayoutInflater.from(getContext()).inflate(R.layout.script_and_folder_list_recycler_view_file, parent, false));
case VIEW_TYPE_DIRECTORY:
return new DefaultViewHolder(LayoutInflater.from(getContext()).inflate(R.layout.script_and_folder_list_recycler_view_directory, parent, false));
}
return null;
}
};
private ScriptFile mCurrentDirectory;
private ScriptFile mRootDirectory;
private Adapter mAdapter;
private boolean mCanGoBack = false;
private StorageFileProvider mStorageFileProvider;
private FileProcessListener mFileProcessListener;
private OnCurrentDirectoryChangeListener mOnCurrentDirectoryChangeListener;
private boolean mScriptFileOperationEnabled = true;
public ScriptListRecyclerView(Context context) {
super(context);
init();
}
public ScriptListRecyclerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public ScriptListRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void setCurrentDirectory(final ScriptFile directory, boolean canGoBack) {
if (!directory.equals(mCurrentDirectory) && mOnCurrentDirectoryChangeListener != null) {
mOnCurrentDirectoryChangeListener.onChange(mCurrentDirectory, directory);
}
mCurrentDirectory = directory;
mCanGoBack = canGoBack;
if (mFileProcessListener != null) {
mFileProcessListener.onFilesListing();
}
mStorageFileProvider.getDirectoryScriptFiles(directory)
.subscribeOn(Schedulers.io())
.toList()
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<List<ScriptFile>>() {
@Override
public void accept(@NonNull List<ScriptFile> scriptFiles) throws Exception {
mAdapter.setScripts(scriptFiles.toArray(new ScriptFile[0]));
if (mFileProcessListener != null)
mFileProcessListener.onFileListed();
smoothScrollToPosition(0);
}
});
}
public void setCurrentDirectory(final ScriptFile directory) {
setCurrentDirectory(directory, !directory.equals(mRootDirectory));
}
private void setRootDirectory(ScriptFile directory) {
mRootDirectory = directory;
}
public void setFileProcessListener(FileProcessListener fileProcessListener) {
mFileProcessListener = fileProcessListener;
}
public void setStorageFileProvider(StorageFileProvider storageFileProvider) {
if (mStorageFileProvider != null)
mStorageFileProvider.unregisterDirectoryChangeListener(this);
mStorageFileProvider = storageFileProvider;
mStorageFileProvider.registerDirectoryChangeListener(this);
setRootDirectory(mStorageFileProvider.getInitialDirectory());
}
public StorageFileProvider getStorageFileProvider() {
return mStorageFileProvider;
}
public void setOnItemClickListener(OnScriptFileClickListener onItemClickListener) {
mOnItemClickListener = onItemClickListener;
}
public void setOnItemLongClickListener(OnScriptFileLongClickListener onItemLongClickListener) {
mOnItemLongClickListener = onItemLongClickListener;
}
public void setOnCurrentDirectoryChangeListener(OnCurrentDirectoryChangeListener onCurrentDirectoryChangeListener) {
mOnCurrentDirectoryChangeListener = onCurrentDirectoryChangeListener;
}
public ScriptFile getCurrentDirectory() {
return mCurrentDirectory;
}
public void setScriptFileOperationEnabled(boolean scriptFileOperationEnabled) {
mScriptFileOperationEnabled = scriptFileOperationEnabled;
}
public void setViewHolderSupplier(ViewHolderSupplier<ViewHolder> supplier) {
mAdapter.setViewHolderSupplier(supplier);
}
public OnClickListener getOnItemClickListenerProxy() {
return mOnItemClickListenerProxy;
}
public OnLongClickListener getOnItemLongClickListenerProxy() {
return mOnItemLongClickListenerProxy;
}
private void goBack() {
ScriptFile parent = mCurrentDirectory.getParentFile();
setCurrentDirectory(parent, !parent.equals(mRootDirectory));
}
private void init() {
setLayoutManager(new WrapContentLinearLayoutManager(getContext()));
mAdapter = new Adapter(mDefaultViewHolderSupplier);
setAdapter(mAdapter);
addItemDecoration(new HorizontalDividerItemDecoration.Builder(getContext())
.color(0xffd9d9d9)
.size(2)
.marginResId(R.dimen.script_and_folder_list_divider_left_margin, R.dimen.script_and_folder_list_divider_right_margin)
.showLastDivider()
.build());
}
@Override
protected Parcelable onSaveInstanceState() {
Bundle bundle = new Bundle();
bundle.putParcelable("superData", super.onSaveInstanceState());
bundle.putSerializable("current", mCurrentDirectory);
bundle.putSerializable("root", mRootDirectory);
return bundle;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
Bundle bundle = (Bundle) state;
mRootDirectory = (ScriptFile) bundle.getSerializable("root");
mCurrentDirectory = (ScriptFile) bundle.getSerializable("current");
setCurrentDirectory(mCurrentDirectory);
super.onRestoreInstanceState(bundle.getParcelable("superData"));
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (mStorageFileProvider != null)
mStorageFileProvider.registerDirectoryChangeListener(this);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mStorageFileProvider.unregisterDirectoryChangeListener(this);
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
if (mCanGoBack) {
goBack();
return true;
}
}
return false;
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onDirectoryChange(StorageFileProvider.DirectoryChangeEvent event) {
if (event.getDir().equals(mCurrentDirectory)) {
updateCurrentDirectory();
}
}
@Override
public Adapter getAdapter() {
return mAdapter;
}
private void updateCurrentDirectory() {
setCurrentDirectory(mCurrentDirectory, mCanGoBack);
}
private void ensureCurrentDirectory() {
if (mCurrentDirectory == null && mRootDirectory != null) {
setCurrentDirectory(mRootDirectory, false);
}
}
public class Adapter extends ViewHolderMutableAdapter<ViewHolder> {
private ScriptFile[] mScriptFileList = new ScriptFile[0];
public Adapter(ViewHolderSupplier<ViewHolder> viewHolderSupplier) {
super(viewHolderSupplier);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
if (mCanGoBack && position == 0) {
holder.name.setText("..");
} else
holder.bind(getScriptFileAt(position));
}
@Override
public int getItemCount() {
ensureCurrentDirectory();
return mScriptFileList.length + (mCanGoBack ? 1 : 0);
}
@Override
public int getItemViewType(int position) {
if (mCanGoBack && position == 0) {
return VIEW_TYPE_DIRECTORY;
}
return getScriptFileAt(position).isDirectory() ? VIEW_TYPE_DIRECTORY : VIEW_TYPE_FILE;
}
@Nullable
public ScriptFile getScriptFileAt(int position) {
int actualPos = mCanGoBack ? position - 1 : position;
if (actualPos >= mScriptFileList.length || actualPos < 0) {
return null;
}
return mScriptFileList[actualPos];
}
void setScripts(ScriptFile[] scriptFiles) {
mScriptFileList = scriptFiles;
notifyDataSetChanged();
}
}
private class DefaultViewHolder extends ViewHolder {
DefaultViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(mOnItemClickListenerProxy);
itemView.setOnLongClickListener(mOnItemLongClickListenerProxy);
if (!mScriptFileOperationEnabled) {
setMarginRight(name, 0);
}
}
private void setMarginRight(View view, int marginRight) {
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
layoutParams.rightMargin = marginRight;
view.setLayoutParams(layoutParams);
}
}
private class FileViewHolder extends DefaultViewHolder {
private ImageView mIcon;
FileViewHolder(View itemView) {
super(itemView);
mIcon = (ImageView) itemView.findViewById(R.id.icon);
if (mScriptFileOperationEnabled) {
itemView.findViewById(R.id.run).setOnClickListener(mOnRunClickListener);
} else {
itemView.findViewById(R.id.run).setVisibility(GONE);
}
}
@Override
public void bind(ScriptFile file) {
super.bind(file);
mIcon.setImageResource(file.getType() == ScriptFile.TYPE_AUTO ? R.drawable.record_icon_18
: R.drawable.ic_node_js_black);
}
}
}

View File

@ -51,17 +51,23 @@ public class ScriptListView extends SwipeRefreshLayout implements SwipeRefreshLa
void onScriptFileClick(View view, ScriptFile file);
}
public interface OnItemOperatedListener {
void OnItemOperated(ScriptFile file);
}
private static final int positionOfCategoryDir = 0;
private ScriptList mScriptList = new ScriptList();
private RecyclerView mScriptListView;
private ScriptListAdapter mScriptListAdapter = new ScriptListAdapter();
private ScriptFile mCurrentDirectory;
private OnScriptFileClickListener mOnScriptFileClickListener;
private OnItemOperatedListener mOnItemOperatedListener;
private ScriptFile mSelectedScriptFile;
private StorageFileProvider mStorageFileProvider;
private boolean mDirSortMenuShowing = false;
private boolean mDirsCollapsed;
private boolean mFilesCollapsed;
private int mDirectorySpanSize = 1;
public ScriptListView(Context context) {
super(context);
@ -88,6 +94,13 @@ public class ScriptListView extends SwipeRefreshLayout implements SwipeRefreshLa
mOnScriptFileClickListener = onScriptFileClickListener;
}
public void setStorageFileProvider(StorageFileProvider storageFileProvider) {
mStorageFileProvider = storageFileProvider;
}
public void setOnItemOperatedListener(OnItemOperatedListener onItemOperatedListener) {
mOnItemOperatedListener = onItemOperatedListener;
}
public boolean canGoBack() {
return !mCurrentDirectory.equals(mStorageFileProvider.getInitialDirectory());
@ -97,6 +110,10 @@ public class ScriptListView extends SwipeRefreshLayout implements SwipeRefreshLa
setCurrentDirectory(mCurrentDirectory.getParentFile());
}
public void setDirectorySpanSize(int directorySpanSize) {
mDirectorySpanSize = directorySpanSize;
}
private void init() {
setOnRefreshListener(this);
mScriptListView = new RecyclerView(getContext());
@ -115,7 +132,7 @@ public class ScriptListView extends SwipeRefreshLayout implements SwipeRefreshLa
public int getSpanSize(int position) {
//For directories
if (position > positionOfCategoryDir && position < positionOfCategoryFile()) {
return 1;
return mDirectorySpanSize;
}
//For files and category
return 2;
@ -186,6 +203,7 @@ public class ScriptListView extends SwipeRefreshLayout implements SwipeRefreshLa
case R.id.run_repeatedly:
new ScriptLoopDialog(getContext(), mSelectedScriptFile)
.show();
notifyOperated();
break;
case R.id.create_shortcut:
new ScriptOperations(getContext(), this)
@ -193,6 +211,7 @@ public class ScriptListView extends SwipeRefreshLayout implements SwipeRefreshLa
break;
case R.id.open_by_other_apps:
Scripts.openByOtherApps(mSelectedScriptFile);
notifyOperated();
break;
case R.id.action_sort_by_date:
sort(ScriptList.SORT_TYPE_DATE, mDirSortMenuShowing);
@ -212,6 +231,12 @@ public class ScriptListView extends SwipeRefreshLayout implements SwipeRefreshLa
return true;
}
private void notifyOperated() {
if (mOnItemOperatedListener != null) {
mOnItemOperatedListener.OnItemOperated(mSelectedScriptFile);
}
}
private void sort(final int sortType, final boolean isDir) {
setRefreshing(true);
Observable.fromCallable(new Callable<ScriptList>() {
@ -348,16 +373,19 @@ public class ScriptListView extends SwipeRefreshLayout implements SwipeRefreshLa
if (mOnScriptFileClickListener != null) {
mOnScriptFileClickListener.onScriptFileClick(itemView, mScriptFile);
}
notifyOperated();
}
@OnClick(R.id.run)
void run() {
Scripts.run(mScriptFile);
notifyOperated();
}
@OnClick(R.id.edit)
void edit() {
Scripts.edit(mScriptFile);
notifyOperated();
}
@OnClick(R.id.more)

View File

@ -1,117 +0,0 @@
package com.stardust.scriptdroid.ui.main.scripts;
import android.content.Context;
import android.os.Build;
import android.os.Parcelable;
import android.support.annotation.AttrRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.support.annotation.StyleRes;
import android.support.v4.widget.SwipeRefreshLayout;
import android.util.AttributeSet;
import android.widget.FrameLayout;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.script.ScriptFile;
import com.stardust.scriptdroid.script.StorageFileProvider;
/**
* Created by Stardust on 2017/4/3.
*/
public class ScriptListWithProgressBarView extends FrameLayout {
private ScriptListRecyclerView mScriptAndFolderListRecyclerView;
private SwipeRefreshLayout mSwipeRefreshLayout;
public ScriptListWithProgressBarView(@NonNull Context context) {
super(context);
init();
}
public ScriptListWithProgressBarView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public ScriptListWithProgressBarView(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public ScriptListWithProgressBarView(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init() {
inflate(getContext(), R.layout.script_and_folder_list_view, this);
mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh_layout);
mScriptAndFolderListRecyclerView = (ScriptListRecyclerView) findViewById(R.id.script_list_recycler_view);
mScriptAndFolderListRecyclerView.setFileProcessListener(new ScriptListRecyclerView.FileProcessListener() {
@Override
public void onFilesListing() {
showProgressBar();
}
@Override
public void onFileListed() {
hideProgressBar();
}
});
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
mScriptAndFolderListRecyclerView.getStorageFileProvider().refreshAll();
}
});
}
public ScriptListRecyclerView getScriptAndFolderListRecyclerView() {
return mScriptAndFolderListRecyclerView;
}
public void setStorageScriptProvider(StorageFileProvider storageFileProvider) {
mScriptAndFolderListRecyclerView.setStorageFileProvider(storageFileProvider);
}
public void setOnItemClickListener(ScriptListRecyclerView.OnScriptFileClickListener onItemClickListener) {
mScriptAndFolderListRecyclerView.setOnItemClickListener(onItemClickListener);
}
public void setScriptFileOperationEnabled(boolean enabled) {
mScriptAndFolderListRecyclerView.setScriptFileOperationEnabled(enabled);
}
public void showProgressBar() {
mSwipeRefreshLayout.setRefreshing(true);
mScriptAndFolderListRecyclerView.setEnabled(false);
}
public void hideProgressBar() {
mSwipeRefreshLayout.setRefreshing(false);
mScriptAndFolderListRecyclerView.setEnabled(true);
}
public void setCurrentDirectory(ScriptFile directory) {
mScriptAndFolderListRecyclerView.setCurrentDirectory(directory);
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
super.onRestoreInstanceState(state);
//in some phones, SwipeRefreshLayout will keep refreshing after screen orientation change
mSwipeRefreshLayout.post(new Runnable() {
@Override
public void run() {
mSwipeRefreshLayout.setRefreshing(false);
}
});
}
}

View File

@ -6,7 +6,7 @@
<item
android:bottom="214dp"
android:drawable="@drawable/autojs_material"
android:drawable="@drawable/autojs_logo"
android:gravity="center"
android:left="100dp"
android:right="100dp"

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -47,7 +47,7 @@
android:layout_width="90dp"
android:layout_height="90dp"
android:layout_centerInParent="true"
android:src="@drawable/autojs_material"/>
android:src="@drawable/autojs_logo"/>
<TextView
android:id="@+id/version"

View File

@ -24,7 +24,7 @@
</com.stardust.theme.widget.ThemeColorToolbar>
</android.support.design.widget.AppBarLayout>
<com.stardust.scriptdroid.ui.main.scripts.ScriptListWithProgressBarView
<com.stardust.scriptdroid.ui.main.scripts.ScriptListView
android:id="@+id/script_list"
android:layout_width="match_parent"
android:layout_height="match_parent"

View File

@ -49,7 +49,7 @@
android:textSize="16sp"/>
</LinearLayout>
<com.stardust.scriptdroid.ui.main.scripts.ScriptListWithProgressBarView
<com.stardust.scriptdroid.ui.main.scripts.ScriptListView
android:id="@+id/script_list"
android:layout_width="match_parent"
android:layout_height="match_parent"

View File

@ -7,6 +7,7 @@
android:orientation="horizontal"
android:paddingBottom="16dp"
android:paddingLeft="24dp"
android:paddingRight="16dp"
android:paddingTop="16dp">
<com.stardust.theme.widget.ThemeColorImageView

View File

@ -4,5 +4,6 @@
<item name="open_by_other_apps" type="id"/>
<item name="create_shortcut" type="id"/>
<item name="delete" type="id"/>
<item name="loop" type="id"/>
<item name="package_name" type="id"/>
<item name="class_name" type="id"/>
</resources>

View File

@ -281,6 +281,7 @@
<string name="text_show_type">显示变量类型</string>
<string name="text_close">关闭</string>
<string name="text_adjust">调整</string>
<string name="text_exit_floating_window">退出悬浮窗</string>
<string-array name="record_control_keys">

View File

@ -15,12 +15,6 @@
android:summary="@string/summary_use_volume_control_record"
android:title="@string/text_use_volume_control_record"/>
<com.stardust.theme.preference.ThemeColorSwitchPreference
android:defaultValue="false"
android:key="@string/key_record_with_root"
android:layout="@layout/preference_custom"
android:title="@string/text_record_with_root"/>
<com.stardust.theme.preference.ThemeColorSwitchPreference
android:defaultValue="true"
android:key="@string/key_record_toast"