diff --git a/.idea/assetWizardSettings.xml b/.idea/assetWizardSettings.xml index dade6b2..eb4cef2 100644 --- a/.idea/assetWizardSettings.xml +++ b/.idea/assetWizardSettings.xml @@ -14,8 +14,8 @@ diff --git a/DialogX/src/main/java/com/kongzue/dialogx/style/MaterialStyle.java b/DialogX/src/main/java/com/kongzue/dialogx/style/MaterialStyle.java index f9aee1e..d7936ce 100644 --- a/DialogX/src/main/java/com/kongzue/dialogx/style/MaterialStyle.java +++ b/DialogX/src/main/java/com/kongzue/dialogx/style/MaterialStyle.java @@ -161,7 +161,7 @@ public class MaterialStyle implements DialogXStyle { @Override public int overrideMenuTextColor(boolean light) { - return light ? R.color.black90 : R.color.white90; + return light ? R.color.black90 : R.color.dialogxMIUITextDark; } @Override diff --git a/app/src/main/assets/updatelog.fy b/app/src/main/assets/updatelog.fy index 317c7f8..cd57edd 100644 --- a/app/src/main/assets/updatelog.fy +++ b/app/src/main/assets/updatelog.fy @@ -1,3 +1,7 @@ +风月读书v2.0.8 +更新内容: +1、优化书籍、书源拖拽移动效果 + 2021.06.03 风月读书v2.0.7 更新内容: diff --git a/app/src/main/java/xyz/fycz/myreader/application/App.java b/app/src/main/java/xyz/fycz/myreader/application/App.java index 402d064..f09164e 100644 --- a/app/src/main/java/xyz/fycz/myreader/application/App.java +++ b/app/src/main/java/xyz/fycz/myreader/application/App.java @@ -26,6 +26,7 @@ import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatDelegate; import com.kongzue.dialogx.DialogX; +import com.kongzue.dialogx.style.MaterialStyle; import com.liulishuo.filedownloader.FileDownloader; import com.liulishuo.filedownloader.connection.FileDownloadUrlConnection; @@ -112,6 +113,7 @@ public class App extends Application { private void initDialogX() { DialogX.init(this); DialogX.DEBUGMODE = debug; + DialogX.globalStyle = MaterialStyle.style(); } public void initNightTheme() { diff --git a/app/src/main/java/xyz/fycz/myreader/base/adapter/BaseListAdapter.java b/app/src/main/java/xyz/fycz/myreader/base/adapter/BaseListAdapter.java index 2c03f78..6631a4e 100644 --- a/app/src/main/java/xyz/fycz/myreader/base/adapter/BaseListAdapter.java +++ b/app/src/main/java/xyz/fycz/myreader/base/adapter/BaseListAdapter.java @@ -43,7 +43,7 @@ public abstract class BaseListAdapter extends RecyclerView.Adapter iHolder = ((BaseViewHolder) holder).holder; - iHolder.onBind(getItem(position),position); + iHolder.onBind(holder, getItem(position), position); //设置点击事件 holder.itemView.setOnClickListener((v)->{ diff --git a/app/src/main/java/xyz/fycz/myreader/base/adapter/IViewHolder.java b/app/src/main/java/xyz/fycz/myreader/base/adapter/IViewHolder.java index 54d2952..c8ba71b 100644 --- a/app/src/main/java/xyz/fycz/myreader/base/adapter/IViewHolder.java +++ b/app/src/main/java/xyz/fycz/myreader/base/adapter/IViewHolder.java @@ -3,6 +3,8 @@ package xyz.fycz.myreader.base.adapter; import android.view.View; import android.view.ViewGroup; +import androidx.recyclerview.widget.RecyclerView; + /** * @author fengyue * @date 2020/8/12 20:02 @@ -11,6 +13,6 @@ import android.view.ViewGroup; public interface IViewHolder { View createItemView(ViewGroup parent); void initView(); - void onBind(T data,int pos); + void onBind(RecyclerView.ViewHolder holder, T data, int pos); void onClick(); } diff --git a/app/src/main/java/xyz/fycz/myreader/ui/activity/BookDetailedActivity.java b/app/src/main/java/xyz/fycz/myreader/ui/activity/BookDetailedActivity.java index 24575d3..c342fce 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/activity/BookDetailedActivity.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/activity/BookDetailedActivity.java @@ -77,6 +77,7 @@ import xyz.fycz.myreader.util.utils.FileUtils; import xyz.fycz.myreader.util.utils.GsonExtensionsKt; import xyz.fycz.myreader.util.utils.NetworkUtils; 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.webapi.BookApi; import xyz.fycz.myreader.webapi.crawler.ReadCrawlerUtil; @@ -640,7 +641,7 @@ public class BookDetailedActivity extends BaseActivity { mSourceDialog.show(); break; case R.id.action_share: - shareBook(); + ShareBookUtil.shareBook(this, mBook, binding.ih.bookDetailIvCover); break; case R.id.action_edit: Intent editIntent = new Intent(this, BookInfoEditActivity.class); @@ -660,17 +661,7 @@ public class BookDetailedActivity extends BaseActivity { startActivity(intent); break; case R.id.action_group_setting: - mBookGroupDia.addGroup(mBook, new BookGroupDialog.OnGroup() { - @Override - public void change() { - - } - - @Override - public void addGroup() { - - } - }); + mBookGroupDia.addGroup(mBook, null); break; case R.id.action_edit_source: 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) 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() { - @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 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 getDescLines(int width, TextPaint textPaint) { - List 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() { return mReadCrawler instanceof ThirdCrawler; diff --git a/app/src/main/java/xyz/fycz/myreader/ui/adapter/BookSourceAdapter.java b/app/src/main/java/xyz/fycz/myreader/ui/adapter/BookSourceAdapter.java index 6baf78e..ab7aa16 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/adapter/BookSourceAdapter.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/adapter/BookSourceAdapter.java @@ -7,10 +7,12 @@ import androidx.fragment.app.FragmentActivity; import java.util.Collections; +import xyz.fycz.myreader.application.App; import xyz.fycz.myreader.base.adapter.IViewHolder; import xyz.fycz.myreader.greendao.DbManager; import xyz.fycz.myreader.greendao.entity.rule.BookSource; import xyz.fycz.myreader.ui.adapter.helper.ItemTouchCallback; +import xyz.fycz.myreader.ui.adapter.helper.OnStartDragListener; 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 { private final FragmentActivity activity; private final OnSwipeListener onSwipeListener; + private OnStartDragListener onStartDragListener; private boolean mEditState; private final ItemTouchCallback.OnItemTouchListener itemTouchListener = new ItemTouchCallback.OnItemTouchListener() { @Override @@ -32,26 +35,41 @@ public class BookSourceAdapter extends BaseSourceAdapter { public boolean onMove(int srcPosition, int targetPosition) { Collections.swap(mList, srcPosition, targetPosition); notifyItemMoved(srcPosition, targetPosition); - notifyItemChanged(srcPosition); + /*notifyItemChanged(srcPosition); notifyItemChanged(targetPosition); AsyncTask.execute(() -> { for (int i = 1; i <= mList.size(); i++) { mList.get(i - 1).setOrderNum(i); } DbManager.getDaoSession().getBookSourceDao().insertOrReplaceInTx(mList); - }); + });*/ 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.onSwipeListener = onSwipeListener; + this.onStartDragListener = onStartDragListener; } @Override protected IViewHolder createViewHolder(int viewType) { - return new BookSourceHolder(activity, this, onSwipeListener); + return new BookSourceHolder(activity, this, onSwipeListener, onStartDragListener); } public ItemTouchCallback.OnItemTouchListener getItemTouchListener() { diff --git a/app/src/main/java/xyz/fycz/myreader/ui/adapter/BookcaseAdapter.java b/app/src/main/java/xyz/fycz/myreader/ui/adapter/BookcaseAdapter.java index f458cd7..9bd38ce 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/adapter/BookcaseAdapter.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/adapter/BookcaseAdapter.java @@ -1,14 +1,20 @@ package xyz.fycz.myreader.ui.adapter; +import android.app.Activity; import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.text.TextUtils; import android.view.View; import android.widget.*; import androidx.annotation.NonNull; +import androidx.appcompat.widget.SwitchCompat; import androidx.recyclerview.widget.RecyclerView; import com.kongzue.dialogx.dialogs.BottomDialog; import com.kongzue.dialogx.dialogs.BottomMenu; +import com.kongzue.dialogx.interfaces.OnBindView; import com.kongzue.dialogx.interfaces.OnDialogButtonClickListener; import com.kongzue.dialogx.interfaces.OnMenuItemSelectListener; @@ -22,12 +28,29 @@ import java.io.FileWriter; import java.io.IOException; import java.util.*; +import io.reactivex.Single; +import io.reactivex.SingleOnSubscribe; import xyz.fycz.myreader.R; 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.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.dialog.DialogCreator; 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.custom.DragAdapter; import xyz.fycz.myreader.greendao.entity.Book; @@ -351,7 +374,7 @@ public abstract class BookcaseAdapter extends RecyclerView.Adapter { + 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) emitter -> { + emitter.onSuccess(unionChapterCathe(mBook)); + }).compose(RxUtils::toSimpleSingle).subscribe(new MySingleObserver() { + @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; CoverImageView ivBookImg; TextView tvBookName; @@ -370,6 +596,16 @@ public abstract class BookcaseAdapter extends RecyclerView.Adapter notifyDataSetChanged(), 500); + } + }; } @@ -151,90 +157,7 @@ public class BookcaseDetailedAdapter extends BookcaseAdapter { }); viewHolder.llBookRead.setOnLongClickListener(v -> { if (!ismEditState()) { - /*AlertDialog bookDialog = MyAlertDialog.build(mContext) - .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; - }); + showBookMenu(book, position); return true; } return false; diff --git a/app/src/main/java/xyz/fycz/myreader/ui/adapter/BookcaseDragAdapter.java b/app/src/main/java/xyz/fycz/myreader/ui/adapter/BookcaseDragAdapter.java index 95f0b91..a64b290 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/adapter/BookcaseDragAdapter.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/adapter/BookcaseDragAdapter.java @@ -57,15 +57,21 @@ public class BookcaseDragAdapter extends BookcaseAdapter { list.remove(srcPosition); list.add(targetPosition, shelfBean); notifyItemMoved(srcPosition, targetPosition); - int start = srcPosition; + /*int start = srcPosition; int end = targetPosition; if (start > end) { start = targetPosition; end = srcPosition; } - notifyItemRangeChanged(start, end - start + 1); + notifyItemRangeChanged(start, end - start + 1);*/ return true; } + + @Override + public void onEnd() { + App.getHandler().postDelayed(() -> notifyDataSetChanged(), 500); + } + }; } @@ -136,106 +142,7 @@ public class BookcaseDragAdapter extends BookcaseAdapter { }); viewHolder.ivBookImg.setOnLongClickListener(v -> { if (!ismEditState()) { - /*AlertDialog bookDialog = MyAlertDialog.build(mContext) - .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; - }); + showBookMenu(book, position); return true; } return false; diff --git a/app/src/main/java/xyz/fycz/myreader/ui/adapter/helper/IItemTouchHelperViewHolder.java b/app/src/main/java/xyz/fycz/myreader/ui/adapter/helper/IItemTouchHelperViewHolder.java new file mode 100644 index 0000000..78cdd0c --- /dev/null +++ b/app/src/main/java/xyz/fycz/myreader/ui/adapter/helper/IItemTouchHelperViewHolder.java @@ -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(); +} diff --git a/app/src/main/java/xyz/fycz/myreader/ui/adapter/helper/ItemTouchCallback.java b/app/src/main/java/xyz/fycz/myreader/ui/adapter/helper/ItemTouchCallback.java index 794a5ae..7c0eaa5 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/adapter/helper/ItemTouchCallback.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/adapter/helper/ItemTouchCallback.java @@ -9,6 +9,9 @@ import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import androidx.viewpager.widget.ViewPager; + +import org.jetbrains.annotations.NotNull; + /** * @author fengyue * @date 2021/2/9 10:08 @@ -44,11 +47,11 @@ public class ItemTouchCallback extends ItemTouchHelper.Callback { } /** - * 设置是否可以被拖拽 + * 设置是否可以被长按拖拽 * * @param canDrag 是true,否false */ - public void setDragEnable(boolean canDrag) { + public void setLongPressDragEnable(boolean canDrag) { isCanDrag = canDrag; } @@ -133,6 +136,19 @@ public class ItemTouchCallback extends ItemTouchHelper.Callback { @Override 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); final boolean swiping = actionState == ItemTouchHelper.ACTION_STATE_DRAG; 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 { /** * 当某个Item被滑动删除的时候 @@ -156,5 +187,10 @@ public class ItemTouchCallback extends ItemTouchHelper.Callback { * @return 开发者处理了操作应该返回true,开发者没有处理就返回false */ boolean onMove(int srcPosition, int targetPosition); + + /** + * 当滑动删除或拖拽结束时调用 + */ + void onEnd(); } } diff --git a/app/src/main/java/xyz/fycz/myreader/ui/adapter/helper/OnStartDragListener.java b/app/src/main/java/xyz/fycz/myreader/ui/adapter/helper/OnStartDragListener.java new file mode 100644 index 0000000..ae4f33d --- /dev/null +++ b/app/src/main/java/xyz/fycz/myreader/ui/adapter/helper/OnStartDragListener.java @@ -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); +} diff --git a/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/BookSourceHolder.java b/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/BookSourceHolder.java index b9eb580..f2657b2 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/BookSourceHolder.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/BookSourceHolder.java @@ -1,6 +1,8 @@ package xyz.fycz.myreader.ui.adapter.holder; +import android.annotation.SuppressLint; import android.content.Intent; +import android.view.MotionEvent; import android.view.View; import android.widget.Button; import android.widget.CheckBox; @@ -9,6 +11,7 @@ import android.widget.RelativeLayout; import android.widget.TextView; import androidx.fragment.app.FragmentActivity; +import androidx.recyclerview.widget.RecyclerView; 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.ui.activity.SourceEditActivity; 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.help.StringHelper; import xyz.fycz.myreader.util.ToastUtils; @@ -36,7 +41,7 @@ import xyz.fycz.myreader.widget.swipemenu.SwipeMenuLayout; * @author fengyue * @date 2021/2/10 16:52 */ -public class BookSourceHolder extends ViewHolderImpl { +public class BookSourceHolder extends ViewHolderImpl implements IItemTouchHelperViewHolder { private FragmentActivity activity; private BookSourceAdapter adapter; private HashMap mCheckMap; @@ -46,16 +51,22 @@ public class BookSourceHolder extends ViewHolderImpl { private CheckBox cbSourceSelect; private TextView tvSourceName; private ImageView ivSwipeLeft; + private ImageView ivMove; private Button btTop; private Button btBan; private Button btShare; 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.adapter = adapter; this.onSwipeListener = onSwipeListener; mCheckMap = adapter.getCheckMap(); + this.onStartDragListener = onStartDragListener; } @Override @@ -70,25 +81,39 @@ public class BookSourceHolder extends ViewHolderImpl { cbSourceSelect = findById(R.id.cb_source_select); tvSourceName = findById(R.id.tv_source_name); ivSwipeLeft = findById(R.id.iv_swipe_left); + ivMove = findById(R.id.iv_move); btTop = findById(R.id.bt_top); btBan = findById(R.id.bt_ban); btShare = findById(R.id.bt_share); btDelete = findById(R.id.btnDelete); } + @SuppressLint("ClickableViewAccessibility") @Override - public void onBind(BookSource data, int pos) { + public void onBind(RecyclerView.ViewHolder holder, BookSource data, int pos) { banOrUse(data); initClick(data, pos); layout.setSwipeEnable(!adapter.ismEditState()); if (adapter.ismEditState()) { cbSourceSelect.setVisibility(View.VISIBLE); ivSwipeLeft.setVisibility(View.GONE); + ivMove.setVisibility(View.VISIBLE); } else { cbSourceSelect.setVisibility(View.GONE); ivSwipeLeft.setVisibility(View.VISIBLE); + ivMove.setVisibility(View.GONE); } 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) { @@ -175,4 +200,14 @@ public class BookSourceHolder extends ViewHolderImpl { btBan.setText(R.string.enable_use); } } + + @Override + public void onItemSelected() { + getItemView().setTranslationZ(10); + } + + @Override + public void onItemClear() { + getItemView().setTranslationZ(0); + } } diff --git a/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/BookStoreBookHolder.java b/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/BookStoreBookHolder.java index 134b502..26322f6 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/BookStoreBookHolder.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/BookStoreBookHolder.java @@ -4,12 +4,15 @@ import android.app.Activity; import android.view.View; import android.widget.TextView; +import androidx.recyclerview.widget.RecyclerView; + import xyz.fycz.myreader.R; import xyz.fycz.myreader.application.App; import xyz.fycz.myreader.base.adapter.ViewHolderImpl; import xyz.fycz.myreader.greendao.entity.Book; import xyz.fycz.myreader.greendao.entity.rule.BookSource; 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.utils.NetworkUtils; import xyz.fycz.myreader.webapi.crawler.ReadCrawlerUtil; @@ -20,7 +23,7 @@ import xyz.fycz.myreader.widget.CoverImageView; * @author fengyue * @date 2020/9/7 7:35 */ -public class BookStoreBookHolder extends ViewHolderImpl { +public class BookStoreBookHolder extends ViewHolderImpl implements IItemTouchHelperViewHolder { private CoverImageView tvBookImg; private TextView tvBookName; @@ -54,7 +57,7 @@ public class BookStoreBookHolder extends ViewHolderImpl { } @Override - public void onBind(Book data, int pos) { + public void onBind(RecyclerView.ViewHolder holder, Book data, int pos) { tvBookName.setText(data.getName()); tvBookAuthor.setText(data.getAuthor()); tvBookNewestChapter.setText(StringHelper.isEmpty(data.getNewestChapterTitle()) ? @@ -75,4 +78,13 @@ public class BookStoreBookHolder extends ViewHolderImpl { } } + @Override + public void onItemSelected() { + getItemView().setTranslationZ(10); + } + + @Override + public void onItemClear() { + getItemView().setTranslationZ(0); + } } diff --git a/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/CatalogHolder.java b/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/CatalogHolder.java index 564f5ee..2ebf079 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/CatalogHolder.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/CatalogHolder.java @@ -3,6 +3,7 @@ package xyz.fycz.myreader.ui.adapter.holder; import android.widget.TextView; import androidx.core.content.ContextCompat; +import androidx.recyclerview.widget.RecyclerView; import xyz.fycz.myreader.R; import xyz.fycz.myreader.base.adapter.ViewHolderImpl; @@ -26,7 +27,7 @@ public class CatalogHolder extends ViewHolderImpl { } @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) { tvTitle.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(getContext(),R.drawable.selector_category_load), null, null, null); } else { diff --git a/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/FileHolder.java b/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/FileHolder.java index 35a299d..a51fdd5 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/FileHolder.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/FileHolder.java @@ -5,6 +5,9 @@ import android.widget.CheckBox; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; + +import androidx.recyclerview.widget.RecyclerView; + import xyz.fycz.myreader.R; import xyz.fycz.myreader.base.adapter.ViewHolderImpl; import xyz.fycz.myreader.common.APPCONST; @@ -49,7 +52,7 @@ public class FileHolder extends ViewHolderImpl { } @Override - public void onBind(File data, int pos) { + public void onBind(RecyclerView.ViewHolder holder, File data, int pos) { //判断是文件还是文件夹 if (data.isDirectory()){ setFolder(data); diff --git a/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/LocalSourceHolder.java b/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/LocalSourceHolder.java index 28037ba..6378914 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/LocalSourceHolder.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/LocalSourceHolder.java @@ -3,6 +3,8 @@ package xyz.fycz.myreader.ui.adapter.holder; import android.widget.CheckBox; import android.widget.TextView; +import androidx.recyclerview.widget.RecyclerView; + import java.util.HashMap; import xyz.fycz.myreader.R; @@ -40,7 +42,7 @@ public class LocalSourceHolder extends ViewHolderImpl { } @Override - public void onBind(BookSource data, int pos) { + public void onBind(RecyclerView.ViewHolder holder, BookSource data, int pos) { banOrUse(data); cbSource.setChecked(mCheckMap.get(data)); tvEnable.setOnClickListener(v -> { diff --git a/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/ReadRecordHolder.java b/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/ReadRecordHolder.java index 0569e5f..e5be7ce 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/ReadRecordHolder.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/ReadRecordHolder.java @@ -6,6 +6,8 @@ import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; +import androidx.recyclerview.widget.RecyclerView; + import com.kongzue.dialogx.dialogs.BottomMenu; import com.kongzue.dialogx.interfaces.OnMenuItemClickListener; @@ -49,7 +51,7 @@ public class ReadRecordHolder extends ViewHolderImpl { } @Override - public void onBind(ReadRecord data, int pos) { + public void onBind(RecyclerView.ViewHolder holder, ReadRecord data, int pos) { if (!App.isDestroy((Activity) getContext())) { ivBookImg.load(data.getBookImg(), data.getBookName(), data.getBookAuthor()); } diff --git a/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/ReplaceRuleHolder.java b/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/ReplaceRuleHolder.java index 246bbd7..d40bdb8 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/ReplaceRuleHolder.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/ReplaceRuleHolder.java @@ -6,6 +6,7 @@ import android.widget.RelativeLayout; import android.widget.TextView; import androidx.appcompat.app.AppCompatActivity; +import androidx.recyclerview.widget.RecyclerView; import java.util.ArrayList; @@ -67,7 +68,7 @@ public class ReplaceRuleHolder extends ViewHolderImpl { } @Override - public void onBind(ReplaceRuleBean data, int pos) { + public void onBind(RecyclerView.ViewHolder holder, ReplaceRuleBean data, int pos) { banOrUse(data); rlContent.setOnClickListener(v -> { diff --git a/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/SearchBookHolder.java b/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/SearchBookHolder.java index 435b572..5ba1d59 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/SearchBookHolder.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/SearchBookHolder.java @@ -5,6 +5,8 @@ import android.app.Activity; import android.util.Log; import android.widget.TextView; +import androidx.recyclerview.widget.RecyclerView; + import com.zhy.view.flowlayout.TagFlowLayout; import java.util.ArrayList; @@ -75,7 +77,7 @@ public class SearchBookHolder extends ViewHolderImpl { @SuppressLint("SetTextI18n") @Override - public void onBind(SearchBookBean data, int pos) { + public void onBind(RecyclerView.ViewHolder holder, SearchBookBean data, int pos) { List aBooks = mBooks.getValues(data); if (aBooks == null || aBooks.size() == 0){ aBooks = new ArrayList<>(); diff --git a/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/SourceEditHolder.kt b/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/SourceEditHolder.kt index cdf97ac..6230f7a 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/SourceEditHolder.kt +++ b/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/SourceEditHolder.kt @@ -5,6 +5,7 @@ import android.text.TextUtils import android.text.TextWatcher import android.view.View import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView import com.google.android.material.textfield.TextInputEditText import com.google.android.material.textfield.TextInputLayout import xyz.fycz.myreader.R @@ -30,7 +31,7 @@ class SourceEditHolder : ViewHolderImpl() { 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) { val listener = object : View.OnAttachStateChangeListener { override fun onViewAttachedToWindow(v: View) { diff --git a/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/SourceExchangeHolder.java b/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/SourceExchangeHolder.java index 36d7bcb..8f0b8d4 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/SourceExchangeHolder.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/SourceExchangeHolder.java @@ -3,6 +3,9 @@ package xyz.fycz.myreader.ui.adapter.holder; import android.view.View; import android.widget.ImageView; import android.widget.TextView; + +import androidx.recyclerview.widget.RecyclerView; + import xyz.fycz.myreader.R; import xyz.fycz.myreader.base.adapter.ViewHolderImpl; import xyz.fycz.myreader.greendao.entity.Book; @@ -36,7 +39,7 @@ public class SourceExchangeHolder extends ViewHolderImpl { } @Override - public void onBind(Book data, int pos) { + public void onBind(RecyclerView.ViewHolder holder, Book data, int pos) { sourceTvTitle.setText(BookSourceManager.getSourceNameByStr(data.getSource())); sourceTvChapter.setText(data.getNewestChapterTitle()); if (data.getSource() != null && data.getSource().equals(dialog.getmShelfBook().getSource())) diff --git a/app/src/main/java/xyz/fycz/myreader/ui/dialog/BookGroupDialog.java b/app/src/main/java/xyz/fycz/myreader/ui/dialog/BookGroupDialog.java index e773076..f0c7977 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/dialog/BookGroupDialog.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/dialog/BookGroupDialog.java @@ -15,8 +15,6 @@ import androidx.appcompat.app.AlertDialog; import com.google.android.material.textfield.TextInputLayout; 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.List; @@ -70,7 +68,7 @@ public class BookGroupDialog { mGroupNames[i] = groupName; } 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) { - 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); String oldName = bookGroup.getName(); - if (isRename) { - editText.setText(oldName); - } - editText.requestFocus(); - InputMethodManager imm = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE); - mHandler.postDelayed(() -> { - imm.toggleSoftInput(0, InputMethodManager.SHOW_FORCED); - }, 220); - AlertDialog newGroupDia = MyAlertDialog.build(mContext) - .setTitle(!isRename ? "新建分组" : "重命名分组") - .setView(view) - .setCancelable(false) - .setPositiveButton("确认", null) - .setNegativeButton("取消", null) - .show(); - Button posBtn = newGroupDia.getButton(AlertDialog.BUTTON_POSITIVE); - posBtn.setEnabled(false); - posBtn.setOnClickListener(v1 -> { - CharSequence newGroupName = editText.getText().toString(); - for (CharSequence oldGroupName : mGroupNames) { - if (oldGroupName.equals(newGroupName)) { - ToastUtils.showWarring("分组[" + newGroupName + "]已存在,无法" + (!isRename ? "添加!" : "重命名!")); - return; - } - } - 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); - } - } - }); + int maxLen = 20; + MyAlertDialog.showFullScreenInputDia(mContext, !isRename ? "新建分组" : "重命名分组", "请输入分组名", + isRename ? oldName : "", null, true, maxLen, newGroupName -> { + for (CharSequence oldGroupName : mGroupNames) { + if (oldGroupName.equals(newGroupName)) { + ToastUtils.showWarring("分组[" + newGroupName + "]已存在,无法" + (!isRename ? "添加!" : "重命名!")); + return; + } + } + bookGroup.setName(newGroupName); + 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() + "]"); + if (isAddGroup) { + if (onGroup != null) onGroup.addGroup(); + } + }); } /** diff --git a/app/src/main/java/xyz/fycz/myreader/ui/dialog/MyAlertDialog.java b/app/src/main/java/xyz/fycz/myreader/ui/dialog/MyAlertDialog.java index e58ed7a..f25950b 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/dialog/MyAlertDialog.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/dialog/MyAlertDialog.java @@ -1,5 +1,6 @@ package xyz.fycz.myreader.ui.dialog; +import android.app.Activity; import android.content.Context; import android.content.DialogInterface; import android.text.Editable; @@ -18,6 +19,7 @@ import androidx.appcompat.app.AppCompatActivity; import com.google.android.material.textfield.TextInputLayout; import com.kongzue.dialogx.dialogs.BottomDialog; +import com.kongzue.dialogx.dialogs.FullScreenDialog; import com.kongzue.dialogx.interfaces.OnBindView; 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.util.CyptoUtils; import xyz.fycz.myreader.util.SharedPreUtils; +import xyz.fycz.myreader.util.StatusBarUtil; import xyz.fycz.myreader.util.help.StringHelper; import xyz.fycz.myreader.util.ToastUtils; 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); } + 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, Integer inputType, boolean cancelable, int maxLen, onInputChangeListener oic, DialogInterface.OnClickListener posListener, DialogInterface.OnClickListener negListener, String neutralBtn, 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.setCounterMaxLength(maxLen); @@ -126,12 +135,62 @@ public class MyAlertDialog { 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(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) { showPrivateVerifyDia(activity, onVerify, null); } + public static void showPrivateVerifyDia(AppCompatActivity activity, OnVerify onVerify, OnCancel onCancel) { boolean openPrivate = SharedPreUtils.getInstance().getBoolean("openPrivate"); boolean openFingerprint = SharedPreUtils.getInstance().getBoolean("openFingerprint"); @@ -168,13 +228,15 @@ public class MyAlertDialog { /** * 输入隐私密码对话框 + * * @param activity * @param onVerify */ - public static void showPrivatePwdInputDia(AppCompatActivity activity, OnVerify onVerify){ + public static void showPrivatePwdInputDia(AppCompatActivity activity, OnVerify onVerify) { 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]; String pwds = SharedPreUtils.getInstance().getString("privatePwd"); MyAlertDialog.createInputDia(activity, activity.getString(R.string.input_private_pwd), @@ -195,7 +257,7 @@ public class MyAlertDialog { if (onCancel != null) { onCancel.cancel(); } - },"忘记密码", (dialog, which) -> { + }, "忘记密码", (dialog, which) -> { DialogCreator.createCommonDialog(activity, "忘记密码", "忘记密码无法找回!\n您可点击确定按钮关闭私密书架并删除私密书架所有书籍,确定关闭吗?", false, (dialog1, which1) -> { @@ -213,15 +275,16 @@ public class MyAlertDialog { }); } - public static void showTipDialogWithLink(Context context, int msgId){ - showTipDialogWithLink(context,"提示", msgId); + public static void showTipDialogWithLink(Context context, int 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); view.setText(msgId); view.setMovementMethod(LinkMovementMethod.getInstance()); build(context).setTitle(title).setView(view).setPositiveButton("知道了", null).show();*/ - BottomDialog.show(title, new OnBindView(R.layout.dialog_textview){ + BottomDialog.show(title, new OnBindView(R.layout.dialog_textview) { @Override public void onBind(BottomDialog dialog, View v) { TextView view = (TextView) v; @@ -231,6 +294,7 @@ public class MyAlertDialog { }).setCancelButton("知道了"); } + public interface OnVerify { void success(boolean needGoTo); } @@ -242,4 +306,8 @@ public class MyAlertDialog { public interface onInputChangeListener { void onChange(String text); } + + public interface OnInputFinishListener{ + void finish(String text); + } } diff --git a/app/src/main/java/xyz/fycz/myreader/ui/fragment/DIYSourceFragment.java b/app/src/main/java/xyz/fycz/myreader/ui/fragment/DIYSourceFragment.java index 4aee230..d43283a 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/fragment/DIYSourceFragment.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/fragment/DIYSourceFragment.java @@ -15,6 +15,7 @@ import android.widget.PopupMenu; import androidx.annotation.Nullable; import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; 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.adapter.BookSourceAdapter; 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.LoadingDialog; import xyz.fycz.myreader.ui.dialog.MyAlertDialog; @@ -70,6 +72,7 @@ public class DIYSourceFragment extends BaseFragment { private boolean isSearch; private PopupMenu featuresMenu; private ItemTouchCallback itemTouchCallback; + private ItemTouchHelper itemTouchHelper; private Disposable importSourceDis; public DIYSourceFragment() { @@ -104,7 +107,7 @@ public class DIYSourceFragment extends BaseFragment { mAdapter.toTop(which, bean); } } - }); + }, viewHolder -> itemTouchHelper.startDrag(viewHolder)); refreshSources(); } @@ -118,9 +121,9 @@ public class DIYSourceFragment extends BaseFragment { //设置拖拽 itemTouchCallback = new ItemTouchCallback(); itemTouchCallback.setOnItemTouchListener(mAdapter.getItemTouchListener()); - ItemTouchHelper itemTouchHelper = new ItemTouchHelper(itemTouchCallback); + itemTouchHelper = new ItemTouchHelper(itemTouchCallback); itemTouchHelper.attachToRecyclerView(binding.recyclerView); - itemTouchCallback.setDragEnable(false); + itemTouchCallback.setLongPressDragEnable(false); } @SuppressLint("ClickableViewAccessibility") @@ -341,12 +344,10 @@ public class DIYSourceFragment extends BaseFragment { featuresMenu.getMenu().setGroupVisible(R.id.edit_mode, true); featuresMenu.getMenu().setGroupVisible(R.id.non_edit_mode, false); mAdapter.setmEditState(true); - itemTouchCallback.setDragEnable(true); } else if (itemId == R.id.action_finish) { featuresMenu.getMenu().setGroupVisible(R.id.edit_mode, false); featuresMenu.getMenu().setGroupVisible(R.id.non_edit_mode, true); mAdapter.setmEditState(false); - itemTouchCallback.setDragEnable(false); } else if (itemId == R.id.action_export) { exportSources(mBookSources); } else if (itemId == R.id.action_share) { diff --git a/app/src/main/java/xyz/fycz/myreader/ui/presenter/BookcasePresenter.java b/app/src/main/java/xyz/fycz/myreader/ui/presenter/BookcasePresenter.java index 2633e07..4b7eedb 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/presenter/BookcasePresenter.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/presenter/BookcasePresenter.java @@ -28,6 +28,7 @@ import org.jetbrains.annotations.NotNull; import java.text.Collator; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.List; @@ -127,19 +128,6 @@ public class BookcasePresenter implements BasePresenter { @Override public void handleMessage(Message msg) { switch (msg.what) { - case 1: - break; - case 2: - break; - case 3: - break; - case 4: - - break; - case 5: - break; - case 6: - break; case 7: init(); break; @@ -298,7 +286,7 @@ public class BookcasePresenter implements BasePresenter { ItemTouchHelper itemTouchHelper = new ItemTouchHelper(itemTouchCallback); itemTouchHelper.attachToRecyclerView(mBookcaseFragment.getRvBook()); itemTouchCallback.setOnItemTouchListener(mBookcaseAdapter.getItemTouchCallbackListener()); - itemTouchCallback.setDragEnable(false); + itemTouchCallback.setLongPressDragEnable(false); isBookcaseStyleChange = false; } else { 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 mChapters = (ArrayList) 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() { + @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() { refreshIndex++; if (refreshIndex < mBooks.size()) { @@ -529,7 +554,7 @@ public class BookcasePresenter implements BasePresenter { if (canEditBookcase()) { mMainActivity.getViewPagerMain().setEnableScroll(false); mBookcaseFragment.getSrlContent().setEnableRefresh(false); - itemTouchCallback.setDragEnable(mSetting.getSortStyle() == 0); + itemTouchCallback.setLongPressDragEnable(mSetting.getSortStyle() == 0); mBookcaseAdapter.setmEditState(true); mBookcaseFragment.getRlBookEdit().setVisibility(View.VISIBLE); mMainActivity.initMenuAnim(); @@ -543,7 +568,7 @@ public class BookcasePresenter implements BasePresenter { } else { mMainActivity.getViewPagerMain().setEnableScroll(true); mBookcaseFragment.getSrlContent().setEnableRefresh(true); - itemTouchCallback.setDragEnable(false); + itemTouchCallback.setLongPressDragEnable(false); mBookcaseAdapter.setmEditState(false); mBookcaseFragment.getRlBookEdit().setVisibility(View.GONE); mMainActivity.initMenuAnim(); @@ -661,6 +686,21 @@ public class BookcasePresenter implements BasePresenter { 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(); + } + }); + } + /**********************************************缓存书籍***************************************************************/ /** * 缓存所有书籍 diff --git a/app/src/main/java/xyz/fycz/myreader/util/help/JsExtensions.java b/app/src/main/java/xyz/fycz/myreader/util/help/JsExtensions.java index f7dea3e..e1c2fdb 100644 --- a/app/src/main/java/xyz/fycz/myreader/util/help/JsExtensions.java +++ b/app/src/main/java/xyz/fycz/myreader/util/help/JsExtensions.java @@ -33,6 +33,7 @@ import xyz.fycz.myreader.util.utils.OkHttpUtils; import xyz.fycz.myreader.util.utils.StringUtils; @Keep + @SuppressWarnings({"unused"}) public interface JsExtensions { String TAG = JsExtensions.class.getSimpleName(); diff --git a/app/src/main/java/xyz/fycz/myreader/util/utils/ShareBookUtil.java b/app/src/main/java/xyz/fycz/myreader/util/utils/ShareBookUtil.java new file mode 100644 index 0000000..8c0f06a --- /dev/null +++ b/app/src/main/java/xyz/fycz/myreader/util/utils/ShareBookUtil.java @@ -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) 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() { + @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 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 getDescLines(Book mBook, int width, TextPaint textPaint) { + List 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; + } +} diff --git a/app/src/main/res/drawable/ic_leaderboard.xml b/app/src/main/res/drawable/ic_leaderboard.xml new file mode 100644 index 0000000..0574938 --- /dev/null +++ b/app/src/main/res/drawable/ic_leaderboard.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/app/src/main/res/drawable/ic_top.xml b/app/src/main/res/drawable/ic_top.xml index 0574938..c577827 100644 --- a/app/src/main/res/drawable/ic_top.xml +++ b/app/src/main/res/drawable/ic_top.xml @@ -4,15 +4,12 @@ android:viewportWidth="1024" android:viewportHeight="1024"> + android:fillColor="#FF000000" + android:pathData="M192,106.67m32,0l576,0q32,0 32,32l0,0q0,32 -32,32l-576,0q-32,0 -32,-32l0,0q0,-32 32,-32Z"/> + android:fillColor="#FF000000" + android:pathData="M544,248.36m0,32l0,576q0,32 -32,32l0,0q-32,0 -32,-32l0,-576q0,-32 32,-32l0,0q32,0 32,32Z"/> - + android:fillColor="#FF000000" + 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"/> diff --git a/app/src/main/res/drawable/menu_book_detail.xml b/app/src/main/res/drawable/menu_book_detail.xml new file mode 100644 index 0000000..8d2623f --- /dev/null +++ b/app/src/main/res/drawable/menu_book_detail.xml @@ -0,0 +1,14 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_btn_input_finish.xml b/app/src/main/res/drawable/selector_btn_input_finish.xml new file mode 100644 index 0000000..84efb69 --- /dev/null +++ b/app/src/main/res/drawable/selector_btn_input_finish.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_input.xml b/app/src/main/res/layout/dialog_input.xml new file mode 100644 index 0000000..4c43be2 --- /dev/null +++ b/app/src/main/res/layout/dialog_input.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/edit_dialog.xml b/app/src/main/res/layout/edit_dialog.xml deleted file mode 100644 index a06af11..0000000 --- a/app/src/main/res/layout/edit_dialog.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - diff --git a/app/src/main/res/layout/edit_text.xml b/app/src/main/res/layout/edit_text.xml new file mode 100644 index 0000000..cd3bdac --- /dev/null +++ b/app/src/main/res/layout/edit_text.xml @@ -0,0 +1,16 @@ + + + + + + diff --git a/app/src/main/res/layout/fragment_book_list.xml b/app/src/main/res/layout/fragment_book_list.xml index 32bd14b..6aef0b3 100644 --- a/app/src/main/res/layout/fragment_book_list.xml +++ b/app/src/main/res/layout/fragment_book_list.xml @@ -31,6 +31,7 @@ diff --git a/app/src/main/res/layout/fragment_find.xml b/app/src/main/res/layout/fragment_find.xml index ba6c558..faf2f71 100644 --- a/app/src/main/res/layout/fragment_find.xml +++ b/app/src/main/res/layout/fragment_find.xml @@ -26,7 +26,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" - android:src="@drawable/ic_top" + android:src="@drawable/ic_leaderboard" /> + + diff --git a/app/src/main/res/layout/item_read_record.xml b/app/src/main/res/layout/item_read_record.xml index 85ef379..e0b6e1e 100644 --- a/app/src/main/res/layout/item_read_record.xml +++ b/app/src/main/res/layout/item_read_record.xml @@ -15,18 +15,6 @@ android:orientation="horizontal" android:padding="5dp"> - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/menu_book_local.xml b/app/src/main/res/layout/menu_book_local.xml new file mode 100644 index 0000000..90db3f0 --- /dev/null +++ b/app/src/main/res/layout/menu_book_local.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2ba6c4e..57a20ca 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -61,7 +61,7 @@ 书籍详情 缓存书籍 导出缓存 - 删除/移除书籍 + 删除书籍 编辑书架 切换布局 diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 26950b7..4a12a85 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -192,6 +192,7 @@ @dimen/text_small_size + + + + diff --git a/app/version_code.properties b/app/version_code.properties index 07bb564..39ff7ff 100644 --- a/app/version_code.properties +++ b/app/version_code.properties @@ -1,2 +1,2 @@ -#Wed Jun 02 20:55:52 CST 2021 -VERSION_CODE=206 +#Thu Jun 03 14:18:11 CST 2021 +VERSION_CODE=207