parent
5f73042209
commit
f2a98582f1
Binary file not shown.
@ -1,9 +1,11 @@ |
||||
package xyz.fycz.myreader.base; |
||||
package xyz.fycz.myreader.base.adapter; |
||||
|
||||
import android.os.Handler; |
||||
import android.view.View; |
||||
import android.view.ViewGroup; |
||||
import androidx.recyclerview.widget.RecyclerView; |
||||
import xyz.fycz.myreader.base.BaseViewHolder; |
||||
import xyz.fycz.myreader.base.IViewHolder; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.Collections; |
@ -0,0 +1,353 @@ |
||||
package xyz.fycz.myreader.ui.bookinfo; |
||||
|
||||
import android.annotation.SuppressLint; |
||||
import android.content.Intent; |
||||
import android.net.Uri; |
||||
import android.os.Bundle; |
||||
import android.os.Handler; |
||||
import android.os.Message; |
||||
import android.view.Menu; |
||||
import android.view.MenuItem; |
||||
import android.view.View; |
||||
import android.widget.FrameLayout; |
||||
import android.widget.ImageView; |
||||
import android.widget.ProgressBar; |
||||
import android.widget.TextView; |
||||
import androidx.appcompat.app.AlertDialog; |
||||
import androidx.appcompat.widget.Toolbar; |
||||
import androidx.recyclerview.widget.RecyclerView; |
||||
import butterknife.BindView; |
||||
import com.bumptech.glide.Glide; |
||||
import com.bumptech.glide.load.resource.bitmap.RoundedCorners; |
||||
import com.bumptech.glide.request.RequestOptions; |
||||
import xyz.fycz.myreader.R; |
||||
import xyz.fycz.myreader.base.BaseActivity2; |
||||
import xyz.fycz.myreader.callback.ResultCallback; |
||||
import xyz.fycz.myreader.common.APPCONST; |
||||
import xyz.fycz.myreader.crawler.BookInfoCrawler; |
||||
import xyz.fycz.myreader.crawler.ReadCrawler; |
||||
import xyz.fycz.myreader.crawler.ReadCrawlerUtil; |
||||
import xyz.fycz.myreader.creator.ChangeSourceDialog; |
||||
import xyz.fycz.myreader.creator.DialogCreator; |
||||
import xyz.fycz.myreader.enums.BookSource; |
||||
import xyz.fycz.myreader.greendao.entity.Book; |
||||
import xyz.fycz.myreader.greendao.service.BookService; |
||||
import xyz.fycz.myreader.ui.read.ReadActivity; |
||||
import xyz.fycz.myreader.util.StringHelper; |
||||
import xyz.fycz.myreader.util.TextHelper; |
||||
import xyz.fycz.myreader.util.utils.NetworkUtils; |
||||
import xyz.fycz.myreader.webapi.CommonApi; |
||||
|
||||
import java.util.ArrayList; |
||||
|
||||
/** |
||||
* @author fengyue |
||||
* @date 2020/8/17 11:39 |
||||
*/ |
||||
public class BookDetailedActivity extends BaseActivity2 { |
||||
@BindView(R.id.book_detail_iv_cover) |
||||
ImageView mIvCover; |
||||
@BindView(R.id.book_detail_tv_author) |
||||
TextView mTvAuthor; |
||||
@BindView(R.id.book_detail_tv_type) |
||||
TextView mTvType; |
||||
@BindView(R.id.book_detail_newest_chapter) |
||||
TextView mTvNewestChapter; |
||||
@BindView(R.id.book_detail_source) |
||||
TextView mTvSource; |
||||
@BindView(R.id.book_detail_tv_add) |
||||
TextView bookDetailTvAdd; |
||||
@BindView(R.id.book_detail_tv_open) |
||||
TextView bookDetailTvOpen; |
||||
@BindView(R.id.toolbar) |
||||
Toolbar toolbar; |
||||
@BindView(R.id.book_detail_tv_desc) |
||||
TextView mTvDesc; |
||||
@BindView(R.id.tv_disclaimer) |
||||
TextView mTvDisclaimer; |
||||
@BindView(R.id.fl_add_bookcase) |
||||
FrameLayout flAddBookcase; |
||||
@BindView(R.id.fl_open_book) |
||||
FrameLayout flOpenBook; |
||||
@BindView(R.id.book_detail_rv_catalog) |
||||
RecyclerView bookDetailRvCatalog; |
||||
@BindView(R.id.pb_loading) |
||||
ProgressBar pbLoading; |
||||
|
||||
|
||||
private Book mBook; |
||||
private ArrayList<Book> aBooks; |
||||
private BookService mBookService; |
||||
private ReadCrawler mReadCrawler; |
||||
@SuppressLint("HandlerLeak") |
||||
private Handler mHandler = new Handler() { |
||||
@Override |
||||
public void handleMessage(Message msg) { |
||||
switch (msg.what) { |
||||
case 1: |
||||
initBookInfo(); |
||||
break; |
||||
case 2: |
||||
createChangeSourceDia(); |
||||
break; |
||||
case 3: |
||||
pbLoading.setVisibility(View.GONE); |
||||
DialogCreator.createTipDialog(BookDetailedActivity.this, "未搜索到该书籍,书源加载失败!"); |
||||
break; |
||||
case 4: |
||||
initOtherInfo(); |
||||
break; |
||||
} |
||||
} |
||||
}; |
||||
|
||||
@Override |
||||
protected int getContentId() { |
||||
return R.layout.activity_book_detail; |
||||
} |
||||
|
||||
@Override |
||||
protected void initData(Bundle savedInstanceState) { |
||||
super.initData(savedInstanceState); |
||||
mBookService = BookService.getInstance(); |
||||
aBooks = (ArrayList<Book>) getIntent().getSerializableExtra(APPCONST.SEARCH_BOOK_BEAN); |
||||
if (aBooks != null) { |
||||
mBook = aBooks.get(0); |
||||
} else { |
||||
mBook = (Book) getIntent().getSerializableExtra(APPCONST.BOOK); |
||||
} |
||||
mReadCrawler = ReadCrawlerUtil.getReadCrawler(mBook.getSource()); |
||||
} |
||||
|
||||
@Override |
||||
protected void setUpToolbar(Toolbar toolbar) { |
||||
super.setUpToolbar(toolbar); |
||||
getSupportActionBar().setTitle(mBook.getName()); |
||||
} |
||||
|
||||
@Override |
||||
protected void initWidget() { |
||||
super.initWidget(); |
||||
initBookInfo(); |
||||
mTvDisclaimer.setOnClickListener(v -> DialogCreator.createAssetTipDialog(this, "免责声明", "disclaimer.fy")); |
||||
if (isBookCollected()) { |
||||
bookDetailTvAdd.setText("移除书籍"); |
||||
bookDetailTvOpen.setText("继续阅读"); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Override |
||||
protected void initClick() { |
||||
super.initClick(); |
||||
flAddBookcase.setOnClickListener(view -> { |
||||
if (!isBookCollected()) { |
||||
mBookService.addBook(mBook); |
||||
TextHelper.showText("成功加入书架"); |
||||
bookDetailTvAdd.setText("移除书籍"); |
||||
} else { |
||||
mBookService.deleteBookById(mBook.getId()); |
||||
TextHelper.showText("成功移除书籍"); |
||||
bookDetailTvAdd.setText("加入书架"); |
||||
bookDetailTvOpen.setText("开始阅读"); |
||||
} |
||||
}); |
||||
flOpenBook.setOnClickListener(view -> { |
||||
final boolean isCollected; |
||||
if (isBookCollected()) { |
||||
isCollected = true; |
||||
} else { |
||||
mBookService.addBook(mBook); |
||||
isCollected = false; |
||||
CommonApi.getBookChapters(mBook.getChapterUrl(), mReadCrawler, new ResultCallback() { |
||||
@Override |
||||
public void onFinish(Object o, int code) { |
||||
mBookService.updateEntity(mBook); |
||||
} |
||||
|
||||
@Override |
||||
public void onError(Exception e) { |
||||
} |
||||
}); |
||||
} |
||||
Intent intent = new Intent(this, ReadActivity.class); |
||||
intent.putExtra(APPCONST.BOOK, mBook); |
||||
intent.putExtra("isCollected", isCollected); |
||||
startActivityForResult(intent, APPCONST.REQUEST_READ); |
||||
}); |
||||
} |
||||
|
||||
@Override |
||||
protected void processLogic() { |
||||
super.processLogic(); |
||||
} |
||||
|
||||
private boolean isBookCollected() { |
||||
Book book = mBookService.findBookByAuthorAndName(mBook.getName(), mBook.getAuthor()); |
||||
if (book == null) { |
||||
return false; |
||||
} else { |
||||
mBook = book; |
||||
return true; |
||||
} |
||||
} |
||||
|
||||
private void initBookInfo() { |
||||
mTvAuthor.setText(mBook.getAuthor()); |
||||
if (StringHelper.isEmpty(mBook.getImgUrl())) { |
||||
mBook.setImgUrl(""); |
||||
} |
||||
assert mBook.getNewestChapterTitle() != null; |
||||
mTvNewestChapter.setText("最新章节:" + mBook.getNewestChapterTitle().replace("最近更新 ", "")); |
||||
mTvDesc.setText(""); |
||||
mTvType.setText(""); |
||||
if (!"null".equals(mBook.getSource())) { |
||||
mTvSource.setText("书源:" + BookSource.fromString(mBook.getSource()).text); |
||||
} |
||||
ReadCrawler rc = ReadCrawlerUtil.getReadCrawler(mBook.getSource()); |
||||
if (rc instanceof BookInfoCrawler && StringHelper.isEmpty(mBook.getImgUrl())) { |
||||
BookInfoCrawler bic = (BookInfoCrawler) rc; |
||||
CommonApi.getBookInfo(mBook, bic, new ResultCallback() { |
||||
@Override |
||||
public void onFinish(Object o, int code) { |
||||
mHandler.sendMessage(mHandler.obtainMessage(4)); |
||||
} |
||||
|
||||
@Override |
||||
public void onError(Exception e) { |
||||
|
||||
} |
||||
}); |
||||
} else { |
||||
initOtherInfo(); |
||||
} |
||||
} |
||||
|
||||
private void initOtherInfo() { |
||||
mTvDesc.setText(mBook.getDesc()); |
||||
mTvType.setText(mBook.getType()); |
||||
Glide.with(this) |
||||
.load(mBook.getImgUrl()) |
||||
.error(R.mipmap.no_image) |
||||
.placeholder(R.mipmap.no_image) |
||||
//设置圆角
|
||||
.apply(RequestOptions.bitmapTransform(new RoundedCorners(8))) |
||||
.into(mIvCover); |
||||
} |
||||
|
||||
private void createChangeSourceDia() { |
||||
if (aBooks == null){ |
||||
mHandler.sendMessage(mHandler.obtainMessage(3)); |
||||
return; |
||||
} |
||||
pbLoading.setVisibility(View.GONE); |
||||
CharSequence[] sources = new CharSequence[aBooks.size()]; |
||||
int checkedItem = 0; |
||||
for (int i = 0; i < sources.length; i++) { |
||||
sources[i] = BookSource.fromString(aBooks.get(i).getSource()).text |
||||
+ "\n" + aBooks.get(i).getNewestChapterTitle(); |
||||
if (sources[i].equals(BookSource.fromString(mBook.getSource()).text |
||||
+ "\n" + aBooks.get(i).getNewestChapterTitle())) { |
||||
checkedItem = i; |
||||
} |
||||
} |
||||
final int finalCheckedItem = checkedItem; |
||||
AlertDialog dialog = new AlertDialog.Builder(this) |
||||
.setTitle("切换书源") |
||||
.setCancelable(true) |
||||
.setSingleChoiceItems(sources, checkedItem, (dialog1, which) -> { |
||||
boolean isBookCollected = isBookCollected(); |
||||
if (finalCheckedItem == which) { |
||||
dialog1.dismiss(); |
||||
return; |
||||
} |
||||
Book book = aBooks.get(which); |
||||
Book bookTem = new Book(mBook); |
||||
bookTem.setChapterUrl(book.getChapterUrl()); |
||||
bookTem.setImgUrl(book.getImgUrl()); |
||||
bookTem.setType(book.getType()); |
||||
bookTem.setDesc(book.getDesc()); |
||||
bookTem.setSource(book.getSource()); |
||||
if (isBookCollected) { |
||||
mBookService.updateBook(mBook, bookTem); |
||||
} |
||||
mBook = bookTem; |
||||
mHandler.sendMessage(mHandler.obtainMessage(1)); |
||||
if (isBookCollected) { |
||||
DialogCreator.createTipDialog(this, |
||||
"换源成功,由于不同书源的章节数量不一定相同,故换源后历史章节可能出错!"); |
||||
} |
||||
dialog1.dismiss(); |
||||
}).create(); |
||||
dialog.show(); |
||||
} |
||||
|
||||
/********************************Event***************************************/ |
||||
@Override |
||||
public boolean onCreateOptionsMenu(Menu menu) { |
||||
getMenuInflater().inflate(R.menu.menu_book_detail, menu); |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* 导航栏菜单点击事件 |
||||
* |
||||
* @param item |
||||
* @return |
||||
*/ |
||||
@Override |
||||
public boolean onOptionsItemSelected(MenuItem item) { |
||||
switch (item.getItemId()) { |
||||
case R.id.action_change_source: //换源
|
||||
if (!NetworkUtils.isNetWorkAvailable()){ |
||||
TextHelper.showText("无网络连接!"); |
||||
return true; |
||||
} |
||||
pbLoading.setVisibility(View.VISIBLE); |
||||
if (aBooks == null) { |
||||
ChangeSourceDialog csd = new ChangeSourceDialog(this, mBook); |
||||
csd.init(new ResultCallback() { |
||||
@Override |
||||
public void onFinish(Object o, int code) { |
||||
aBooks = (ArrayList<Book>) o; |
||||
mHandler.sendMessage(mHandler.obtainMessage(2)); |
||||
} |
||||
|
||||
@Override |
||||
public void onError(Exception e) { |
||||
mHandler.sendMessage(mHandler.obtainMessage(3)); |
||||
} |
||||
}); |
||||
} else { |
||||
createChangeSourceDia(); |
||||
} |
||||
break; |
||||
case R.id.action_reload: //重新加载
|
||||
initWidget(); |
||||
processLogic(); |
||||
break; |
||||
case R.id.action_open_link: //打开链接
|
||||
Uri uri = Uri.parse(mBook.getChapterUrl()); |
||||
Intent intent = new Intent(Intent.ACTION_VIEW, uri); |
||||
startActivity(intent); |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
return super.onOptionsItemSelected(item); |
||||
} |
||||
|
||||
@Override |
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) { |
||||
if (requestCode == APPCONST.REQUEST_READ) { |
||||
if (data == null) { |
||||
return; |
||||
} |
||||
boolean isCollected = data.getBooleanExtra(APPCONST.RESULT_IS_COLLECTED, false); |
||||
if (isCollected) { |
||||
bookDetailTvAdd.setText("移除书籍"); |
||||
bookDetailTvOpen.setText("继续阅读"); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,23 @@ |
||||
package xyz.fycz.myreader.util.notification; |
||||
|
||||
import android.content.BroadcastReceiver; |
||||
import android.content.Context; |
||||
import android.content.Intent; |
||||
import xyz.fycz.myreader.application.MyApplication; |
||||
|
||||
/** |
||||
* @author fengyue |
||||
* @date 2020/8/14 22:04 |
||||
*/ |
||||
public class NotificationClickReceiver extends BroadcastReceiver { |
||||
|
||||
public static final String CANCEL_ACTION = "cancelAction"; |
||||
|
||||
@Override |
||||
public void onReceive(Context context, Intent intent) { |
||||
//todo 跳转之前要处理的逻辑
|
||||
if (CANCEL_ACTION.equals(intent.getAction())){ |
||||
MyApplication.getApplication().shutdownThreadPool(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,171 @@ |
||||
package xyz.fycz.myreader.util.notification; |
||||
|
||||
import android.annotation.TargetApi; |
||||
import android.app.*; |
||||
import android.content.Context; |
||||
import android.content.Intent; |
||||
import android.content.pm.ApplicationInfo; |
||||
import android.graphics.BitmapFactory; |
||||
import android.graphics.Color; |
||||
import android.net.Uri; |
||||
import android.os.Build; |
||||
import android.provider.Settings; |
||||
import androidx.appcompat.app.AlertDialog; |
||||
import androidx.core.app.NotificationCompat; |
||||
import androidx.core.app.NotificationManagerCompat; |
||||
import xyz.fycz.myreader.R; |
||||
import xyz.fycz.myreader.application.MyApplication; |
||||
import xyz.fycz.myreader.common.APPCONST; |
||||
import xyz.fycz.myreader.creator.DialogCreator; |
||||
import xyz.fycz.myreader.greendao.service.BookMarkService; |
||||
|
||||
import java.lang.reflect.Field; |
||||
import java.lang.reflect.Method; |
||||
|
||||
import static xyz.fycz.myreader.util.notification.NotificationClickReceiver.CANCEL_ACTION; |
||||
|
||||
/** |
||||
* @author fengyue |
||||
* @date 2020/8/14 22:07 |
||||
*/ |
||||
public class NotificationUtil { |
||||
private static volatile NotificationUtil sInstance; |
||||
private NotificationManager notificationManager; |
||||
|
||||
public static NotificationUtil getInstance() { |
||||
if (sInstance == null){ |
||||
synchronized (NotificationUtil.class){ |
||||
if (sInstance == null){ |
||||
sInstance = new NotificationUtil(); |
||||
} |
||||
} |
||||
} |
||||
return sInstance; |
||||
} |
||||
|
||||
public NotificationUtil() { |
||||
notificationManager = (NotificationManager) MyApplication.getmContext().getSystemService(Context.NOTIFICATION_SERVICE); |
||||
|
||||
} |
||||
|
||||
public NotificationCompat.Builder createBuilder(Context context, String channelId){ |
||||
return new NotificationCompat.Builder(context, channelId); |
||||
} |
||||
|
||||
@TargetApi(26) |
||||
public void createNotificationChannel(String channelId, String channelName) { |
||||
NotificationManager notificationManager = (NotificationManager) MyApplication.getApplication().getSystemService(Context.NOTIFICATION_SERVICE); |
||||
NotificationChannel channel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_LOW); |
||||
channel.enableLights(true);//是否在桌面icon右上角展示小红点
|
||||
channel.setLightColor(Color.RED);//小红点颜色
|
||||
channel.setShowBadge(false); //是否在久按桌面图标时显示此渠道的通知
|
||||
notificationManager.createNotificationChannel(channel); |
||||
} |
||||
|
||||
public NotificationCompat.Builder build(String channelId){ |
||||
return new NotificationCompat.Builder(MyApplication.getmContext(), channelId); |
||||
} |
||||
|
||||
public void sendDownloadNotification(String title, String text, PendingIntent pendingIntent){ |
||||
NotificationCompat.Builder builder = build(APPCONST.channelIdDownload) |
||||
.setSmallIcon(R.drawable.ic_download) |
||||
//通知栏大图标
|
||||
.setLargeIcon(BitmapFactory.decodeResource(MyApplication.getApplication().getResources(), R.mipmap.ic_launcher)) |
||||
.setOngoing(true) |
||||
//点击通知后自动清除
|
||||
.setAutoCancel(true) |
||||
.setContentTitle(title) |
||||
.setContentText(text); |
||||
if (pendingIntent == null) { |
||||
pendingIntent = getChancelPendingIntent(NotificationClickReceiver.class); |
||||
} |
||||
builder.addAction(R.drawable.ic_stop_black_24dp, "停止", pendingIntent); |
||||
notificationManager.notify(1000, builder.build()); |
||||
} |
||||
|
||||
public PendingIntent getChancelPendingIntent(Class<?> clz) { |
||||
Intent intent = new Intent(MyApplication.getmContext(), clz); |
||||
intent.setAction(CANCEL_ACTION); |
||||
return PendingIntent.getBroadcast(MyApplication.getmContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); |
||||
} |
||||
|
||||
public void cancel(int id){ |
||||
notificationManager.cancel(id); |
||||
} |
||||
public void cancelAll(){ |
||||
notificationManager.cancelAll(); |
||||
} |
||||
public void notify(int id, Notification notification){ |
||||
notificationManager.notify(id, notification); |
||||
} |
||||
|
||||
/** |
||||
* 跳到通知栏设置界面 |
||||
* @param context |
||||
*/ |
||||
public void requestNotificationPermission(Context context){ |
||||
if (!isNotificationEnabled(context)) { |
||||
try { |
||||
// 根据isOpened结果,判断是否需要提醒用户跳转AppInfo页面,去打开App通知权限
|
||||
Intent intent = new Intent(); |
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
||||
intent.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS); |
||||
//这种方案适用于 API 26, 即8.0(含8.0)以上可以用
|
||||
intent.putExtra(Settings.EXTRA_APP_PACKAGE, context.getPackageName()); |
||||
intent.putExtra(Settings.EXTRA_CHANNEL_ID, context.getApplicationInfo().uid); |
||||
|
||||
//这种方案适用于 API21——25,即 5.0——7.1 之间的版本可以使用
|
||||
intent.putExtra("app_package", context.getPackageName()); |
||||
intent.putExtra("app_uid", context.getApplicationInfo().uid); |
||||
|
||||
// 小米6 -MIUI9.6-8.0.0系统,是个特例,通知设置界面只能控制"允许使用通知圆点"——然而这个玩意并没有卵用,我想对雷布斯说:I'm not ok!!!
|
||||
if ("MI 6".equals(Build.MODEL)) { |
||||
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); |
||||
Uri uri = Uri.fromParts("package", context.getPackageName(), null); |
||||
intent.setData(uri); |
||||
intent.setAction("com.android.settings/.SubSettings"); |
||||
} |
||||
context.startActivity(intent); |
||||
} catch (Exception e) { |
||||
e.printStackTrace(); |
||||
// 出现异常则跳转到应用设置界面:锤子坚果3——OC105 API25
|
||||
Intent intent = new Intent(); |
||||
//下面这种方案是直接跳转到当前应用的设置界面。
|
||||
//https://blog.csdn.net/ysy950803/article/details/71910806
|
||||
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); |
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
||||
Uri uri = Uri.fromParts("package", context.getPackageName(), null); |
||||
intent.setData(uri); |
||||
context.startActivity(intent); |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
public void requestNotificationPermissionDialog(Context context){ |
||||
if (!isNotificationEnabled(context)) { |
||||
new AlertDialog.Builder(context) |
||||
.setTitle("开启通知") |
||||
.setMessage("检测到未开启通知权限,无法在通知栏查看缓存进度,是否前往开启?") |
||||
.setCancelable(true) |
||||
.setPositiveButton("确定", (dialog, which) -> requestNotificationPermission(context)) |
||||
.setNegativeButton("取消", null) |
||||
.show(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 获取通知权限 |
||||
* @param context |
||||
*/ |
||||
public boolean isNotificationEnabled(Context context) { |
||||
boolean isOpened = false; |
||||
try { |
||||
NotificationManagerCompat manager = NotificationManagerCompat.from(context); |
||||
isOpened = manager.areNotificationsEnabled(); |
||||
} catch (Exception e) { |
||||
e.printStackTrace(); |
||||
} |
||||
return isOpened; |
||||
} |
||||
} |
@ -0,0 +1,12 @@ |
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:width="24dp" |
||||
android:height="24dp" |
||||
android:viewportWidth="1065.0" |
||||
android:viewportHeight="1024.0"> |
||||
<path |
||||
android:pathData="M486.4,1024h-102.4a76.9,76.9 0,0 1,-76.8 -76.8V76.8A76.9,76.9 0,0 1,384 0h102.4a76.9,76.9 0,0 1,76.8 76.8v870.4a76.9,76.9 0,0 1,-76.8 76.8zM384,51.2A25.6,25.6 0,0 0,358.4 76.8v870.4a25.6,25.6 0,0 0,25.6 25.6h102.4a25.6,25.6 0,0 0,25.6 -25.6V76.8a25.6,25.6 0,0 0,-25.6 -25.6zM179.2,1024H76.8A76.9,76.9 0,0 1,0 947.2V128a76.9,76.9 0,0 1,76.8 -76.8H179.2a76.9,76.9 0,0 1,76.8 76.8v819.2A76.9,76.9 0,0 1,179.2 1024zM76.8,102.4a25.6,25.6 0,0 0,-25.6 25.6v819.2a25.6,25.6 0,0 0,25.6 25.6H179.2a25.6,25.6 0,0 0,25.6 -25.6V128A25.6,25.6 0,0 0,179.2 102.4z" |
||||
android:fillColor="@color/black"/> |
||||
<path |
||||
android:pathData="M799.4,636.8l-130.9,-488.6a25.6,25.6 0,0 1,18.1 -31.4l98.9,-26.5a25.3,25.3 0,0 1,6.7 -0.9,25.6 25.6,0 0,1 24.7,19l141.6,528.4h53L866.3,95.2a76.7,76.7 0,0 0,-94.1 -54.3l-98.9,26.5a76.9,76.9 0,0 0,-54.3 94.1l127.4,475.3zM1065.6,841.6h-128v-128h-51.2v128h-128v51.2h128v128h51.2v-128h128v-51.2z" |
||||
android:fillColor="@color/black"/> |
||||
</vector> |
@ -0,0 +1,9 @@ |
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:width="24dp" |
||||
android:height="24dp" |
||||
android:viewportWidth="1024.0" |
||||
android:viewportHeight="1024.0"> |
||||
<path |
||||
android:pathData="M911.8,44L663.3,44c-63.7,0 -119.6,33.4 -150.9,83.4 -31.3,-50.1 -87.1,-83.4 -150.8,-83.4L111.3,44c-49,0 -88.7,39.5 -88.7,88.2v706.8c0,48.7 39.7,88.2 88.7,88.2h298.3c22.4,32 59.7,52.9 101.9,52.9 42.2,0 79.5,-20.9 101.9,-52.9h298.3c49,0 88.7,-39.5 88.7,-88.2L1000.6,132.2c0,-48.7 -39.7,-88.2 -88.7,-88.2zM947.3,839c0,9.3 -3.7,18.3 -10.4,24.9a35.8,35.8 0,0 1,-25.1 10.3L580.3,874.3c-7.9,30.4 -35.7,52.9 -68.8,52.9 -33.1,0 -60.9,-22.5 -68.8,-52.9L111.3,874.3c-9.4,0 -18.5,-3.7 -25.1,-10.3a35.2,35.2 0,0 1,-10.4 -24.9L75.8,132.2a35.2,35.2 0,0 1,10.4 -24.9c6.6,-6.6 15.7,-10.3 25.1,-10.3h250.4c68.6,0 124.2,55.3 124.2,123.4v473.5h0.1c1.1,13.8 12.6,24.4 26.5,24.4 13.9,0 25.5,-10.6 26.5,-24.4h0.1L539.1,220.4c0,-68.2 55.6,-123.4 124.2,-123.4h248.5a35.7,35.7 0,0 1,25.1 10.3,35.2 35.2,0 0,1 10.4,24.9v706.8h0z" |
||||
android:fillColor="@color/white"/> |
||||
</vector> |
@ -1,6 +0,0 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android"> |
||||
<item android:drawable="@mipmap/pwd_visiable" android:state_checked="true"/> |
||||
<item android:drawable="@mipmap/pwd_gone" android:state_checked="false"/> |
||||
<item android:drawable="@mipmap/pwd_gone" /> |
||||
</selector> |
@ -0,0 +1,79 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<RelativeLayout |
||||
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="match_parent" |
||||
android:background="@color/white"> |
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout |
||||
android:layout_width="match_parent" |
||||
android:layout_height="match_parent" |
||||
android:orientation="vertical"> |
||||
|
||||
<com.google.android.material.appbar.AppBarLayout |
||||
android:id="@+id/app_bar" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> |
||||
|
||||
<com.google.android.material.appbar.CollapsingToolbarLayout |
||||
android:id="@+id/toolbar_layout" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="match_parent" |
||||
android:fitsSystemWindows="true" |
||||
app:contentScrim="?attr/colorPrimary" |
||||
app:expandedTitleGravity="top" |
||||
app:expandedTitleMarginStart="114dp" |
||||
app:expandedTitleMarginTop="66dp" |
||||
app:expandedTitleTextAppearance="@style/Base.TextAppearance.AppCompat.Title" |
||||
app:layout_scrollFlags="scroll|exitUntilCollapsed"> |
||||
|
||||
<include layout="@layout/layout_book_detail_header"/> |
||||
|
||||
<androidx.appcompat.widget.Toolbar |
||||
android:id="@+id/toolbar" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="?attr/actionBarSize" |
||||
app:layout_collapseMode="pin" |
||||
app:popupTheme="@style/Theme.ToolBar.Menu"/> |
||||
|
||||
</com.google.android.material.appbar.CollapsingToolbarLayout> |
||||
</com.google.android.material.appbar.AppBarLayout> |
||||
|
||||
<!--详情简介--> |
||||
<androidx.core.widget.NestedScrollView |
||||
android:layout_width="match_parent" |
||||
android:layout_height="match_parent" |
||||
android:layout_marginBottom="56dp" |
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"> |
||||
|
||||
<include layout="@layout/layout_book_detail_content"/> |
||||
|
||||
</androidx.core.widget.NestedScrollView> |
||||
|
||||
<!--底部button--> |
||||
<FrameLayout |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:layout_gravity="bottom" |
||||
android:orientation="vertical"> |
||||
|
||||
<include layout="@layout/layout_book_detail_bottom"/> |
||||
|
||||
<View |
||||
android:layout_width="match_parent" |
||||
android:layout_height="1dp" |
||||
android:layout_gravity="top" |
||||
android:background="#140000"/> |
||||
</FrameLayout> |
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout> |
||||
|
||||
<ProgressBar |
||||
android:id="@+id/pb_loading" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:layout_centerInParent="true" |
||||
android:visibility="gone"/> |
||||
</RelativeLayout> |
@ -0,0 +1,43 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<LinearLayout |
||||
xmlns:android="http://schemas.android.com/apk/res/android" |
||||
style="@style/BottomNavigation.GroupView" |
||||
android:background="@color/white"> |
||||
|
||||
|
||||
|
||||
<FrameLayout |
||||
android:id="@+id/fl_add_bookcase" |
||||
style="@style/BottomNavigation.ItemView"> |
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView |
||||
style="@style/BottomNavigation.ItemView.Icon" |
||||
android:background="@drawable/ic_vector_add_bookcase"/> |
||||
|
||||
<TextView |
||||
android:id="@+id/book_detail_tv_add" |
||||
style="@style/BottomNavigation.ItemView.Title" |
||||
android:text="加入书架" |
||||
android:textColor="@color/black"/> |
||||
|
||||
</FrameLayout> |
||||
|
||||
<FrameLayout |
||||
android:id="@+id/fl_open_book" |
||||
style="@style/BottomNavigation.ItemView" |
||||
android:background="?colorPrimary"> |
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView |
||||
style="@style/BottomNavigation.ItemView.Icon" |
||||
android:background="@drawable/ic_vector_book_read"/> |
||||
|
||||
<TextView |
||||
android:id="@+id/book_detail_tv_open" |
||||
style="@style/BottomNavigation.ItemView.Title" |
||||
android:text="开始阅读" |
||||
android:textColor="@color/white"/> |
||||
|
||||
</FrameLayout> |
||||
|
||||
|
||||
</LinearLayout> |
@ -0,0 +1,98 @@ |
||||
<?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="wrap_content" |
||||
android:orientation="vertical"> |
||||
|
||||
<!--简介--> |
||||
<TextView |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:padding="10dp" |
||||
android:text="简介:" |
||||
android:textColor="@color/black" |
||||
android:textSize="18sp"/> |
||||
<TextView |
||||
android:id="@+id/book_detail_tv_desc" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:layout_marginTop="-10dp" |
||||
android:ellipsize="end" |
||||
android:maxLines="5" |
||||
android:padding="15dp" |
||||
android:lineSpacingMultiplier="1.2" |
||||
android:text="简介: " |
||||
android:textColor="@color/title_black" |
||||
android:textSize="16sp" /> |
||||
<LinearLayout |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:padding="10dp" |
||||
android:orientation="vertical"> |
||||
<TextView |
||||
android:layout_marginTop="5dp" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:lineSpacingMultiplier="1.2" |
||||
android:textSize="14sp" |
||||
android:text="@string/statement" |
||||
android:textColor="@color/title_black" |
||||
/> |
||||
<TextView |
||||
android:id="@+id/tv_disclaimer" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:layout_marginTop="10dp" |
||||
android:text="@string/disclaimer" |
||||
android:textColor="#2196F3" |
||||
android:textSize="14sp"/> |
||||
</LinearLayout> |
||||
|
||||
<View |
||||
android:layout_width="match_parent" |
||||
android:layout_height="10dp" |
||||
android:background="@color/sys_window_back" |
||||
android:visibility="gone"/> |
||||
|
||||
<!--书籍目录--> |
||||
<RelativeLayout |
||||
android:id="@+id/book_detail_rl_catalog" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:visibility="gone"> |
||||
|
||||
<TextView |
||||
android:id="@+id/book_detail_tv_catalog" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:padding="15dp" |
||||
android:text="最新章节" |
||||
android:textColor="@color/black" |
||||
android:textSize="15sp" /> |
||||
|
||||
<TextView |
||||
android:id="@+id/book_detail_tv_catalog_more" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:gravity="right" |
||||
android:padding="15dp" |
||||
android:text="更多" |
||||
android:textColor="@color/title_black" |
||||
android:textSize="15sp" /> |
||||
|
||||
<androidx.recyclerview.widget.RecyclerView |
||||
android:id="@+id/book_detail_rv_catalog" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:layout_below="@+id/book_detail_tv_catalog" |
||||
android:foregroundGravity="center" /> |
||||
</RelativeLayout> |
||||
|
||||
|
||||
<!--底部空白,给底部bottom预留位置--> |
||||
<!--<View--> |
||||
<!--android:layout_width="match_parent"--> |
||||
<!--android:layout_height="56dp"--> |
||||
<!--android:background="@color/divider_wide" />--> |
||||
|
||||
</LinearLayout> |
@ -0,0 +1,98 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||
xmlns:tools="http://schemas.android.com/tools" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:background="?colorPrimary" |
||||
android:paddingLeft="@dimen/activity_horizontal_margin" |
||||
android:paddingTop="64.0dp" |
||||
android:paddingRight="@dimen/activity_horizontal_margin" |
||||
android:paddingBottom="16.0dp" |
||||
app:layout_collapseMode="parallax" |
||||
app:layout_collapseParallaxMultiplier="0.7"> |
||||
|
||||
<androidx.cardview.widget.CardView |
||||
android:id="@+id/cover" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
app:cardCornerRadius="0dp" |
||||
app:cardElevation="2dp"> |
||||
|
||||
<ImageView |
||||
android:id="@+id/book_detail_iv_cover" |
||||
android:layout_width="82dp" |
||||
android:layout_height="110dp" |
||||
android:scaleType="centerCrop" |
||||
android:background="@color/colorPrimary" |
||||
tools:src="@mipmap/no_image" /> |
||||
|
||||
</androidx.cardview.widget.CardView> |
||||
|
||||
<LinearLayout |
||||
android:id="@+id/book_detail_author_type" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:layout_alignTop="@+id/cover" |
||||
android:layout_marginLeft="14dp" |
||||
android:layout_marginTop="30dp" |
||||
android:layout_toRightOf="@+id/cover"> |
||||
<TextView |
||||
android:id="@+id/book_detail_tv_author" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:ellipsize="end" |
||||
android:maxLines="1" |
||||
android:textColor="@color/white" |
||||
tools:text=" 茶叶蛋" /> |
||||
<TextView |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:text=" | " |
||||
android:textColor="@color/little_black_white"/> |
||||
<TextView |
||||
android:id="@+id/book_detail_tv_type" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:ellipsize="end" |
||||
android:maxLines="1" |
||||
android:textColor="@color/white" |
||||
tools:text="仙侠" /> |
||||
</LinearLayout> |
||||
|
||||
<TextView |
||||
android:id="@+id/book_detail_newest_chapter" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:layout_below="@+id/book_detail_author_type" |
||||
android:layout_alignLeft="@id/book_detail_author_type" |
||||
android:layout_marginTop="6dp" |
||||
android:ellipsize="end" |
||||
android:maxLines="1" |
||||
android:textColor="@color/white" |
||||
tools:text="最新章节" /> |
||||
|
||||
<TextView |
||||
android:id="@+id/book_detail_source" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:layout_below="@id/book_detail_newest_chapter" |
||||
android:layout_alignLeft="@id/book_detail_newest_chapter" |
||||
android:layout_marginTop="6dp" |
||||
android:textColor="@color/white" |
||||
tools:text="书源" /> |
||||
|
||||
<!--<TextView--> |
||||
<!--android:id="@+id/book_detail_tv_lately_update"--> |
||||
<!--android:layout_width="wrap_content"--> |
||||
<!--android:layout_height="wrap_content"--> |
||||
<!--android:layout_below="@id/book_detail_tv_author"--> |
||||
<!--android:layout_marginTop="10dp"--> |
||||
<!--android:layout_toRightOf="@id/cover"--> |
||||
<!--android:ellipsize="end"--> |
||||
<!--android:singleLine="true"--> |
||||
<!--android:textColor="@color/textAssist"--> |
||||
<!--android:textSize="13sp"--> |
||||
<!--tools:text="4月前"/>--> |
||||
|
||||
</RelativeLayout> |
@ -0,0 +1,19 @@ |
||||
<?xml version ="1.0" encoding ="utf-8"?> |
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android" |
||||
xmlns:app="http://schemas.android.com/apk/res-auto"> |
||||
|
||||
<item |
||||
android:id="@+id/action_change_source" |
||||
android:icon="@mipmap/ic_menu_exchange" |
||||
android:title="更换书源" |
||||
app:showAsAction="always" /> |
||||
<item |
||||
android:id="@+id/action_reload" |
||||
android:icon="@mipmap/ic_menu_refresh" |
||||
android:title="重新加载"/> |
||||
|
||||
<item |
||||
android:id="@+id/action_open_link" |
||||
android:title="打开链接" /> |
||||
|
||||
</menu> |
After Width: | Height: | Size: 659 B |
After Width: | Height: | Size: 901 B |
Before Width: | Height: | Size: 920 B |
Before Width: | Height: | Size: 1.4 KiB |
@ -1,2 +1,2 @@ |
||||
#Wed Aug 12 21:27:50 CST 2020 |
||||
VERSION_CODE=141 |
||||
#Sat Aug 15 23:51:09 CST 2020 |
||||
VERSION_CODE=142 |
||||
|
Loading…
Reference in new issue