diff --git a/app/src/main/java/com/hippo/ehviewer/EhDB.java b/app/src/main/java/com/hippo/ehviewer/EhDB.java index 0a5e84589..f39a649a2 100644 --- a/app/src/main/java/com/hippo/ehviewer/EhDB.java +++ b/app/src/main/java/com/hippo/ehviewer/EhDB.java @@ -472,4 +472,34 @@ public class EhDB { QuickSearchDao dao = sDaoSession.getQuickSearchDao(); dao.update(quickSearch); } + + public static synchronized void deleteQuickSearch(QuickSearch quickSearch) { + QuickSearchDao dao = sDaoSession.getQuickSearchDao(); + dao.delete(quickSearch); + } + + public static synchronized void moveQuickSearch(int fromPosition, int toPosition) { + if (fromPosition == toPosition) { + return; + } + + boolean reverse = fromPosition > toPosition; + int offset = reverse ? toPosition : fromPosition; + int limit = reverse ? fromPosition - toPosition + 1 : toPosition - fromPosition + 1; + + QuickSearchDao dao = sDaoSession.getQuickSearchDao(); + List list = dao.queryBuilder().orderAsc(QuickSearchDao.Properties.Time) + .offset(offset).limit(limit).list(); + + int step = reverse ? 1 : -1; + int start = reverse ? limit - 1 : 0; + int end = reverse ? 0 : limit - 1; + long toTime = list.get(end).getTime(); + for (int i = end; reverse ? i < start : i > start; i += step) { + list.get(i).setTime(list.get(i + step).getTime()); + } + list.get(start).setTime(toTime); + + dao.updateInTx(list); + } } diff --git a/app/src/main/java/com/hippo/ehviewer/ui/MainActivity.java b/app/src/main/java/com/hippo/ehviewer/ui/MainActivity.java index 13bf1f93a..7d1013804 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/MainActivity.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/MainActivity.java @@ -51,6 +51,7 @@ import com.hippo.ehviewer.ui.scene.GalleryListScene; import com.hippo.ehviewer.ui.scene.GalleryPreviewsScene; import com.hippo.ehviewer.ui.scene.LoginScene; import com.hippo.ehviewer.ui.scene.ProgressScene; +import com.hippo.ehviewer.ui.scene.QuickSearchScene; import com.hippo.ehviewer.ui.scene.WarningScene; import com.hippo.scene.Announcer; import com.hippo.scene.SceneFragment; @@ -91,6 +92,7 @@ public final class MainActivity extends StageActivity registerLaunchMode(AnalyticsScene.class, SceneFragment.LAUNCH_MODE_SINGLE_TASK); registerLaunchMode(LoginScene.class, SceneFragment.LAUNCH_MODE_SINGLE_TASK); registerLaunchMode(GalleryListScene.class, SceneFragment.LAUNCH_MODE_SINGLE_TOP); + registerLaunchMode(QuickSearchScene.class, SceneFragment.LAUNCH_MODE_SINGLE_TASK); registerLaunchMode(GalleryDetailScene.class, SceneFragment.LAUNCH_MODE_STANDARD); registerLaunchMode(GalleryInfoScene.class, SceneFragment.LAUNCH_MODE_STANDARD); registerLaunchMode(GalleryCommentsScene.class, SceneFragment.LAUNCH_MODE_STANDARD); diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.java b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.java index afab13543..15ba74612 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.java @@ -485,6 +485,7 @@ public final class GalleryListScene extends BaseScene showAddQuickSearchDialog(list, adapter, listView, tip); break; case R.id.action_settings: + startScene(new Announcer(QuickSearchScene.class)); break; } return true; diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/QuickSearchScene.java b/app/src/main/java/com/hippo/ehviewer/ui/scene/QuickSearchScene.java new file mode 100644 index 000000000..c62f5b1c0 --- /dev/null +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/QuickSearchScene.java @@ -0,0 +1,301 @@ +/* + * 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.content.DialogInterface; +import android.graphics.drawable.NinePatchDrawable; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v7.app.AlertDialog; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.h6ah4i.android.widget.advrecyclerview.animator.GeneralItemAnimator; +import com.h6ah4i.android.widget.advrecyclerview.animator.SwipeDismissItemAnimator; +import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemAdapter; +import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange; +import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager; +import com.h6ah4i.android.widget.advrecyclerview.swipeable.RecyclerViewSwipeManager; +import com.h6ah4i.android.widget.advrecyclerview.swipeable.SwipeableItemAdapter; +import com.h6ah4i.android.widget.advrecyclerview.swipeable.SwipeableItemConstants; +import com.h6ah4i.android.widget.advrecyclerview.swipeable.action.SwipeResultAction; +import com.h6ah4i.android.widget.advrecyclerview.swipeable.action.SwipeResultActionDefault; +import com.h6ah4i.android.widget.advrecyclerview.swipeable.action.SwipeResultActionMoveToSwipedDirection; +import com.h6ah4i.android.widget.advrecyclerview.touchguard.RecyclerViewTouchActionGuardManager; +import com.h6ah4i.android.widget.advrecyclerview.utils.AbstractDraggableSwipeableItemViewHolder; +import com.hippo.easyrecyclerview.EasyRecyclerView; +import com.hippo.ehviewer.EhDB; +import com.hippo.ehviewer.R; +import com.hippo.ehviewer.dao.QuickSearch; +import com.hippo.view.ViewTransition; +import com.hippo.yorozuya.ViewUtils; + +import java.util.List; + +public final class QuickSearchScene extends ToolbarScene { + + /*--------------- + Whole life cycle + ---------------*/ + @Nullable + private List mQuickSearchList; + + /*--------------- + View life cycle + ---------------*/ + @Nullable + private EasyRecyclerView mRecyclerView; + @Nullable + private ViewTransition mViewTransition; + @Nullable + private RecyclerView.Adapter mAdapter; + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mQuickSearchList = EhDB.getAllQuickSearch(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + mQuickSearchList = null; + } + + @SuppressWarnings("deprecation") + @Nullable + @Override + public View onCreateView2(LayoutInflater inflater, + @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.scene_download_label, container, false); + + mRecyclerView = (EasyRecyclerView) ViewUtils.$$(view, R.id.recycler_view); + View tip = ViewUtils.$$(view, R.id.tip); + TextView tipText = (TextView) ViewUtils.$$(tip, R.id.tip_text); + mViewTransition = new ViewTransition(mRecyclerView, tip); + + tipText.setText(R.string.no_quick_search); + + // touch guard manager (this class is required to suppress scrolling while swipe-dismiss animation is running) + RecyclerViewTouchActionGuardManager guardManager = new RecyclerViewTouchActionGuardManager(); + guardManager.setInterceptVerticalScrollingWhileAnimationRunning(true); + guardManager.setEnabled(true); + // drag & drop manager + RecyclerViewDragDropManager dragDropManager = new RecyclerViewDragDropManager(); + dragDropManager.setDraggingItemShadowDrawable( + (NinePatchDrawable) getResources().getDrawable(R.drawable.shadow_8dp)); + // swipe manager + RecyclerViewSwipeManager swipeManager = new RecyclerViewSwipeManager(); + RecyclerView.Adapter adapter = new QuickSearchAdapter(); + adapter.setHasStableIds(true); + adapter = dragDropManager.createWrappedAdapter(adapter); // wrap for dragging + adapter = swipeManager.createWrappedAdapter(adapter); // wrap for swiping + mAdapter = adapter; + final GeneralItemAnimator animator = new SwipeDismissItemAnimator(); + animator.setSupportsChangeAnimations(false); + mRecyclerView.hasFixedSize(); + mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext())); + mRecyclerView.setAdapter(adapter); + mRecyclerView.setItemAnimator(animator); + guardManager.attachRecyclerView(mRecyclerView); + swipeManager.attachRecyclerView(mRecyclerView); + dragDropManager.attachRecyclerView(mRecyclerView); + + updateView(); + + return view; + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + setTitle(R.string.quick_search); + setNavigationIcon(R.drawable.v_arrow_left_dark_x24); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + + mRecyclerView = null; + mViewTransition = null; + mAdapter = null; + } + + + private void updateView() { + if (mViewTransition != null) { + if (mQuickSearchList != null && mQuickSearchList.size() > 0) { + mViewTransition.showView(0); + } else { + mViewTransition.showView(1); + } + } + } + + private class QuickSearchHolder extends AbstractDraggableSwipeableItemViewHolder + implements View.OnClickListener { + + public final View swipeHandler; + public final TextView label; + public final View dragHandler; + + public QuickSearchHolder(View itemView) { + super(itemView); + + swipeHandler = ViewUtils.$$(itemView, R.id.swipe_handler); + label = (TextView) ViewUtils.$$(itemView, R.id.label); + dragHandler = ViewUtils.$$(itemView, R.id.drag_handler); + } + + @Override + public View getSwipeableContainerView() { + return swipeHandler; + } + + @Override + public void onClick(View v) { + + } + } + + + private class QuickSearchAdapter extends RecyclerView.Adapter + implements DraggableItemAdapter, + SwipeableItemAdapter { + + @Override + public QuickSearchHolder onCreateViewHolder(ViewGroup parent, int viewType) { + return new QuickSearchHolder(getActivity().getLayoutInflater() + .inflate(R.layout.item_quick_search, parent, false)); + } + + @Override + public void onBindViewHolder(QuickSearchHolder holder, int position) { + if (mQuickSearchList != null) { + holder.label.setText(mQuickSearchList.get(position).name); + } + holder.setSwipeItemHorizontalSlideAmount(0); + } + + @Override + public long getItemId(int position) { + return mQuickSearchList != null ? mQuickSearchList.get(position).getId() : 0; + } + + @Override + public int getItemCount() { + return mQuickSearchList != null ? mQuickSearchList.size() : 0; + } + + @Override + public boolean onCheckCanStartDrag(QuickSearchHolder holder, int position, int x, int y) { + return ViewUtils.isViewUnder(holder.dragHandler, x, y, 0); + } + + @Override + public ItemDraggableRange onGetItemDraggableRange(QuickSearchHolder holder, int position) { + return null; + } + + @Override + public void onMoveItem(int fromPosition, int toPosition) { + if (fromPosition == toPosition) { + return; + } + if (null == mQuickSearchList) { + return; + } + + EhDB.moveQuickSearch(fromPosition, toPosition); + final QuickSearch item = mQuickSearchList.remove(fromPosition); + mQuickSearchList.add(toPosition, item); + notifyItemMoved(fromPosition, toPosition); + } + + @Override + public int onGetSwipeReactionType(QuickSearchHolder holder, int position, int x, int y) { + if (ViewUtils.isViewUnder(holder.getSwipeableContainerView(), x, y, 0)) { + return SwipeableItemConstants.REACTION_CAN_SWIPE_LEFT; + } else { + return SwipeableItemConstants.REACTION_CAN_NOT_SWIPE_BOTH_H; + } + } + + @Override + public void onSetSwipeBackground(QuickSearchHolder holder, int position, int type) {} + + @Override + public SwipeResultAction onSwipeItem(QuickSearchHolder holder, int position, int result) { + switch (result) { + // swipe left --- pin + case SwipeableItemConstants.RESULT_SWIPED_LEFT: + return new SwipeLeftResultAction(position); + // other --- do nothing + case SwipeableItemConstants.RESULT_SWIPED_RIGHT: + case SwipeableItemConstants.RESULT_CANCELED: + default: + return new SwipeResultActionDefault(); + } + } + } + + private class SwipeLeftResultAction extends SwipeResultActionMoveToSwipedDirection { + + private final int mPosition; + + public SwipeLeftResultAction(int position) { + mPosition = position; + } + + @Override + protected void onPerformAction() { + super.onPerformAction(); + + final List quickSearchList = mQuickSearchList; + if (quickSearchList == null || mPosition < 0 || mPosition >= quickSearchList.size()) { + return; + } + + final QuickSearch quickSearch = quickSearchList.get(mPosition); + + new AlertDialog.Builder(getContext()) + .setTitle(R.string.delete_quick_search_title) + .setMessage(getString(R.string.delete_quick_search_message, quickSearch.name)) + .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + EhDB.deleteQuickSearch(quickSearch); + quickSearchList.remove(mPosition); + } + }) + .setOnDismissListener(new DialogInterface.OnDismissListener() { + @Override + public void onDismiss(DialogInterface dialog) { + if (null != mAdapter) { + mAdapter.notifyDataSetChanged(); + } + updateView(); + } + }).show(); + } + } +} diff --git a/app/src/main/res/layout/item_quick_search.xml b/app/src/main/res/layout/item_quick_search.xml new file mode 100644 index 000000000..378222568 --- /dev/null +++ b/app/src/main/res/layout/item_quick_search.xml @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/scene_download_label.xml b/app/src/main/res/layout/scene_download_label.xml index 1a1500474..2b840fd98 100644 --- a/app/src/main/res/layout/scene_download_label.xml +++ b/app/src/main/res/layout/scene_download_label.xml @@ -43,14 +43,14 @@ app:srcCompat="@drawable/sad_panda"/> + android:paddingBottom="16dp"/> diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index f717e83df..1bd68e35e 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -98,7 +98,11 @@ 快速搜索 点击“+”来添加快速搜索 添加快速搜索 - Name is empty + 名称为空 + 删除 + 删除快速搜索 + 删除 %s? + 未添加快速搜索 2 星 diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index e052fcfad..6acb11d3b 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -98,7 +98,11 @@ 快速搜索 點擊“+”來添加快速搜索 添加快速搜索 - Name is empty + 名稱為空 + 刪除 + 刪除快速搜索 + 刪除 %s? + 未添加快速搜索 2 星 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 54b29eddf..49e1824d2 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -98,7 +98,11 @@ 快速搜尋 點選“+”來新增快速搜尋 新增快速搜尋 - Name is empty + 名稱為空 + 刪除 + 刪除快速搜尋 + 刪除 %s? + 未新增快速搜尋 2 星 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 41a7245c7..5743f0dc0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -138,6 +138,10 @@ Click \"+\" to add Quick Search Add Quick Search Name is empty + Delete + Delete Quick Search + Delete %s? + No quick search saved yet 2 stars