();
+ private static final int TAG_KEY = R.id.first;
+ // private static final int TAG_KEY = R.id.tag_key;
+ private int mCurrentY = 0;
+ /**
+ * 触摸区域,0不滚动区域,1可向上滚动的区域,-1可向下滚动的区域
+ */
+ private int mTouchArea = 0;
+ /**
+ * gridview能否滚动,是否内容太多
+ */
+ private boolean canScroll = true;
+ /**
+ * 是否可以拖动,点击拖动策略下直接开启,长按拖动需要长按以后开启
+ */
+ private boolean isDragable = true;
+ /**
+ * 自动滚屏的动画
+ */
+ private ValueAnimator animator;
+ /**
+ * view是否加载完成,如果未加载完成,没有宽高,无法接受事件
+ */
+ private boolean isViewInitDone = false;
+
+ /**
+ * 是否有位置发生改变,否则不用重绘
+ */
+ private boolean hasPositionChange = false;
+
+ /**
+ * 适配器的观察者,观察适配器的数据改变
+ */
+ private DataSetObserver observer = new DataSetObserver() {
+ @Override
+ public void onChanged() {
+ mChildCount = adapter.getCount();
+ // 下列属性状态清除,才会在被调用notifyDataSetChange时,在gridview测量布局完成后重新获取
+ mChilds.clear();
+ mColHeight = mColWidth = mMaxHeight = 0;
+ isViewInitDone = false;
+ }
+
+ @Override
+ public void onInvalidated() {
+ mChildCount = adapter.getCount();
+ }
+ };
+ private float[] lastLocation = null;
+ /**
+ * 手势监听器,滚动和单击
+ */
+ private GestureDetector.SimpleOnGestureListener simpleOnGestureListener = new GestureDetector.SimpleOnGestureListener() {
+
+ @Override
+ public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
+ if (hasSendDragMsg) {
+ hasSendDragMsg = false;
+ handler.removeMessages(0x123);
+ }
+ if (isDragable && mCopyView != null) {// 可以拖动,实现跟随手指的拖动效果
+
+ // /// 2015/11/27补充修正跟随手指移动方法,适用于当本控件在drag时同时滚动的情况
+ if (lastLocation == null) {
+ lastLocation = new float[]{e1.getRawX(), e1.getRawY()};
+ }
+ distanceX = lastLocation[0] - e2.getRawX();
+ distanceY = lastLocation[1] - e2.getRawY();
+ lastLocation[0] = e2.getRawX();
+ lastLocation[1] = e2.getRawY();
+ // ////////
+
+ mCopyView.setX(mCopyView.getX() - distanceX);
+ mCopyView.setY(mCopyView.getY() - distanceY);
+ mCopyView.invalidate();
+ int to = eventToPosition(e2);
+ if (to != currentDragPosition && to >= headDragPosition && to < mChildCount - footDragPosition) {
+ onDragPositionChange(currentDragPosition, to);
+ }
+ }
+ return true;
+ }
+
+
+
+ @Override
+ public void onShowPress(final MotionEvent e) {
+ /** 响应长按拖拽 */
+
+ handler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ if (isLongOnClick) {
+ if (itemLongClickListener != null) {
+ itemLongClickListener.onItemLongClick(mGridView, childAt(currentDragPosition), currentDragPosition, 0);
+ }
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mDragMode == DRAG_BY_LONG_CLICK) {
+
+ // 启动拖拽模式
+ // isDragable = true;
+ // 通知父控件不拦截我的事件
+ getParent().requestDisallowInterceptTouchEvent(true);
+ // 根据点击的位置生成该位置上的view镜像
+ int position = eventToPosition(e);
+ if (position >= headDragPosition && position < mChildCount - footDragPosition) {
+ // copyView(currentDragPosition = position);
+ Message msg = handler.obtainMessage(0x123, position, 0);
+ // showpress本身大概需要170毫秒
+// handler.sendMessageDelayed(msg, dragLongPressTime - 170);
+ handler.sendMessage(msg);
+ hasSendDragMsg = true;
+ }
+ }
+ }
+ });
+ }
+ }
+ },dragLongPressTime - 170);
+ };
+ };
+ private boolean hasSendDragMsg = false;
+ private Handler handler = new Handler(new Handler.Callback() {
+ @Override
+ public boolean handleMessage(Message msg) {
+ switch (msg.what) {
+ case 0x123:
+ // 启动拖拽模式
+ isDragable = true;
+ // 根据点击的位置生成该位置上的view镜像
+ copyView(currentDragPosition = msg.arg1);
+ hasSendDragMsg = false;
+ break;
+ default:
+ break;
+ }
+ return false;
+ }
+ });
+
+ public DragSortGridView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ public DragSortGridView(Context context) {
+ super(context);
+ init();
+ }
+
+ private void init() {
+ Context context = getContext();
+ mGridView = new NoScrollGridView(context);
+ mGridView.setVerticalScrollBarEnabled(false);
+ mGridView.setStretchMode(GridView.STRETCH_COLUMN_WIDTH);
+ mGridView.setSelector(new ColorDrawable());
+ // View的宽高之类必须在测量,布局,绘制一系列过程之后才能获取到
+ mGridView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
+
+ @Override
+ public void onGlobalLayout() {
+ if (mChilds.isEmpty()) {
+ for (int i = 0; i < mGridView.getChildCount(); i++) {
+ View view = mGridView.getChildAt(i);
+ view.setTag(TAG_KEY, new int[]{0, 0});
+ view.clearAnimation();
+ mChilds.add(view);
+ }
+ }
+ if (!mChilds.isEmpty()) {
+ mColHeight = mChilds.get(0).getHeight();
+ }
+ mColWidth = mGridView.getColumnWidth();
+ if (mChildCount % mNumColumns == 0) {
+ mMaxHeight = mColHeight * mChildCount / mNumColumns;
+ } else {
+ mMaxHeight = mColHeight * (mChildCount / mNumColumns + 1);
+ }
+ canScroll = mMaxHeight - getHeight() > 0;
+ // 告知事件处理,完成View加载,许多属性也已经初始化了
+ isViewInitDone = true;
+ }
+ });
+ mScrollView = new ListenScrollView(context);
+
+ mDragFrame = new FrameLayout(context);
+ addView(mScrollView, -1, -1);
+ mScrollView.addView(mGridView, -1, -1);
+
+ addView(mDragFrame, new LayoutParams(-1, -1));
+ detector = new GestureDetector(context, simpleOnGestureListener);
+ detector.setIsLongpressEnabled(false);
+ mGridView.setNumColumns(mNumColumns);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ try {
+ switch (ev.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ isLongOnClick = true;
+ break;
+
+ case MotionEvent.ACTION_UP:
+ isLongOnClick = false;
+ break;
+ default:
+ break;
+ }
+ if (l != null) {
+ l.onTouch(this, ev);
+ }
+ if (!isViewInitDone) {
+ return false;
+ }
+
+ if (isDragable) {
+ handleScrollAndCreMirror(ev);
+ } else {
+ // 交给子控件自己处理
+ if (canScroll) {
+ mScrollView.dispatchTouchEvent(ev);
+ } else {
+ mGridView.dispatchTouchEvent(ev);
+ }
+ }
+ // 处理拖动
+ detector.onTouchEvent(ev);
+ if (ev.getAction() == MotionEvent.ACTION_CANCEL || ev.getAction() == MotionEvent.ACTION_UP) {
+ lastLocation = null;
+ if (hasSendDragMsg) {
+ hasSendDragMsg = false;
+ handler.removeMessages(0x123);
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return true;
+ }
+
+ /**
+ * Author :[pWX273343] 2015年7月22日
+ *
+ * Description :拦截所有事件
+ */
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ return true;
+ }
+
+ /**
+ * 处理自动滚屏,和单击生成镜像
+ */
+ private void handleScrollAndCreMirror(MotionEvent ev) {
+ switch (ev.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ // 通知父控件不拦截我的事件
+ getParent().requestDisallowInterceptTouchEvent(true);
+ if (touchClashparent != null) {
+ touchClashparent.requestDisallowInterceptTouchEvent(true);
+ }
+ // 根据点击的位置生成该位置上的view镜像
+ int position = eventToPosition(ev);
+ if (position >= headDragPosition && position < mChildCount - footDragPosition) {
+ copyView(currentDragPosition = position);
+ }
+ break;
+ case MotionEvent.ACTION_MOVE:
+ // 通知父控件不拦截我的事件
+ getParent().requestDisallowInterceptTouchEvent(true);
+ if (touchClashparent != null) {
+ touchClashparent.requestDisallowInterceptTouchEvent(true);
+ }
+ // 内容太多时,移动到边缘会自动滚动
+ if (canScroll) {
+
+ int touchArea = decodeTouchArea(ev);
+ if (touchArea != mTouchArea) {
+ onTouchAreaChange(touchArea);
+ mTouchArea = touchArea;
+ }
+ }
+ break;
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP:
+ if (hideView != null) {
+ hideView.setVisibility(View.VISIBLE);
+ if (onDragSelectListener != null) {
+ onDragSelectListener.onPutDown(hideView);
+ }
+ }
+ mDragFrame.removeAllViews();
+ // mDragFrame.scrollTo(0, 0);
+ // isNotifyByDragSort = true;
+ if (hasPositionChange) {
+ hasPositionChange = false;
+ adapter.notifyDataSetChanged();
+ } else if (mDragMode == DRAG_BY_LONG_CLICK && itemLongClickListener != null) {
+ itemLongClickListener.onItemLongClick(mGridView, childAt(currentDragPosition), currentDragPosition, 0);
+ }
+ // 停止滚动
+ if (canScroll) {
+ int scrollStates2 = decodeTouchArea(ev);
+ if (scrollStates2 != 0) {
+ onTouchAreaChange(0);
+ mTouchArea = 0;
+ }
+ }
+ // 放手时取消拖动排序模式
+ if (mDragMode == DRAG_BY_LONG_CLICK) {
+ isDragable = false;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * @param ev 事件
+ * @return 0中间区域, 1底部,-1顶部
+ * @描述: 检查当前触摸事件位于哪个区域, 顶部1/5可能触发下滚,底部1/5可能触发上滚
+ * @作者 [pWX273343] 2015年6月30日
+ */
+ private int decodeTouchArea(MotionEvent ev) {
+ if (ev.getY() > getHeight() * 4 / (double) 5) {
+ return 1;
+ } else if (ev.getY() < getHeight() / (double) 5) {
+ return -1;
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * @param ev
+ * @return
+ * @描述 得到事件触发点, 摸到的是哪一个item
+ * @作者 [pWX273343] 2015年7月6日
+ */
+ public int eventToPosition(MotionEvent ev) {
+
+ if (ev != null) {
+ int m = (int) ev.getX() / mColWidth;
+ int n = (int) (ev.getY() + mCurrentY) / mColHeight;
+ int position = n * mNumColumns + m;
+ if (position >= mChildCount) {
+ return mChildCount - 1;
+ } else {
+ return position;
+ }
+ }
+ return 0;
+ }
+
+ // 这里把控件作为假的横向ListView,所以返回position跟高度无关,暂时这样
+ // public int eventToPosition(MotionEvent ev) {
+ //
+ // if (ev != null) {
+ // int m = (int) ev.getX() / mColWidth;
+ // if (m >= mChildCount) {
+ // return mChildCount - 1;
+ // } else {
+ // return m;
+ // }
+ // }
+ // return 0;
+ // }
+
+ /**
+ * @param dragPosition
+ * @描述:复制一个镜像,并添加到透明层
+ * @作者 [pWX273343] 2015年7月6日
+ */
+ private void copyView(int dragPosition) {
+ hideView = mChilds.get(dragPosition);
+ int realPosition = mGridView.indexOfChild(hideView);
+ if (!adapter.isUseCopyView()) {
+ mCopyView = adapter.getView(realPosition, mCopyView, mDragFrame);
+ } else {
+ mCopyView = adapter.copyView(realPosition, mCopyView, mDragFrame);
+ }
+ hideView.setVisibility(View.INVISIBLE);
+ mDragFrame.addView(mCopyView, mColWidth, mColHeight);
+
+ int[] l1 = new int[2];
+ int[] l2 = new int[2];
+ hideView.getLocationOnScreen(l1);
+ mDragFrame.getLocationOnScreen(l2);
+
+ // mCopyView.setX(hideView.getLeft());
+ // mCopyView.setY(hideView.getTop() - mCurrentY);
+ mCopyView.setX(l1[0] - l2[0]);
+ mCopyView.setY(l1[1] - l2[1]);
+ if (onDragSelectListener == null) {
+ mCopyView.setScaleX(1.2f);
+ mCopyView.setScaleY(1.2f);
+ } else {
+ onDragSelectListener.onDragSelect(mCopyView);
+ }
+ }
+
+ /**
+ * @param from
+ * @param to
+ * @描述:动画效果移动View
+ * @作者 [pWX273343] 2015年6月24日
+ */
+ private void translateView(int from, int to) {
+ View view = mChilds.get(from);
+ int fromXValue = ((int[]) view.getTag(TAG_KEY))[0];
+ int fromYValue = ((int[]) view.getTag(TAG_KEY))[1];
+ int toXValue = to % mNumColumns - from % mNumColumns + fromXValue;
+ int toYValue = to / mNumColumns - from / mNumColumns + fromYValue;
+ Animation animation = new TranslateAnimation(1, fromXValue, 1, toXValue, 1, fromYValue, 1, toYValue);
+ animation.setDuration(ANIM_DURING);
+ animation.setFillAfter(true);
+ view.setTag(TAG_KEY, new int[]{toXValue, toYValue});
+ view.startAnimation(animation);
+ }
+
+ /**
+ * @param from
+ * @param to
+ * @描述:拖动View使位置发生改变时
+ * @作者 [pWX273343] 2015年7月6日
+ */
+ private void onDragPositionChange(int from, int to) {
+ if (from > to) {
+ for (int i = to; i < from; i++) {
+ translateView(i, i + 1);
+ }
+ } else {
+ for (int i = to; i > from; i--) {
+ translateView(i, i - 1);
+ }
+ }
+ if (!hasPositionChange) {
+ hasPositionChange = true;
+ }
+ adapter.onDataModelMove(from, to);
+ View view = mChilds.remove(from);
+ mChilds.add(to, view);
+ currentDragPosition = to;
+ }
+
+ /**
+ * Function :setAdapter
+ *
+ * Author :[pWX273343] 2015年6月24日
+ *
+ * Description :设置适配器.该适配器必须实现一个方法,当view的位置发生变动时,对实际数据的改动
+ *
+ * @param adapter
+ * @see GridView#setAdapter(android.widget.ListAdapter)
+ */
+ public void setAdapter(DragAdapter adapter) {
+ if (this.adapter != null && observer != null) {
+ this.adapter.unregisterDataSetObserver(observer);
+ }
+ this.adapter = adapter;
+ mGridView.setAdapter(adapter);
+ adapter.registerDataSetObserver(observer);
+ mChildCount = adapter.getCount();
+ }
+
+ public int getNumColumns() {
+ return mNumColumns;
+ }
+
+ /**
+ * 每行几个
+ */
+ public void setNumColumns(int numColumns) {
+ this.mNumColumns = numColumns;
+ mGridView.setNumColumns(numColumns);
+ }
+
+ /**
+ * 设置前几个item不可以改变位置
+ */
+ public void setNoPositionChangeItemCount(int count) {
+ headDragPosition = count;
+ }
+
+ /**
+ * 设置后几个item不可以改变位置
+ */
+ public void setFootNoPositionChangeItemCount(int count) {
+ footDragPosition = count;
+ }
+
+ /**
+ * 控制自动滚屏的动画监听器.
+ */
+ private ValueAnimator.AnimatorUpdateListener animUpdateListener = new ValueAnimator.AnimatorUpdateListener() {
+
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ int targetY = Math.round((Float) animation.getAnimatedValue());
+ if (targetY < 0) {
+ targetY = 0;
+ } else if (targetY > mMaxHeight - getHeight()) {
+ targetY = mMaxHeight - getHeight();
+ }
+ // mGridView.scrollTo(0, targetY);
+ mScrollView.smoothScrollTo(0, targetY);
+ // mCurrentY = targetY;
+ }
+
+ };
+
+ /**
+ * @param scrollStates
+ * @描述:触摸区域改变,做相应处理,开始滚动或停止滚动
+ * @作者 [pWX273343] 2015年6月29日
+ */
+ protected void onTouchAreaChange(int scrollStates) {
+ if (!canScroll) {
+ return;
+ }
+ if (animator != null) {
+ animator.removeUpdateListener(animUpdateListener);
+ }
+ if (scrollStates == 1) {// 从普通区域进入触发向上滚动的区域
+ int instance = mMaxHeight - getHeight() - mCurrentY;
+ animator = ValueAnimator.ofFloat(mCurrentY, mMaxHeight - getHeight());
+ animator.setDuration((long) (instance / 0.5f));
+ animator.setTarget(mGridView);
+ animator.addUpdateListener(animUpdateListener);
+ animator.start();
+ } else if (scrollStates == -1) {// 进入触发向下滚动的区域
+ animator = ValueAnimator.ofFloat(mCurrentY, 0);
+ animator.setDuration((long) (mCurrentY / 0.5f));
+ animator.setTarget(mGridView);
+ animator.addUpdateListener(animUpdateListener);
+ animator.start();
+ }
+ }
+
+ private OnDragSelectListener onDragSelectListener;
+
+ /**
+ * @描述:一个item view刚被拖拽和放下时起来生成镜像时调用.
+ * @作者 [pWX273343] 2015年6月30日
+ */
+ public void setOnDragSelectListener(OnDragSelectListener onDragSelectListener) {
+ this.onDragSelectListener = onDragSelectListener;
+ }
+
+ public interface OnDragSelectListener {
+ /**
+ * @param mirror 所拖拽起来的view生成的镜像 ,并不是实际的view.可对这个镜像实施变换效果,但是并不改变放下后的效果
+ * @描述:拖拽起一个view时调用
+ * @作者 [pWX273343] 2015年6月30日
+ */
+ void onDragSelect(View mirror);
+
+ /**
+ * @param itemView
+ * @描述:拖拽的View放下时调用
+ * @作者 [pWX273343] 2015年7月3日
+ */
+ void onPutDown(View itemView);
+ }
+
+ class NoScrollGridView extends GridView {
+
+ public NoScrollGridView(Context context) {
+ super(context);
+ }
+
+ /**
+ * @return
+ * @描述:兼容老版本的getColumWidth
+ * @作者 [pWX273343] 2015年7月1日
+ */
+ public int getColumnWidth() {
+ return getWidth() / getNumColumns();
+ }
+
+ public NoScrollGridView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int mExpandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
+ super.onMeasure(widthMeasureSpec, mExpandSpec);
+ }
+ }
+
+ /**
+ * Copyright (C), 2008-2015, Huawei Tech. Co., Ltd.
+ *
+ * Description : 监听滚动的scrollview,我们需要实时知道他已滚动的距离
+ *
+ * @author [pWX273343] 2015年7月22日
+ * @version V100R001
+ * @since V100R001
+ */
+ class ListenScrollView extends ScrollView {
+ public ListenScrollView(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected void onScrollChanged(int l, int t, int oldl, int oldt) {
+ super.onScrollChanged(l, t, oldl, oldt);
+ mCurrentY = getScrollY();
+ }
+ }
+
+ public View getChildViewAtIndex(int index) {
+ if (index < mChilds.size()) {
+ return mChilds.get(index);
+ }
+ return null;
+ }
+
+ // 转交给gridview一些常用监听器
+ private AdapterView.OnItemLongClickListener itemLongClickListener;
+
+ /**
+ * @param itemClickListener
+ * @描述:item 转交给gridview一些常用监听器
+ * @作者 [pWX273343] 2015年7月27日
+ */
+ public void setOnItemClickListener(AdapterView.OnItemClickListener itemClickListener) {
+ mGridView.setOnItemClickListener(itemClickListener);
+ }
+
+ /**
+ * 长按监听器自己触发,点击拖动模式不存在长按
+ *
+ * @param
+ */
+ public void setOnItemLongClickListener(AdapterView.OnItemLongClickListener itemLongClickListener) {
+ this.itemLongClickListener = itemLongClickListener;
+ }
+
+ /**
+ * 点击拖动
+ */
+ public static final int DRAG_WHEN_TOUCH = 0;
+ /**
+ * 长按拖动
+ */
+ public static final int DRAG_BY_LONG_CLICK = 1;
+
+ private int mDragMode = DRAG_WHEN_TOUCH;
+
+ /**
+ * @param mode int类型
+ * @描述:设置拖动的策略是点击还是长按
+ * @作者 [pWX273343] 2015年7月20日 参考 DRAG_WHEN_TOUCH,DRAG_BY_LONG_CLICK
+ */
+ public void setDragModel(int mode) {
+ this.mDragMode = mode;
+ isDragable = mode == DRAG_WHEN_TOUCH;
+ }
+
+ public View childAt(int index) {
+ return mGridView.getChildAt(index);
+ }
+
+ public int childCount() {
+ return mGridView.getChildCount();
+ }
+
+ public void setAnimFrame(FrameLayout mDragFrame) {
+ this.mDragFrame = mDragFrame;
+ }
+
+ private OnTouchListener l;
+
+ @Override
+ public void setOnTouchListener(OnTouchListener l) {
+ this.l = l;
+ }
+
+ private long dragLongPressTime = 600;
+
+ /**
+ * 设置长按需要用时
+ *
+ * @param time
+ */
+ public void setDragLongPressTime(long time) {
+ dragLongPressTime = time;
+ }
+
+ /**
+ * 设置触摸事件冲突父控件
+ *
+ * @param touchClashparent
+ */
+ public void setTouchClashparent(ViewGroup touchClashparent) {
+ this.touchClashparent = touchClashparent;
+ }
+
+ public ScrollView getmScrollView() {
+ return mScrollView;
+ }
+}
diff --git a/app/src/main/java/xyz/fycz/myreader/custom/MyTextView.java b/app/src/main/java/xyz/fycz/myreader/custom/MyTextView.java
new file mode 100644
index 0000000..56704d0
--- /dev/null
+++ b/app/src/main/java/xyz/fycz/myreader/custom/MyTextView.java
@@ -0,0 +1,69 @@
+package xyz.fycz.myreader.custom;
+
+
+import android.content.Context;
+
+
+
+import android.util.AttributeSet;
+
+
+import android.view.GestureDetector;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.TextView;
+import android.widget.Toast;
+import androidx.appcompat.widget.AppCompatTextView;
+
+
+public class MyTextView extends /*AppCompatEditText*/ AppCompatTextView {
+
+ /* private OnTouchListener mOnTouchListener;
+ private long timeDown;
+ private long timeUp;*/
+
+
+ public MyTextView(Context context) {
+ super(context);
+
+ }
+
+ public MyTextView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ }
+
+ public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+
+ }
+
+
+ /* @Override
+ public boolean dispatchTouchEvent(MotionEvent event) {
+
+ if (timeUp - timeDown > 0 && timeUp - timeDown < 1000){
+ return false;
+ }else {
+ return super.dispatchTouchEvent(event);
+ }
+
+ }
+
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ if (event.getAction() == MotionEvent.ACTION_DOWN){
+ timeDown = System.currentTimeMillis();
+ }else if (event.getAction() == MotionEvent.ACTION_UP){
+ timeUp = System.currentTimeMillis();
+ }
+ return super.onTouchEvent(event);
+ }*/
+
+
+
+
+}
+
diff --git a/app/src/main/java/xyz/fycz/myreader/custom/ReadTextView.java b/app/src/main/java/xyz/fycz/myreader/custom/ReadTextView.java
new file mode 100644
index 0000000..426fb96
--- /dev/null
+++ b/app/src/main/java/xyz/fycz/myreader/custom/ReadTextView.java
@@ -0,0 +1,13 @@
+package xyz.fycz.myreader.custom;
+
+import android.content.Context;
+import android.widget.TextView;
+import androidx.appcompat.widget.AppCompatTextView;
+
+
+public class ReadTextView extends AppCompatTextView {
+
+ public ReadTextView(Context context){
+ super(context);
+ }
+}
diff --git a/app/src/main/java/xyz/fycz/myreader/entity/ContactsTree.java b/app/src/main/java/xyz/fycz/myreader/entity/ContactsTree.java
new file mode 100644
index 0000000..08c6437
--- /dev/null
+++ b/app/src/main/java/xyz/fycz/myreader/entity/ContactsTree.java
@@ -0,0 +1,212 @@
+package xyz.fycz.myreader.entity;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+
+/**
+ * Created by zhao on 2016/11/9.
+ * APP通迅录树结构
+ *
+ */
+
+public class ContactsTree implements Serializable {
+
+ private static final long serialVersionUID = 7184368467231587092L;
+
+ //根节点赋值字段(部门节点)
+ private String DepartId;//部门id
+ private String DepartName;//部门名
+ private String orgCode; //部门编码
+ private String departOrder; //部门排序
+ private boolean select;
+
+ //叶节点赋值字段(个人信息节点)
+ private String id;
+ private String userDepartId;//用户所属部门ID
+ private String userDepartName;//用户所属部门名
+ private boolean moreDepartUser;// 用户是否多部门 true是 false不是
+ private boolean transpondPerson;//是否转发人员 true是 false不是
+ private String userName;//用户名
+ private String realName;//姓名
+ private String wholeSpellName;//姓名全拼
+ private String firstLetterName;//拼音首字母 eg:hzh
+ private String mobilePhone;//手机
+ private String sex;//性别
+ private String email;//邮箱
+
+ private ArrayList children;//孩子节点
+
+ private ContactsTree parent;//父节点
+
+ public boolean isTranspondPerson() {
+ return transpondPerson;
+ }
+
+ public void setTranspondPerson(boolean transpondPerson) {
+ this.transpondPerson = transpondPerson;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getDepartOrder() {
+ return departOrder;
+ }
+
+ public String getOrgCode() {
+ return orgCode;
+ }
+
+ public void setDepartOrder(String departOrder) {
+ this.departOrder = departOrder;
+ }
+
+ public void setOrgCode(String orgCode) {
+ this.orgCode = orgCode;
+ }
+
+ public boolean isMoreDepartUser() {
+ return moreDepartUser;
+ }
+
+ public void setMoreDepartUser(boolean moreDepartUser) {
+ this.moreDepartUser = moreDepartUser;
+ }
+
+ public String getUserDepartId() {
+ return userDepartId;
+ }
+
+ public String getUserDepartName() {
+ return userDepartName;
+ }
+
+ public void setUserDepartId(String userDepartId) {
+ this.userDepartId = userDepartId;
+ }
+
+ public void setUserDepartName(String userDepartName) {
+ this.userDepartName = userDepartName;
+ }
+
+ public boolean isSelect() {
+ return select;
+ }
+
+ public void setSelect(boolean select) {
+ this.select = select;
+ }
+
+ public ContactsTree getParent() {
+ return parent;
+ }
+
+ public void setParent(ContactsTree parent) {
+ this.parent = parent;
+ }
+
+ public ContactsTree(){
+ children = new ArrayList<>();
+ }
+
+ public String getSex() {
+ return sex;
+ }
+
+ public void setSex(String sex) {
+ this.sex = sex;
+ }
+
+ public String getMobilePhone() {
+ return mobilePhone;
+ }
+
+ public void setMobilePhone(String mobilePhone) {
+ this.mobilePhone = mobilePhone;
+ }
+
+ public ArrayList getChildren() {
+ return children;
+ }
+
+ public String getDepartId() {
+ return DepartId;
+ }
+
+ public String getDepartName() {
+ return DepartName;
+ }
+
+ public String getFirstLetterName() {
+ return firstLetterName;
+ }
+
+ public String getRealName() {
+ return realName;
+ }
+
+ public String getUserName() {
+ return userName;
+ }
+
+ public String getWholeSpellName() {
+ return wholeSpellName;
+ }
+
+ public void setChildren(ArrayList children) {
+ this.children = children;
+ }
+
+ public void setDepartId(String departId) {
+ DepartId = departId;
+ }
+
+ public void setDepartName(String departName) {
+ DepartName = departName;
+ }
+
+ public void setFirstLetterName(String firstLetterName) {
+ this.firstLetterName = firstLetterName;
+ }
+
+ public void setRealName(String realName) {
+ this.realName = realName;
+ }
+
+ public void setUserName(String userName) {
+ this.userName = userName;
+ }
+
+ public void setWholeSpellName(String wholeSpellName) {
+ this.wholeSpellName = wholeSpellName;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ @Override
+ public String toString() {
+ return "ContactsTree{" +
+ "DepartId='" + DepartId + '\'' +
+ ", DepartName='" + DepartName + '\'' +
+ ", userName='" + userName + '\'' +
+ ", realName='" + realName + '\'' +
+ ", wholeSpellName='" + wholeSpellName + '\'' +
+ ", firstLetterName='" + firstLetterName + '\'' +
+ ", mobilePhone='" + mobilePhone + '\'' +
+ ", sex='" + sex + '\'' +
+ ", email='" + email + '\'' +
+ ", children=" + children +
+ '}';
+ }
+}
diff --git a/app/src/main/java/xyz/fycz/myreader/entity/Custom.java b/app/src/main/java/xyz/fycz/myreader/entity/Custom.java
new file mode 100644
index 0000000..8c4ffee
--- /dev/null
+++ b/app/src/main/java/xyz/fycz/myreader/entity/Custom.java
@@ -0,0 +1,36 @@
+package xyz.fycz.myreader.entity;
+
+import java.io.Serializable;
+
+
+public class Custom implements Serializable {
+
+ private static final long serialVersionUID = 5088810102696918656L;
+
+ private String id;
+ private String type;//类型
+
+ public String getId() {
+ return id;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ @Override
+ public String toString() {
+ return "Custom{" +
+ "id='" + id + '\'' +
+ ", type='" + type + '\'' +
+ '}';
+ }
+}
diff --git a/app/src/main/java/xyz/fycz/myreader/entity/Date.java b/app/src/main/java/xyz/fycz/myreader/entity/Date.java
new file mode 100644
index 0000000..c75a59b
--- /dev/null
+++ b/app/src/main/java/xyz/fycz/myreader/entity/Date.java
@@ -0,0 +1,166 @@
+package xyz.fycz.myreader.entity;
+
+
+import xyz.fycz.myreader.util.CalendarHelper;
+
+import java.io.Serializable;
+
+
+
+public class Date implements Serializable {
+
+ private static final long serialVersionUID = -1251952358800941760L;
+
+ private int year; //年
+ private int month; //月
+ private int date; //日
+ private int day; //星期
+
+
+ private boolean festival;
+
+
+
+ public Date(){
+
+
+ }
+
+ public int compare(Date date){
+ if(year == date.getYear() && month == date.getMonth() && this.date == date.getDate()){
+ return 0;
+ }else if(year > date.getYear()
+ || (year == date.getYear() && month > date.getMonth())
+ ||(year == date.getYear() && month == date.getMonth() && this.date > date.getDate())){
+ return 1;
+ }else if(year < date.getYear()
+ || (year == date.getYear() && month < date.getMonth())
+ ||(year == date.getYear() && month == date.getMonth() && this.date < date.getDate())){
+ return -1;
+ }else {
+ return -101;
+ }
+ }
+
+ public boolean isSameDate(Date date){
+ return year == date.getYear() && month == date.getMonth() && this.date == date.getDate();
+ }
+
+
+
+ public Date copyDate(){
+ Date resDate = new Date();
+ resDate.setYear(year);
+ resDate.setMonth(month);
+ resDate.setDate(this.date);
+ resDate.setDay(day);
+ return resDate;
+ }
+
+ public void lastMonth(){
+ if(month == 1){
+ year--;
+ month = 12;
+ }else {
+ month--;
+ }
+ }
+
+ public void nextMonth(){
+ if(month == 12){
+ year++;
+ month = 1;
+ }else {
+ month++;
+ }
+ }
+
+ public Date lastDate(){
+ Date date = copyDate();
+ if(date.getDate() == 1){
+ if(month == 1){
+ date.setMonth(12);
+ date.setYear(date.getYear() - 1);
+ }else {
+ date.setMonth(date.getMonth() - 1);
+ }
+ date.setDate(CalendarHelper.getMonthDays(date.getYear(),date.getMonth()));
+ }else {
+ date.setDate(date.getDate() - 1);
+ }
+ if(date.getDay() == 0){
+ date.setDay(6);
+ }else {
+ date.setDay(date.getDay() - 1);
+ }
+ return date;
+ }
+
+ public Date nextDate(){
+ Date date = copyDate();
+ if(date.getDate() == CalendarHelper.getMonthDays(date.getYear(),date.getMonth())){
+ if(month == 12){
+ date.setMonth(1);
+ date.setYear(date.getYear() + 1);
+ }else {
+ date.setMonth(date.getMonth() + 1);
+ }
+ date.setDate(1);
+ }else {
+ date.setDate(date.getDate() + 1);
+ }
+ if(date.getDay() == 6){
+ date.setDay(0);
+ }else {
+ date.setDay(date.getDay() + 1);
+ }
+ return date;
+ }
+
+ public long toTime(){
+ java.util.Date date1 = new java.util.Date(year-1900,month-1,date);
+ return date1.getTime();
+ }
+
+
+
+ public int getDay() {
+ return day;
+ }
+
+ public void setDay(int day) {
+ this.day = day;
+ }
+
+ public int getDate() {
+ return date;
+ }
+
+ public int getMonth() {
+ return month;
+ }
+
+ public int getYear() {
+ return year;
+ }
+
+ public void setDate(int date) {
+ this.date = date;
+ }
+
+ public void setMonth(int month) {
+ this.month = month;
+ }
+
+ public void setYear(int year) {
+ this.year = year;
+ }
+
+ public boolean isFestival() {
+ return festival;
+ }
+
+ public void setFestival(boolean festival) {
+ this.festival = festival;
+ }
+}
diff --git a/app/src/main/java/xyz/fycz/myreader/entity/JsonModel.java b/app/src/main/java/xyz/fycz/myreader/entity/JsonModel.java
new file mode 100644
index 0000000..16f3d4e
--- /dev/null
+++ b/app/src/main/java/xyz/fycz/myreader/entity/JsonModel.java
@@ -0,0 +1,105 @@
+package xyz.fycz.myreader.entity;
+
+import java.io.Serializable;
+
+
+
+
+public class JsonModel implements Serializable {
+
+ private static final long serialVersionUID = -7169864463597942730L;
+
+ private int error;//错误码
+ private boolean success;//请求是否成功
+ private String result;//服务器返回的json数据存放与此
+ private String token;
+ private int datasize;
+ private String publicKey;
+
+
+ private int visibleLastIndex = 0;
+ private int visibleItemCount;
+
+
+ public JsonModel() {
+
+ }
+
+ public String getPublicKey() {
+ return publicKey;
+ }
+
+ public void setPublicKey(String publicKey) {
+ this.publicKey = publicKey;
+ }
+
+ public int getError() {
+ return this.error;
+ }
+
+ public void setError(int error) {
+ this.error = error;
+ }
+
+ public String getResult() {
+ return this.result;
+ }
+
+ public void setResult(String result) {
+ this.result = result;
+ }
+
+ public String getToken() {
+ return this.token;
+ }
+
+ public void setToken(String token) {
+ this.token = token;
+ }
+
+ public boolean isSuccess() {
+ return this.success;
+ }
+
+ public void setSuccess(boolean success) {
+ this.success = success;
+ }
+
+ public int getVisibleLastIndex() {
+ return this.visibleLastIndex;
+ }
+
+ public void setVisibleLastIndex(int visibleLastIndex) {
+ this.visibleLastIndex = visibleLastIndex;
+ }
+
+ public int getVisibleItemCount() {
+ return this.visibleItemCount;
+ }
+
+ public void setVisibleItemCount(int visibleItemCount) {
+ this.visibleItemCount = visibleItemCount;
+ }
+
+ public int getDatasize() {
+ return this.datasize;
+ }
+
+ public void setDatasize(int datasize) {
+ this.datasize = datasize;
+ }
+
+
+ @Override
+ public String toString() {
+ return "JsonModel{" +
+ "error=" + error +
+ ", success=" + success +
+ ", result='" + result + '\'' +
+ ", token='" + token + '\'' +
+ ", datasize=" + datasize +
+ ", visibleLastIndex=" + visibleLastIndex +
+ ", visibleItemCount=" + visibleItemCount +
+ '}';
+ }
+}
diff --git a/app/src/main/java/xyz/fycz/myreader/entity/SearchBookBean.java b/app/src/main/java/xyz/fycz/myreader/entity/SearchBookBean.java
new file mode 100644
index 0000000..7970fb6
--- /dev/null
+++ b/app/src/main/java/xyz/fycz/myreader/entity/SearchBookBean.java
@@ -0,0 +1,53 @@
+package xyz.fycz.myreader.entity;
+
+import java.util.Objects;
+
+/**
+ * @author fengyue
+ * @date 2020/5/19 9:19
+ */
+public class SearchBookBean {
+ private String name;//书名
+ private String author;//作者
+
+ public SearchBookBean() {
+ }
+
+ public SearchBookBean(String name, String author) {
+ this.name = name;
+ this.author = author;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getAuthor() {
+ return author;
+ }
+
+ public void setAuthor(String author) {
+ this.author = author;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ SearchBookBean that = (SearchBookBean) o;
+ if (author == null){
+ return name.equals(that.name);
+ }
+ return name.equals(that.name) &&
+ author.equals(that.author);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name, author);
+ }
+}
diff --git a/app/src/main/java/xyz/fycz/myreader/entity/Setting.java b/app/src/main/java/xyz/fycz/myreader/entity/Setting.java
new file mode 100644
index 0000000..e0382be
--- /dev/null
+++ b/app/src/main/java/xyz/fycz/myreader/entity/Setting.java
@@ -0,0 +1,173 @@
+package xyz.fycz.myreader.entity;
+
+import xyz.fycz.myreader.enums.BookcaseStyle;
+import xyz.fycz.myreader.enums.Font;
+import xyz.fycz.myreader.enums.Language;
+import xyz.fycz.myreader.enums.ReadStyle;
+import xyz.fycz.myreader.widget.page.PageMode;
+
+import java.io.Serializable;
+
+/**
+ * 用户设置
+ *
+ */
+
+public class Setting implements Serializable {
+
+ private static final long serialVersionUID = 2295691810299441757L;
+
+ private int readWordColor;//阅读字体颜色
+ private int readBgColor;//阅读背景颜色
+ private float readWordSize;//阅读字体大小
+
+ private ReadStyle readStyle;//阅读模式
+
+ private boolean dayStyle;//是否日间模式
+ private int brightProgress;//亮度 1- 100
+ private boolean brightFollowSystem;//亮度跟随系统
+ private Language language;//简繁体
+ private Font font;//字体
+
+ private int autoScrollSpeed = 5;//自动滑屏速度
+
+ private PageMode pageMode;//翻页模式
+
+ private boolean isVolumeTurnPage;//是否开启音量键翻页
+
+ private BookcaseStyle bookcaseStyle;//书架布局
+
+ private int newestVersionCode;//最新版本号
+
+ private String localFontName;//本地字体名字
+
+ private int settingVersion;//设置版本号
+
+ public int getAutoScrollSpeed() {
+ return autoScrollSpeed;
+ }
+
+ public void setAutoScrollSpeed(int autoScrollSpeed) {
+ this.autoScrollSpeed = autoScrollSpeed;
+ }
+
+ public Font getFont() {
+ return font;
+ }
+
+ public void setFont(Font font) {
+ this.font = font;
+ }
+
+ public Language getLanguage() {
+ return language;
+ }
+
+ public void setLanguage(Language language) {
+ this.language = language;
+ }
+
+ public boolean isBrightFollowSystem() {
+ return brightFollowSystem;
+ }
+
+ public void setBrightFollowSystem(boolean brightFollowSystem) {
+ this.brightFollowSystem = brightFollowSystem;
+ }
+
+ public void setBrightProgress(int brightProgress) {
+ this.brightProgress = brightProgress;
+ }
+
+ public int getBrightProgress() {
+ return brightProgress;
+ }
+
+ public boolean isDayStyle() {
+ return dayStyle;
+ }
+
+ public void setDayStyle(boolean dayStyle) {
+ this.dayStyle = dayStyle;
+ }
+
+ public int getReadWordColor() {
+ return readWordColor;
+ }
+
+ public void setReadWordColor(int readWordColor) {
+ this.readWordColor = readWordColor;
+ }
+
+ public int getReadBgColor() {
+ return readBgColor;
+ }
+
+ public void setReadBgColor(int readBgColor) {
+ this.readBgColor = readBgColor;
+ }
+
+ public float getReadWordSize() {
+ return readWordSize;
+ }
+
+ public void setReadWordSize(float readWordSize) {
+ this.readWordSize = readWordSize;
+ }
+
+ public ReadStyle getReadStyle() {
+ return readStyle;
+ }
+
+ public void setReadStyle(ReadStyle readStyle) {
+ this.readStyle = readStyle;
+ }
+
+ public PageMode getPageMode() {
+ return pageMode;
+ }
+
+ public void setPageMode(PageMode pageMode) {
+ this.pageMode = pageMode;
+ }
+
+ public boolean isVolumeTurnPage() {
+ return isVolumeTurnPage;
+ }
+
+ public void setVolumeTurnPage(boolean volumeTurnPage) {
+ isVolumeTurnPage = volumeTurnPage;
+ }
+
+ public BookcaseStyle getBookcaseStyle() {
+ return bookcaseStyle;
+ }
+
+ public void setBookcaseStyle(BookcaseStyle bookcaseStyle) {
+ this.bookcaseStyle = bookcaseStyle;
+ }
+
+ public int getNewestVersionCode() {
+ return newestVersionCode;
+ }
+
+ public void setNewestVersionCode(int newestVersionCode) {
+ this.newestVersionCode = newestVersionCode;
+ }
+
+ public String getLocalFontName() {
+ return localFontName;
+ }
+
+ public void setLocalFontName(String localFontName) {
+ this.localFontName = localFontName;
+ }
+
+ public int getSettingVersion() {
+ return settingVersion;
+ }
+
+ public void setSettingVersion(int settingVersion) {
+ this.settingVersion = settingVersion;
+ }
+}
diff --git a/app/src/main/java/xyz/fycz/myreader/entity/Time.java b/app/src/main/java/xyz/fycz/myreader/entity/Time.java
new file mode 100644
index 0000000..b3eba78
--- /dev/null
+++ b/app/src/main/java/xyz/fycz/myreader/entity/Time.java
@@ -0,0 +1,201 @@
+package xyz.fycz.myreader.entity;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+
+
+public class Time implements Parcelable{
+ private int year;
+ private int month;
+ private int date;
+ private int hour;
+ private int minute;
+ private int second;
+
+ public long getLongTime(){
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.append(year);
+ if(month < 10){
+ stringBuilder.append("0"+month);
+ }else {
+ stringBuilder.append(month);
+ }
+ if(date < 10){
+ stringBuilder.append("0" + date);
+ }else {
+ stringBuilder.append(date);
+ }
+ if(hour < 10){
+ stringBuilder.append("0" + hour);
+ }else {
+ stringBuilder.append(hour);
+ }
+ if(minute < 10){
+ stringBuilder.append("0" + minute);
+ }else {
+ stringBuilder.append(minute);
+ }
+ if(second < 10){
+ stringBuilder.append("0" + second);
+ }else {
+ stringBuilder.append(second);
+ }
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
+ java.util.Date date = null;
+ try {
+ date = sdf.parse(stringBuilder.toString());
+ return date.getTime();
+ } catch (ParseException e) {
+ e.printStackTrace();
+ return 0;
+ }
+ }
+
+
+ public void init(Date date){
+ year = date.getYear() + 1900;
+ month = date.getMonth() + 1;
+ this.date = date.getDate();
+ hour = date.getHours();
+ minute = date.getMinutes();
+ second = 0;
+ }
+
+ public void init(xyz.fycz.myreader.entity.Date date){
+ Date date1 = new Date();
+ year = date.getYear();
+ month = date.getMonth();
+ this.date = date.getDate();
+ hour = date1.getHours();
+ minute = date1.getMinutes();
+ second = 0;
+ }
+
+ public void setToDayZero(){
+ hour = 0;
+ minute = 0;
+ second = 0;
+ }
+
+ public void setToDayLast(){
+ hour = 23;
+ minute = 59;
+ second = 59;
+ }
+
+ public void lastMonth(){
+ if(month == 1){
+ month = 12;
+ year = year - 1;
+ }else {
+ month = month - 1;
+ }
+ }
+
+ public void nextMonth(){
+ if(month == 12){
+ month = 1;
+ year = year + 1;
+ }else {
+ month = month + 1;
+ }
+ }
+
+ public void init(long time){
+ Date date = new Date(time);
+ init(date);
+ }
+
+
+ public int getDate() {
+ return date;
+ }
+
+ public int getHour() {
+ return hour;
+ }
+
+ public int getMinute() {
+ return minute;
+ }
+
+ public int getMonth() {
+ return month;
+ }
+
+ public int getSecond() {
+ return second;
+ }
+
+ public int getYear() {
+ return year;
+ }
+
+ public void setDate(int date) {
+ this.date = date;
+ }
+
+ public void setHour(int hour) {
+ this.hour = hour;
+ }
+
+ public void setMinute(int minute) {
+ this.minute = minute;
+ }
+
+ public void setMonth(int month) {
+ this.month = month;
+ }
+
+ public void setSecond(int second) {
+ this.second = second;
+ }
+
+ public void setYear(int year) {
+ this.year = year;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(this.year);
+ dest.writeInt(this.month);
+ dest.writeInt(this.date);
+ dest.writeInt(this.hour);
+ dest.writeInt(this.minute);
+ dest.writeInt(this.second);
+ }
+
+ public Time() {
+ }
+
+ protected Time(Parcel in) {
+ this.year = in.readInt();
+ this.month = in.readInt();
+ this.date = in.readInt();
+ this.hour = in.readInt();
+ this.minute = in.readInt();
+ this.second = in.readInt();
+ }
+
+ public static final Creator