书籍长按菜单优化

pull/5/head
fengyuecanzhu 4 years ago
parent 1848beef19
commit 8b30c0a72b
  1. 4
      .idea/assetWizardSettings.xml
  2. 2
      DialogX/src/main/java/com/kongzue/dialogx/style/MaterialStyle.java
  3. 4
      app/src/main/assets/updatelog.fy
  4. 2
      app/src/main/java/xyz/fycz/myreader/application/App.java
  5. 2
      app/src/main/java/xyz/fycz/myreader/base/adapter/BaseListAdapter.java
  6. 4
      app/src/main/java/xyz/fycz/myreader/base/adapter/IViewHolder.java
  7. 199
      app/src/main/java/xyz/fycz/myreader/ui/activity/BookDetailedActivity.java
  8. 26
      app/src/main/java/xyz/fycz/myreader/ui/adapter/BookSourceAdapter.java
  9. 240
      app/src/main/java/xyz/fycz/myreader/ui/adapter/BookcaseAdapter.java
  10. 95
      app/src/main/java/xyz/fycz/myreader/ui/adapter/BookcaseDetailedAdapter.java
  11. 111
      app/src/main/java/xyz/fycz/myreader/ui/adapter/BookcaseDragAdapter.java
  12. 18
      app/src/main/java/xyz/fycz/myreader/ui/adapter/helper/IItemTouchHelperViewHolder.java
  13. 40
      app/src/main/java/xyz/fycz/myreader/ui/adapter/helper/ItemTouchCallback.java
  14. 16
      app/src/main/java/xyz/fycz/myreader/ui/adapter/helper/OnStartDragListener.java
  15. 41
      app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/BookSourceHolder.java
  16. 16
      app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/BookStoreBookHolder.java
  17. 3
      app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/CatalogHolder.java
  18. 5
      app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/FileHolder.java
  19. 4
      app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/LocalSourceHolder.java
  20. 4
      app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/ReadRecordHolder.java
  21. 3
      app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/ReplaceRuleHolder.java
  22. 4
      app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/SearchBookHolder.java
  23. 3
      app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/SourceEditHolder.kt
  24. 5
      app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/SourceExchangeHolder.java
  25. 103
      app/src/main/java/xyz/fycz/myreader/ui/dialog/BookGroupDialog.java
  26. 94
      app/src/main/java/xyz/fycz/myreader/ui/dialog/MyAlertDialog.java
  27. 11
      app/src/main/java/xyz/fycz/myreader/ui/fragment/DIYSourceFragment.java
  28. 72
      app/src/main/java/xyz/fycz/myreader/ui/presenter/BookcasePresenter.java
  29. 1
      app/src/main/java/xyz/fycz/myreader/util/help/JsExtensions.java
  30. 225
      app/src/main/java/xyz/fycz/myreader/util/utils/ShareBookUtil.java
  31. 18
      app/src/main/res/drawable/ic_leaderboard.xml
  32. 15
      app/src/main/res/drawable/ic_top.xml
  33. 14
      app/src/main/res/drawable/menu_book_detail.xml
  34. 5
      app/src/main/res/drawable/selector_btn_input_finish.xml
  35. 45
      app/src/main/res/layout/dialog_input.xml
  36. 16
      app/src/main/res/layout/edit_dialog.xml
  37. 16
      app/src/main/res/layout/edit_text.xml
  38. 1
      app/src/main/res/layout/fragment_book_list.xml
  39. 2
      app/src/main/res/layout/fragment_find.xml
  40. 11
      app/src/main/res/layout/item_book_source.xml
  41. 12
      app/src/main/res/layout/item_read_record.xml
  42. 233
      app/src/main/res/layout/menu_book.xml
  43. 124
      app/src/main/res/layout/menu_book_local.xml
  44. 2
      app/src/main/res/values/strings.xml
  45. 12
      app/src/main/res/values/styles.xml
  46. 4
      app/version_code.properties

@ -14,8 +14,8 @@
<option name="values"> <option name="values">
<map> <map>
<entry key="assetSourceType" value="FILE" /> <entry key="assetSourceType" value="FILE" />
<entry key="outputName" value="ic_more" /> <entry key="outputName" value="ic_top" />
<entry key="sourceFile" value="F:\SVG图标\更多.svg" /> <entry key="sourceFile" value="F:\SVG图标\置顶.svg" />
</map> </map>
</option> </option>
</PersistentState> </PersistentState>

