diff --git a/app/build.gradle b/app/build.gradle index 8182adbc..78b3724b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,8 +9,8 @@ android { applicationId "com.stardust.scriptdroid" minSdkVersion 17 targetSdkVersion 23 - versionCode 201 - versionName "3.0.0 Alpha2" + versionCode 202 + versionName "3.0.0 Alpha3" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" multiDexEnabled true ndk { diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/common/ScriptOperations.java b/app/src/main/java/com/stardust/scriptdroid/ui/common/ScriptOperations.java index 5104caa5..10dd170e 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/common/ScriptOperations.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/common/ScriptOperations.java @@ -55,7 +55,7 @@ public class ScriptOperations { } public ScriptOperations(Context context, View view) { - this(context, view, MyScriptListFragment.getCurrentDirectory()); + this(context, view, StorageFileProvider.DEFAULT_DIRECTORY); } public void newScriptFileForScript(final String script) { diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/main/FloatingActionMenu.java b/app/src/main/java/com/stardust/scriptdroid/ui/main/FloatingActionMenu.java new file mode 100644 index 00000000..05a8ccd6 --- /dev/null +++ b/app/src/main/java/com/stardust/scriptdroid/ui/main/FloatingActionMenu.java @@ -0,0 +1,153 @@ +package com.stardust.scriptdroid.ui.main; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.content.Context; +import android.support.annotation.AttrRes; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.design.widget.FloatingActionButton; +import android.support.v4.view.animation.FastOutSlowInInterpolator; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.view.animation.Interpolator; +import android.widget.FrameLayout; +import android.widget.TextView; + +import com.stardust.scriptdroid.R; +import com.stardust.scriptdroid.ui.common.ScriptOperations; + +import io.reactivex.Observable; +import io.reactivex.subjects.PublishSubject; + +/** + * Created by Stardust on 2017/9/24. + */ + +public class FloatingActionMenu extends FrameLayout implements View.OnClickListener { + + public interface OnFloatingActionButtonClickListener { + void onClick(FloatingActionButton button, int pos); + } + + private static final int[] ICONS = { + R.drawable.ic_floating_action_menu_dir, + R.drawable.ic_floating_action_menu_file, + R.drawable.ic_floating_action_menu_open}; + private static final int[] LABELS = {R.string.text_directory, R.string.text_file, R.string.text_import}; + private TextView[] mLabels; + private FloatingActionButton[] mFabs; + private View[] mFabContainers; + private boolean mExpanded = false; + private int mInterval = 30; + private int mDuration = 300; + private final Interpolator mInterpolator = new FastOutSlowInInterpolator(); + private final PublishSubject mState = PublishSubject.create(); + private OnFloatingActionButtonClickListener mOnFloatingActionButtonClickListener; + + public FloatingActionMenu(@NonNull Context context) { + super(context); + init(); + } + + public FloatingActionMenu(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + init(); + } + + public FloatingActionMenu(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(); + } + + private void init() { + buildFabs(ICONS, LABELS); + } + + public boolean isExpanded() { + return mExpanded; + } + + public void expand() { + setVisibility(VISIBLE); + int h = mFabs[0].getHeight(); + for (int i = 0; i < mFabContainers.length; i++) { + animateY(mFabContainers[i], -(h + mInterval) * (i + 1), null); + } + mExpanded = true; + mState.onNext(true); + } + + + private void animateY(View view, float y, Animator.AnimatorListener l) { + view.animate() + .translationY(y) + .setDuration(mDuration) + .setInterpolator(mInterpolator) + .setListener(l) + .start(); + } + + public void collapse() { + animateY(mFabContainers[0], 0, new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + setVisibility(INVISIBLE); + } + }); + for (int i = 1; i < mFabContainers.length; i++) { + animateY(mFabContainers[i], 0, null); + } + mExpanded = false; + mState.onNext(false); + } + + private void buildFabs(int[] icons, int[] labels) { + if (icons.length != labels.length) + throw new IllegalArgumentException("icons.length = " + icons.length + " is not equal to labels.length = " + labels.length); + mFabs = new FloatingActionButton[icons.length]; + mLabels = new TextView[icons.length]; + mFabContainers = new View[icons.length]; + LayoutInflater inflater = LayoutInflater.from(getContext()); + for (int i = 0; i < icons.length; i++) { + mFabContainers[i] = inflater.inflate(R.layout.item_floating_action_menu, this, false); + mFabs[i] = (FloatingActionButton) mFabContainers[i].findViewById(R.id.floating_action_button); + mFabs[i].setImageResource(icons[i]); + mFabs[i].setOnClickListener(this); + mFabs[i].setTag(i); + mLabels[i] = (TextView) mFabContainers[i].findViewById(R.id.label); + mLabels[i].setText(labels[i]); + addView(mFabContainers[i]); + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int heightMode = MeasureSpec.getMode(heightMeasureSpec); + // Call super.onMeasure to measure children and width + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + if (heightMode == MeasureSpec.EXACTLY) { + return; + } + int h = mFabContainers[0].getMeasuredHeight(); + setMeasuredDimension(getMeasuredWidth(), (h + mInterval) * mFabs.length + h); + } + + public PublishSubject getState() { + return mState; + } + + @Override + public void onClick(View v) { + collapse(); + if (mOnFloatingActionButtonClickListener != null) { + mOnFloatingActionButtonClickListener.onClick((FloatingActionButton) v, (int) v.getTag()); + } + + } + + public void setOnFloatingActionButtonClickListener(OnFloatingActionButtonClickListener onFloatingActionButtonClickListener) { + mOnFloatingActionButtonClickListener = onFloatingActionButtonClickListener; + } +} diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/main/MainActivity.java b/app/src/main/java/com/stardust/scriptdroid/ui/main/MainActivity.java index 7b04dfa0..edba880c 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/main/MainActivity.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/main/MainActivity.java @@ -154,17 +154,23 @@ public class MainActivity extends BaseActivity implements OnActivityResultDelega public void OnInstantiate(int pos, Fragment fragment) { ((ViewPagerFragment) fragment).setFab(mFab); if (pos == mViewPager.getCurrentItem()) { - ((ViewPagerFragment) fragment).onPageSelected(); + ((ViewPagerFragment) fragment).onPageShow(); } } }); mViewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { + private ViewPagerFragment mPreviousFragment; + @Override public void onPageSelected(int position) { Fragment fragment = mPagerAdapter.getStoredFragment(position); if (fragment == null) return; - ((ViewPagerFragment) fragment).onPageSelected(); + if (mPreviousFragment != null) { + mPreviousFragment.onPageHide(); + } + mPreviousFragment = (ViewPagerFragment) fragment; + mPreviousFragment.onPageShow(); } }); } diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/main/NewFileDialogBuilder.java b/app/src/main/java/com/stardust/scriptdroid/ui/main/NewFileDialogBuilder.java deleted file mode 100644 index 126eed8d..00000000 --- a/app/src/main/java/com/stardust/scriptdroid/ui/main/NewFileDialogBuilder.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.stardust.scriptdroid.ui.main; - -import android.content.Context; -import android.view.View; - -import com.github.aakira.expandablelayout.ExpandableRelativeLayout; -import com.stardust.scriptdroid.R; -import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder; - -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; - -/** - * Created by Stardust on 2017/8/25. - */ - -public class NewFileDialogBuilder extends ThemeColorMaterialDialogBuilder { - - @BindView(R.id.layout_new_file) - ExpandableRelativeLayout mLayoutNewFile; - - @BindView(R.id.layout_import) - ExpandableRelativeLayout mLayoutImport; - - ExpandableRelativeLayout mExpandedLayout; - - - public NewFileDialogBuilder(Context context) { - super(context); - View view = View.inflate(context, R.layout.new_file_dialog, null); - customView(view, true); - title(R.string.text_new); - positiveText(R.string.ok); - negativeText(R.string.cancel); - ButterKnife.bind(this, view); - mExpandedLayout = mLayoutNewFile; - } - - @OnClick(R.id.option_new_file) - void expandLayoutNewFile() { - if (mExpandedLayout != mLayoutNewFile) { - if(mExpandedLayout != null){ - mExpandedLayout.collapse(); - } - mLayoutNewFile.expand(); - mExpandedLayout = mLayoutNewFile; - } - } - - - @OnClick(R.id.option_import) - void expandLayoutImport() { - if (mExpandedLayout != mLayoutImport) { - if(mExpandedLayout != null){ - mExpandedLayout.collapse(); - } - mLayoutImport.expand(); - mExpandedLayout = mLayoutImport; - } - } - -} - diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/main/ViewPagerFragment.java b/app/src/main/java/com/stardust/scriptdroid/ui/main/ViewPagerFragment.java index 5f6705df..1c8716df 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/main/ViewPagerFragment.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/main/ViewPagerFragment.java @@ -32,7 +32,7 @@ public abstract class ViewPagerFragment extends Fragment { protected abstract void onFabClick(FloatingActionButton fab); - public void onPageSelected() { + public void onPageShow() { if (mFabRotation == ROTATION_GONE) { if (mFab.getVisibility() == View.VISIBLE) { mFab.hide(); @@ -54,4 +54,7 @@ public abstract class ViewPagerFragment extends Fragment { } + public void onPageHide() { + + } } diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/main/drawer/DrawerFragment.java b/app/src/main/java/com/stardust/scriptdroid/ui/main/drawer/DrawerFragment.java index e944fc34..c229ad1a 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/main/drawer/DrawerFragment.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/main/drawer/DrawerFragment.java @@ -244,6 +244,9 @@ public class DrawerFragment extends android.support.v4.app.Fragment { @Override public void onError(@io.reactivex.annotations.NonNull Throwable e) { + if(isHidden()){ + return; + } Toast.makeText(App.getApp(), e.getMessage(), Toast.LENGTH_SHORT).show(); mConnectionItem.getSwitchCompat().setChecked(false, false); mConnectionItem.setProgress(false); diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/main/scripts/MyScriptListFragment.java b/app/src/main/java/com/stardust/scriptdroid/ui/main/scripts/MyScriptListFragment.java index fa60a1ed..c74d9781 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/main/scripts/MyScriptListFragment.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/main/scripts/MyScriptListFragment.java @@ -1,5 +1,6 @@ package com.stardust.scriptdroid.ui.main.scripts; +import android.app.Activity; import android.support.annotation.NonNull; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.Snackbar; @@ -12,9 +13,12 @@ import com.stardust.scriptdroid.R; import com.stardust.scriptdroid.script.ScriptFile; import com.stardust.scriptdroid.script.Scripts; import com.stardust.scriptdroid.script.StorageFileProvider; +import com.stardust.scriptdroid.tool.SimpleObserver; import com.stardust.scriptdroid.ui.common.ScriptLoopDialog; -import com.stardust.scriptdroid.ui.main.NewFileDialogBuilder; +import com.stardust.scriptdroid.ui.common.ScriptOperations; +import com.stardust.scriptdroid.ui.main.FloatingActionMenu; import com.stardust.scriptdroid.ui.main.ViewPagerFragment; +import com.stardust.util.BackPressedHandler; import org.androidannotations.annotations.AfterViews; import org.androidannotations.annotations.EFragment; @@ -26,6 +30,7 @@ import butterknife.OnClick; import butterknife.Optional; import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; import io.reactivex.functions.Consumer; import io.reactivex.schedulers.Schedulers; @@ -33,12 +38,10 @@ import io.reactivex.schedulers.Schedulers; * Created by Stardust on 2017/3/13. */ @EFragment(R.layout.fragment_my_script_list) -public class MyScriptListFragment extends ViewPagerFragment { +public class MyScriptListFragment extends ViewPagerFragment implements BackPressedHandler, FloatingActionMenu.OnFloatingActionButtonClickListener { private static final String TAG = "MyScriptListFragment"; - private static ScriptFile sCurrentDirectory = StorageFileProvider.DEFAULT_DIRECTORY; - public MyScriptListFragment() { super(0); } @@ -46,6 +49,8 @@ public class MyScriptListFragment extends ViewPagerFragment { @ViewById(R.id.script_file_list) ScriptListView mScriptFileList; + private FloatingActionMenu mFloatingActionMenu; + @AfterViews void setUpViews() { mScriptFileList.setOnScriptFileClickListener(new ScriptListView.OnScriptFileClickListener() { @@ -56,14 +61,87 @@ public class MyScriptListFragment extends ViewPagerFragment { }); } + @Override + public void onResume() { + super.onResume(); + ((BackPressedHandler.HostActivity) getActivity()) + .getBackPressedObserver() + .registerHandlerAtFront(this); + } - public static ScriptFile getCurrentDirectory() { - return sCurrentDirectory; + @Override + public void onPause() { + super.onPause(); + ((BackPressedHandler.HostActivity) getActivity()) + .getBackPressedObserver() + .unregisterHandler(this); } @Override protected void onFabClick(FloatingActionButton fab) { - new NewFileDialogBuilder(getContext()) - .show(); + initFloatingActionMenuIfNeeded(fab); + if (mFloatingActionMenu.isExpanded()) { + mFloatingActionMenu.collapse(); + } else { + mFloatingActionMenu.expand(); + + } + } + + private void initFloatingActionMenuIfNeeded(final FloatingActionButton fab) { + if (mFloatingActionMenu != null) + return; + mFloatingActionMenu = ((FloatingActionMenu) getActivity().findViewById(R.id.floating_action_menu)); + mFloatingActionMenu.getState() + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new SimpleObserver() { + @Override + public void onNext(@io.reactivex.annotations.NonNull Boolean expanding) { + fab.animate() + .rotation(expanding ? 45 : 0) + .setDuration(300) + .start(); + } + }); + mFloatingActionMenu.setOnFloatingActionButtonClickListener(this); + } + + @Override + public boolean onBackPressed(Activity activity) { + if (mFloatingActionMenu != null && mFloatingActionMenu.isExpanded()) { + mFloatingActionMenu.expand(); + return true; + } + return false; + } + + @Override + public void onPageHide() { + if (mFloatingActionMenu != null && mFloatingActionMenu.isExpanded()) { + mFloatingActionMenu.collapse(); + } + } + + @Override + public void onDetach() { + super.onDetach(); + mFloatingActionMenu.setOnFloatingActionButtonClickListener(null); + } + + @Override + public void onClick(FloatingActionButton button, int pos) { + switch (pos) { + case 0: + new ScriptOperations(getContext(), mScriptFileList, mScriptFileList.getCurrentDirectory()) + .newDirectory(); + break; + case 1: + new ScriptOperations(getContext(), mScriptFileList, mScriptFileList.getCurrentDirectory()) + .newScriptFile(); + break; + case 2: + break; + + } } } diff --git a/app/src/main/res/drawable/floating_action_menu_label_bg.xml b/app/src/main/res/drawable/floating_action_menu_label_bg.xml new file mode 100644 index 00000000..38a3db5e --- /dev/null +++ b/app/src/main/res/drawable/floating_action_menu_label_bg.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_floating_action_menu_dir.png b/app/src/main/res/drawable/ic_floating_action_menu_dir.png new file mode 100644 index 00000000..5973d3d9 Binary files /dev/null and b/app/src/main/res/drawable/ic_floating_action_menu_dir.png differ diff --git a/app/src/main/res/drawable/ic_floating_action_menu_file.png b/app/src/main/res/drawable/ic_floating_action_menu_file.png new file mode 100644 index 00000000..4c4a686f Binary files /dev/null and b/app/src/main/res/drawable/ic_floating_action_menu_file.png differ diff --git a/app/src/main/res/drawable/ic_floating_action_menu_open.png b/app/src/main/res/drawable/ic_floating_action_menu_open.png new file mode 100644 index 00000000..0144ab46 Binary files /dev/null and b/app/src/main/res/drawable/ic_floating_action_menu_open.png differ diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index dbe986e8..ea27b980 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -42,17 +42,31 @@ android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior"/> - + > + + + + + diff --git a/app/src/main/res/layout/item_floating_action_menu.xml b/app/src/main/res/layout/item_floating_action_menu.xml new file mode 100644 index 00000000..6eadaaf5 --- /dev/null +++ b/app/src/main/res/layout/item_floating_action_menu.xml @@ -0,0 +1,32 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/new_file_dialog.xml b/app/src/main/res/layout/new_file_dialog.xml index 3ec31000..1624c434 100644 --- a/app/src/main/res/layout/new_file_dialog.xml +++ b/app/src/main/res/layout/new_file_dialog.xml @@ -31,6 +31,7 @@ android:layout_marginTop="@dimen/air_baseline" android:checked="true" android:paddingLeft="16dp" + android:button="@null" android:text="@string/text_file" android:textSize="16sp"/> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ebd246b7..459842cf 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -236,7 +236,7 @@ 未登录 音量下键控制 其他 - 导入… + 导入 auto模式 ui模式 新建