You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
reader/app/src/main/java/com/novel/read/activity/NovelReadActivity.kt

658 lines
24 KiB

package com.novel.read.activity
import android.annotation.SuppressLint
import android.app.Activity
import android.app.Service
import android.content.*
import android.os.Build
import android.os.Handler
import android.os.IBinder
import android.os.Message
import android.util.Log
import android.view.KeyEvent
import android.view.View.*
import android.view.WindowManager
import android.view.animation.Animation
import android.view.animation.AnimationUtils
import android.widget.SeekBar
import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat
import androidx.core.view.GravityCompat
import androidx.drawerlayout.widget.DrawerLayout
import androidx.recyclerview.widget.LinearLayoutManager
import com.mango.mangolib.event.EventManager
import com.novel.read.R
import com.novel.read.adapter.CategoryAdapter
import com.novel.read.adapter.MarkAdapter
import com.novel.read.base.NovelBaseActivity
import com.novel.read.constants.Constant
import com.novel.read.constants.Constant.ResultCode.Companion.RESULT_IS_COLLECTED
import com.novel.read.event.BookArticleEvent
import com.novel.read.event.ErrorChapterEvent
import com.novel.read.event.FinishChapterEvent
import com.novel.read.event.RxBus
import com.novel.read.http.AccountManager
import com.novel.read.model.db.BookChapterBean
import com.novel.read.model.db.BookSignTable
import com.novel.read.model.db.CollBookBean
import com.novel.read.model.db.DownloadTaskBean
import com.novel.read.model.db.dbManage.BookRepository
import com.novel.read.service.DownloadMessage
import com.novel.read.service.DownloadService
import com.novel.read.showToast
import com.novel.read.utlis.BrightnessUtils
import com.novel.read.utlis.ScreenUtils
import com.novel.read.utlis.SpUtil
import com.novel.read.utlis.SystemBarUtils
import com.novel.read.widget.dialog.ReadSettingDialog
import com.novel.read.widget.page.PageLoader
import com.novel.read.widget.page.PageView
import com.novel.read.widget.page.ReadSettingManager
import com.novel.read.widget.page.TxtChapter
import com.squareup.otto.Subscribe
import kotlinx.android.synthetic.main.activity_read.*
import kotlinx.android.synthetic.main.layout_download.*
import kotlinx.android.synthetic.main.layout_light.*
import kotlinx.android.synthetic.main.layout_read_mark.*
import java.util.*
/**
* 阅读页📕
*/
class NovelReadActivity : NovelBaseActivity(), DownloadService.OnDownloadListener {
private lateinit var mCategoryAdapter: CategoryAdapter
private val mChapters = ArrayList<TxtChapter>()
private lateinit var mCurrentChapter: TxtChapter //当前章节
private var currentChapter = 0
private lateinit var mMarkAdapter: MarkAdapter
private val mMarks = ArrayList<BookSignTable>()
private lateinit var mPageLoader: PageLoader
private var mTopInAnim: Animation? = null
private var mTopOutAnim: Animation? = null
private var mBottomInAnim: Animation? = null
private var mBottomOutAnim: Animation? = null
private lateinit var mSettingDialog: ReadSettingDialog
private var isCollected = false // isFromSDCard
private var isNightMode = false
private var isFullScreen = false
private val isRegistered = false
private lateinit var mCollBook: CollBookBean
private lateinit var mBookId: String
@SuppressLint("HandlerLeak")
private val mHandler = object : Handler() {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
when (msg.what) {
WHAT_CATEGORY -> rlv_list.setSelection(mPageLoader.chapterPos)
WHAT_CHAPTER -> mPageLoader.openChapter()
}
}
}
override val layoutId: Int get() = R.layout.activity_read
// 接收电池信息和时间更新的广播
private val mReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (Objects.requireNonNull(intent.action) == Intent.ACTION_BATTERY_CHANGED) {
val level = intent.getIntExtra("level", 0)
mPageLoader.updateBattery(level)
} else if (intent.action == Intent.ACTION_TIME_TICK) {
mPageLoader.updateTime()
}// 监听分钟的变化
}
}
private var mService: DownloadService.IDownloadManager? = null
private var mConn: ServiceConnection? = null
override fun initView() {
EventManager.instance.registerSubscriber(this)
mCollBook = intent.getSerializableExtra(EXTRA_COLL_BOOK) as CollBookBean
isCollected = intent.getBooleanExtra(EXTRA_IS_COLLECTED, false)
mBookId = mCollBook.id
initService()
// 如果 API < 18 取消硬件加速
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
read_pv_page.setLayerType(LAYER_TYPE_SOFTWARE, null)
}
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
//获取页面加载器
mPageLoader = read_pv_page.getPageLoader(mCollBook)
mSettingDialog = ReadSettingDialog(this, mPageLoader)
//禁止滑动展示DrawerLayout
read_dl_slide.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
//侧边打开后,返回键能够起作用
read_dl_slide.isFocusableInTouchMode = false
//半透明化StatusBar
SystemBarUtils.transparentStatusBar(this)
//隐藏StatusBar
read_pv_page.post { this.hideSystemBar() }
read_abl_top_menu.setPadding(0, ScreenUtils.statusBarHeight, 0, 0)
ll_download.setPadding(0, ScreenUtils.statusBarHeight, 0, ScreenUtils.dpToPx(15))
val lp = window.attributes
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
lp.layoutInDisplayCutoutMode = 1
}
window.attributes = lp
//设置当前Activity的Brightness
if (ReadSettingManager.getInstance().isBrightnessAuto) {
BrightnessUtils.setDefaultBrightness(this)
} else {
BrightnessUtils.setBrightness(this, ReadSettingManager.getInstance().brightness)
}
//注册广播
val intentFilter = IntentFilter()
intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED)
intentFilter.addAction(Intent.ACTION_TIME_TICK)
registerReceiver(mReceiver, intentFilter)
if (!SpUtil.getBooleanValue(Constant.BookGuide, false)) {
iv_guide.visibility = VISIBLE
toggleMenu(false)
}
Log.e(TAG, "mBookId: $mBookId")
if (isCollected) {
mPageLoader.collBook.bookChapters =
BookRepository.getInstance().getBookChaptersInRx(mBookId)
// 刷新章节列表
mPageLoader.refreshChapterList()
// 如果是网络小说并被标记更新的,则从网络下载目录
if (mCollBook.isUpdate && !mCollBook.isLocal) {
AccountManager.getInstance().getBookArticle(mBookId, "2", "1", "10000")
}
} else {
AccountManager.getInstance().getBookArticle(mBookId, "2", "1", "10000")
}
}
override fun initData() {
tv_book_name.text = mCollBook.title
mCategoryAdapter = CategoryAdapter()
rlv_list.adapter = mCategoryAdapter
rlv_list.isFastScrollEnabled = true
rlv_mark.layoutManager = LinearLayoutManager(this)
mMarkAdapter = MarkAdapter(mMarks)
rlv_mark.adapter = mMarkAdapter
isNightMode = ReadSettingManager.getInstance().isNightMode
//夜间模式按钮的状态
toggleNightMode()
isFullScreen = ReadSettingManager.getInstance().isFullScreen
toolbar.setNavigationOnClickListener { finish() }
read_setting_sb_brightness.progress = ReadSettingManager.getInstance().brightness
mPageLoader.setOnPageChangeListener(
object : PageLoader.OnPageChangeListener {
override fun onChapterChange(pos: Int) {
var index: Int = pos
if (pos >= mChapters.size) {
index = mChapters.size - 1
}
mCategoryAdapter.setChapter(index)
mCurrentChapter = mChapters[index]
currentChapter = index
}
override fun requestChapters(requestChapters: List<TxtChapter>) {
AccountManager.getInstance().getBookArticleDetail(mBookId, requestChapters)
mHandler.sendEmptyMessage(WHAT_CATEGORY)
}
override fun onCategoryFinish(chapters: List<TxtChapter>) {
mChapters.clear()
mChapters.addAll(chapters)
mCategoryAdapter.refreshItems(mChapters)
}
override fun onPageCountChange(count: Int) {}
override fun onPageChange(pos: Int) {
}
}
)
read_pv_page.setTouchListener(object : PageView.TouchListener {
override fun onTouch(): Boolean {
return !hideReadMenu()
}
override fun center() {
toggleMenu(true)
}
override fun prePage() {}
override fun nextPage() {}
override fun cancel() {}
})
read_tv_category.setOnClickListener {
//移动到指定位置
if (mCategoryAdapter.count > 0) {
rlv_list.setSelection(mPageLoader.chapterPos)
}
//切换菜单
toggleMenu(true)
//打开侧滑动栏
read_dl_slide.openDrawer(GravityCompat.START)
}
tv_light.setOnClickListener {
ll_light.visibility = GONE
rlReadMark.visibility = GONE
if (isVisible(ll_light)) {
ll_light.visibility = GONE
} else {
ll_light.visibility = VISIBLE
}
}
tv_setting.setOnClickListener {
ll_light.visibility = GONE
rlReadMark.visibility = GONE
toggleMenu(false)
mSettingDialog.show()
}
read_setting_sb_brightness.setOnSeekBarChangeListener(object :
SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
}
override fun onStartTrackingTouch(seekBar: SeekBar) {
}
override fun onStopTrackingTouch(seekBar: SeekBar) {
val progress = seekBar.progress
//设置当前 Activity 的亮度
BrightnessUtils.setBrightness(this@NovelReadActivity, progress)
//存储亮度的进度条
ReadSettingManager.getInstance().brightness = progress
}
})
tvBookReadMode.setOnClickListener {
isNightMode = !isNightMode
mPageLoader.setNightMode(isNightMode)
toggleNightMode()
}
read_tv_brief.setOnClickListener {
val intent = Intent(this, NovelBookDetailActivity::class.java)
intent.putExtra(Constant.Bundle.BookId, Integer.valueOf(mBookId))
startActivity(intent)
}
read_tv_community.setOnClickListener {
if (isVisible(read_ll_bottom_menu)) {
if (isVisible(rlReadMark)) {
gone(rlReadMark)
} else {
gone(ll_light)
updateMark()
visible(rlReadMark)
}
}
}
tvAddMark.setOnClickListener {
mMarkAdapter.edit = false
if (BookRepository.getInstance().getSignById(mCurrentChapter.chapterId)) {
showToast(getString(R.string.sign_exist))
return@setOnClickListener
}
BookRepository.getInstance().addSign(mBookId, mCurrentChapter.chapterId, mCurrentChapter.title)
updateMark()
}
tvClear.setOnClickListener {
if (mMarkAdapter.edit) {
val sign = mMarkAdapter.selectList
if (sign != "") {
BookRepository.getInstance().deleteSign(sign)
updateMark()
}
mMarkAdapter.edit = false
} else {
mMarkAdapter.edit = true
}
}
tv_cache.setOnClickListener {
if (!isCollected) { //没有收藏 先收藏 然后弹框
//设置为已收藏
isCollected = true
//设置阅读时间
mCollBook.lastRead = System.currentTimeMillis().toString()
BookRepository.getInstance().saveCollBookWithAsync(mCollBook)
}
showDownLoadDialog()
}
rlv_list.setOnItemClickListener { _, _, position, _ ->
read_dl_slide.closeDrawer(GravityCompat.START)
mPageLoader.skipToChapter(position)
}
iv_guide.setOnClickListener {
iv_guide.visibility = GONE
SpUtil.setBooleanValue(Constant.BookGuide, true)
}
}
private fun showDownLoadDialog() {
val builder = AlertDialog.Builder(this)
builder.setTitle(getString(R.string.d_cache_num))
.setItems(
arrayOf(
getString(R.string.d_cache_last_50),
getString(R.string.d_cache_last_all),
getString(R.string.d_cache_all)
)
) { _, which ->
when (which) {
0 -> {
//50章
val last = currentChapter + 50
if (last > mCollBook.bookChapters.size) {
downLoadCache(mCollBook.bookChapters, mCollBook.bookChapters.size)
} else {
downLoadCache(mCollBook.bookChapters, last)
}
}
1 -> {
//后面所有
val lastBeans = ArrayList<BookChapterBean>()
for (i in currentChapter until mCollBook.bookChapters.size) {
lastBeans.add(mCollBook.bookChapters[i])
}
downLoadCache(lastBeans, mCollBook.bookChapters.size - currentChapter)
}
2 -> downLoadCache(mCollBook.bookChapters, mCollBook.bookChapters.size) //所有
else -> {
}
}
toggleMenu(true)
}
builder.show()
}
private fun downLoadCache(beans: List<BookChapterBean>, size: Int) {
val task = DownloadTaskBean()
task.taskName = mCollBook.title
task.bookId = mCollBook.id
task.bookChapters = beans //计算要缓存的章节
task.currentChapter = currentChapter
task.lastChapter = size
RxBus.getInstance().post(task)
startService(Intent(this, DownloadService::class.java))
}
private fun toggleNightMode() {
if (isNightMode) {
tvBookReadMode.text = resources.getString(R.string.book_read_mode_day)
val drawable = ContextCompat.getDrawable(this, R.drawable.ic_read_menu_moring)
tvBookReadMode.setCompoundDrawablesWithIntrinsicBounds(null, drawable, null, null)
cl_layout.setBackgroundColor(ContextCompat.getColor(this, R.color.read_bg_night))
} else {
tvBookReadMode.text = resources.getString(R.string.book_read_mode_day)
val drawable = ContextCompat.getDrawable(this, R.drawable.ic_read_menu_night)
tvBookReadMode.setCompoundDrawablesWithIntrinsicBounds(null, drawable, null, null)
cl_layout.setBackgroundColor(
ContextCompat.getColor(
this,
ReadSettingManager.getInstance().pageStyle.bgColor
)
)
}
}
/**
* 隐藏阅读界面的菜单显示
*
* @return 是否隐藏成功
*/
private fun hideReadMenu(): Boolean {
hideSystemBar()
if (read_abl_top_menu.visibility == VISIBLE) {
toggleMenu(true)
return true
} else if (mSettingDialog.isShowing) {
mSettingDialog.dismiss()
return true
}
return false
}
private fun showSystemBar() {
//显示
SystemBarUtils.showUnStableStatusBar(this)
if (isFullScreen) {
SystemBarUtils.showUnStableNavBar(this)
}
}
private fun hideSystemBar() {
//隐藏
SystemBarUtils.hideStableStatusBar(this)
if (isFullScreen) {
SystemBarUtils.hideStableNavBar(this)
}
}
/**
* 切换菜单栏的可视状态
* 默认是隐藏的
*/
private fun toggleMenu(hideStatusBar: Boolean) {
initMenuAnim()
gone(ll_light, rlReadMark)
if (read_abl_top_menu.visibility == VISIBLE) {
//关闭
read_abl_top_menu.startAnimation(mTopOutAnim)
read_ll_bottom_menu.startAnimation(mBottomOutAnim)
read_abl_top_menu.visibility = GONE
read_ll_bottom_menu.visibility = GONE
if (hideStatusBar) {
hideSystemBar()
}
} else {
read_abl_top_menu.visibility = VISIBLE
read_ll_bottom_menu.visibility = VISIBLE
read_abl_top_menu.startAnimation(mTopInAnim)
read_ll_bottom_menu.startAnimation(mBottomInAnim)
showSystemBar()
}
}
//初始化菜单动画
private fun initMenuAnim() {
if (mTopInAnim != null) return
mTopInAnim = AnimationUtils.loadAnimation(this, R.anim.slide_top_in)
mTopOutAnim = AnimationUtils.loadAnimation(this, R.anim.slide_top_out)
mBottomInAnim = AnimationUtils.loadAnimation(this, R.anim.slide_bottom_in)
mBottomOutAnim = AnimationUtils.loadAnimation(this, R.anim.slide_bottom_out)
//退出的速度要快
mTopOutAnim!!.duration = 200
mBottomOutAnim!!.duration = 200
}
@Subscribe
fun getBookArticle(event: BookArticleEvent) {
if (event.isFail) {
//获取章节失败处理
Log.e(TAG, event.er!!.msg)
} else {
val chapterBeans = event.result!!.chapterBean
mPageLoader.collBook.bookChapters = chapterBeans
mPageLoader.refreshChapterList()
// 如果是目录更新的情况,那么就需要存储更新数据
if (mCollBook.isUpdate && isCollected) {
BookRepository.getInstance().saveBookChaptersWithAsync(chapterBeans, mCollBook)
}
}
}
@Subscribe
fun finishChapter(event: FinishChapterEvent) {
if (mPageLoader.pageStatus == PageLoader.STATUS_LOADING) {
mHandler.sendEmptyMessage(WHAT_CHAPTER)
}
// 当完成章节的时候,刷新列表
mCategoryAdapter.notifyDataSetChanged()
}
@Subscribe
fun errorChapter(event: ErrorChapterEvent) {
if (mPageLoader.pageStatus == PageLoader.STATUS_LOADING) {
mPageLoader.chapterError()
}
}
private fun updateMark() {
mMarks.clear()
mMarks.addAll(BookRepository.getInstance().getSign(mBookId))
mMarkAdapter.notifyDataSetChanged()
}
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
when (keyCode) {
KeyEvent.KEYCODE_VOLUME_UP -> return mPageLoader.skipToPrePage()
KeyEvent.KEYCODE_VOLUME_DOWN -> return mPageLoader.skipToNextPage()
}
return super.onKeyDown(keyCode, event)
}
override fun onBackPressed() {
if (read_abl_top_menu.visibility == VISIBLE) {
// 非全屏下才收缩,全屏下直接退出
if (!ReadSettingManager.getInstance().isFullScreen) {
toggleMenu(true)
return
}
} else if (mSettingDialog.isShowing) {
mSettingDialog.dismiss()
return
} else if (read_dl_slide.isDrawerOpen(GravityCompat.START)) {
read_dl_slide.closeDrawer(GravityCompat.START)
return
}
Log.e(TAG, "onBackPressed: " + mCollBook.bookChapters.isEmpty())
if (!mCollBook.isLocal && !isCollected && mCollBook.bookChapters.isNotEmpty()) {
val alertDialog = AlertDialog.Builder(this)
.setTitle(getString(R.string.add_book))
.setMessage(getString(R.string.like_book))
.setPositiveButton(getString(R.string.sure)) { dialog, which ->
//设置为已收藏
isCollected = true
//设置阅读时间
mCollBook.lastRead = System.currentTimeMillis().toString()
BookRepository.getInstance().saveCollBookWithAsync(mCollBook)
exit()
}
.setNegativeButton(getString(R.string.cancel)) { dialog, which -> exit() }.create()
alertDialog.show()
} else {
exit()
}
}
// 退出
private fun exit() {
// 返回给BookDetail。
val result = Intent()
result.putExtra(RESULT_IS_COLLECTED, isCollected)
setResult(Activity.RESULT_OK, result)
super.onBackPressed()
}
override fun onPause() {
super.onPause()
if (isCollected) {
mPageLoader.saveRecord()
}
}
override fun onDestroy() {
super.onDestroy()
EventManager.instance.unregisterSubscriber(this)
mPageLoader.closeBook()
// mPageLoader = null
unbindService(mConn)
unregisterReceiver(mReceiver)
}
private fun initService() {
mConn = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName, service: IBinder) {
mService = service as DownloadService.IDownloadManager
mService!!.setOnDownloadListener(this@NovelReadActivity)
}
override fun onServiceDisconnected(name: ComponentName) {}
}
//绑定
bindService(Intent(this, DownloadService::class.java), mConn, Service.BIND_AUTO_CREATE)
}
override fun onDownloadChange(pos: Int, status: Int, msg: String) {
Log.e(TAG, "onDownloadChange: $pos $status $msg")
if (msg == getString(R.string.download_success) || msg == getString(R.string.download_error)) {
//下载成功或失败后隐藏下载视图
if (ll_download != null) {
ll_download.visibility = GONE
showToast(msg)
}
} else {
if (ll_download != null) {
ll_download.visibility = VISIBLE
tv_progress.text = getString(
R.string.download_loading,
mService!!.downloadTaskList[pos].currentChapter,
mService!!.downloadTaskList[pos].lastChapter
)
pb_loading.max = mService!!.downloadTaskList[pos].lastChapter
pb_loading.progress = mService!!.downloadTaskList[pos].currentChapter
}
}
}
override fun onDownloadResponse(pos: Int, status: Int) {
Log.e(TAG, "onDownloadResponse: $pos $status")
}
@Subscribe
fun onDownLoadEvent(message: DownloadMessage) {
showToast(message.message)
}
companion object {
private const val TAG = "NovelReadActivity"
const val EXTRA_COLL_BOOK = "extra_coll_book"
const val EXTRA_IS_COLLECTED = "extra_is_collected"
private const val WHAT_CATEGORY = 1
private const val WHAT_CHAPTER = 2
}
}