@ -161,7 +161,7 @@ public class MaterialStyle implements DialogXStyle {
@Override @Override
public int overrideMenuTextColor(boolean light) { public int overrideMenuTextColor(boolean light) {
return light ? R.color.black90 : R.color.white90; return light ? R.color.black90 : R.color.dialogxMIUITextDark;
} }
@Override @Override

@ -1,3 +1,7 @@
风月读书v2.0.8
更新内容:
1、优化书籍、书源拖拽移动效果
2021.06.03 2021.06.03
风月读书v2.0.7 风月读书v2.0.7
更新内容: 更新内容:

@ -26,6 +26,7 @@ import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate; import androidx.appcompat.app.AppCompatDelegate;
import com.kongzue.dialogx.DialogX; import com.kongzue.dialogx.DialogX;
import com.kongzue.dialogx.style.MaterialStyle;
import com.liulishuo.filedownloader.FileDownloader; import com.liulishuo.filedownloader.FileDownloader;
import com.liulishuo.filedownloader.connection.FileDownloadUrlConnection; import com.liulishuo.filedownloader.connection.FileDownloadUrlConnection;
@ -112,6 +113,7 @@ public class App extends Application {
private void initDialogX() { private void initDialogX() {
DialogX.init(this); DialogX.init(this);
DialogX.DEBUGMODE = debug; DialogX.DEBUGMODE = debug;
DialogX.globalStyle = MaterialStyle.style();
} }
public void initNightTheme() { public void initNightTheme() {

@ -43,7 +43,7 @@ public abstract class BaseListAdapter<T> extends RecyclerView.Adapter<RecyclerVi
throw new IllegalArgumentException("The ViewHolder item must extend BaseViewHolder"); throw new IllegalArgumentException("The ViewHolder item must extend BaseViewHolder");
IViewHolder<T> iHolder = ((BaseViewHolder) holder).holder; IViewHolder<T> iHolder = ((BaseViewHolder) holder).holder;
iHolder.onBind(getItem(position),position); iHolder.onBind(holder, getItem(position), position);
//设置点击事件 //设置点击事件
holder.itemView.setOnClickListener((v)->{ holder.itemView.setOnClickListener((v)->{

@ -3,6 +3,8 @@ package xyz.fycz.myreader.base.adapter;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import androidx.recyclerview.widget.RecyclerView;
/** /**
* @author fengyue * @author fengyue
* @date 2020/8/12 20:02 * @date 2020/8/12 20:02
@ -11,6 +13,6 @@ import android.view.ViewGroup;
public interface IViewHolder<T> { public interface IViewHolder<T> {
View createItemView(ViewGroup parent); View createItemView(ViewGroup parent);
void initView(); void initView();
void onBind(T data,int pos); void onBind(RecyclerView.ViewHolder holder, T data, int pos);
void onClick(); void onClick();
} }

@ -77,6 +77,7 @@ import xyz.fycz.myreader.util.utils.FileUtils;
import xyz.fycz.myreader.util.utils.GsonExtensionsKt; import xyz.fycz.myreader.util.utils.GsonExtensionsKt;
import xyz.fycz.myreader.util.utils.NetworkUtils; import xyz.fycz.myreader.util.utils.NetworkUtils;
import xyz.fycz.myreader.util.utils.RxUtils; import xyz.fycz.myreader.util.utils.RxUtils;
import xyz.fycz.myreader.util.utils.ShareBookUtil;
import xyz.fycz.myreader.util.utils.StringUtils; import xyz.fycz.myreader.util.utils.StringUtils;
import xyz.fycz.myreader.webapi.BookApi; import xyz.fycz.myreader.webapi.BookApi;
import xyz.fycz.myreader.webapi.crawler.ReadCrawlerUtil; import xyz.fycz.myreader.webapi.crawler.ReadCrawlerUtil;
@ -640,7 +641,7 @@ public class BookDetailedActivity extends BaseActivity {
mSourceDialog.show(); mSourceDialog.show();
break; break;
case R.id.action_share: case R.id.action_share:
shareBook(); ShareBookUtil.shareBook(this, mBook, binding.ih.bookDetailIvCover);
break; break;
case R.id.action_edit: case R.id.action_edit:
Intent editIntent = new Intent(this, BookInfoEditActivity.class); Intent editIntent = new Intent(this, BookInfoEditActivity.class);
@ -660,17 +661,7 @@ public class BookDetailedActivity extends BaseActivity {
startActivity(intent); startActivity(intent);
break; break;
case R.id.action_group_setting: case R.id.action_group_setting:
mBookGroupDia.addGroup(mBook, new BookGroupDialog.OnGroup() { mBookGroupDia.addGroup(mBook, null);
@Override
public void change() {
}
@Override
public void addGroup() {
}
});
break; break;
case R.id.action_edit_source: case R.id.action_edit_source:
BookSource source = BookSourceManager.getBookSourceByStr(mBook.getSource()); BookSource source = BookSourceManager.getBookSourceByStr(mBook.getSource());
@ -738,190 +729,6 @@ public class BookDetailedActivity extends BaseActivity {
} }
} }
/**
* 分享书籍
*/
private void shareBook() {
if ("本地书籍".equals(mBook.getType())) {
File file = new File(mBook.getChapterUrl());
if (!file.exists()) {
ToastUtils.showWarring("书籍源文件不存在,无法分享!");
return;
}
try {
ShareUtils.share(this, file, mBook.getName() + ".txt", "text/plain");
} catch (Exception e) {
String dest = APPCONST.SHARE_FILE_DIR + File.separator + mBook.getName() + ".txt";
FileUtils.copy(mBook.getChapterUrl(), dest);
ShareUtils.share(this, new File(dest), mBook.getName() + ".txt", "text/plain");
}
return;
}
ToastUtils.showInfo("正在生成分享图片");
Single.create((SingleOnSubscribe<File>) emitter -> {
// 使用url
String url = SharedPreUtils.getInstance().getString(getString(R.string.downloadLink), URLCONST.LAN_ZOUS_URL);
if (url == null)
url = "";
int maxLength = 1273 - 1 - url.length();
SharedBook sharedBook = SharedBook.bookToSharedBook(mBook);
url = url + "#" + GsonExtensionsKt.getGSON().toJson(sharedBook);
Log.d("QRcode", "Length=" + url.length() + "\n" + url);
Bitmap bitmap;
QRCodeEncoder.HINTS.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);
bitmap = QRCodeEncoder.syncEncodeQRCode(url, 360);
QRCodeEncoder.HINTS.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
File share = makeShareFile(bitmap);
if (share == null) {
ToastUtils.showError("分享图片生成失败");
return;
}
emitter.onSuccess(share);
}).compose(RxUtils::toSimpleSingle)
.subscribe(new MySingleObserver<File>() {
@Override
public void onSuccess(@NonNull File File) {
share(File);
}
});
}
/**
* 生成分享图片
*
* @param QRCode
* @return
*/
private File makeShareFile(Bitmap QRCode) {
FileOutputStream fos = null;
try {
Bitmap back = BitmapFactory.decodeStream(getResources().getAssets().open("share.png")).copy(Bitmap.Config.ARGB_8888, true);
int backWidth = back.getWidth();
int backHeight = back.getHeight();
int margin = 60;
int marginTop = 24;
binding.ih.bookDetailIvCover.setDrawingCacheEnabled(true);
Bitmap img = Bitmap.createBitmap(binding.ih.bookDetailIvCover.getDrawingCache()).copy(Bitmap.Config.ARGB_8888, true);
binding.ih.bookDetailIvCover.setDrawingCacheEnabled(false);
img = BitmapUtil.getBitmap(img, 152, 209);
Canvas cv = new Canvas(back);
cv.drawBitmap(img, margin, margin + marginTop * 2, null);
TextPaint textPaint = new TextPaint();
textPaint.setAntiAlias(true);
textPaint.setFilterBitmap(true);
textPaint.setColor(Color.BLACK);
textPaint.setTextSize(40);
String name = TextUtils.ellipsize(mBook.getName(), textPaint, backWidth - margin + marginTop * 3 - img.getWidth(), TextUtils.TruncateAt.END).toString();
cv.drawText(name, margin + marginTop + img.getWidth(), margin + marginTop * 4, textPaint);
textPaint.setColor(getResources().getColor(R.color.origin));
textPaint.setTextSize(32);
cv.drawText(mBook.getAuthor(), margin + marginTop + img.getWidth(), margin + marginTop * 6, textPaint);
textPaint.setColor(Color.BLACK);
cv.drawText(mBook.getType() == null ? "" : mBook.getType(), margin + marginTop + img.getWidth(), margin + marginTop * 8, textPaint);
cv.drawText("书源:" + BookSourceManager.getSourceNameByStr(mBook.getSource()), margin + marginTop + img.getWidth(), margin + marginTop * 10, textPaint);
int textSize = 35;
int textInterval = textSize / 2;
textPaint.setTextSize(textSize);
drawDesc(getDescLines(backWidth - margin * 2, textPaint), textPaint, cv, margin + marginTop * 4 + img.getHeight(), margin, textInterval);
cv.drawBitmap(QRCode, backWidth - QRCode.getWidth(), backHeight - QRCode.getHeight(), null);
cv.save();// 保存
cv.restore();// 存储
File share = FileUtils.getFile(APPCONST.SHARE_FILE_DIR + mBook.getName() + "_share.png");
fos = new FileOutputStream(share);
back.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.flush();
Log.i("tag", "saveBitmap success: " + share.getAbsolutePath());
back.recycle();
img.recycle();
QRCode.recycle();
return share;
} catch (Exception e) {
e.printStackTrace();
ToastUtils.showError(e.getLocalizedMessage() + "");
return null;
} finally {
IOUtils.close(fos);
}
}
/**
* 分享生成的图片
*
* @param share
*/
private void share(File share) {
ShareUtils.share(this, share, "分享书籍", "image/png");
}
/**
* 绘制简介
*
* @param lines
* @param textPaint
* @param canvas
* @param top
* @param left
* @param textInterval
*/
private void drawDesc(List<String> lines, TextPaint textPaint, Canvas canvas, int top, int left, int textInterval) {
float interval = textInterval + textPaint.getTextSize();
for (String line : lines) {
canvas.drawText(line, left, top, textPaint);
top += interval;
}
}
/**
* 生成简介lines
*
* @param width
* @param textPaint
* @return
*/
private List<String> getDescLines(int width, TextPaint textPaint) {
List<String> lines = new ArrayList<>();
String desc = StringUtils.halfToFull(" ") + mBook.getDesc();
int i = 0;
int wordCount = 0;
String subStr = null;
while (desc.length() > 0) {
if (i == 9) {
lines.add(TextUtils.ellipsize(desc, textPaint, width / 1.8f, TextUtils.TruncateAt.END).toString());
break;
}
wordCount = textPaint.breakText(desc, true, width, null);
subStr = desc.substring(0, wordCount);
lines.add(subStr);
desc = desc.substring(wordCount);
i++;
}
return lines;
}
private boolean isThirdSource() { private boolean isThirdSource() {
return mReadCrawler instanceof ThirdCrawler; return mReadCrawler instanceof ThirdCrawler;

@ -7,10 +7,12 @@ import androidx.fragment.app.FragmentActivity;
import java.util.Collections; import java.util.Collections;
import xyz.fycz.myreader.application.App;
import xyz.fycz.myreader.base.adapter.IViewHolder; import xyz.fycz.myreader.base.adapter.IViewHolder;
import xyz.fycz.myreader.greendao.DbManager; import xyz.fycz.myreader.greendao.DbManager;
import xyz.fycz.myreader.greendao.entity.rule.BookSource; import xyz.fycz.myreader.greendao.entity.rule.BookSource;
import xyz.fycz.myreader.ui.adapter.helper.ItemTouchCallback; import xyz.fycz.myreader.ui.adapter.helper.ItemTouchCallback;
import xyz.fycz.myreader.ui.adapter.helper.OnStartDragListener;
import xyz.fycz.myreader.ui.adapter.holder.BookSourceHolder; import xyz.fycz.myreader.ui.adapter.holder.BookSourceHolder;
/** /**
@ -21,6 +23,7 @@ import xyz.fycz.myreader.ui.adapter.holder.BookSourceHolder;
public class BookSourceAdapter extends BaseSourceAdapter { public class BookSourceAdapter extends BaseSourceAdapter {
private final FragmentActivity activity; private final FragmentActivity activity;
private final OnSwipeListener onSwipeListener; private final OnSwipeListener onSwipeListener;
private OnStartDragListener onStartDragListener;
private boolean mEditState; private boolean mEditState;
private final ItemTouchCallback.OnItemTouchListener itemTouchListener = new ItemTouchCallback.OnItemTouchListener() { private final ItemTouchCallback.OnItemTouchListener itemTouchListener = new ItemTouchCallback.OnItemTouchListener() {
@Override @Override
@ -32,26 +35,41 @@ public class BookSourceAdapter extends BaseSourceAdapter {
public boolean onMove(int srcPosition, int targetPosition) { public boolean onMove(int srcPosition, int targetPosition) {
Collections.swap(mList, srcPosition, targetPosition); Collections.swap(mList, srcPosition, targetPosition);
notifyItemMoved(srcPosition, targetPosition); notifyItemMoved(srcPosition, targetPosition);
notifyItemChanged(srcPosition); /*notifyItemChanged(srcPosition);
notifyItemChanged(targetPosition); notifyItemChanged(targetPosition);
AsyncTask.execute(() -> { AsyncTask.execute(() -> {
for (int i = 1; i <= mList.size(); i++) { for (int i = 1; i <= mList.size(); i++) {
mList.get(i - 1).setOrderNum(i); mList.get(i - 1).setOrderNum(i);
} }
DbManager.getDaoSession().getBookSourceDao().insertOrReplaceInTx(mList); DbManager.getDaoSession().getBookSourceDao().insertOrReplaceInTx(mList);
}); });*/
return true; return true;
} }
@Override
public void onEnd() {
App.getHandler().postDelayed(() -> notifyDataSetChanged(), 500);
AsyncTask.execute(() -> {
for (int i = 1; i <= mList.size(); i++) {
mList.get(i - 1).setOrderNum(i);
}
DbManager.getDaoSession().getBookSourceDao().insertOrReplaceInTx(mList);
});
}
}; };
public BookSourceAdapter(FragmentActivity activity, OnSwipeListener onSwipeListener) { public BookSourceAdapter(FragmentActivity activity, OnSwipeListener onSwipeListener,
OnStartDragListener onStartDragListener) {
this.activity = activity; this.activity = activity;
this.onSwipeListener = onSwipeListener; this.onSwipeListener = onSwipeListener;
this.onStartDragListener = onStartDragListener;
} }
@Override @Override
protected IViewHolder<BookSource> createViewHolder(int viewType) { protected IViewHolder<BookSource> createViewHolder(int viewType) {
return new BookSourceHolder(activity, this, onSwipeListener); return new BookSourceHolder(activity, this, onSwipeListener, onStartDragListener);
} }
public ItemTouchCallback.OnItemTouchListener getItemTouchListener() { public ItemTouchCallback.OnItemTouchListener getItemTouchListener() {

@ -1,14 +1,20 @@
package xyz.fycz.myreader.ui.adapter; package xyz.fycz.myreader.ui.adapter;
import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.text.TextUtils;
import android.view.View; import android.view.View;
import android.widget.*; import android.widget.*;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.widget.SwitchCompat;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import com.kongzue.dialogx.dialogs.BottomDialog; import com.kongzue.dialogx.dialogs.BottomDialog;
import com.kongzue.dialogx.dialogs.BottomMenu; import com.kongzue.dialogx.dialogs.BottomMenu;
import com.kongzue.dialogx.interfaces.OnBindView;
import com.kongzue.dialogx.interfaces.OnDialogButtonClickListener; import com.kongzue.dialogx.interfaces.OnDialogButtonClickListener;
import com.kongzue.dialogx.interfaces.OnMenuItemSelectListener; import com.kongzue.dialogx.interfaces.OnMenuItemSelectListener;
@ -22,12 +28,29 @@ import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.util.*; import java.util.*;
import io.reactivex.Single;
import io.reactivex.SingleOnSubscribe;
import xyz.fycz.myreader.R; import xyz.fycz.myreader.R;
import xyz.fycz.myreader.application.App; import xyz.fycz.myreader.application.App;
import xyz.fycz.myreader.application.SysManager;
import xyz.fycz.myreader.base.BitIntentDataManager;
import xyz.fycz.myreader.base.observer.MySingleObserver;
import xyz.fycz.myreader.common.APPCONST; import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.greendao.entity.rule.BookSource;
import xyz.fycz.myreader.model.sourceAnalyzer.BookSourceManager;
import xyz.fycz.myreader.ui.activity.BookDetailedActivity;
import xyz.fycz.myreader.ui.activity.BookInfoEditActivity;
import xyz.fycz.myreader.ui.activity.SourceEditActivity;
import xyz.fycz.myreader.ui.adapter.helper.IItemTouchHelperViewHolder;
import xyz.fycz.myreader.ui.adapter.helper.ItemTouchCallback; import xyz.fycz.myreader.ui.adapter.helper.ItemTouchCallback;
import xyz.fycz.myreader.ui.dialog.DialogCreator; import xyz.fycz.myreader.ui.dialog.DialogCreator;
import xyz.fycz.myreader.ui.dialog.MyAlertDialog; import xyz.fycz.myreader.ui.dialog.MyAlertDialog;
import xyz.fycz.myreader.ui.dialog.SourceExchangeDialog;
import xyz.fycz.myreader.util.help.StringHelper;
import xyz.fycz.myreader.util.utils.RxUtils;
import xyz.fycz.myreader.util.utils.ShareBookUtil;
import xyz.fycz.myreader.webapi.crawler.ReadCrawlerUtil;
import xyz.fycz.myreader.webapi.crawler.base.ReadCrawler;
import xyz.fycz.myreader.widget.CoverImageView; import xyz.fycz.myreader.widget.CoverImageView;
import xyz.fycz.myreader.widget.custom.DragAdapter; import xyz.fycz.myreader.widget.custom.DragAdapter;
import xyz.fycz.myreader.greendao.entity.Book; import xyz.fycz.myreader.greendao.entity.Book;
@ -351,7 +374,7 @@ public abstract class BookcaseAdapter extends RecyclerView.Adapter<BookcaseAdapt
}); });
} }
public void refreshBook(String chapterUrl){ public void refreshBook(String chapterUrl) {
for (int i = 0; i < list.size(); i++) { for (int i = 0; i < list.size(); i++) {
if (Objects.equals(list.get(i).getChapterUrl(), chapterUrl)) { if (Objects.equals(list.get(i).getChapterUrl(), chapterUrl)) {
notifyItemChanged(i); notifyItemChanged(i);
@ -359,8 +382,211 @@ public abstract class BookcaseAdapter extends RecyclerView.Adapter<BookcaseAdapt
} }
} }
public void showBookMenu(Book book, int pos) {
BottomDialog.show(new BookMenuDialog(book, pos));
}
class BookMenuDialog extends OnBindView<BottomDialog> {
private BottomDialog dialog;
private Book mBook;
private int pos;
private RelativeLayout rlBookDetail;
private CoverImageView ivBookImg;
private TextView tvBookName;
private TextView tvBookAuthor;
private TextView tvTop;
private SwitchCompat scIsUpdate;
private TextView tvDownload;
private TextView tvExport;
private TextView tvChangeSource;
private TextView tvSetGroup;
private TextView tvShare;
private TextView tvRemove;
private TextView tvEdit;
private TextView tvRefresh;
private TextView tvLink;
private TextView tvEditSource;
public BookMenuDialog(Book book, int pos) {
super("本地书籍".equals(book.getType()) ? R.layout.menu_book_local : R.layout.menu_book);
mBook = book;
this.pos = pos;
}
@Override
public void onBind(BottomDialog dialog, View v) {
this.dialog = dialog;
bindLocalView(v);
if (!"本地书籍".equals(mBook.getType())) {
bindView(v);
}
}
private void bindView(View v) {
scIsUpdate = v.findViewById(R.id.sc_is_update);
tvDownload = v.findViewById(R.id.tv_download);
tvExport = v.findViewById(R.id.tv_export_cathe);
tvChangeSource = v.findViewById(R.id.tv_change_source);
tvShare = v.findViewById(R.id.tv_share);
tvRefresh = v.findViewById(R.id.tv_refresh);
tvLink = v.findViewById(R.id.tv_link);
tvEditSource = v.findViewById(R.id.tv_edit_source);
bindEvent();
}
private void bindEvent() {
scIsUpdate.setChecked(!mBook.getIsCloseUpdate());
scIsUpdate.setOnCheckedChangeListener((buttonView, isChecked) -> {
mBook.setIsCloseUpdate(!mBook.getIsCloseUpdate());
mBookService.updateEntity(mBook);
});
tvDownload.setOnClickListener(v -> {
dialog.dismiss();
downloadBook(mBook);
});
tvExport.setOnClickListener(v -> {
dialog.dismiss();
Single.create((SingleOnSubscribe<Boolean>) emitter -> {
emitter.onSuccess(unionChapterCathe(mBook));
}).compose(RxUtils::toSimpleSingle).subscribe(new MySingleObserver<Boolean>() {
@Override
public void onSuccess(@NotNull Boolean aBoolean) {
if (aBoolean) {
DialogCreator.createTipDialog(mContext,
"缓存导出成功,导出目录:"
+ APPCONST.TXT_BOOK_DIR);
} else {
DialogCreator.createTipDialog(mContext,
"章节目录为空或未找到缓存文件,缓存导出失败!");
}
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
DialogCreator.createTipDialog(mContext,
"章节目录为空或未找到缓存文件,缓存导出失败!");
}
});
});
tvChangeSource.setOnClickListener(v -> {
this.dialog.dismiss();
SourceExchangeDialog dialog = new SourceExchangeDialog((Activity) mContext, mBook);
dialog.setOnSourceChangeListener((bean, pos) -> {
Book bookTem = (Book) mBook.clone();
bookTem.setChapterUrl(bean.getChapterUrl());
bookTem.setInfoUrl(bean.getInfoUrl());
if (!StringHelper.isEmpty(bean.getImgUrl())) {
bookTem.setImgUrl(bean.getImgUrl());
}
if (!StringHelper.isEmpty(bean.getType())) {
bookTem.setType(bean.getType());
}
if (!StringHelper.isEmpty(bean.getDesc())) {
bookTem.setDesc(bean.getDesc());
}
if (!StringHelper.isEmpty(bean.getUpdateDate())) {
bookTem.setUpdateDate(bean.getUpdateDate());
}
if (!StringHelper.isEmpty(bean.getWordCount())) {
bookTem.setWordCount(bean.getWordCount());
}
if (!StringHelper.isEmpty(bean.getStatus())) {
bookTem.setStatus(bean.getStatus());
}
bookTem.setSource(bean.getSource());
mBookService.updateBook(mBook, bookTem);
mBook = bookTem;
list.set(this.pos, mBook);
mBookcasePresenter.refreshBook(mBook, true);
});
dialog.show();
});
tvShare.setOnClickListener(v -> {
dialog.dismiss();
ShareBookUtil.shareBook(mContext, mBook, ivBookImg);
});
tvRefresh.setOnClickListener(v -> {
dialog.dismiss();
mBookcasePresenter.refreshBook(mBook, false);
});
tvLink.setOnClickListener(v -> {
ReadCrawler rc = ReadCrawlerUtil.getReadCrawler(mBook.getSource());
Uri uri = Uri.parse(NetworkUtils.getAbsoluteURL(rc.getNameSpace(), mBook.getChapterUrl()));
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
App.getHandler().postDelayed(() -> mContext.startActivity(intent), 300);
dialog.dismiss();
});
tvEditSource.setOnClickListener(v -> {
BookSource source = BookSourceManager.getBookSourceByStr(mBook.getSource());
if (!TextUtils.isEmpty(source.getSourceEName())) {
ToastUtils.showWarring("内置书源无法编辑!");
} else {
Intent sourceIntent = new Intent(mContext, SourceEditActivity.class);
sourceIntent.putExtra(APPCONST.BOOK_SOURCE, source);
App.getHandler().postDelayed(() -> mContext.startActivity(sourceIntent), 300);
dialog.dismiss();
}
});
}
private void bindLocalView(View v) {
rlBookDetail = v.findViewById(R.id.rl_book_detail);
ivBookImg = v.findViewById(R.id.iv_book_img);
tvBookName = v.findViewById(R.id.tv_book_name);
tvBookAuthor = v.findViewById(R.id.tv_book_author);
tvEdit = v.findViewById(R.id.tv_edit);
tvTop = v.findViewById(R.id.tv_top);
tvSetGroup = v.findViewById(R.id.tv_set_group);
tvRemove = v.findViewById(R.id.tv_remove);
bindLocalEvent();
}
private void bindLocalEvent() {
rlBookDetail.setOnClickListener(v -> {
Intent intent = new Intent(mContext, BookDetailedActivity.class);
BitIntentDataManager.getInstance().putData(intent, mBook);
App.getHandler().postDelayed(() -> mContext.startActivity(intent), 300);
dialog.dismiss();
});
if (!App.isDestroy((Activity) mContext)) {
ReadCrawler rc = ReadCrawlerUtil.getReadCrawler(mBook.getSource());
ivBookImg.load(NetworkUtils.getAbsoluteURL(rc.getNameSpace(), mBook.getImgUrl()), mBook.getName(), mBook.getAuthor());
}
tvBookName.setText(mBook.getName());
tvBookAuthor.setText(mBook.getAuthor());
tvEdit.setOnClickListener(v -> {
Intent editIntent = new Intent(mContext, BookInfoEditActivity.class);
BitIntentDataManager.getInstance().putData(editIntent, mBook);
App.getHandler().postDelayed(() -> mContext.startActivity(editIntent), 300);
dialog.dismiss();
});
tvTop.setOnClickListener(v -> {
if (!isGroup) {
mBook.setSortCode(0);
} else {
mBook.setGroupSort(0);
}
mBookService.updateEntity(mBook);
mBookcasePresenter.init();
ToastUtils.showSuccess("书籍《" + mBook.getName() + "》移至顶部成功!");
dialog.dismiss();
});
tvSetGroup.setOnClickListener(v -> {
dialog.dismiss();
mBookcasePresenter.addGroup(mBook);
});
tvRemove.setOnClickListener(v -> {
dialog.dismiss();
showDeleteBookDialog(mBook);
});
}
static class ViewHolder extends RecyclerView.ViewHolder { }
static class ViewHolder extends RecyclerView.ViewHolder implements IItemTouchHelperViewHolder {
CheckBox cbBookChecked; CheckBox cbBookChecked;
CoverImageView ivBookImg; CoverImageView ivBookImg;
TextView tvBookName; TextView tvBookName;
@ -370,6 +596,16 @@ public abstract class BookcaseAdapter extends RecyclerView.Adapter<BookcaseAdapt
public ViewHolder(@NonNull @NotNull View itemView) { public ViewHolder(@NonNull @NotNull View itemView) {
super(itemView); super(itemView);
} }
@Override
public void onItemSelected() {
itemView.setTranslationZ(10);
}
@Override
public void onItemClear() {
itemView.setTranslationZ(0);
}
} }
public void setOnBookCheckedListener(OnBookCheckedListener listener) { public void setOnBookCheckedListener(OnBookCheckedListener listener) {

@ -56,10 +56,16 @@ public class BookcaseDetailedAdapter extends BookcaseAdapter {
public boolean onMove(int srcPosition, int targetPosition) { public boolean onMove(int srcPosition, int targetPosition) {
Collections.swap(list, srcPosition, targetPosition); Collections.swap(list, srcPosition, targetPosition);
notifyItemMoved(srcPosition, targetPosition); notifyItemMoved(srcPosition, targetPosition);
notifyItemChanged(srcPosition); /*notifyItemChanged(srcPosition);
notifyItemChanged(targetPosition); notifyItemChanged(targetPosition);*/
return true; return true;
} }
@Override
public void onEnd() {
App.getHandler().postDelayed(() -> notifyDataSetChanged(), 500);
}
}; };
} }
@ -151,90 +157,7 @@ public class BookcaseDetailedAdapter extends BookcaseAdapter {
}); });
viewHolder.llBookRead.setOnLongClickListener(v -> { viewHolder.llBookRead.setOnLongClickListener(v -> {
if (!ismEditState()) { if (!ismEditState()) {
/*AlertDialog bookDialog = MyAlertDialog.build(mContext) showBookMenu(book, position);
.setTitle(book.getName())
.setItems(menu, (dialog, which) -> {
switch (which) {
case 0:
if (!isGroup) {
book.setSortCode(0);
}else {
book.setGroupSort(0);
}
mBookService.updateEntity(book);
mBookcasePresenter.init();
ToastUtils.showSuccess("书籍《" + book.getName() + "》移至顶部成功!");
break;
case 1:
downloadBook(book);
break;
case 2:
App.getApplication().newThread(() -> {
try {
if (unionChapterCathe(book)) {
DialogCreator.createTipDialog(mContext,
"缓存导出成功,导出目录:"
+ APPCONST.TXT_BOOK_DIR);
} else {
DialogCreator.createTipDialog(mContext,
"章节目录为空或未找到缓存文件,缓存导出失败!");
}
} catch (IOException e) {
e.printStackTrace();
DialogCreator.createTipDialog(mContext,
"章节目录为空或未找到缓存文件,缓存导出失败!");
}
});
break;
case 3:
showDeleteBookDialog(book);
break;
}
})
.setNegativeButton(null, null)
.setPositiveButton(null, null)
.create();
bookDialog.show();*/
BottomMenu.show(book.getName(), menu)
.setOnMenuItemClickListener((dialog, text, which) -> {
switch (which) {
case 0:
if (!isGroup) {
book.setSortCode(0);
} else {
book.setGroupSort(0);
}
mBookService.updateEntity(book);
mBookcasePresenter.init();
ToastUtils.showSuccess("书籍《" + book.getName() + "》移至顶部成功!");
break;
case 1:
downloadBook(book);
break;
case 2:
App.getApplication().newThread(() -> {
try {
if (unionChapterCathe(book)) {
DialogCreator.createTipDialog(mContext,
"缓存导出成功,导出目录:"
+ APPCONST.TXT_BOOK_DIR);
} else {
DialogCreator.createTipDialog(mContext,
"章节目录为空或未找到缓存文件,缓存导出失败!");
}
} catch (IOException e) {
e.printStackTrace();
DialogCreator.createTipDialog(mContext,
"章节目录为空或未找到缓存文件,缓存导出失败!");
}
});
break;
case 3:
showDeleteBookDialog(book);
break;
}
return false;
});
return true; return true;
} }
return false; return false;

@ -57,15 +57,21 @@ public class BookcaseDragAdapter extends BookcaseAdapter {
list.remove(srcPosition); list.remove(srcPosition);
list.add(targetPosition, shelfBean); list.add(targetPosition, shelfBean);
notifyItemMoved(srcPosition, targetPosition); notifyItemMoved(srcPosition, targetPosition);
int start = srcPosition; /*int start = srcPosition;
int end = targetPosition; int end = targetPosition;
if (start > end) { if (start > end) {
start = targetPosition; start = targetPosition;
end = srcPosition; end = srcPosition;
} }
notifyItemRangeChanged(start, end - start + 1); notifyItemRangeChanged(start, end - start + 1);*/
return true; return true;
} }
@Override
public void onEnd() {
App.getHandler().postDelayed(() -> notifyDataSetChanged(), 500);
}
}; };
} }
@ -136,106 +142,7 @@ public class BookcaseDragAdapter extends BookcaseAdapter {
}); });
viewHolder.ivBookImg.setOnLongClickListener(v -> { viewHolder.ivBookImg.setOnLongClickListener(v -> {
if (!ismEditState()) { if (!ismEditState()) {
/*AlertDialog bookDialog = MyAlertDialog.build(mContext) showBookMenu(book, position);
.setTitle(book.getName())
.setItems(menu, (dialog, which) -> {
switch (which) {
case 0:
Intent intent = new Intent(mContext, BookDetailedActivity.class);
BitIntentDataManager.getInstance().putData(intent, book);
mContext.startActivity(intent);
break;
case 1:
if (!isGroup) {
book.setSortCode(0);
}else {
book.setGroupSort(0);
}
mBookService.updateEntity(book);
mBookcasePresenter.init();
ToastUtils.showSuccess("书籍《" + book.getName() + "》移至顶部成功!");
break;
case 2:
downloadBook(book);
break;
case 3:
App.getApplication().newThread(new Runnable() {
@Override
public void run() {
try {
if (unionChapterCathe(book)) {
DialogCreator.createTipDialog(mContext,
"缓存导出成功,导出目录:"
+ APPCONST.TXT_BOOK_DIR);
} else {
DialogCreator.createTipDialog(mContext,
"章节目录为空或未找到缓存文件,缓存导出失败!");
}
} catch (IOException e) {
e.printStackTrace();
DialogCreator.createTipDialog(mContext,
"章节目录为空或未找到缓存文件,缓存导出失败!");
}
}
});
break;
case 4:
showDeleteBookDialog(book);
break;
}
})
.setNegativeButton(null, null)
.setPositiveButton(null, null)
.create();
bookDialog.show();*/
BottomMenu.show(book.getName(), menu)
.setOnMenuItemClickListener((dialog, text, which) -> {
switch (which) {
case 0:
Intent intent = new Intent(mContext, BookDetailedActivity.class);
BitIntentDataManager.getInstance().putData(intent, book);
mContext.startActivity(intent);
break;
case 1:
if (!isGroup) {
book.setSortCode(0);
} else {
book.setGroupSort(0);
}
mBookService.updateEntity(book);
mBookcasePresenter.init();
ToastUtils.showSuccess("书籍《" + book.getName() + "》移至顶部成功!");
break;
case 2:
downloadBook(book);
break;
case 3:
App.getApplication().newThread(new Runnable() {
@Override
public void run() {
try {
if (unionChapterCathe(book)) {
DialogCreator.createTipDialog(mContext,
"缓存导出成功,导出目录:"
+ APPCONST.TXT_BOOK_DIR);
} else {
DialogCreator.createTipDialog(mContext,
"章节目录为空或未找到缓存文件,缓存导出失败!");
}
} catch (IOException e) {
e.printStackTrace();
DialogCreator.createTipDialog(mContext,
"章节目录为空或未找到缓存文件,缓存导出失败!");
}
}
});
break;
case 4:
showDeleteBookDialog(book);
break;
}
return false;
});
return true; return true;
} }
return false; return false;

@ -0,0 +1,18 @@
package xyz.fycz.myreader.ui.adapter.helper;
/**
* @author fengyue
* @date 2021/6/3 17:47
*/
public interface IItemTouchHelperViewHolder {
/**
* item被选中在侧滑或拖拽过程中更新状态
*/
void onItemSelected();
/**
* item的拖拽或侧滑结束恢复默认的状态
*/
void onItemClear();
}

@ -9,6 +9,9 @@ import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import androidx.viewpager.widget.ViewPager; import androidx.viewpager.widget.ViewPager;
import org.jetbrains.annotations.NotNull;
/** /**
* @author fengyue * @author fengyue
* @date 2021/2/9 10:08 * @date 2021/2/9 10:08
@ -44,11 +47,11 @@ public class ItemTouchCallback extends ItemTouchHelper.Callback {
} }
/** /**
* 设置是否可以被拖拽 * 设置是否可以被长按拖拽
* *
* @param canDrag 是true否false * @param canDrag 是true否false
*/ */
public void setDragEnable(boolean canDrag) { public void setLongPressDragEnable(boolean canDrag) {
isCanDrag = canDrag; isCanDrag = canDrag;
} }
@ -133,6 +136,19 @@ public class ItemTouchCallback extends ItemTouchHelper.Callback {
@Override @Override
public void onSelectedChanged(@Nullable RecyclerView.ViewHolder viewHolder, int actionState) { public void onSelectedChanged(@Nullable RecyclerView.ViewHolder viewHolder, int actionState) {
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
//不为空闲状态,即为拖拽或侧滑状态
if (viewHolder instanceof IItemTouchHelperViewHolder) {
IItemTouchHelperViewHolder itemTouchHelperViewHolder =
(IItemTouchHelperViewHolder) viewHolder;
itemTouchHelperViewHolder.onItemSelected();
}
}
if (onItemTouchListener != null) {
if (viewHolder == null) {
onItemTouchListener.onEnd();
}
}
super.onSelectedChanged(viewHolder, actionState); super.onSelectedChanged(viewHolder, actionState);
final boolean swiping = actionState == ItemTouchHelper.ACTION_STATE_DRAG; final boolean swiping = actionState == ItemTouchHelper.ACTION_STATE_DRAG;
if (viewPager != null) { if (viewPager != null) {
@ -140,6 +156,21 @@ public class ItemTouchCallback extends ItemTouchHelper.Callback {
} }
} }
@Override
public void clearView(@NonNull @NotNull RecyclerView recyclerView, @NonNull @NotNull RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
if (viewHolder instanceof IItemTouchHelperViewHolder) {
IItemTouchHelperViewHolder itemTouchHelperViewHolder =
(IItemTouchHelperViewHolder) viewHolder;
itemTouchHelperViewHolder.onItemClear();
}
}
@Override
public void onMoved(@NonNull @NotNull RecyclerView recyclerView, @NonNull @NotNull RecyclerView.ViewHolder viewHolder, int fromPos, @NonNull @NotNull RecyclerView.ViewHolder target, int toPos, int x, int y) {
super.onMoved(recyclerView, viewHolder, fromPos, target, toPos, x, y);
}
public interface OnItemTouchListener { public interface OnItemTouchListener {
/** /**
* 当某个Item被滑动删除的时候 * 当某个Item被滑动删除的时候
@ -156,5 +187,10 @@ public class ItemTouchCallback extends ItemTouchHelper.Callback {
* @return 开发者处理了操作应该返回true开发者没有处理就返回false * @return 开发者处理了操作应该返回true开发者没有处理就返回false
*/ */
boolean onMove(int srcPosition, int targetPosition); boolean onMove(int srcPosition, int targetPosition);
/**
* 当滑动删除或拖拽结束时调用
*/
void onEnd();
} }
} }

@ -0,0 +1,16 @@
package xyz.fycz.myreader.ui.adapter.helper;
import androidx.recyclerview.widget.RecyclerView;
/**
* @author fengyue
* @date 2021/6/3 18:39
*/
public interface OnStartDragListener {
/**
* 当View需要拖拽时回调
*
* @param viewHolder The holder of view to drag
*/
void onStartDrag(RecyclerView.ViewHolder viewHolder);
}

@ -1,6 +1,8 @@
package xyz.fycz.myreader.ui.adapter.holder; package xyz.fycz.myreader.ui.adapter.holder;
import android.annotation.SuppressLint;
import android.content.Intent; import android.content.Intent;
import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.widget.Button; import android.widget.Button;
import android.widget.CheckBox; import android.widget.CheckBox;
@ -9,6 +11,7 @@ import android.widget.RelativeLayout;
import android.widget.TextView; import android.widget.TextView;
import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentActivity;
import androidx.recyclerview.widget.RecyclerView;
import java.util.HashMap; import java.util.HashMap;
@ -26,6 +29,8 @@ import xyz.fycz.myreader.greendao.entity.rule.BookSource;
import xyz.fycz.myreader.model.sourceAnalyzer.BookSourceManager; import xyz.fycz.myreader.model.sourceAnalyzer.BookSourceManager;
import xyz.fycz.myreader.ui.activity.SourceEditActivity; import xyz.fycz.myreader.ui.activity.SourceEditActivity;
import xyz.fycz.myreader.ui.adapter.BookSourceAdapter; import xyz.fycz.myreader.ui.adapter.BookSourceAdapter;
import xyz.fycz.myreader.ui.adapter.helper.IItemTouchHelperViewHolder;
import xyz.fycz.myreader.ui.adapter.helper.OnStartDragListener;
import xyz.fycz.myreader.util.ShareUtils; import xyz.fycz.myreader.util.ShareUtils;
import xyz.fycz.myreader.util.help.StringHelper; import xyz.fycz.myreader.util.help.StringHelper;
import xyz.fycz.myreader.util.ToastUtils; import xyz.fycz.myreader.util.ToastUtils;
@ -36,7 +41,7 @@ import xyz.fycz.myreader.widget.swipemenu.SwipeMenuLayout;
* @author fengyue * @author fengyue
* @date 2021/2/10 16:52 * @date 2021/2/10 16:52
*/ */
public class BookSourceHolder extends ViewHolderImpl<BookSource> { public class BookSourceHolder extends ViewHolderImpl<BookSource> implements IItemTouchHelperViewHolder {
private FragmentActivity activity; private FragmentActivity activity;
private BookSourceAdapter adapter; private BookSourceAdapter adapter;
private HashMap<BookSource, Boolean> mCheckMap; private HashMap<BookSource, Boolean> mCheckMap;
@ -46,16 +51,22 @@ public class BookSourceHolder extends ViewHolderImpl<BookSource> {
private CheckBox cbSourceSelect; private CheckBox cbSourceSelect;
private TextView tvSourceName; private TextView tvSourceName;
private ImageView ivSwipeLeft; private ImageView ivSwipeLeft;
private ImageView ivMove;
private Button btTop; private Button btTop;
private Button btBan; private Button btBan;
private Button btShare; private Button btShare;
private Button btDelete; private Button btDelete;
public BookSourceHolder(FragmentActivity activity, BookSourceAdapter adapter, BookSourceAdapter.OnSwipeListener onSwipeListener) { private OnStartDragListener onStartDragListener;
public BookSourceHolder(FragmentActivity activity, BookSourceAdapter adapter,
BookSourceAdapter.OnSwipeListener onSwipeListener,
OnStartDragListener onStartDragListener) {
this.activity = activity; this.activity = activity;
this.adapter = adapter; this.adapter = adapter;
this.onSwipeListener = onSwipeListener; this.onSwipeListener = onSwipeListener;
mCheckMap = adapter.getCheckMap(); mCheckMap = adapter.getCheckMap();
this.onStartDragListener = onStartDragListener;
} }
@Override @Override
@ -70,25 +81,39 @@ public class BookSourceHolder extends ViewHolderImpl<BookSource> {
cbSourceSelect = findById(R.id.cb_source_select); cbSourceSelect = findById(R.id.cb_source_select);
tvSourceName = findById(R.id.tv_source_name); tvSourceName = findById(R.id.tv_source_name);
ivSwipeLeft = findById(R.id.iv_swipe_left); ivSwipeLeft = findById(R.id.iv_swipe_left);
ivMove = findById(R.id.iv_move);
btTop = findById(R.id.bt_top); btTop = findById(R.id.bt_top);
btBan = findById(R.id.bt_ban); btBan = findById(R.id.bt_ban);
btShare = findById(R.id.bt_share); btShare = findById(R.id.bt_share);
btDelete = findById(R.id.btnDelete); btDelete = findById(R.id.btnDelete);
} }
@SuppressLint("ClickableViewAccessibility")
@Override @Override
public void onBind(BookSource data, int pos) { public void onBind(RecyclerView.ViewHolder holder, BookSource data, int pos) {
banOrUse(data); banOrUse(data);
initClick(data, pos); initClick(data, pos);
layout.setSwipeEnable(!adapter.ismEditState()); layout.setSwipeEnable(!adapter.ismEditState());
if (adapter.ismEditState()) { if (adapter.ismEditState()) {
cbSourceSelect.setVisibility(View.VISIBLE); cbSourceSelect.setVisibility(View.VISIBLE);
ivSwipeLeft.setVisibility(View.GONE); ivSwipeLeft.setVisibility(View.GONE);
ivMove.setVisibility(View.VISIBLE);
} else { } else {
cbSourceSelect.setVisibility(View.GONE); cbSourceSelect.setVisibility(View.GONE);
ivSwipeLeft.setVisibility(View.VISIBLE); ivSwipeLeft.setVisibility(View.VISIBLE);
ivMove.setVisibility(View.GONE);
} }
cbSourceSelect.setChecked(mCheckMap.get(data)); cbSourceSelect.setChecked(mCheckMap.get(data));
ivMove.setOnTouchListener((view, motionEvent) -> {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
//通知ItemTouchHelper开始拖拽
if (onStartDragListener != null) {
onStartDragListener.onStartDrag(holder);
}
}
return false;
}
);
} }
private void initClick(BookSource data, int pos) { private void initClick(BookSource data, int pos) {
@ -175,4 +200,14 @@ public class BookSourceHolder extends ViewHolderImpl<BookSource> {
btBan.setText(R.string.enable_use); btBan.setText(R.string.enable_use);
} }
} }
@Override
public void onItemSelected() {
getItemView().setTranslationZ(10);
}
@Override
public void onItemClear() {
getItemView().setTranslationZ(0);
}
} }

@ -4,12 +4,15 @@ import android.app.Activity;
import android.view.View; import android.view.View;
import android.widget.TextView; import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import xyz.fycz.myreader.R; import xyz.fycz.myreader.R;
import xyz.fycz.myreader.application.App; import xyz.fycz.myreader.application.App;
import xyz.fycz.myreader.base.adapter.ViewHolderImpl; import xyz.fycz.myreader.base.adapter.ViewHolderImpl;
import xyz.fycz.myreader.greendao.entity.Book; import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.entity.rule.BookSource; import xyz.fycz.myreader.greendao.entity.rule.BookSource;
import xyz.fycz.myreader.model.sourceAnalyzer.BookSourceManager; import xyz.fycz.myreader.model.sourceAnalyzer.BookSourceManager;
import xyz.fycz.myreader.ui.adapter.helper.IItemTouchHelperViewHolder;
import xyz.fycz.myreader.util.help.StringHelper; import xyz.fycz.myreader.util.help.StringHelper;
import xyz.fycz.myreader.util.utils.NetworkUtils; import xyz.fycz.myreader.util.utils.NetworkUtils;
import xyz.fycz.myreader.webapi.crawler.ReadCrawlerUtil; import xyz.fycz.myreader.webapi.crawler.ReadCrawlerUtil;
@ -20,7 +23,7 @@ import xyz.fycz.myreader.widget.CoverImageView;
* @author fengyue * @author fengyue
* @date 2020/9/7 7:35 * @date 2020/9/7 7:35
*/ */
public class BookStoreBookHolder extends ViewHolderImpl<Book> { public class BookStoreBookHolder extends ViewHolderImpl<Book> implements IItemTouchHelperViewHolder {
private CoverImageView tvBookImg; private CoverImageView tvBookImg;
private TextView tvBookName; private TextView tvBookName;
@ -54,7 +57,7 @@ public class BookStoreBookHolder extends ViewHolderImpl<Book> {
} }
@Override @Override
public void onBind(Book data, int pos) { public void onBind(RecyclerView.ViewHolder holder, Book data, int pos) {
tvBookName.setText(data.getName()); tvBookName.setText(data.getName());
tvBookAuthor.setText(data.getAuthor()); tvBookAuthor.setText(data.getAuthor());
tvBookNewestChapter.setText(StringHelper.isEmpty(data.getNewestChapterTitle()) ? tvBookNewestChapter.setText(StringHelper.isEmpty(data.getNewestChapterTitle()) ?
@ -75,4 +78,13 @@ public class BookStoreBookHolder extends ViewHolderImpl<Book> {
} }
} }
@Override
public void onItemSelected() {
getItemView().setTranslationZ(10);
}
@Override
public void onItemClear() {
getItemView().setTranslationZ(0);
}
} }

@ -3,6 +3,7 @@ package xyz.fycz.myreader.ui.adapter.holder;
import android.widget.TextView; import android.widget.TextView;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
import xyz.fycz.myreader.R; import xyz.fycz.myreader.R;
import xyz.fycz.myreader.base.adapter.ViewHolderImpl; import xyz.fycz.myreader.base.adapter.ViewHolderImpl;
@ -26,7 +27,7 @@ public class CatalogHolder extends ViewHolderImpl<Chapter> {
} }
@Override @Override
public void onBind(Chapter data, int pos) { public void onBind(RecyclerView.ViewHolder holder, Chapter data, int pos) {
if (ChapterService.isChapterCached(data.getBookId(), data.getTitle()) || data.getEnd() > 0) { if (ChapterService.isChapterCached(data.getBookId(), data.getTitle()) || data.getEnd() > 0) {
tvTitle.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(getContext(),R.drawable.selector_category_load), null, null, null); tvTitle.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(getContext(),R.drawable.selector_category_load), null, null, null);
} else { } else {

@ -5,6 +5,9 @@ import android.widget.CheckBox;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import xyz.fycz.myreader.R; import xyz.fycz.myreader.R;
import xyz.fycz.myreader.base.adapter.ViewHolderImpl; import xyz.fycz.myreader.base.adapter.ViewHolderImpl;
import xyz.fycz.myreader.common.APPCONST; import xyz.fycz.myreader.common.APPCONST;
@ -49,7 +52,7 @@ public class FileHolder extends ViewHolderImpl<File> {
} }
@Override @Override
public void onBind(File data, int pos) { public void onBind(RecyclerView.ViewHolder holder, File data, int pos) {
//判断是文件还是文件夹 //判断是文件还是文件夹
if (data.isDirectory()){ if (data.isDirectory()){
setFolder(data); setFolder(data);

@ -3,6 +3,8 @@ package xyz.fycz.myreader.ui.adapter.holder;
import android.widget.CheckBox; import android.widget.CheckBox;
import android.widget.TextView; import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import java.util.HashMap; import java.util.HashMap;
import xyz.fycz.myreader.R; import xyz.fycz.myreader.R;
@ -40,7 +42,7 @@ public class LocalSourceHolder extends ViewHolderImpl<BookSource> {
} }
@Override @Override
public void onBind(BookSource data, int pos) { public void onBind(RecyclerView.ViewHolder holder, BookSource data, int pos) {
banOrUse(data); banOrUse(data);
cbSource.setChecked(mCheckMap.get(data)); cbSource.setChecked(mCheckMap.get(data));
tvEnable.setOnClickListener(v -> { tvEnable.setOnClickListener(v -> {

@ -6,6 +6,8 @@ import android.view.ViewGroup;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import com.kongzue.dialogx.dialogs.BottomMenu; import com.kongzue.dialogx.dialogs.BottomMenu;
import com.kongzue.dialogx.interfaces.OnMenuItemClickListener; import com.kongzue.dialogx.interfaces.OnMenuItemClickListener;
@ -49,7 +51,7 @@ public class ReadRecordHolder extends ViewHolderImpl<ReadRecord> {
} }
@Override @Override
public void onBind(ReadRecord data, int pos) { public void onBind(RecyclerView.ViewHolder holder, ReadRecord data, int pos) {
if (!App.isDestroy((Activity) getContext())) { if (!App.isDestroy((Activity) getContext())) {
ivBookImg.load(data.getBookImg(), data.getBookName(), data.getBookAuthor()); ivBookImg.load(data.getBookImg(), data.getBookName(), data.getBookAuthor());
} }

@ -6,6 +6,7 @@ import android.widget.RelativeLayout;
import android.widget.TextView; import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList; import java.util.ArrayList;
@ -67,7 +68,7 @@ public class ReplaceRuleHolder extends ViewHolderImpl<ReplaceRuleBean> {
} }
@Override @Override
public void onBind(ReplaceRuleBean data, int pos) { public void onBind(RecyclerView.ViewHolder holder, ReplaceRuleBean data, int pos) {
banOrUse(data); banOrUse(data);
rlContent.setOnClickListener(v -> { rlContent.setOnClickListener(v -> {

@ -5,6 +5,8 @@ import android.app.Activity;
import android.util.Log; import android.util.Log;
import android.widget.TextView; import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import com.zhy.view.flowlayout.TagFlowLayout; import com.zhy.view.flowlayout.TagFlowLayout;
import java.util.ArrayList; import java.util.ArrayList;
@ -75,7 +77,7 @@ public class SearchBookHolder extends ViewHolderImpl<SearchBookBean> {
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
@Override @Override
public void onBind(SearchBookBean data, int pos) { public void onBind(RecyclerView.ViewHolder holder, SearchBookBean data, int pos) {
List<Book> aBooks = mBooks.getValues(data); List<Book> aBooks = mBooks.getValues(data);
if (aBooks == null || aBooks.size() == 0){ if (aBooks == null || aBooks.size() == 0){
aBooks = new ArrayList<>(); aBooks = new ArrayList<>();

@ -5,6 +5,7 @@ import android.text.TextUtils
import android.text.TextWatcher import android.text.TextWatcher
import android.view.View import android.view.View
import android.widget.TextView import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.textfield.TextInputEditText import com.google.android.material.textfield.TextInputEditText
import com.google.android.material.textfield.TextInputLayout import com.google.android.material.textfield.TextInputLayout
import xyz.fycz.myreader.R import xyz.fycz.myreader.R
@ -30,7 +31,7 @@ class SourceEditHolder : ViewHolderImpl<EditEntity>() {
tvTip = findById(R.id.tv_tip) tvTip = findById(R.id.tv_tip)
} }
override fun onBind(data: EditEntity, pos: Int) { override fun onBind(holder: RecyclerView.ViewHolder, data: EditEntity, pos: Int) {
if (editText?.getTag(R.id.tag1) == null) { if (editText?.getTag(R.id.tag1) == null) {
val listener = object : View.OnAttachStateChangeListener { val listener = object : View.OnAttachStateChangeListener {
override fun onViewAttachedToWindow(v: View) { override fun onViewAttachedToWindow(v: View) {

@ -3,6 +3,9 @@ package xyz.fycz.myreader.ui.adapter.holder;
import android.view.View; import android.view.View;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import xyz.fycz.myreader.R; import xyz.fycz.myreader.R;
import xyz.fycz.myreader.base.adapter.ViewHolderImpl; import xyz.fycz.myreader.base.adapter.ViewHolderImpl;
import xyz.fycz.myreader.greendao.entity.Book; import xyz.fycz.myreader.greendao.entity.Book;
@ -36,7 +39,7 @@ public class SourceExchangeHolder extends ViewHolderImpl<Book> {
} }
@Override @Override
public void onBind(Book data, int pos) { public void onBind(RecyclerView.ViewHolder holder, Book data, int pos) {
sourceTvTitle.setText(BookSourceManager.getSourceNameByStr(data.getSource())); sourceTvTitle.setText(BookSourceManager.getSourceNameByStr(data.getSource()));
sourceTvChapter.setText(data.getNewestChapterTitle()); sourceTvChapter.setText(data.getNewestChapterTitle());
if (data.getSource() != null && data.getSource().equals(dialog.getmShelfBook().getSource())) if (data.getSource() != null && data.getSource().equals(dialog.getmShelfBook().getSource()))

@ -15,8 +15,6 @@ import androidx.appcompat.app.AlertDialog;
import com.google.android.material.textfield.TextInputLayout; import com.google.android.material.textfield.TextInputLayout;
import com.kongzue.dialogx.dialogs.BottomMenu; import com.kongzue.dialogx.dialogs.BottomMenu;
import com.kongzue.dialogx.interfaces.BaseDialog;
import com.kongzue.dialogx.interfaces.OnDialogButtonClickListener;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -70,7 +68,7 @@ public class BookGroupDialog {
mGroupNames[i] = groupName; mGroupNames[i] = groupName;
} }
if (isAdd) { if (isAdd) {
mGroupNames[mBookGroups.size()] = "添加分组"; mGroupNames[mBookGroups.size()] = "+ 新建分组";
} }
} }
@ -118,80 +116,35 @@ public class BookGroupDialog {
* 添加/重命名分组对话框 * 添加/重命名分组对话框
*/ */
public void showAddOrRenameGroupDia(boolean isRename, boolean isAddGroup, int groupNum, OnGroup onGroup) { public void showAddOrRenameGroupDia(boolean isRename, boolean isAddGroup, int groupNum, OnGroup onGroup) {
View view = LayoutInflater.from(mContext).inflate(R.layout.edit_dialog, null);
TextInputLayout textInputLayout = view.findViewById(R.id.text_input_lay);
int maxLen = 20;
textInputLayout.setCounterMaxLength(maxLen);
EditText editText = textInputLayout.getEditText();
editText.setHint("请输入分组名");
BookGroup bookGroup = !isRename ? new BookGroup() : mBookGroups.get(groupNum); BookGroup bookGroup = !isRename ? new BookGroup() : mBookGroups.get(groupNum);
String oldName = bookGroup.getName(); String oldName = bookGroup.getName();
if (isRename) { int maxLen = 20;
editText.setText(oldName); MyAlertDialog.showFullScreenInputDia(mContext, !isRename ? "新建分组" : "重命名分组", "请输入分组名",
} isRename ? oldName : "", null, true, maxLen, newGroupName -> {
editText.requestFocus(); for (CharSequence oldGroupName : mGroupNames) {
InputMethodManager imm = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE); if (oldGroupName.equals(newGroupName)) {
mHandler.postDelayed(() -> { ToastUtils.showWarring("分组[" + newGroupName + "]已存在,无法" + (!isRename ? "添加!" : "重命名!"));
imm.toggleSoftInput(0, InputMethodManager.SHOW_FORCED); return;
}, 220); }
AlertDialog newGroupDia = MyAlertDialog.build(mContext) }
.setTitle(!isRename ? "新建分组" : "重命名分组") bookGroup.setName(newGroupName);
.setView(view) if (!isRename) {
.setCancelable(false) mBookGroupService.addBookGroup(bookGroup);
.setPositiveButton("确认", null) } else {
.setNegativeButton("取消", null) mBookGroupService.updateEntity(bookGroup);
.show(); SharedPreUtils spu = SharedPreUtils.getInstance();
Button posBtn = newGroupDia.getButton(AlertDialog.BUTTON_POSITIVE); if (spu.getString(mContext.getString(R.string.curBookGroupName), "").equals(oldName)) {
posBtn.setEnabled(false); spu.putString(mContext.getString(R.string.curBookGroupName), newGroupName.toString());
posBtn.setOnClickListener(v1 -> { if (onGroup != null) onGroup.change();
CharSequence newGroupName = editText.getText().toString(); }
for (CharSequence oldGroupName : mGroupNames) { }
if (oldGroupName.equals(newGroupName)) { ToastUtils.showSuccess("成功" +
ToastUtils.showWarring("分组[" + newGroupName + "]已存在,无法" + (!isRename ? "添加!" : "重命名!")); (!isRename ? "添加分组[" : "成功将[" + oldName + "]重命名为[")
return; + bookGroup.getName() + "]");
} if (isAddGroup) {
} if (onGroup != null) onGroup.addGroup();
bookGroup.setName(newGroupName.toString()); }
if (!isRename) { });
mBookGroupService.addBookGroup(bookGroup);
} else {
mBookGroupService.updateEntity(bookGroup);
SharedPreUtils spu = SharedPreUtils.getInstance();
if (spu.getString(mContext.getString(R.string.curBookGroupName), "").equals(oldName)) {
spu.putString(mContext.getString(R.string.curBookGroupName), newGroupName.toString());
if (onGroup != null) onGroup.change();
}
}
ToastUtils.showSuccess("成功" +
(!isRename ? "添加分组[" : "成功将[" + oldName + "]重命名为[")
+ bookGroup.getName() + "]");
imm.toggleSoftInput(0, InputMethodManager.SHOW_FORCED);
newGroupDia.dismiss();
if (isAddGroup) {
if (onGroup != null) onGroup.addGroup();
}
});
editText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
String text = editText.getText().toString();
if (editText.getText().length() > 0 && editText.getText().length() <= maxLen && !text.equals(oldName)) {
posBtn.setEnabled(true);
} else {
posBtn.setEnabled(false);
}
}
});
} }
/** /**

@ -1,5 +1,6 @@
package xyz.fycz.myreader.ui.dialog; package xyz.fycz.myreader.ui.dialog;
import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.text.Editable; import android.text.Editable;
@ -18,6 +19,7 @@ import androidx.appcompat.app.AppCompatActivity;
import com.google.android.material.textfield.TextInputLayout; import com.google.android.material.textfield.TextInputLayout;
import com.kongzue.dialogx.dialogs.BottomDialog; import com.kongzue.dialogx.dialogs.BottomDialog;
import com.kongzue.dialogx.dialogs.FullScreenDialog;
import com.kongzue.dialogx.interfaces.OnBindView; import com.kongzue.dialogx.interfaces.OnBindView;
import xyz.fycz.myreader.R; import xyz.fycz.myreader.R;
@ -26,6 +28,7 @@ import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.greendao.service.BookGroupService; import xyz.fycz.myreader.greendao.service.BookGroupService;
import xyz.fycz.myreader.util.CyptoUtils; import xyz.fycz.myreader.util.CyptoUtils;
import xyz.fycz.myreader.util.SharedPreUtils; import xyz.fycz.myreader.util.SharedPreUtils;
import xyz.fycz.myreader.util.StatusBarUtil;
import xyz.fycz.myreader.util.help.StringHelper; import xyz.fycz.myreader.util.help.StringHelper;
import xyz.fycz.myreader.util.ToastUtils; import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.util.utils.FingerprintUtils; import xyz.fycz.myreader.util.utils.FingerprintUtils;
@ -45,12 +48,18 @@ public class MyAlertDialog {
return createInputDia(context, title, hint, initText, inputType, cancelable, maxLen, oic, posListener, null, null, null); return createInputDia(context, title, hint, initText, inputType, cancelable, maxLen, oic, posListener, null, null, null);
} }
public static AlertDialog createInputDia(Context context, String title, String hint, String initText,
boolean cancelable, int maxLen, onInputChangeListener oic,
DialogInterface.OnClickListener posListener) {
return createInputDia(context, title, hint, initText, InputType.TYPE_CLASS_TEXT, cancelable, maxLen, oic, posListener);
}
public static AlertDialog createInputDia(Context context, String title, String hint, String initText, public static AlertDialog createInputDia(Context context, String title, String hint, String initText,
Integer inputType, boolean cancelable, int maxLen, onInputChangeListener oic, Integer inputType, boolean cancelable, int maxLen, onInputChangeListener oic,
DialogInterface.OnClickListener posListener, DialogInterface.OnClickListener posListener,
DialogInterface.OnClickListener negListener, String neutralBtn, DialogInterface.OnClickListener negListener, String neutralBtn,
DialogInterface.OnClickListener neutralListener) { DialogInterface.OnClickListener neutralListener) {
View view = LayoutInflater.from(context).inflate(R.layout.edit_dialog, null); View view = LayoutInflater.from(context).inflate(R.layout.edit_text, null);
TextInputLayout textInputLayout = view.findViewById(R.id.text_input_lay); TextInputLayout textInputLayout = view.findViewById(R.id.text_input_lay);
textInputLayout.setCounterMaxLength(maxLen); textInputLayout.setCounterMaxLength(maxLen);
@ -126,12 +135,62 @@ public class MyAlertDialog {
return inputDia; return inputDia;
} }
public static AlertDialog createInputDia(Context context, String title, String hint, String initText,
boolean cancelable, int maxLen, onInputChangeListener oic,
DialogInterface.OnClickListener posListener) {
return createInputDia(context, title, hint, initText, InputType.TYPE_CLASS_TEXT, cancelable, maxLen, oic, posListener);
}
public static void showFullScreenInputDia(Context context, String title, String hint, String initText,
Integer inputType, boolean cancelable, int maxLen,
OnInputFinishListener posListener) {
FullScreenDialog.show(new OnBindView<FullScreenDialog>(R.layout.dialog_input) {
@Override
public void onBind(FullScreenDialog dialog, View view) {
TextView cancelBtn = view.findViewById(R.id.btn_cancel);
TextView finishBtn = view.findViewById(R.id.btn_finish);
TextView tvTitle = view.findViewById(R.id.tv_title);
TextInputLayout textInputLayout = view.findViewById(R.id.text_input_lay);
EditText editText = textInputLayout.getEditText();
InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
tvTitle.setText(title);
cancelBtn.setOnClickListener(v -> {
imm.hideSoftInputFromWindow(editText.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
dialog.dismiss();
});
finishBtn.setOnClickListener(v -> {
imm.hideSoftInputFromWindow(editText.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
posListener.finish(editText.getText().toString());
dialog.dismiss();
});
textInputLayout.setCounterMaxLength(maxLen);
editText.setHint(hint);
if (inputType != null) editText.setInputType(inputType);
if (!StringHelper.isEmpty(initText)) editText.setText(initText);
editText.requestFocus();
App.getHandler().postDelayed(() -> imm.toggleSoftInput(0, InputMethodManager.SHOW_FORCED), 220);
finishBtn.setEnabled(false);
editText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
String text = editText.getText().toString();
if (editText.getText().length() > 0 && editText.getText().length() <= maxLen && !text.equals(initText)) {
finishBtn.setEnabled(true);
} else {
finishBtn.setEnabled(false);
}
}
});
}
}).setCancelable(cancelable);
}
/** /**
* 验证隐私密码对话框 * 验证隐私密码对话框
@ -142,6 +201,7 @@ public class MyAlertDialog {
public static void showPrivateVerifyDia(AppCompatActivity activity, OnVerify onVerify) { public static void showPrivateVerifyDia(AppCompatActivity activity, OnVerify onVerify) {
showPrivateVerifyDia(activity, onVerify, null); showPrivateVerifyDia(activity, onVerify, null);
} }
public static void showPrivateVerifyDia(AppCompatActivity activity, OnVerify onVerify, OnCancel onCancel) { public static void showPrivateVerifyDia(AppCompatActivity activity, OnVerify onVerify, OnCancel onCancel) {
boolean openPrivate = SharedPreUtils.getInstance().getBoolean("openPrivate"); boolean openPrivate = SharedPreUtils.getInstance().getBoolean("openPrivate");
boolean openFingerprint = SharedPreUtils.getInstance().getBoolean("openFingerprint"); boolean openFingerprint = SharedPreUtils.getInstance().getBoolean("openFingerprint");
@ -168,13 +228,15 @@ public class MyAlertDialog {
/** /**
* 输入隐私密码对话框 * 输入隐私密码对话框
*
* @param activity * @param activity
* @param onVerify * @param onVerify
*/ */
public static void showPrivatePwdInputDia(AppCompatActivity activity, OnVerify onVerify){ public static void showPrivatePwdInputDia(AppCompatActivity activity, OnVerify onVerify) {
showPrivatePwdInputDia(activity, onVerify, null); showPrivatePwdInputDia(activity, onVerify, null);
} }
public static void showPrivatePwdInputDia(AppCompatActivity activity, OnVerify onVerify, OnCancel onCancel){
public static void showPrivatePwdInputDia(AppCompatActivity activity, OnVerify onVerify, OnCancel onCancel) {
final String[] pwd = new String[1]; final String[] pwd = new String[1];
String pwds = SharedPreUtils.getInstance().getString("privatePwd"); String pwds = SharedPreUtils.getInstance().getString("privatePwd");
MyAlertDialog.createInputDia(activity, activity.getString(R.string.input_private_pwd), MyAlertDialog.createInputDia(activity, activity.getString(R.string.input_private_pwd),
@ -195,7 +257,7 @@ public class MyAlertDialog {
if (onCancel != null) { if (onCancel != null) {
onCancel.cancel(); onCancel.cancel();
} }
},"忘记密码", (dialog, which) -> { }, "忘记密码", (dialog, which) -> {
DialogCreator.createCommonDialog(activity, "忘记密码", DialogCreator.createCommonDialog(activity, "忘记密码",
"忘记密码无法找回!\n您可点击确定按钮关闭私密书架并删除私密书架所有书籍,确定关闭吗?", "忘记密码无法找回!\n您可点击确定按钮关闭私密书架并删除私密书架所有书籍,确定关闭吗?",
false, (dialog1, which1) -> { false, (dialog1, which1) -> {
@ -213,15 +275,16 @@ public class MyAlertDialog {
}); });
} }
public static void showTipDialogWithLink(Context context, int msgId){ public static void showTipDialogWithLink(Context context, int msgId) {
showTipDialogWithLink(context,"提示", msgId); showTipDialogWithLink(context, "提示", msgId);
} }
public static void showTipDialogWithLink(Context context, String title, int msgId){
public static void showTipDialogWithLink(Context context, String title, int msgId) {
/*TextView view = (TextView) LayoutInflater.from(context).inflate(R.layout.dialog_textview, null); /*TextView view = (TextView) LayoutInflater.from(context).inflate(R.layout.dialog_textview, null);
view.setText(msgId); view.setText(msgId);
view.setMovementMethod(LinkMovementMethod.getInstance()); view.setMovementMethod(LinkMovementMethod.getInstance());
build(context).setTitle(title).setView(view).setPositiveButton("知道了", null).show();*/ build(context).setTitle(title).setView(view).setPositiveButton("知道了", null).show();*/
BottomDialog.show(title, new OnBindView<BottomDialog>(R.layout.dialog_textview){ BottomDialog.show(title, new OnBindView<BottomDialog>(R.layout.dialog_textview) {
@Override @Override
public void onBind(BottomDialog dialog, View v) { public void onBind(BottomDialog dialog, View v) {
TextView view = (TextView) v; TextView view = (TextView) v;
@ -231,6 +294,7 @@ public class MyAlertDialog {
}).setCancelButton("知道了"); }).setCancelButton("知道了");
} }
public interface OnVerify { public interface OnVerify {
void success(boolean needGoTo); void success(boolean needGoTo);
} }
@ -242,4 +306,8 @@ public class MyAlertDialog {
public interface onInputChangeListener { public interface onInputChangeListener {
void onChange(String text); void onChange(String text);
} }
public interface OnInputFinishListener{
void finish(String text);
}
} }

@ -15,6 +15,7 @@ import android.widget.PopupMenu;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.kongzue.dialogx.dialogs.BottomMenu; import com.kongzue.dialogx.dialogs.BottomMenu;
@ -41,6 +42,7 @@ import xyz.fycz.myreader.ui.activity.BookSourceActivity;
import xyz.fycz.myreader.ui.activity.SourceEditActivity; import xyz.fycz.myreader.ui.activity.SourceEditActivity;
import xyz.fycz.myreader.ui.adapter.BookSourceAdapter; import xyz.fycz.myreader.ui.adapter.BookSourceAdapter;
import xyz.fycz.myreader.ui.adapter.helper.ItemTouchCallback; import xyz.fycz.myreader.ui.adapter.helper.ItemTouchCallback;
import xyz.fycz.myreader.ui.adapter.helper.OnStartDragListener;
import xyz.fycz.myreader.ui.dialog.DialogCreator; import xyz.fycz.myreader.ui.dialog.DialogCreator;
import xyz.fycz.myreader.ui.dialog.LoadingDialog; import xyz.fycz.myreader.ui.dialog.LoadingDialog;
import xyz.fycz.myreader.ui.dialog.MyAlertDialog; import xyz.fycz.myreader.ui.dialog.MyAlertDialog;
@ -70,6 +72,7 @@ public class DIYSourceFragment extends BaseFragment {
private boolean isSearch; private boolean isSearch;
private PopupMenu featuresMenu; private PopupMenu featuresMenu;
private ItemTouchCallback itemTouchCallback; private ItemTouchCallback itemTouchCallback;
private ItemTouchHelper itemTouchHelper;
private Disposable importSourceDis; private Disposable importSourceDis;
public DIYSourceFragment() { public DIYSourceFragment() {
@ -104,7 +107,7 @@ public class DIYSourceFragment extends BaseFragment {
mAdapter.toTop(which, bean); mAdapter.toTop(which, bean);
} }
} }
}); }, viewHolder -> itemTouchHelper.startDrag(viewHolder));
refreshSources(); refreshSources();
} }
@ -118,9 +121,9 @@ public class DIYSourceFragment extends BaseFragment {
//设置拖拽 //设置拖拽
itemTouchCallback = new ItemTouchCallback(); itemTouchCallback = new ItemTouchCallback();
itemTouchCallback.setOnItemTouchListener(mAdapter.getItemTouchListener()); itemTouchCallback.setOnItemTouchListener(mAdapter.getItemTouchListener());
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(itemTouchCallback); itemTouchHelper = new ItemTouchHelper(itemTouchCallback);
itemTouchHelper.attachToRecyclerView(binding.recyclerView); itemTouchHelper.attachToRecyclerView(binding.recyclerView);
itemTouchCallback.setDragEnable(false); itemTouchCallback.setLongPressDragEnable(false);
} }
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")
@ -341,12 +344,10 @@ public class DIYSourceFragment extends BaseFragment {
featuresMenu.getMenu().setGroupVisible(R.id.edit_mode, true); featuresMenu.getMenu().setGroupVisible(R.id.edit_mode, true);
featuresMenu.getMenu().setGroupVisible(R.id.non_edit_mode, false); featuresMenu.getMenu().setGroupVisible(R.id.non_edit_mode, false);
mAdapter.setmEditState(true); mAdapter.setmEditState(true);
itemTouchCallback.setDragEnable(true);
} else if (itemId == R.id.action_finish) { } else if (itemId == R.id.action_finish) {
featuresMenu.getMenu().setGroupVisible(R.id.edit_mode, false); featuresMenu.getMenu().setGroupVisible(R.id.edit_mode, false);
featuresMenu.getMenu().setGroupVisible(R.id.non_edit_mode, true); featuresMenu.getMenu().setGroupVisible(R.id.non_edit_mode, true);
mAdapter.setmEditState(false); mAdapter.setmEditState(false);
itemTouchCallback.setDragEnable(false);
} else if (itemId == R.id.action_export) { } else if (itemId == R.id.action_export) {
exportSources(mBookSources); exportSources(mBookSources);
} else if (itemId == R.id.action_share) { } else if (itemId == R.id.action_share) {

@ -28,6 +28,7 @@ import org.jetbrains.annotations.NotNull;
import java.text.Collator; import java.text.Collator;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@ -127,19 +128,6 @@ public class BookcasePresenter implements BasePresenter {
@Override @Override
public void handleMessage(Message msg) { public void handleMessage(Message msg) {
switch (msg.what) { switch (msg.what) {
case 1:
break;
case 2:
break;
case 3:
break;
case 4:
break;
case 5:
break;
case 6:
break;
case 7: case 7:
init(); init();
break; break;
@ -298,7 +286,7 @@ public class BookcasePresenter implements BasePresenter {
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(itemTouchCallback); ItemTouchHelper itemTouchHelper = new ItemTouchHelper(itemTouchCallback);
itemTouchHelper.attachToRecyclerView(mBookcaseFragment.getRvBook()); itemTouchHelper.attachToRecyclerView(mBookcaseFragment.getRvBook());
itemTouchCallback.setOnItemTouchListener(mBookcaseAdapter.getItemTouchCallbackListener()); itemTouchCallback.setOnItemTouchListener(mBookcaseAdapter.getItemTouchCallbackListener());
itemTouchCallback.setDragEnable(false); itemTouchCallback.setLongPressDragEnable(false);
isBookcaseStyleChange = false; isBookcaseStyleChange = false;
} else { } else {
mBookcaseAdapter.notifyDataSetChanged(); mBookcaseAdapter.notifyDataSetChanged();
@ -368,6 +356,43 @@ public class BookcasePresenter implements BasePresenter {
} }
public void refreshBook(Book book, boolean isChangeSource){
mBookcaseAdapter.getIsLoading().put(book.getId(), true);
mBookcaseAdapter.refreshBook(book.getChapterUrl());
final ArrayList<Chapter> mChapters = (ArrayList<Chapter>) mChapterService.findBookAllChapterByBookId(book.getId());
final ReadCrawler mReadCrawler = ReadCrawlerUtil.getReadCrawler(book.getSource());
BookApi.getBookChapters(book, mReadCrawler).flatMap(chapters -> Observable.create(emitter -> {
int noReadNum = chapters.size() - book.getChapterTotalNum();
book.setNoReadNum(Math.max(noReadNum, 0));
book.setNewestChapterTitle(chapters.get(chapters.size() - 1).getTitle());
mChapterService.updateAllOldChapterData(mChapters, chapters, book.getId());
mBookService.updateEntity(book);
if (isChangeSource){
if (mBookService.matchHistoryChapterPos(book, chapters)) {
ToastUtils.showSuccess("历史阅读章节匹配成功!");
} else {
ToastUtils.showError("历史阅读章节匹配失败!");
}
}
emitter.onNext(book);
emitter.onComplete();
})).compose(RxUtils::toSimpleSingle).subscribe(new MyObserver<Object>() {
@Override
public void onNext(@NotNull Object o) {
mBookcaseAdapter.getIsLoading().put(book.getId(), false);
mBookcaseAdapter.refreshBook(book.getChapterUrl());
}
@Override
public void onError(Throwable e) {
mBookcaseAdapter.getIsLoading().put(book.getId(), false);
mBookcaseAdapter.refreshBook(book.getChapterUrl());
ToastUtils.showError(String.format("《%s》目录刷新失败", book.getName()));
if (App.isDebug()) e.printStackTrace();
}
});
}
private synchronized void refreshBookshelf() { private synchronized void refreshBookshelf() {
refreshIndex++; refreshIndex++;
if (refreshIndex < mBooks.size()) { if (refreshIndex < mBooks.size()) {
@ -529,7 +554,7 @@ public class BookcasePresenter implements BasePresenter {
if (canEditBookcase()) { if (canEditBookcase()) {
mMainActivity.getViewPagerMain().setEnableScroll(false); mMainActivity.getViewPagerMain().setEnableScroll(false);
mBookcaseFragment.getSrlContent().setEnableRefresh(false); mBookcaseFragment.getSrlContent().setEnableRefresh(false);
itemTouchCallback.setDragEnable(mSetting.getSortStyle() == 0); itemTouchCallback.setLongPressDragEnable(mSetting.getSortStyle() == 0);
mBookcaseAdapter.setmEditState(true); mBookcaseAdapter.setmEditState(true);
mBookcaseFragment.getRlBookEdit().setVisibility(View.VISIBLE); mBookcaseFragment.getRlBookEdit().setVisibility(View.VISIBLE);
mMainActivity.initMenuAnim(); mMainActivity.initMenuAnim();
@ -543,7 +568,7 @@ public class BookcasePresenter implements BasePresenter {
} else { } else {
mMainActivity.getViewPagerMain().setEnableScroll(true); mMainActivity.getViewPagerMain().setEnableScroll(true);
mBookcaseFragment.getSrlContent().setEnableRefresh(true); mBookcaseFragment.getSrlContent().setEnableRefresh(true);
itemTouchCallback.setDragEnable(false); itemTouchCallback.setLongPressDragEnable(false);
mBookcaseAdapter.setmEditState(false); mBookcaseAdapter.setmEditState(false);
mBookcaseFragment.getRlBookEdit().setVisibility(View.GONE); mBookcaseFragment.getRlBookEdit().setVisibility(View.GONE);
mMainActivity.initMenuAnim(); mMainActivity.initMenuAnim();
@ -661,6 +686,21 @@ public class BookcasePresenter implements BasePresenter {
return this.ogcl != null; return this.ogcl != null;
} }
//加入分组
public void addGroup(Book book){
mBookGroupDia.addGroup(book, new BookGroupDialog.OnGroup() {
@Override
public void change() {
init();
}
@Override
public void addGroup() {
mBookcaseFragment.getmBtnAddGroup().performClick();
}
});
}
/**********************************************缓存书籍***************************************************************/ /**********************************************缓存书籍***************************************************************/
/** /**
* 缓存所有书籍 * 缓存所有书籍

@ -33,6 +33,7 @@ import xyz.fycz.myreader.util.utils.OkHttpUtils;
import xyz.fycz.myreader.util.utils.StringUtils; import xyz.fycz.myreader.util.utils.StringUtils;
@Keep @Keep
@SuppressWarnings({"unused"}) @SuppressWarnings({"unused"})
public interface JsExtensions { public interface JsExtensions {
String TAG = JsExtensions.class.getSimpleName(); String TAG = JsExtensions.class.getSimpleName();

@ -0,0 +1,225 @@
package xyz.fycz.myreader.util.utils;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.text.TextPaint;
import android.text.TextUtils;
import android.util.Log;
import android.widget.ImageView;
import com.google.zxing.EncodeHintType;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;
import cn.bingoogolapple.qrcode.zxing.QRCodeEncoder;
import io.reactivex.Single;
import io.reactivex.SingleOnSubscribe;
import io.reactivex.annotations.NonNull;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.base.observer.MySingleObserver;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.common.URLCONST;
import xyz.fycz.myreader.entity.SharedBook;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.model.sourceAnalyzer.BookSourceManager;
import xyz.fycz.myreader.util.IOUtils;
import xyz.fycz.myreader.util.ShareUtils;
import xyz.fycz.myreader.util.SharedPreUtils;
import xyz.fycz.myreader.util.ToastUtils;
/**
* @author fengyue
* @date 2021/6/3 21:46
*/
public class ShareBookUtil {
/**
* 分享书籍
*/
public static void shareBook(Context context, Book mBook, ImageView cover) {
if ("本地书籍".equals(mBook.getType())) {
File file = new File(mBook.getChapterUrl());
if (!file.exists()) {
ToastUtils.showWarring("书籍源文件不存在,无法分享!");
return;
}
try {
ShareUtils.share(context, file, mBook.getName() + ".txt", "text/plain");
} catch (Exception e) {
String dest = APPCONST.SHARE_FILE_DIR + File.separator + mBook.getName() + ".txt";
FileUtils.copy(mBook.getChapterUrl(), dest);
ShareUtils.share(context, new File(dest), mBook.getName() + ".txt", "text/plain");
}
return;
}
ToastUtils.showInfo("正在生成分享图片");
Single.create((SingleOnSubscribe<File>) emitter -> {
// 使用url
String url = SharedPreUtils.getInstance().getString(context.getString(R.string.downloadLink), URLCONST.LAN_ZOUS_URL);
if (url == null)
url = "";
int maxLength = 1273 - 1 - url.length();
SharedBook sharedBook = SharedBook.bookToSharedBook(mBook);
url = url + "#" + GsonExtensionsKt.getGSON().toJson(sharedBook);
Log.d("QRcode", "Length=" + url.length() + "\n" + url);
Bitmap bitmap;
QRCodeEncoder.HINTS.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L);
bitmap = QRCodeEncoder.syncEncodeQRCode(url, 360);
QRCodeEncoder.HINTS.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
File share = makeShareFile(context, mBook, cover, bitmap);
if (share == null) {
ToastUtils.showError("分享图片生成失败");
return;
}
emitter.onSuccess(share);
}).compose(RxUtils::toSimpleSingle)
.subscribe(new MySingleObserver<File>() {
@Override
public void onSuccess(@NonNull File File) {
share(context, File);
}
});
}
/**
* 生成分享图片
*
* @param QRCode
* @return
*/
private static File makeShareFile(Context context, Book mBook, ImageView cover, Bitmap QRCode) {
FileOutputStream fos = null;
try {
Bitmap back = BitmapFactory.decodeStream(context.getResources().getAssets().open("share.png")).copy(Bitmap.Config.ARGB_8888, true);
int backWidth = back.getWidth();
int backHeight = back.getHeight();
int margin = 60;
int marginTop = 24;
cover.setDrawingCacheEnabled(true);
Bitmap img = Bitmap.createBitmap(cover.getDrawingCache()).copy(Bitmap.Config.ARGB_8888, true);
cover.setDrawingCacheEnabled(false);
img = BitmapUtil.getBitmap(img, 152, 209);
Canvas cv = new Canvas(back);
cv.drawBitmap(img, margin, margin + marginTop * 2, null);
TextPaint textPaint = new TextPaint();
textPaint.setAntiAlias(true);
textPaint.setFilterBitmap(true);
textPaint.setColor(Color.BLACK);
textPaint.setTextSize(40);
String name = TextUtils.ellipsize(mBook.getName(), textPaint, backWidth - margin + marginTop * 3 - img.getWidth(), TextUtils.TruncateAt.END).toString();
cv.drawText(name, margin + marginTop + img.getWidth(), margin + marginTop * 4, textPaint);
textPaint.setColor(context.getResources().getColor(R.color.origin));
textPaint.setTextSize(32);
cv.drawText(mBook.getAuthor(), margin + marginTop + img.getWidth(), margin + marginTop * 6, textPaint);
textPaint.setColor(Color.BLACK);
cv.drawText(mBook.getType() == null ? "" : mBook.getType(), margin + marginTop + img.getWidth(), margin + marginTop * 8, textPaint);
cv.drawText("书源:" + BookSourceManager.getSourceNameByStr(mBook.getSource()), margin + marginTop + img.getWidth(), margin + marginTop * 10, textPaint);
int textSize = 35;
int textInterval = textSize / 2;
textPaint.setTextSize(textSize);
drawDesc(getDescLines(mBook, backWidth - margin * 2, textPaint), textPaint, cv, margin + marginTop * 4 + img.getHeight(), margin, textInterval);
cv.drawBitmap(QRCode, backWidth - QRCode.getWidth(), backHeight - QRCode.getHeight(), null);
cv.save();// 保存
cv.restore();// 存储
File share = FileUtils.getFile(APPCONST.SHARE_FILE_DIR + mBook.getName() + "_share.png");
fos = new FileOutputStream(share);
back.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.flush();
Log.i("tag", "saveBitmap success: " + share.getAbsolutePath());
back.recycle();
img.recycle();
QRCode.recycle();
return share;
} catch (Exception e) {
e.printStackTrace();
ToastUtils.showError(e.getLocalizedMessage() + "");
return null;
} finally {
IOUtils.close(fos);
}
}
/**
* 分享生成的图片
*
* @param share
*/
private static void share(Context context, File share) {
ShareUtils.share(context, share, "分享书籍", "image/png");
}
/**
* 绘制简介
*
* @param lines
* @param textPaint
* @param canvas
* @param top
* @param left
* @param textInterval
*/
private static void drawDesc(List<String> lines, TextPaint textPaint, Canvas canvas, int top, int left, int textInterval) {
float interval = textInterval + textPaint.getTextSize();
for (String line : lines) {
canvas.drawText(line, left, top, textPaint);
top += interval;
}
}
/**
* 生成简介lines
*
* @param width
* @param textPaint
* @return
*/
private static List<String> getDescLines(Book mBook, int width, TextPaint textPaint) {
List<String> lines = new ArrayList<>();
String desc = StringUtils.halfToFull(" ") + mBook.getDesc();
int i = 0;
int wordCount = 0;
String subStr = null;
while (desc.length() > 0) {
if (i == 9) {
lines.add(TextUtils.ellipsize(desc, textPaint, width / 1.8f, TextUtils.TruncateAt.END).toString());
break;
}
wordCount = textPaint.breakText(desc, true, width, null);
subStr = desc.substring(0, wordCount);
lines.add(subStr);
desc = desc.substring(wordCount);
i++;
}
return lines;
}
}

@ -0,0 +1,18 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:pathData="M348.16,153.6m40.96,0l245.76,0q40.96,0 40.96,40.96l0,286.72q0,40.96 -40.96,40.96l-245.76,0q-40.96,0 -40.96,-40.96l0,-286.72q0,-40.96 40.96,-40.96Z"
android:fillColor="#689CD5"/>
<path
android:pathData="M174.08,409.6m40.96,0l593.92,0q40.96,0 40.96,40.96l0,378.88q0,40.96 -40.96,40.96l-593.92,0q-40.96,0 -40.96,-40.96l0,-378.88q0,-40.96 40.96,-40.96Z"
android:fillColor="#81B7EF"/>
<path
android:pathData="M122.88,588.8m40.96,0l696.32,0q40.96,0 40.96,40.96l0,199.68q0,40.96 -40.96,40.96l-696.32,0q-40.96,0 -40.96,-40.96l0,-199.68q0,-40.96 40.96,-40.96Z"
android:fillColor="#689CD5"/>
<path
android:pathData="M511.99,481.51C479.65,507.55 458.66,516.92 449.02,509.59c-9.64,-7.31 -7.6,-31.05 6.12,-71.22 -33.6,-24.41 -48.61,-42.36 -45.03,-53.86 3.58,-11.51 25.83,-16.82 66.74,-15.93C488.57,327.66 500.28,307.2 511.99,307.2s23.42,20.46 35.13,61.38c40.83,-1.17 63.08,4.15 66.74,15.93 3.67,11.79 -11.35,29.74 -45.03,53.86 13.34,40.45 15.38,64.19 6.12,71.22 -9.27,7.03 -30.25,-2.33 -62.96,-28.09z"
android:fillColor="#E2EEFD"/>
</vector>

@ -4,15 +4,12 @@
android:viewportWidth="1024" android:viewportWidth="1024"
android:viewportHeight="1024"> android:viewportHeight="1024">
<path <path
android:pathData="M348.16,153.6m40.96,0l245.76,0q40.96,0 40.96,40.96l0,286.72q0,40.96 -40.96,40.96l-245.76,0q-40.96,0 -40.96,-40.96l0,-286.72q0,-40.96 40.96,-40.96Z" android:fillColor="#FF000000"
android:fillColor="#689CD5"/> android:pathData="M192,106.67m32,0l576,0q32,0 32,32l0,0q0,32 -32,32l-576,0q-32,0 -32,-32l0,0q0,-32 32,-32Z"/>
<path <path
android:pathData="M174.08,409.6m40.96,0l593.92,0q40.96,0 40.96,40.96l0,378.88q0,40.96 -40.96,40.96l-593.92,0q-40.96,0 -40.96,-40.96l0,-378.88q0,-40.96 40.96,-40.96Z" android:fillColor="#FF000000"
android:fillColor="#81B7EF"/> android:pathData="M544,248.36m0,32l0,576q0,32 -32,32l0,0q-32,0 -32,-32l0,-576q0,-32 32,-32l0,0q32,0 32,32Z"/>
<path <path
android:pathData="M122.88,588.8m40.96,0l696.32,0q40.96,0 40.96,40.96l0,199.68q0,40.96 -40.96,40.96l-696.32,0q-40.96,0 -40.96,-40.96l0,-199.68q0,-40.96 40.96,-40.96Z" android:fillColor="#FF000000"
android:fillColor="#689CD5"/> android:pathData="M489.39,251.56a32,32 0,0 1,41.64 -3.07l3.58,3.07 232.32,232.32a32,32 0,0 1,-41.69 48.34l-3.58,-3.11L512,319.45l-209.66,209.66a32,32 0,0 1,-41.69 3.11l-3.58,-3.11a32,32 0,0 1,-3.07 -41.64l3.07,-3.58 232.32,-232.32z"/>
<path
android:pathData="M511.99,481.51C479.65,507.55 458.66,516.92 449.02,509.59c-9.64,-7.31 -7.6,-31.05 6.12,-71.22 -33.6,-24.41 -48.61,-42.36 -45.03,-53.86 3.58,-11.51 25.83,-16.82 66.74,-15.93C488.57,327.66 500.28,307.2 511.99,307.2s23.42,20.46 35.13,61.38c40.83,-1.17 63.08,4.15 66.74,15.93 3.67,11.79 -11.35,29.74 -45.03,53.86 13.34,40.45 15.38,64.19 6.12,71.22 -9.27,7.03 -30.25,-2.33 -62.96,-28.09z"
android:fillColor="#E2EEFD"/>
</vector> </vector>

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/nothing" />
<stroke
android:width="1dp"
android:color="@color/textAssist" />
<corners
android:topLeftRadius="20dp"
android:topRightRadius="20dp"
android:bottomRightRadius="20dp"
android:bottomLeftRadius="20dp"/>
</shape>

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="true" android:color="@color/md_blue_400"/>
<item android:state_enabled="false" android:color="@color/textSecondary"/>
</selector>

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="600dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal">
<TextView
android:id="@+id/btn_cancel"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:text="@string/cancel"
android:textColor="@color/textPrimary"
android:textSize="@dimen/text_normal_size" />
<TextView
android:id="@+id/tv_title"
android:layout_width="0dp"
android:layout_height="match_parent"
android:gravity="center"
android:text="@string/app_name"
android:textColor="@color/textPrimary"
android:textSize="@dimen/text_medium_size"
android:layout_weight="1" />
<TextView
android:id="@+id/btn_finish"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:text="@string/finish"
android:textColor="@drawable/selector_btn_input_finish"
android:textSize="@dimen/text_normal_size" />
</LinearLayout>
<include layout="@layout/edit_text"/>
</LinearLayout>

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.textfield.TextInputLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/text_input_lay"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
app:counterEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"/>
</com.google.android.material.textfield.TextInputLayout>

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.textfield.TextInputLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/text_input_lay"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal="10dp"
android:paddingVertical="5dp"
app:counterEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text" />
</com.google.android.material.textfield.TextInputLayout>

@ -31,6 +31,7 @@
<com.scwang.smartrefresh.layout.SmartRefreshLayout <com.scwang.smartrefresh.layout.SmartRefreshLayout
android:id="@+id/srl_book_list" android:id="@+id/srl_book_list"
android:layout_above="@+id/rl_book_edit"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">

@ -26,7 +26,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:src="@drawable/ic_top" android:src="@drawable/ic_leaderboard"
/> />
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"

@ -47,6 +47,17 @@
app:srcCompat="@drawable/ic_swipe_left" app:srcCompat="@drawable/ic_swipe_left"
app:tint="@color/textAssist" /> app:tint="@color/textAssist" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_move"
android:visibility="gone"
android:layout_width="30dp"
android:layout_height="30dp"
android:padding="7dp"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
app:srcCompat="@drawable/ic_line_spacing3"
app:tint="@color/textAssist" />
</RelativeLayout> </RelativeLayout>

@ -15,18 +15,6 @@
android:orientation="horizontal" android:orientation="horizontal"
android:padding="5dp"> android:padding="5dp">
<CheckBox
android:id="@+id/cb_book_select"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center"
android:clickable="false"
android:enabled="true"
android:focusable="true"
android:paddingEnd="2dp"
android:theme="@style/MyCheckBox"
android:visibility="gone" />
<xyz.fycz.myreader.widget.CoverImageView <xyz.fycz.myreader.widget.CoverImageView
android:id="@+id/iv_book_img" android:id="@+id/iv_book_img"
android:layout_width="48dp" android:layout_width="48dp"

@ -0,0 +1,233 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginBottom="10dp"
android:paddingHorizontal="10dp">
<RelativeLayout
android:id="@+id/rl_book_detail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingVertical="5dp">
<LinearLayout
android:id="@+id/ll_book_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="5dp">
<xyz.fycz.myreader.widget.CoverImageView
android:id="@+id/iv_book_img"
android:layout_width="40dp"
android:layout_height="55dp"
android:scaleType="fitXY"
app:srcCompat="@mipmap/default_cover" />
<LinearLayout
android:id="@+id/ll_book_read"
android:paddingHorizontal="5dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/tv_book_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:padding="4dp"
android:text="@string/app_name"
android:textColor="@color/textPrimary"
android:textSize="@dimen/text_normal_size" />
<TextView
android:id="@+id/tv_book_author"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="1"
android:padding="4dp"
android:text="@string/app_name"
android:textColor="@color/textSecondary"
android:textSize="@dimen/text_default_size" />
</LinearLayout>
</LinearLayout>
<TextView
android:id="@+id/tv_theme_mode_select"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginEnd="5dp"
android:background="@drawable/menu_book_detail"
android:paddingHorizontal="10dp"
android:paddingVertical="5dp"
android:text="详情"
android:textColor="@color/textPrimary"
android:textSize="@dimen/text_small_size" />
</RelativeLayout>
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="@color/sys_window_back" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="55dp"
android:layout_marginVertical="5dp"
android:paddingVertical="5dp">
<TextView
android:id="@+id/tv_top"
style="@style/MAppTheme.TextAppearance.BookMenu"
android:clickable="true"
android:focusable="true"
android:text="@string/menu_book_Top"
app:drawableTint="@color/textPrimary"
app:drawableTopCompat="@drawable/ic_top" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical">
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/sc_is_update"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:textColor="@color/textPrimary"
android:textSize="@dimen/text_small_size"
android:text="@string/menu_is_update"/>
</LinearLayout>
<TextView
android:id="@+id/tv_download"
style="@style/MAppTheme.TextAppearance.BookMenu"
android:clickable="true"
android:focusable="true"
android:text="@string/menu_book_download"
app:drawableTint="@color/textPrimary"
app:drawableTopCompat="@drawable/ic_download" />
<TextView
android:id="@+id/tv_export_cathe"
style="@style/MAppTheme.TextAppearance.BookMenu"
android:clickable="true"
android:focusable="true"
android:text="@string/menu_book_cache"
app:drawableTint="@color/textPrimary"
app:drawableTopCompat="@drawable/ic_export" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="@color/sys_window_back" />
<LinearLayout
android:layout_width="match_parent"
android:layout_marginVertical="5dp"
android:layout_height="55dp"
android:paddingVertical="5dp">
<TextView
android:id="@+id/tv_change_source"
style="@style/MAppTheme.TextAppearance.BookMenu"
android:clickable="true"
android:focusable="true"
android:text="@string/menu_change_source"
app:drawableTint="@color/textPrimary"
app:drawableTopCompat="@drawable/ic_change" />
<TextView
android:id="@+id/tv_set_group"
style="@style/MAppTheme.TextAppearance.BookMenu"
android:clickable="true"
android:focusable="true"
android:text="@string/menu_group_setting"
app:drawableTint="@color/textPrimary"
app:drawableTopCompat="@drawable/ic_group" />
<TextView
android:id="@+id/tv_share"
style="@style/MAppTheme.TextAppearance.BookMenu"
android:clickable="true"
android:focusable="true"
android:text="@string/menu_share"
app:drawableTint="@color/textPrimary"
app:drawableTopCompat="@drawable/ic_share" />
<TextView
android:id="@+id/tv_remove"
style="@style/MAppTheme.TextAppearance.BookMenu"
android:clickable="true"
android:focusable="true"
android:text="@string/menu_book_delete"
app:drawableTint="@color/textPrimary"
app:drawableTopCompat="@drawable/ic_delete" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="@color/sys_window_back" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="55dp"
android:layout_marginVertical="5dp"
android:paddingVertical="5dp">
<TextView
android:id="@+id/tv_edit"
style="@style/MAppTheme.TextAppearance.BookMenu"
android:clickable="true"
android:focusable="true"
android:text="@string/menu_edit"
app:drawableTint="@color/textPrimary"
app:drawableTopCompat="@drawable/ic_edit" />
<TextView
android:id="@+id/tv_refresh"
style="@style/MAppTheme.TextAppearance.BookMenu"
android:clickable="true"
android:focusable="true"
android:text="@string/refresh_books"
app:drawableTint="@color/textPrimary"
app:drawableTopCompat="@drawable/ic_refresh" />
<TextView
android:id="@+id/tv_link"
style="@style/MAppTheme.TextAppearance.BookMenu"
android:clickable="true"
android:focusable="true"
android:text="@string/menu_open_link"
app:drawableTint="@color/textPrimary"
app:drawableTopCompat="@drawable/ic_link" />
<TextView
android:id="@+id/tv_edit_source"
style="@style/MAppTheme.TextAppearance.BookMenu"
android:clickable="true"
android:focusable="true"
android:text="@string/book_source"
app:drawableTint="@color/textPrimary"
app:drawableTopCompat="@drawable/ic_source" />
</LinearLayout>
</LinearLayout>

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginBottom="10dp"
android:paddingHorizontal="10dp">
<RelativeLayout
android:id="@+id/rl_book_detail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingVertical="5dp">
<LinearLayout
android:id="@+id/ll_book_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="5dp">
<xyz.fycz.myreader.widget.CoverImageView
android:id="@+id/iv_book_img"
android:layout_width="40dp"
android:layout_height="55dp"
android:scaleType="fitXY"
app:srcCompat="@mipmap/default_cover" />
<LinearLayout
android:id="@+id/ll_book_read"
android:paddingHorizontal="5dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/tv_book_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:padding="4dp"
android:text="@string/app_name"
android:textColor="@color/textPrimary"
android:textSize="@dimen/text_normal_size" />
<TextView
android:id="@+id/tv_book_author"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="1"
android:padding="4dp"
android:text="@string/app_name"
android:textColor="@color/textSecondary"
android:textSize="@dimen/text_default_size" />
</LinearLayout>
</LinearLayout>
<TextView
android:id="@+id/tv_theme_mode_select"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginEnd="5dp"
android:background="@drawable/menu_book_detail"
android:paddingHorizontal="10dp"
android:paddingVertical="5dp"
android:text="详情"
android:textColor="@color/textPrimary"
android:textSize="@dimen/text_small_size" />
</RelativeLayout>
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="@color/sys_window_back" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="55dp"
android:layout_marginVertical="5dp"
android:paddingVertical="5dp">
<TextView
android:id="@+id/tv_edit"
style="@style/MAppTheme.TextAppearance.BookMenu"
android:clickable="true"
android:focusable="true"
android:text="@string/menu_edit"
app:drawableTint="@color/textPrimary"
app:drawableTopCompat="@drawable/ic_edit" />
<TextView
android:id="@+id/tv_top"
style="@style/MAppTheme.TextAppearance.BookMenu"
android:clickable="true"
android:focusable="true"
android:text="@string/menu_book_Top"
app:drawableTint="@color/textPrimary"
app:drawableTopCompat="@drawable/ic_top" />
<TextView
android:id="@+id/tv_set_group"
style="@style/MAppTheme.TextAppearance.BookMenu"
android:clickable="true"
android:focusable="true"
android:text="@string/menu_group_setting"
app:drawableTint="@color/textPrimary"
app:drawableTopCompat="@drawable/ic_group" />
<TextView
android:id="@+id/tv_remove"
style="@style/MAppTheme.TextAppearance.BookMenu"
android:clickable="true"
android:focusable="true"
android:text="@string/menu_book_delete"
app:drawableTint="@color/textPrimary"
app:drawableTopCompat="@drawable/ic_delete" />
</LinearLayout>
</LinearLayout>

@ -61,7 +61,7 @@
<string name="menu_book_detail">书籍详情</string> <string name="menu_book_detail">书籍详情</string>
<string name="menu_book_download">缓存书籍</string> <string name="menu_book_download">缓存书籍</string>
<string name="menu_book_cache">导出缓存</string> <string name="menu_book_cache">导出缓存</string>
<string name="menu_book_delete">删除/移除书籍</string> <string name="menu_book_delete">删除书籍</string>
<string name="menu_bookcase_edit">编辑书架</string> <string name="menu_bookcase_edit">编辑书架</string>
<string name="menu_bookcase_style">切换布局</string> <string name="menu_bookcase_style">切换布局</string>

@ -192,6 +192,7 @@
<item name="android:textSize">@dimen/text_small_size</item> <item name="android:textSize">@dimen/text_small_size</item>
</style> </style>
<style name="dialogWindowAnim" parent="android:Animation" mce_bogus="1"> <style name="dialogWindowAnim" parent="android:Animation" mce_bogus="1">
<item name="android:windowEnterAnimation">@anim/slide_bottom_in</item> <item name="android:windowEnterAnimation">@anim/slide_bottom_in</item>
<item name="android:windowExitAnimation">@anim/slide_bottom_out</item> <item name="android:windowExitAnimation">@anim/slide_bottom_out</item>
@ -226,4 +227,15 @@
<item name="android:windowBackground">@android:color/transparent</item> <item name="android:windowBackground">@android:color/transparent</item>
<item name="android:backgroundDimEnabled">false</item> <item name="android:backgroundDimEnabled">false</item>
</style> </style>
<!--bookMenu-->
<style name="MAppTheme.TextAppearance.BookMenu">
<item name="android:background">?android:attr/selectableItemBackground</item>
<item name="android:gravity">center_horizontal|bottom</item>
<item name="android:layout_width">0dp</item>
<item name="android:layout_height">match_parent</item>
<item name="android:layout_weight">1</item>
<item name="android:textColor">@color/textPrimary</item>
<item name="android:textSize">@dimen/text_small_size</item>
</style>
</resources> </resources>

@ -1,2 +1,2 @@
#Wed Jun 02 20:55:52 CST 2021 #Thu Jun 03 14:18:11 CST 2021
VERSION_CODE=206 VERSION_CODE=207

Loading…
Cancel
Save