Java tutorial
/* * Copyright 2016 Hippo Seven * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.hippo.ehviewer.ui.scene; import android.animation.Animator; import android.app.Activity; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.res.Resources; import android.graphics.Point; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.support.annotation.IntDef; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.design.widget.FloatingActionButton; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.AlertDialog; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.Toolbar; import android.text.InputType; import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.TextUtils; import android.text.style.ImageSpan; import android.view.Display; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.TextView; import com.github.amlcurran.showcaseview.ShowcaseView; import com.github.amlcurran.showcaseview.SimpleShowcaseEventListener; import com.github.amlcurran.showcaseview.targets.PointTarget; import com.hippo.app.CheckBoxDialogBuilder; import com.hippo.app.EditTextDialogBuilder; import com.hippo.drawable.AddDeleteDrawable; import com.hippo.drawable.DrawerArrowDrawable; import com.hippo.easyrecyclerview.EasyRecyclerView; import com.hippo.easyrecyclerview.FastScroller; import com.hippo.ehviewer.EhApplication; import com.hippo.ehviewer.EhDB; import com.hippo.ehviewer.R; import com.hippo.ehviewer.Settings; import com.hippo.ehviewer.client.EhClient; import com.hippo.ehviewer.client.EhRequest; import com.hippo.ehviewer.client.EhUrl; import com.hippo.ehviewer.client.EhUtils; import com.hippo.ehviewer.client.data.GalleryInfo; import com.hippo.ehviewer.client.data.ListUrlBuilder; import com.hippo.ehviewer.client.exception.EhException; import com.hippo.ehviewer.client.parser.GalleryListParser; import com.hippo.ehviewer.dao.QuickSearch; import com.hippo.ehviewer.ui.CommonOperations; import com.hippo.ehviewer.ui.MainActivity; import com.hippo.ehviewer.widget.SearchBar; import com.hippo.ehviewer.widget.SearchLayout; import com.hippo.refreshlayout.RefreshLayout; import com.hippo.ripple.Ripple; import com.hippo.scene.Announcer; import com.hippo.scene.SceneFragment; import com.hippo.util.ApiHelper; import com.hippo.util.AppHelper; import com.hippo.util.DrawableManager; import com.hippo.view.ViewTransition; import com.hippo.widget.ContentLayout; import com.hippo.widget.FabLayout; import com.hippo.widget.SearchBarMover; import com.hippo.yorozuya.AnimationUtils; import com.hippo.yorozuya.MathUtils; import com.hippo.yorozuya.SimpleAnimatorListener; import com.hippo.yorozuya.StringUtils; import com.hippo.yorozuya.ViewUtils; import junit.framework.Assert; import java.io.File; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.List; public final class GalleryListScene extends BaseScene implements EasyRecyclerView.OnItemClickListener, EasyRecyclerView.OnItemLongClickListener, SearchBar.Helper, SearchBar.OnStateChangeListener, FastScroller.OnDragHandlerListener, SearchLayout.Helper, SearchBarMover.Helper, View.OnClickListener, FabLayout.OnClickFabListener, FabLayout.OnExpandListener { @IntDef({ STATE_NORMAL, STATE_SIMPLE_SEARCH, STATE_SEARCH, STATE_SEARCH_SHOW_LIST }) @Retention(RetentionPolicy.SOURCE) private @interface State { } private static final int BACK_PRESSED_INTERVAL = 2000; public final static int REQUEST_CODE_SELECT_IMAGE = 0; public final static String KEY_ACTION = "action"; public final static String ACTION_HOMEPAGE = "action_homepage"; public final static String ACTION_WHATS_HOT = "action_whats_hot"; public final static String ACTION_LIST_URL_BUILDER = "action_list_url_builder"; public final static String KEY_LIST_URL_BUILDER = "list_url_builder"; public final static String KEY_HAS_FIRST_REFRESH = "has_first_refresh"; public final static String KEY_STATE = "state"; private final static int STATE_NORMAL = 0; private final static int STATE_SIMPLE_SEARCH = 1; private final static int STATE_SEARCH = 2; private final static int STATE_SEARCH_SHOW_LIST = 3; private static final long ANIMATE_TIME = 300L; /*--------------- Whole life cycle ---------------*/ @Nullable private EhClient mClient; @Nullable private ListUrlBuilder mUrlBuilder; /*--------------- View life cycle ---------------*/ @Nullable private EasyRecyclerView mRecyclerView; @Nullable private SearchLayout mSearchLayout; @Nullable private SearchBar mSearchBar; @Nullable private View mSearchFab; @Nullable private FabLayout mFabLayout; @Nullable private ViewTransition mViewTransition; @Nullable private GalleryListAdapter mAdapter; @Nullable private GalleryListHelper mHelper; @Nullable private DrawerArrowDrawable mLeftDrawable; @Nullable private AddDeleteDrawable mRightDrawable; @Nullable private SearchBarMover mSearchBarMover; @Nullable private AddDeleteDrawable mActionFabDrawable; @Nullable private final Animator.AnimatorListener mActionFabAnimatorListener = new SimpleAnimatorListener() { @Override public void onAnimationEnd(Animator animation) { if (null != mFabLayout) { mFabLayout.getPrimaryFab().setVisibility(View.INVISIBLE); } } }; @Nullable private final Animator.AnimatorListener mSearchFabAnimatorListener = new SimpleAnimatorListener() { @Override public void onAnimationEnd(Animator animation) { if (null != mSearchFab) { mSearchFab.setVisibility(View.INVISIBLE); } } }; private int mHideActionFabSlop; private boolean mShowActionFab = true; @Nullable private final RecyclerView.OnScrollListener mOnScrollListener = new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { if (dy >= mHideActionFabSlop) { hideActionFab(); } else if (dy <= -mHideActionFabSlop / 2) { showActionFab(); } } }; @State private int mState = STATE_NORMAL; // Double click back exit private long mPressBackTime = 0; private boolean mHasFirstRefresh = false; private int mNavCheckedId = 0; private ShowcaseView mShowcaseView; @Override public int getNavCheckedItem() { return mNavCheckedId; } private void handleArgs(Bundle args) { if (null == args || null == mUrlBuilder) { return; } String action = args.getString(KEY_ACTION); if (ACTION_HOMEPAGE.equals(action)) { mUrlBuilder.reset(); } else if (ACTION_WHATS_HOT.equals(action)) { mUrlBuilder.setMode(ListUrlBuilder.MODE_WHATS_HOT); } else if (ACTION_LIST_URL_BUILDER.equals(action)) { ListUrlBuilder builder = args.getParcelable(KEY_LIST_URL_BUILDER); if (builder != null) { mUrlBuilder.set(builder); } } } @Override public void onNewArguments(@NonNull Bundle args) { handleArgs(args); onUpdateUrlBuilder(); if (null != mHelper) { mHelper.refresh(); } setState(STATE_NORMAL); if (null != mSearchBarMover) { mSearchBarMover.showSearchBar(); } } @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); Context context = getContext2(); Assert.assertNotNull(context); mClient = EhApplication.getEhClient(context); if (savedInstanceState == null) { onInit(); } else { onRestore(savedInstanceState); } } public void onInit() { mUrlBuilder = new ListUrlBuilder(); handleArgs(getArguments()); } @SuppressWarnings("WrongConstant") private void onRestore(Bundle savedInstanceState) { mHasFirstRefresh = savedInstanceState.getBoolean(KEY_HAS_FIRST_REFRESH); mUrlBuilder = savedInstanceState.getParcelable(KEY_LIST_URL_BUILDER); mState = savedInstanceState.getInt(KEY_STATE); } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); boolean hasFirstRefresh; if (mHelper != null && 1 == mHelper.getShownViewIndex()) { hasFirstRefresh = false; } else { hasFirstRefresh = mHasFirstRefresh; } outState.putBoolean(KEY_HAS_FIRST_REFRESH, hasFirstRefresh); outState.putParcelable(KEY_LIST_URL_BUILDER, mUrlBuilder); outState.putInt(KEY_STATE, mState); } @Override public void onDestroy() { super.onDestroy(); mClient = null; mUrlBuilder = null; } private void setSearchBarHint(Context context, SearchBar searchBar) { Resources resources = context.getResources(); Drawable searchImage = DrawableManager.getDrawable(context, R.drawable.v_magnify_x24); SpannableStringBuilder ssb = new SpannableStringBuilder(" "); ssb.append(resources.getString( EhUrl.SITE_EX == Settings.getGallerySite() ? R.string.gallery_list_search_bar_hint_exhentai : R.string.gallery_list_search_bar_hint_e_hentai)); int textSize = (int) (searchBar.getEditTextTextSize() * 1.25); if (searchImage != null) { searchImage.setBounds(0, 0, textSize, textSize); ssb.setSpan(new ImageSpan(searchImage), 1, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } searchBar.setEditTextHint(ssb); } @Nullable private static String getSuitableTitleForUrlBuilder(Resources resources, ListUrlBuilder urlBuilder, boolean appName) { String keyword = urlBuilder.getKeyword(); int category = urlBuilder.getCategory(); if (ListUrlBuilder.MODE_NORMAL == urlBuilder.getMode() && EhUtils.NONE == category && TextUtils.isEmpty(keyword)) { return resources.getString(appName ? R.string.app_name : R.string.homepage); } else if (ListUrlBuilder.MODE_WHATS_HOT == urlBuilder.getMode()) { return resources.getString(R.string.whats_hot); } else if (!TextUtils.isEmpty(keyword)) { return keyword; } else if (MathUtils.hammingWeight(category) == 1) { return EhUtils.getCategory(category); } else { return null; } } // Update search bar title, drawer checked item private void onUpdateUrlBuilder() { ListUrlBuilder builder = mUrlBuilder; Resources resources = getResources2(); if (null == resources || null == builder) { return; } String keyword = builder.getKeyword(); int category = builder.getCategory(); // Update search edit text if (!TextUtils.isEmpty(keyword) && null != mSearchBar) { mSearchBar.setText(keyword); mSearchBar.cursorToEnd(); } // Update title String title = getSuitableTitleForUrlBuilder(resources, builder, true); if (null == title) { title = resources.getString(R.string.search); } if (null != mSearchBar) { mSearchBar.setTitle(title); } // Update nav checked item int checkedItemId; if (ListUrlBuilder.MODE_NORMAL == builder.getMode() && EhUtils.NONE == category && TextUtils.isEmpty(keyword)) { checkedItemId = R.id.nav_homepage; } else if (ListUrlBuilder.MODE_WHATS_HOT == builder.getMode()) { checkedItemId = R.id.nav_whats_hot; } else { checkedItemId = 0; } setNavCheckedItem(checkedItemId); mNavCheckedId = checkedItemId; } @Nullable @Override public View onCreateView2(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.scene_gallery_list, container, false); Context context = getContext2(); Assert.assertNotNull(context); Resources resources = context.getResources(); mHideActionFabSlop = ViewConfiguration.get(context).getScaledTouchSlop(); mShowActionFab = true; View mainLayout = ViewUtils.$$(view, R.id.main_layout); ContentLayout contentLayout = (ContentLayout) ViewUtils.$$(mainLayout, R.id.content_layout); mRecyclerView = contentLayout.getRecyclerView(); FastScroller fastScroller = contentLayout.getFastScroller(); RefreshLayout refreshLayout = contentLayout.getRefreshLayout(); mSearchLayout = (SearchLayout) ViewUtils.$$(mainLayout, R.id.search_layout); mSearchBar = (SearchBar) ViewUtils.$$(mainLayout, R.id.search_bar); mFabLayout = (FabLayout) ViewUtils.$$(mainLayout, R.id.fab_layout); mSearchFab = ViewUtils.$$(mainLayout, R.id.search_fab); int paddingTopSB = resources.getDimensionPixelOffset(R.dimen.gallery_padding_top_search_bar); int paddingBottomFab = resources.getDimensionPixelOffset(R.dimen.gallery_padding_bottom_fab); mViewTransition = new ViewTransition(contentLayout, mSearchLayout); mHelper = new GalleryListHelper(); mHelper.setEmptyString(resources.getString(R.string.gallery_list_empty_hit)); contentLayout.setHelper(mHelper); contentLayout.getFastScroller().setOnDragHandlerListener(this); mAdapter = new GalleryListAdapter(inflater, resources, mRecyclerView, Settings.getListMode()); mRecyclerView.setSelector(Ripple.generateRippleDrawable(context, false)); mRecyclerView.setDrawSelectorOnTop(true); mRecyclerView.hasFixedSize(); mRecyclerView.setClipToPadding(false); mRecyclerView.setOnItemClickListener(this); mRecyclerView.setOnItemLongClickListener(this); mRecyclerView.addOnScrollListener(mOnScrollListener); fastScroller.setPadding(fastScroller.getPaddingLeft(), fastScroller.getPaddingTop() + paddingTopSB, fastScroller.getPaddingRight(), fastScroller.getPaddingBottom()); refreshLayout.setHeaderTranslationY(paddingTopSB); mLeftDrawable = new DrawerArrowDrawable(context); mRightDrawable = new AddDeleteDrawable(context); mSearchBar.setLeftDrawable(mLeftDrawable); mSearchBar.setRightDrawable(mRightDrawable); mSearchBar.setHelper(this); mSearchBar.setOnStateChangeListener(this); setSearchBarHint(context, mSearchBar); mSearchLayout.setHelper(this); mSearchLayout.setPadding(mSearchLayout.getPaddingLeft(), mSearchLayout.getPaddingTop() + paddingTopSB, mSearchLayout.getPaddingRight(), mSearchLayout.getPaddingBottom() + paddingBottomFab); mFabLayout.setAutoCancel(true); mFabLayout.setExpanded(false); mFabLayout.setHidePrimaryFab(false); mFabLayout.setOnClickFabListener(this); mFabLayout.setOnExpandListener(this); addAboveSnackView(mFabLayout); mActionFabDrawable = new AddDeleteDrawable(context); mActionFabDrawable.setColor(resources.getColor(R.color.primary_drawable_dark)); mFabLayout.getPrimaryFab().setImageDrawable(mActionFabDrawable); mSearchFab.setOnClickListener(this); mSearchBarMover = new SearchBarMover(this, mSearchBar, mRecyclerView, mSearchLayout); // Update list url builder onUpdateUrlBuilder(); // Restore state int newState = mState; mState = STATE_NORMAL; setState(newState, false); // Only refresh for the first time if (!mHasFirstRefresh) { mHasFirstRefresh = true; mHelper.firstRefresh(); } guideQuickSearch(); return view; } private void guideQuickSearch() { Activity activity = getActivity2(); if (null == activity || !Settings.getGuideQuickSearch()) { return; } Display display = activity.getWindowManager().getDefaultDisplay(); Point point = new Point(); display.getSize(point); mShowcaseView = new ShowcaseView.Builder(activity).withMaterialShowcase().setStyle(R.style.Guide) .setTarget(new PointTarget(point.x, point.y / 3)).blockAllTouches() .setContentTitle(R.string.guide_quick_search_title).setContentText(R.string.guide_quick_search_text) .replaceEndButton(R.layout.button_guide) .setShowcaseEventListener(new SimpleShowcaseEventListener() { @Override public void onShowcaseViewDidHide(ShowcaseView showcaseView) { mShowcaseView = null; ViewUtils.removeFromParent(showcaseView); Settings.putGuideQuickSearch(false); openDrawer(Gravity.RIGHT); } }).build(); } @Override public void onDestroyView() { super.onDestroyView(); if (null != mShowcaseView) { ViewUtils.removeFromParent(mShowcaseView); mShowcaseView = null; } if (null != mSearchBarMover) { mSearchBarMover.cancelAnimation(); mSearchBarMover = null; } if (null != mHelper) { if (1 == mHelper.getShownViewIndex()) { mHasFirstRefresh = false; } mHelper = null; } if (null != mRecyclerView) { mRecyclerView.stopScroll(); mRecyclerView = null; } if (null != mFabLayout) { removeAboveSnackView(mFabLayout); mFabLayout = null; } mAdapter = null; mSearchLayout = null; mSearchBar = null; mSearchFab = null; mViewTransition = null; mLeftDrawable = null; mRightDrawable = null; mActionFabDrawable = null; } private void showQuickSearchTipDialog(final List<QuickSearch> list, final ArrayAdapter<QuickSearch> adapter, final ListView listView, final TextView tip) { Context context = getContext2(); if (null == context) { return; } final CheckBoxDialogBuilder builder = new CheckBoxDialogBuilder(context, getString(R.string.add_quick_search_tip), getString(R.string.get_it), false); builder.setTitle(R.string.readme); builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { if (builder.isChecked()) { Settings.putQuickSearchTip(false); } showAddQuickSearchDialog(list, adapter, listView, tip); } }).show(); } private void showAddQuickSearchDialog(final List<QuickSearch> list, final ArrayAdapter<QuickSearch> adapter, final ListView listView, final TextView tip) { Context context = getContext2(); final ListUrlBuilder urlBuilder = mUrlBuilder; if (null == context || null == urlBuilder) { return; } // Can't add image search as quick search if (ListUrlBuilder.MODE_IMAGE_SEARCH == urlBuilder.getMode()) { showTip(R.string.image_search_not_quick_search, LENGTH_SHORT); return; } // Check duplicate for (QuickSearch q : list) { if (urlBuilder.equalsQuickSearch(q)) { showTip(getString(R.string.duplicate_quick_search, q.name), LENGTH_SHORT); return; } } final EditTextDialogBuilder builder = new EditTextDialogBuilder(context, getSuitableTitleForUrlBuilder(context.getResources(), urlBuilder, false), getString(R.string.quick_search)); builder.setTitle(R.string.add_quick_search_dialog_title); builder.setPositiveButton(android.R.string.ok, null); final AlertDialog dialog = builder.show(); dialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String text = builder.getText().trim(); // Check name empty if (TextUtils.isEmpty(text)) { builder.setError(getString(R.string.name_is_empty)); return; } // Check name duplicate for (QuickSearch q : list) { if (text.equals(q.name)) { builder.setError(getString(R.string.duplicate_name)); return; } } builder.setError(null); dialog.dismiss(); QuickSearch quickSearch = urlBuilder.toQuickSearch(); quickSearch.name = text; EhDB.insertQuickSearch(quickSearch); list.add(quickSearch); adapter.notifyDataSetChanged(); if (0 == list.size()) { tip.setVisibility(View.VISIBLE); listView.setVisibility(View.GONE); } else { tip.setVisibility(View.GONE); listView.setVisibility(View.VISIBLE); } } }); } @Override public View onCreateDrawerView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.drawer_list, container, false); Toolbar toolbar = (Toolbar) ViewUtils.$$(view, R.id.toolbar); final TextView tip = (TextView) ViewUtils.$$(view, R.id.tip); final ListView listView = (ListView) ViewUtils.$$(view, R.id.list_view); Context context = getContext2(); Assert.assertNotNull(context); final List<QuickSearch> list = EhDB.getAllQuickSearch(); final ArrayAdapter<QuickSearch> adapter = new ArrayAdapter<>(context, R.layout.item_simple_list, list); listView.setAdapter(adapter); listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { if (null == mHelper || null == mUrlBuilder) { return; } mUrlBuilder.set(list.get(position)); mUrlBuilder.setPageIndex(0); onUpdateUrlBuilder(); mHelper.refresh(); setState(STATE_NORMAL); closeDrawer(Gravity.RIGHT); } }); tip.setText(R.string.quick_search_tip); toolbar.setTitle(R.string.quick_search); toolbar.inflateMenu(R.menu.drawer_gallery_list); toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { int id = item.getItemId(); switch (id) { case R.id.action_add: if (Settings.getQuickSearchTip()) { showQuickSearchTipDialog(list, adapter, listView, tip); } else { showAddQuickSearchDialog(list, adapter, listView, tip); } break; case R.id.action_settings: startScene(new Announcer(QuickSearchScene.class)); break; } return true; } }); if (0 == list.size()) { tip.setVisibility(View.VISIBLE); listView.setVisibility(View.GONE); } else { tip.setVisibility(View.GONE); listView.setVisibility(View.VISIBLE); } return view; } private boolean checkDoubleClickExit() { if (getStackIndex() != 0) { return false; } long time = System.currentTimeMillis(); if (time - mPressBackTime > BACK_PRESSED_INTERVAL) { // It is the last scene mPressBackTime = time; showTip(R.string.press_twice_exit, LENGTH_SHORT); return true; } else { return false; } } @Override public void onBackPressed() { if (null != mShowcaseView) { return; } if (null != mFabLayout && mFabLayout.isExpanded()) { mFabLayout.setExpanded(false); return; } boolean handle; switch (mState) { default: case STATE_NORMAL: handle = checkDoubleClickExit(); break; case STATE_SIMPLE_SEARCH: setState(STATE_NORMAL); handle = true; break; case STATE_SEARCH: setState(STATE_NORMAL); handle = true; break; case STATE_SEARCH_SHOW_LIST: setState(STATE_SEARCH); handle = true; break; } if (!handle) { finish(); } } @Override public boolean onItemClick(EasyRecyclerView parent, View view, int position, long id) { if (null == mHelper || null == mRecyclerView) { return false; } GalleryInfo gi = mHelper.getDataAt(position); Bundle args = new Bundle(); args.putString(GalleryDetailScene.KEY_ACTION, GalleryDetailScene.ACTION_GALLERY_INFO); args.putParcelable(GalleryDetailScene.KEY_GALLERY_INFO, gi); Announcer announcer = new Announcer(GalleryDetailScene.class).setArgs(args); View thumb; if (ApiHelper.SUPPORT_TRANSITION && null != (thumb = view.findViewById(R.id.thumb))) { announcer.setTranHelper(new EnterGalleryDetailTransaction(thumb)); } startScene(announcer); return true; } @Override public void onClick(View v) { if (STATE_NORMAL != mState && null != mSearchBar) { mSearchBar.applySearch(); } } @Override public void onClickPrimaryFab(FabLayout view, FloatingActionButton fab) { if (STATE_NORMAL == mState) { view.toggle(); } } private void showGoToDialog() { Context context = getContext2(); if (null == context || null == mHelper) { return; } final int page = mHelper.getPageForTop(); final int pages = mHelper.getPages(); String hint = getString(R.string.go_to_hint, page + 1, pages); final EditTextDialogBuilder builder = new EditTextDialogBuilder(context, null, hint); builder.getEditText().setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL); final AlertDialog dialog = builder.setTitle(R.string.go_to).setPositiveButton(android.R.string.ok, null) .show(); dialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (null == mHelper) { dialog.dismiss(); return; } String text = builder.getText().trim(); int goTo; try { goTo = Integer.parseInt(text) - 1; } catch (NumberFormatException e) { builder.setError(getString(R.string.error_invalid_number)); return; } if (goTo < 0 || goTo >= pages) { builder.setError(getString(R.string.error_out_of_range)); return; } builder.setError(null); mHelper.goTo(goTo); AppHelper.hideSoftInput(dialog); dialog.dismiss(); } }); } @Override public void onClickSecondaryFab(FabLayout view, FloatingActionButton fab, int position) { if (null == mHelper) { return; } switch (position) { case 0: // Go to if (mHelper.canGoTo()) { showGoToDialog(); } break; case 1: // Refresh mHelper.refresh(); break; } view.setExpanded(false); } @Override public void onExpand(boolean expanded) { if (null == mActionFabDrawable) { return; } if (expanded) { setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, Gravity.LEFT); setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, Gravity.RIGHT); mActionFabDrawable.setDelete(ANIMATE_TIME); } else { setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, Gravity.LEFT); setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, Gravity.RIGHT); mActionFabDrawable.setAdd(ANIMATE_TIME); } } @Override public boolean onItemLongClick(EasyRecyclerView parent, View view, int position, long id) { final Context context = getContext2(); final MainActivity activity = getActivity2(); if (null == context || null == activity || null == mHelper) { return false; } final GalleryInfo gi = mHelper.getDataAt(position); new AlertDialog.Builder(context).setTitle(EhUtils.getSuitableTitle(gi)) .setItems(R.array.gallery_list_menu_entries, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { switch (which) { case 0: // Download CommonOperations.startDownload(activity, gi, false); break; case 1: // Favorites CommonOperations.addToFavorites(activity, gi, new addToFavoriteListener(context, activity.getStageId(), getTag())); break; } } }).show(); return true; } private void showActionFab() { if (null != mFabLayout && STATE_NORMAL == mState && !mShowActionFab) { mShowActionFab = true; View fab = mFabLayout.getPrimaryFab(); fab.setVisibility(View.VISIBLE); fab.setRotation(-45.0f); fab.animate().scaleX(1.0f).scaleY(1.0f).rotation(0.0f).setListener(null).setDuration(ANIMATE_TIME) .setStartDelay(0L).setInterpolator(AnimationUtils.FAST_SLOW_INTERPOLATOR).start(); } } private void hideActionFab() { if (null != mFabLayout && STATE_NORMAL == mState && mShowActionFab) { mShowActionFab = false; View fab = mFabLayout.getPrimaryFab(); fab.animate().scaleX(0.0f).scaleY(0.0f).setListener(mActionFabAnimatorListener) .setDuration(ANIMATE_TIME).setStartDelay(0L) .setInterpolator(AnimationUtils.SLOW_FAST_INTERPOLATOR).start(); } } private void selectSearchFab(boolean animation) { if (null == mFabLayout || null == mSearchFab) { return; } mShowActionFab = false; if (animation) { View fab = mFabLayout.getPrimaryFab(); long delay; if (View.INVISIBLE == fab.getVisibility()) { delay = 0L; } else { delay = ANIMATE_TIME; fab.animate().scaleX(0.0f).scaleY(0.0f).setListener(mActionFabAnimatorListener) .setDuration(ANIMATE_TIME).setStartDelay(0L) .setInterpolator(AnimationUtils.SLOW_FAST_INTERPOLATOR).start(); } mSearchFab.setVisibility(View.VISIBLE); mSearchFab.setRotation(-45.0f); mSearchFab.animate().scaleX(1.0f).scaleY(1.0f).rotation(0.0f).setListener(null) .setDuration(ANIMATE_TIME).setStartDelay(delay) .setInterpolator(AnimationUtils.FAST_SLOW_INTERPOLATOR).start(); } else { mFabLayout.setExpanded(false, false); View fab = mFabLayout.getPrimaryFab(); fab.setVisibility(View.INVISIBLE); fab.setScaleX(0.0f); fab.setScaleY(0.0f); mSearchFab.setVisibility(View.VISIBLE); mSearchFab.setScaleX(1.0f); mSearchFab.setScaleY(1.0f); } } private void selectActionFab(boolean animation) { if (null == mFabLayout || null == mSearchFab) { return; } mShowActionFab = true; if (animation) { long delay; if (View.INVISIBLE == mSearchFab.getVisibility()) { delay = 0L; } else { delay = ANIMATE_TIME; mSearchFab.animate().scaleX(0.0f).scaleY(0.0f).setListener(mSearchFabAnimatorListener) .setDuration(ANIMATE_TIME).setStartDelay(0L) .setInterpolator(AnimationUtils.SLOW_FAST_INTERPOLATOR).start(); } View fab = mFabLayout.getPrimaryFab(); fab.setVisibility(View.VISIBLE); fab.setRotation(-45.0f); fab.animate().scaleX(1.0f).scaleY(1.0f).rotation(0.0f).setListener(null).setDuration(ANIMATE_TIME) .setStartDelay(delay).setInterpolator(AnimationUtils.FAST_SLOW_INTERPOLATOR).start(); } else { mFabLayout.setExpanded(false, false); View fab = mFabLayout.getPrimaryFab(); fab.setVisibility(View.VISIBLE); fab.setScaleX(1.0f); fab.setScaleY(1.0f); mSearchFab.setVisibility(View.INVISIBLE); mSearchFab.setScaleX(0.0f); mSearchFab.setScaleY(0.0f); } } private void setState(@State int state) { setState(state, true); } private void setState(@State int state, boolean animation) { if (null == mSearchBar || null == mSearchBarMover || null == mViewTransition || null == mSearchLayout) { return; } if (mState != state) { int oldState = mState; mState = state; switch (oldState) { case STATE_NORMAL: if (state == STATE_SIMPLE_SEARCH) { mSearchBar.setState(SearchBar.STATE_SEARCH_LIST, animation); mSearchBarMover.returnSearchBarPosition(); selectSearchFab(animation); } else if (state == STATE_SEARCH) { mViewTransition.showView(1, animation); mSearchLayout.scrollSearchContainerToTop(); mSearchBar.setState(SearchBar.STATE_SEARCH, animation); mSearchBarMover.returnSearchBarPosition(); selectSearchFab(animation); } else if (state == STATE_SEARCH_SHOW_LIST) { mViewTransition.showView(1, animation); mSearchLayout.scrollSearchContainerToTop(); mSearchBar.setState(SearchBar.STATE_SEARCH_LIST, animation); mSearchBarMover.returnSearchBarPosition(); selectSearchFab(animation); } break; case STATE_SIMPLE_SEARCH: if (state == STATE_NORMAL) { mSearchBar.setState(SearchBar.STATE_NORMAL, animation); mSearchBarMover.returnSearchBarPosition(); selectActionFab(animation); } else if (state == STATE_SEARCH) { mViewTransition.showView(1, animation); mSearchLayout.scrollSearchContainerToTop(); mSearchBar.setState(SearchBar.STATE_SEARCH, animation); mSearchBarMover.returnSearchBarPosition(); } else if (state == STATE_SEARCH_SHOW_LIST) { mViewTransition.showView(1, animation); mSearchLayout.scrollSearchContainerToTop(); mSearchBar.setState(SearchBar.STATE_SEARCH_LIST, animation); mSearchBarMover.returnSearchBarPosition(); } break; case STATE_SEARCH: if (state == STATE_NORMAL) { mViewTransition.showView(0, animation); mSearchBar.setState(SearchBar.STATE_NORMAL, animation); mSearchBarMover.returnSearchBarPosition(); selectActionFab(animation); } else if (state == STATE_SIMPLE_SEARCH) { mViewTransition.showView(0, animation); mSearchBar.setState(SearchBar.STATE_SEARCH_LIST, animation); mSearchBarMover.returnSearchBarPosition(); } else if (state == STATE_SEARCH_SHOW_LIST) { mSearchBar.setState(SearchBar.STATE_SEARCH_LIST, animation); mSearchBarMover.returnSearchBarPosition(); } break; case STATE_SEARCH_SHOW_LIST: if (state == STATE_NORMAL) { mViewTransition.showView(0, animation); mSearchBar.setState(SearchBar.STATE_NORMAL, animation); mSearchBarMover.returnSearchBarPosition(); selectActionFab(animation); } else if (state == STATE_SIMPLE_SEARCH) { mViewTransition.showView(0, animation); mSearchBar.setState(SearchBar.STATE_SEARCH_LIST, animation); mSearchBarMover.returnSearchBarPosition(); } else if (state == STATE_SEARCH) { mSearchBar.setState(SearchBar.STATE_SEARCH, animation); mSearchBarMover.returnSearchBarPosition(); } break; } } } @Override public void onClickTitle() { if (mState == STATE_NORMAL) { setState(STATE_SIMPLE_SEARCH); } } @Override public void onClickLeftIcon() { if (null == mSearchBar) { return; } if (mSearchBar.getState() == SearchBar.STATE_NORMAL) { toggleDrawer(Gravity.LEFT); } else { setState(STATE_NORMAL); } } @Override public void onClickRightIcon() { if (null == mSearchBar) { return; } if (mSearchBar.getState() == SearchBar.STATE_NORMAL) { setState(STATE_SEARCH); } else { // Clear mSearchBar.setText(""); } } @Override public void onSearchEditTextClick() { if (mState == STATE_SEARCH) { setState(STATE_SEARCH_SHOW_LIST); } } @Override public void onApplySearch(String query) { if (null == mUrlBuilder || null == mHelper || null == mSearchLayout) { return; } if (mState == STATE_SEARCH || mState == STATE_SEARCH_SHOW_LIST) { if (mSearchLayout.isSpecifyGallery()) { int index = query.indexOf(' '); if (index <= 0 || index >= query.length() - 1) { showTip(R.string.error_invalid_specify_gallery, LENGTH_LONG); return; } long gid; String token; try { gid = Long.parseLong(query.substring(0, index)); } catch (NumberFormatException e) { showTip(R.string.error_invalid_specify_gallery, LENGTH_LONG); return; } token = query.substring(index + 1); Bundle args = new Bundle(); args.putString(GalleryDetailScene.KEY_ACTION, GalleryDetailScene.ACTION_GID_TOKEN); args.putLong(GalleryDetailScene.KEY_GID, gid); args.putString(GalleryDetailScene.KEY_TOKEN, token); startScene(new Announcer(GalleryDetailScene.class).setArgs(args)); return; } else { try { mSearchLayout.formatListUrlBuilder(mUrlBuilder, query); } catch (EhException e) { showTip(e.getMessage(), LENGTH_LONG); return; } } } else { mUrlBuilder.reset(); mUrlBuilder.setKeyword(query); } onUpdateUrlBuilder(); mHelper.refresh(); setState(STATE_NORMAL); } @Override public void onSearchEditTextBackPressed() { onBackPressed(); } @Override public void onStartDragHandler() { // Lock right drawer setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, Gravity.RIGHT); } @Override public void onEndDragHandler() { // Restore right drawer setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, Gravity.RIGHT); if (null != mSearchBarMover) { mSearchBarMover.returnSearchBarPosition(); } } @Override public void onStateChange(SearchBar searchBar, int newState, int oldState, boolean animation) { if (null == mLeftDrawable || null == mRightDrawable) { return; } switch (oldState) { default: case SearchBar.STATE_NORMAL: mLeftDrawable.setArrow(animation ? ANIMATE_TIME : 0); mRightDrawable.setDelete(animation ? ANIMATE_TIME : 0); break; case SearchBar.STATE_SEARCH: if (newState == SearchBar.STATE_NORMAL) { mLeftDrawable.setMenu(animation ? ANIMATE_TIME : 0); mRightDrawable.setAdd(animation ? ANIMATE_TIME : 0); } break; case SearchBar.STATE_SEARCH_LIST: if (newState == STATE_NORMAL) { mLeftDrawable.setMenu(animation ? ANIMATE_TIME : 0); mRightDrawable.setAdd(animation ? ANIMATE_TIME : 0); } break; } if (newState == STATE_NORMAL || newState == STATE_SIMPLE_SEARCH) { setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, Gravity.LEFT); setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, Gravity.RIGHT); } else { setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, Gravity.LEFT); setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, Gravity.RIGHT); } } @Override public void onChangeSearchMode() { if (null != mSearchBarMover) { mSearchBarMover.showSearchBar(); } } @Override public void onSelectImage() { Intent intent = new Intent(); intent.setType("image/*"); intent.setAction(Intent.ACTION_GET_CONTENT); startActivityForResult(Intent.createChooser(intent, getString(R.string.select_image)), REQUEST_CODE_SELECT_IMAGE); } // SearchBarMover.Helper @Override public boolean isValidView(RecyclerView recyclerView) { return (mState == STATE_NORMAL && recyclerView == mRecyclerView) || (mState == STATE_SEARCH && recyclerView == mSearchLayout); } // SearchBarMover.Helper @Override public RecyclerView getValidRecyclerView() { if (mState == STATE_NORMAL || mState == STATE_SIMPLE_SEARCH) { return mRecyclerView; } else { return mSearchLayout; } } // SearchBarMover.Helper @Override public boolean forceShowSearchBar() { return mState == STATE_SIMPLE_SEARCH || mState == STATE_SEARCH_SHOW_LIST; } public static void startScene(SceneFragment scene, ListUrlBuilder lub) { scene.startScene(getStartAnnouncer(lub)); } public static Announcer getStartAnnouncer(ListUrlBuilder lub) { Bundle args = new Bundle(); args.putString(KEY_ACTION, ACTION_LIST_URL_BUILDER); args.putParcelable(KEY_LIST_URL_BUILDER, lub); return new Announcer(GalleryListScene.class).setArgs(args); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (REQUEST_CODE_SELECT_IMAGE == requestCode) { if (Activity.RESULT_OK == resultCode && null != mSearchLayout && null != data) { mSearchLayout.setImageUri(data.getData()); } } else { super.onActivityResult(requestCode, resultCode, data); } } private class GalleryListAdapter extends GalleryAdapter { public GalleryListAdapter(@NonNull LayoutInflater inflater, @NonNull Resources resources, @NonNull RecyclerView recyclerView, int type) { super(inflater, resources, recyclerView, type); } @Override public int getItemCount() { return null != mHelper ? mHelper.size() : 0; } @Nullable @Override public GalleryInfo getDataAt(int position) { return null != mHelper ? mHelper.getDataAt(position) : null; } } private class GalleryListHelper extends ContentLayout.ContentHelper<GalleryInfo> { @Override protected void getPageData(int taskId, int type, int page) { MainActivity activity = getActivity2(); if (null == activity || null == mClient || null == mUrlBuilder) { return; } mUrlBuilder.setPageIndex(page); if (ListUrlBuilder.MODE_WHATS_HOT == mUrlBuilder.getMode()) { EhRequest request = new EhRequest(); request.setMethod(EhClient.METHOD_GET_WHATS_HOT); request.setCallback(new GetWhatsHotListener(getContext(), activity.getStageId(), getTag(), taskId)); request.setArgs(); mClient.execute(request); } else if (ListUrlBuilder.MODE_IMAGE_SEARCH == mUrlBuilder.getMode()) { EhRequest request = new EhRequest(); request.setMethod(EhClient.METHOD_IMAGE_SEARCH); request.setCallback( new GetGalleryListListener(getContext(), activity.getStageId(), getTag(), taskId)); request.setArgs(new File(StringUtils.avoidNull(mUrlBuilder.getImagePath())), mUrlBuilder.isUseSimilarityScan(), mUrlBuilder.isOnlySearchCovers(), mUrlBuilder.isShowExpunged()); mClient.execute(request); } else { String url = mUrlBuilder.build(); EhRequest request = new EhRequest(); request.setMethod(EhClient.METHOD_GET_GALLERY_LIST); request.setCallback( new GetGalleryListListener(getContext(), activity.getStageId(), getTag(), taskId)); request.setArgs(url); mClient.execute(request); } } @Override protected Context getContext() { return GalleryListScene.this.getContext2(); } @Override protected void notifyDataSetChanged() { if (null != mAdapter) { mAdapter.notifyDataSetChanged(); } } @Override protected void notifyItemRangeRemoved(int positionStart, int itemCount) { if (null != mAdapter) { mAdapter.notifyItemRangeRemoved(positionStart, itemCount); } } @Override protected void notifyItemRangeInserted(int positionStart, int itemCount) { if (null != mAdapter) { mAdapter.notifyItemRangeInserted(positionStart, itemCount); } } @Override public void onShowView(View hiddenView, View shownView) { if (null != mSearchBarMover) { mSearchBarMover.showSearchBar(); } showActionFab(); } @Override protected void onScrollToPosition(int postion) { if (0 == postion) { if (null != mSearchBarMover) { mSearchBarMover.showSearchBar(); } showActionFab(); } } } private void onGetGalleryListSuccess(GalleryListParser.Result result, int taskId) { if (mHelper != null && mSearchBarMover != null && mHelper.isCurrentTask(taskId)) { mHelper.setPages(taskId, result.pages); mHelper.onGetPageData(taskId, result.galleryInfoList); } } private void onGetGalleryListFailure(Exception e, int taskId) { if (mHelper != null && mSearchBarMover != null && mHelper.isCurrentTask(taskId)) { mHelper.onGetException(taskId, e); } } private void onGetWhatsHotSuccess(List<GalleryInfo> result, int taskId) { if (mHelper != null && mSearchBarMover != null && mHelper.isCurrentTask(taskId)) { mHelper.setPages(taskId, 1); mHelper.onGetPageData(taskId, result); } } private void onGetWhatsHotFailure(Exception e, int taskId) { if (mHelper != null && mSearchBarMover != null && mHelper.isCurrentTask(taskId)) { mHelper.onGetException(taskId, e); } } private static class GetWhatsHotListener extends EhCallback<GalleryListScene, List<GalleryInfo>> { private final int mTaskId; public GetWhatsHotListener(Context context, int stageId, String sceneTag, int taskId) { super(context, stageId, sceneTag); mTaskId = taskId; } @Override public void onSuccess(List<GalleryInfo> result) { GalleryListScene scene = getScene(); if (scene != null) { scene.onGetWhatsHotSuccess(result, mTaskId); } } @Override public void onFailure(Exception e) { GalleryListScene scene = getScene(); if (scene != null) { scene.onGetWhatsHotFailure(e, mTaskId); } } @Override public void onCancel() { } @Override public boolean isInstance(SceneFragment scene) { return scene instanceof GalleryListScene; } } private static class GetGalleryListListener extends EhCallback<GalleryListScene, GalleryListParser.Result> { private final int mTaskId; public GetGalleryListListener(Context context, int stageId, String sceneTag, int taskId) { super(context, stageId, sceneTag); mTaskId = taskId; } @Override public void onSuccess(GalleryListParser.Result result) { GalleryListScene scene = getScene(); if (scene != null) { scene.onGetGalleryListSuccess(result, mTaskId); } } @Override public void onFailure(Exception e) { GalleryListScene scene = getScene(); if (scene != null) { scene.onGetGalleryListFailure(e, mTaskId); } } @Override public void onCancel() { } @Override public boolean isInstance(SceneFragment scene) { return scene instanceof GalleryListScene; } } private static class addToFavoriteListener extends EhCallback<GalleryListScene, Void> { public addToFavoriteListener(Context context, int stageId, String sceneTag) { super(context, stageId, sceneTag); } @Override public void onSuccess(Void result) { showTip(R.string.add_to_favorite_success, LENGTH_SHORT); } @Override public void onFailure(Exception e) { showTip(R.string.add_to_favorite_failure, LENGTH_SHORT); } @Override public void onCancel() { } @Override public boolean isInstance(SceneFragment scene) { return scene instanceof GalleryListScene; } } }