# Conflicts:
#	app/src/main/java/io/legado/app/ui/rss/article/RssSortActivity.kt
#	app/src/main/res/menu/rss_articles.xml
pull/219/head
yangyxd 5 years ago
commit 8130256962
  1. 1
      .gitignore
  2. 2
      app/src/main/assets/18PlusList.txt
  3. 7
      app/src/main/assets/updateLog.md
  4. 2
      app/src/main/java/io/legado/app/constant/AppConst.kt
  5. 20
      app/src/main/java/io/legado/app/help/SourceHelp.kt
  6. 8
      app/src/main/java/io/legado/app/help/http/HttpHelper.kt
  7. 4
      app/src/main/java/io/legado/app/help/storage/OldRule.kt
  8. 32
      app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt
  9. 6
      app/src/main/java/io/legado/app/ui/book/read/ReadMenu.kt
  10. 40
      app/src/main/java/io/legado/app/ui/book/read/page/PageView.kt
  11. 4
      app/src/main/java/io/legado/app/ui/book/read/page/delegate/HorizontalPageDelegate.kt
  12. 8
      app/src/main/java/io/legado/app/ui/book/read/page/delegate/PageDelegate.kt
  13. 4
      app/src/main/java/io/legado/app/ui/book/read/page/delegate/ScrollPageDelegate.kt
  14. 8
      app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt
  15. 50
      app/src/main/java/io/legado/app/ui/replacerule/edit/ReplaceEditDialog.kt
  16. 7
      app/src/main/java/io/legado/app/ui/rss/article/RssSortActivity.kt

1
.gitignore vendored

@ -13,4 +13,3 @@ node_modules/
/app/google /app/google
/app/gradle.properties /app/gradle.properties
package-lock.json package-lock.json
18PlusList.txt

@ -0,0 +1,2 @@
OGN5dS5jb20=
c2cwMC54eXo=

@ -3,6 +3,13 @@
* 请关注公众号[开源阅读]()支持我,同时关注合作公众号[小说拾遗](),阅读公众号小编。 * 请关注公众号[开源阅读]()支持我,同时关注合作公众号[小说拾遗](),阅读公众号小编。
* 新公众号[开源阅读]()已启用,[开源阅读软件]()备用 * 新公众号[开源阅读]()已启用,[开源阅读软件]()备用
**2020/05/18**
* 修复http://alanskycn.gitee.io/书源导入失败问题,被屏蔽UA了
**2020/05/17**
* 自动翻页功能完成
* 替换规则输入时弹出辅助输入条
**2020/05/10** **2020/05/10**
* 添加识别rss分组中的频道信息,在菜单中可以切换频道 from yangyxd * 添加识别rss分组中的频道信息,在菜单中可以切换频道 from yangyxd
* 源管理添加置底,批量置顶,批量置地 * 源管理添加置底,批量置顶,批量置地

@ -20,7 +20,7 @@ object AppConst {
const val UA_NAME = "User-Agent" const val UA_NAME = "User-Agent"
val userAgent: String by lazy { val userAgent: String by lazy {
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36"
} }
val SCRIPT_ENGINE: ScriptEngine by lazy { val SCRIPT_ENGINE: ScriptEngine by lazy {

@ -3,8 +3,9 @@ package io.legado.app.help
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import io.legado.app.App import io.legado.app.App
import io.legado.app.data.entities.BookSource
import io.legado.app.data.entities.RssSource import io.legado.app.data.entities.RssSource
import io.legado.app.utils.EncoderUtils
import io.legado.app.utils.NetworkUtils
import io.legado.app.utils.splitNotBlank import io.legado.app.utils.splitNotBlank
import org.jetbrains.anko.toast import org.jetbrains.anko.toast
@ -32,17 +33,20 @@ object SourceHelp {
} }
} }
fun insertBookSource(vararg bookSources: BookSource) {
App.db.bookSourceDao().insert(*bookSources)
}
private fun is18Plus(url: String?): Boolean { private fun is18Plus(url: String?): Boolean {
url ?: return false url ?: return false
if (AppConfig.isGooglePlay) return false if (AppConfig.isGooglePlay) return false
list18Plus.forEach { val baseUrl = NetworkUtils.getBaseUrl(url)
if (url.contains(it)) { baseUrl ?: return false
return true try {
val host = baseUrl.split("//", ".")
val base64Url = EncoderUtils.base64Encode("${host[host.lastIndex - 1]}.${host.last()}")
list18Plus.forEach {
if (base64Url == it) {
return true
}
} }
} catch (e: Exception) {
} }
return false return false
} }

@ -1,5 +1,6 @@
package io.legado.app.help.http package io.legado.app.help.http
import io.legado.app.constant.AppConst
import io.legado.app.help.http.api.HttpGetApi import io.legado.app.help.http.api.HttpGetApi
import io.legado.app.utils.NetworkUtils import io.legado.app.utils.NetworkUtils
import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.suspendCancellableCoroutine
@ -43,7 +44,11 @@ object HttpHelper {
val response = getApiService<HttpGetApi>(baseUrl, encode) val response = getApiService<HttpGetApi>(baseUrl, encode)
.get(url, mapOf()) .get(url, mapOf())
.execute() .execute()
return response.body() return if (response.body() != null) {
response.body()
} else {
response.errorBody().toString()
}
} }
return null return null
} }
@ -90,6 +95,7 @@ object HttpHelper {
return Interceptor { chain -> return Interceptor { chain ->
val request = chain.request() val request = chain.request()
.newBuilder() .newBuilder()
.addHeader(AppConst.UA_NAME, AppConst.userAgent)
.addHeader("Keep-Alive", "300") .addHeader("Keep-Alive", "300")
.addHeader("Connection", "Keep-Alive") .addHeader("Connection", "Keep-Alive")
.addHeader("Cache-Control", "no-cache") .addHeader("Cache-Control", "no-cache")

@ -20,7 +20,7 @@ object OldRule {
} catch (e: Exception) { } catch (e: Exception) {
null null
} }
runCatching { try {
if (sourceAny?.ruleToc == null) { if (sourceAny?.ruleToc == null) {
source.apply { source.apply {
val jsonItem = jsonPath.parse(json.trim()) val jsonItem = jsonPath.parse(json.trim())
@ -125,6 +125,8 @@ object OldRule {
GSON.fromJsonObject(GSON.toJson(sourceAny.ruleContent)) GSON.fromJsonObject(GSON.toJson(sourceAny.ruleContent))
} }
} }
} catch (e: Exception) {
e.printStackTrace()
} }
return source return source
} }

@ -85,7 +85,9 @@ class ReadBookActivity : VMBaseActivity<ReadBookViewModel>(R.layout.activity_boo
private val mHandler = Handler() private val mHandler = Handler()
private val keepScreenRunnable: Runnable = Runnable { Help.keepScreenOn(window, false) } private val keepScreenRunnable: Runnable = Runnable { Help.keepScreenOn(window, false) }
private val autoPageRunnable: Runnable = Runnable { autoPagePlus() }
override var autoPageProgress = 0
override var isAutoPage = false
private var screenTimeOut: Long = 0 private var screenTimeOut: Long = 0
private var timeBatteryReceiver: TimeBatteryReceiver? = null private var timeBatteryReceiver: TimeBatteryReceiver? = null
override val pageFactory: TextPageFactory get() = page_view.pageFactory override val pageFactory: TextPageFactory get() = page_view.pageFactory
@ -344,6 +346,10 @@ class ReadBookActivity : VMBaseActivity<ReadBookViewModel>(R.layout.activity_boo
toast(R.string.read_aloud_pause) toast(R.string.read_aloud_pause)
return true return true
} }
if (isAutoPage) {
autoPageStop()
return true
}
} }
} }
} }
@ -558,7 +564,31 @@ class ReadBookActivity : VMBaseActivity<ReadBookViewModel>(R.layout.activity_boo
* 自动翻页 * 自动翻页
*/ */
override fun autoPage() { override fun autoPage() {
if (isAutoPage) {
autoPageStop()
} else {
isAutoPage = true
autoPagePlus()
}
read_menu.setAutoPage(isAutoPage)
}
private fun autoPageStop() {
isAutoPage = false
mHandler.removeCallbacks(autoPageRunnable)
page_view.upContent()
}
private fun autoPagePlus() {
mHandler.removeCallbacks(autoPageRunnable)
autoPageProgress++
if (autoPageProgress >= 460) {
autoPageProgress = 0
page_view.fillPage(PageDelegate.Direction.NEXT)
} else {
page_view.invalidate()
}
mHandler.postDelayed(autoPageRunnable, 100)
} }
/** /**

@ -140,7 +140,11 @@ class ReadMenu : FrameLayout {
}) })
//自动翻页 //自动翻页
fabAutoPage.onClick { callBack?.autoPage() } fabAutoPage.onClick {
runMenuOut {
callBack?.autoPage()
}
}
//替换 //替换
fabReplaceRule.onClick { callBack?.openReplaceRule() } fabReplaceRule.onClick { callBack?.openReplaceRule() }

@ -3,14 +3,19 @@ package io.legado.app.ui.book.read.page
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.graphics.Canvas import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Rect
import android.util.AttributeSet import android.util.AttributeSet
import android.view.MotionEvent import android.view.MotionEvent
import android.widget.FrameLayout import android.widget.FrameLayout
import io.legado.app.help.ReadBookConfig import io.legado.app.help.ReadBookConfig
import io.legado.app.lib.theme.accentColor
import io.legado.app.service.help.ReadBook import io.legado.app.service.help.ReadBook
import io.legado.app.ui.book.read.page.delegate.* import io.legado.app.ui.book.read.page.delegate.*
import io.legado.app.ui.book.read.page.entities.TextChapter import io.legado.app.ui.book.read.page.entities.TextChapter
import io.legado.app.utils.activity import io.legado.app.utils.activity
import io.legado.app.utils.screenshot
import kotlinx.android.synthetic.main.activity_book_read.view.*
class PageView(context: Context, attrs: AttributeSet) : class PageView(context: Context, attrs: AttributeSet) :
FrameLayout(context, attrs), FrameLayout(context, attrs),
@ -23,6 +28,12 @@ class PageView(context: Context, attrs: AttributeSet) :
var prevPage: ContentView = ContentView(context) var prevPage: ContentView = ContentView(context)
var curPage: ContentView = ContentView(context) var curPage: ContentView = ContentView(context)
var nextPage: ContentView = ContentView(context) var nextPage: ContentView = ContentView(context)
private val autoPageRect by lazy { Rect() }
private val autoPagePint by lazy {
Paint().apply {
color = context.accentColor
}
}
init { init {
addView(nextPage) addView(nextPage)
@ -44,8 +55,21 @@ class PageView(context: Context, attrs: AttributeSet) :
override fun dispatchDraw(canvas: Canvas) { override fun dispatchDraw(canvas: Canvas) {
super.dispatchDraw(canvas) super.dispatchDraw(canvas)
pageDelegate?.onDraw(canvas) pageDelegate?.onDraw(canvas)
if (callBack.isAutoPage) {
nextPage.screenshot()?.let {
val bottom = page_view.height * callBack.autoPageProgress / 460
autoPageRect.set(0, 0, page_view.width, bottom)
canvas.drawBitmap(it, autoPageRect, autoPageRect, null)
canvas.drawRect(
0f,
bottom.toFloat() - 1,
page_view.width.toFloat(),
bottom.toFloat(),
autoPagePint
)
}
}
} }
override fun computeScroll() { override fun computeScroll() {
@ -146,18 +170,18 @@ class PageView(context: Context, attrs: AttributeSet) :
override val currentChapter: TextChapter? override val currentChapter: TextChapter?
get() { get() {
return if (callBack.isInitFinish) ReadBook.textChapter(0) else null return if (callBack.isInitFinish) ReadBook.textChapter(0) else null
} }
override val nextChapter: TextChapter? override val nextChapter: TextChapter?
get() { get() {
return if (callBack.isInitFinish) ReadBook.textChapter(1) else null return if (callBack.isInitFinish) ReadBook.textChapter(1) else null
} }
override val prevChapter: TextChapter? override val prevChapter: TextChapter?
get() { get() {
return if (callBack.isInitFinish) ReadBook.textChapter(-1) else null return if (callBack.isInitFinish) ReadBook.textChapter(-1) else null
} }
override fun hasNextChapter(): Boolean { override fun hasNextChapter(): Boolean {
return ReadBook.durChapterIndex < ReadBook.chapterSize - 1 return ReadBook.durChapterIndex < ReadBook.chapterSize - 1
@ -169,6 +193,8 @@ class PageView(context: Context, attrs: AttributeSet) :
interface CallBack { interface CallBack {
val isInitFinish: Boolean val isInitFinish: Boolean
val isAutoPage: Boolean
val autoPageProgress: Int
fun clickCenter() fun clickCenter()
fun screenOffTimerStart() fun screenOffTimerStart()
fun showTextActionMenu() fun showTextActionMenu()

@ -104,7 +104,7 @@ abstract class HorizontalPageDelegate(pageView: PageView) : PageDelegate(pageVie
} }
override fun nextPageByAnim() { override fun nextPageByAnim() {
super.nextPageByAnim() abort()
if (!hasNext()) return if (!hasNext()) return
setDirection(Direction.NEXT) setDirection(Direction.NEXT)
setTouchPoint(viewWidth.toFloat(), 0f) setTouchPoint(viewWidth.toFloat(), 0f)
@ -112,7 +112,7 @@ abstract class HorizontalPageDelegate(pageView: PageView) : PageDelegate(pageVie
} }
override fun prevPageByAnim() { override fun prevPageByAnim() {
super.prevPageByAnim() abort()
if (!hasPrev()) return if (!hasPrev()) return
setDirection(Direction.PREV) setDirection(Direction.PREV)
setTouchPoint(0f, 0f) setTouchPoint(0f, 0f)

@ -170,13 +170,9 @@ abstract class PageDelegate(protected val pageView: PageView) :
open fun onScroll() {}//移动contentView, slidePage open fun onScroll() {}//移动contentView, slidePage
open fun nextPageByAnim() { abstract fun nextPageByAnim()
abort()
}
open fun prevPageByAnim() { abstract fun prevPageByAnim()
abort()
}
open fun keyTurnPage(direction: Direction) { open fun keyTurnPage(direction: Direction) {
if (isRunning) return if (isRunning) return

@ -79,12 +79,12 @@ class ScrollPageDelegate(pageView: PageView) : PageDelegate(pageView) {
} }
override fun nextPageByAnim() { override fun nextPageByAnim() {
super.nextPageByAnim() abort()
startScroll(0, 0, 0, -ChapterProvider.visibleHeight) startScroll(0, 0, 0, -ChapterProvider.visibleHeight)
} }
override fun prevPageByAnim() { override fun prevPageByAnim() {
super.prevPageByAnim() abort()
startScroll(0, 0, 0, ChapterProvider.visibleHeight) startScroll(0, 0, 0, ChapterProvider.visibleHeight)
} }
} }

@ -233,6 +233,7 @@ class BookSourceViewModel(application: Application) : BaseViewModel(application)
else -> "格式不对" else -> "格式不对"
} }
}.onError { }.onError {
it.printStackTrace()
finally(it.localizedMessage ?: "") finally(it.localizedMessage ?: "")
}.onSuccess { }.onSuccess {
finally(it) finally(it)
@ -240,7 +241,11 @@ class BookSourceViewModel(application: Application) : BaseViewModel(application)
} }
private fun importSourceUrl(url: String): Int { private fun importSourceUrl(url: String): Int {
HttpHelper.simpleGet(url, "UTF-8")?.let { body -> HttpHelper.simpleGet(url, "UTF-8").let { body ->
if (body == null) {
toast("访问网站失败")
return 0
}
val bookSources = mutableListOf<BookSource>() val bookSources = mutableListOf<BookSource>()
val items: List<Map<String, Any>> = jsonPath.parse(body).read("$") val items: List<Map<String, Any>> = jsonPath.parse(body).read("$")
for (item in items) { for (item in items) {
@ -252,6 +257,5 @@ class BookSourceViewModel(application: Application) : BaseViewModel(application)
App.db.bookSourceDao().insert(*bookSources.toTypedArray()) App.db.bookSourceDao().insert(*bookSources.toTypedArray())
return bookSources.size return bookSources.size
} }
return 0
} }
} }

@ -1,26 +1,32 @@
package io.legado.app.ui.replacerule.edit package io.legado.app.ui.replacerule.edit
import android.os.Bundle import android.os.Bundle
import android.util.DisplayMetrics
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import android.widget.EditText
import android.widget.PopupWindow
import androidx.appcompat.widget.Toolbar import androidx.appcompat.widget.Toolbar
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import io.legado.app.R import io.legado.app.R
import io.legado.app.constant.AppConst
import io.legado.app.constant.Theme import io.legado.app.constant.Theme
import io.legado.app.data.entities.ReplaceRule import io.legado.app.data.entities.ReplaceRule
import io.legado.app.ui.widget.KeyboardToolPop
import io.legado.app.utils.applyTint import io.legado.app.utils.applyTint
import io.legado.app.utils.getViewModel import io.legado.app.utils.getViewModel
import io.legado.app.utils.toast import io.legado.app.utils.toast
import kotlinx.android.synthetic.main.dialog_replace_edit.* import kotlinx.android.synthetic.main.dialog_replace_edit.*
import org.jetbrains.anko.sdk27.listeners.onFocusChange
class ReplaceEditDialog : DialogFragment(), class ReplaceEditDialog : DialogFragment(),
Toolbar.OnMenuItemClickListener { Toolbar.OnMenuItemClickListener,
KeyboardToolPop.CallBack {
companion object { companion object {
@ -41,12 +47,11 @@ class ReplaceEditDialog : DialogFragment(),
} }
private lateinit var viewModel: ReplaceEditViewModel private lateinit var viewModel: ReplaceEditViewModel
private lateinit var mSoftKeyboardTool: PopupWindow
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
val dm = DisplayMetrics() dialog?.window?.setLayout(MATCH_PARENT, WRAP_CONTENT)
activity?.windowManager?.defaultDisplay?.getMetrics(dm)
dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), WRAP_CONTENT)
} }
override fun onCreateView( override fun onCreateView(
@ -60,6 +65,7 @@ class ReplaceEditDialog : DialogFragment(),
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
mSoftKeyboardTool = KeyboardToolPop(requireContext(), AppConst.keyboardToolChars, this)
tool_bar.inflateMenu(R.menu.replace_edit) tool_bar.inflateMenu(R.menu.replace_edit)
tool_bar.menu.applyTint(requireContext(), Theme.getTheme()) tool_bar.menu.applyTint(requireContext(), Theme.getTheme())
tool_bar.setOnMenuItemClickListener(this) tool_bar.setOnMenuItemClickListener(this)
@ -69,12 +75,20 @@ class ReplaceEditDialog : DialogFragment(),
arguments?.let { arguments?.let {
viewModel.initData(it) viewModel.initData(it)
} }
et_replace_rule.onFocusChange { v, hasFocus ->
if (hasFocus) {
mSoftKeyboardTool.width = v.width
mSoftKeyboardTool.showAsDropDown(v)
} else {
mSoftKeyboardTool.dismiss()
}
}
} }
override fun onMenuItemClick(item: MenuItem?): Boolean { override fun onMenuItemClick(item: MenuItem?): Boolean {
when (item?.itemId) { when (item?.itemId) {
R.id.menu_save -> { R.id.menu_save -> {
val rule = getReplaceRule(); val rule = getReplaceRule()
if (!rule.isValid()){ if (!rule.isValid()){
toast(R.string.replace_rule_invalid) toast(R.string.replace_rule_invalid)
} }
@ -111,6 +125,30 @@ class ReplaceEditDialog : DialogFragment(),
val callBack get() = activity as? CallBack val callBack get() = activity as? CallBack
private fun insertText(text: String) {
if (text.isBlank()) return
val view = dialog?.window?.decorView?.findFocus()
if (view is EditText) {
val start = view.selectionStart
val end = view.selectionEnd
val edit = view.editableText//获取EditText的文字
if (start < 0 || start >= edit.length) {
edit.append(text)
} else {
edit.replace(start, end, text)//光标所在位置插入文字
}
}
}
override fun sendText(text: String) {
if (text == AppConst.keyboardToolChars[0]) {
val view = dialog?.window?.decorView?.findFocus()
view?.clearFocus()
} else {
insertText(text)
}
}
interface CallBack { interface CallBack {
fun onReplaceRuleSave() fun onReplaceRuleSave()
} }

@ -17,7 +17,6 @@ import io.legado.app.ui.rss.source.edit.RssSourceEditActivity
import io.legado.app.utils.* import io.legado.app.utils.*
import kotlinx.android.synthetic.main.activity_rss_artivles.* import kotlinx.android.synthetic.main.activity_rss_artivles.*
import org.jetbrains.anko.startActivityForResult import org.jetbrains.anko.startActivityForResult
import java.util.*
class RssSortActivity : VMBaseActivity<RssSortViewModel>(R.layout.activity_rss_artivles) { class RssSortActivity : VMBaseActivity<RssSortViewModel>(R.layout.activity_rss_artivles) {
@ -44,10 +43,13 @@ class RssSortActivity : VMBaseActivity<RssSortViewModel>(R.layout.activity_rss_a
return super.onCompatCreateOptionsMenu(menu) return super.onCompatCreateOptionsMenu(menu)
} }
<<<<<<< HEAD
override fun onPrepareOptionsMenu(menu: Menu?): Boolean { override fun onPrepareOptionsMenu(menu: Menu?): Boolean {
return super.onPrepareOptionsMenu(menu) return super.onPrepareOptionsMenu(menu)
} }
=======
>>>>>>> 6c28abcdcd7b57f40de92223ec9e6241805e2b7c
override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { override fun onCompatOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) { when (item.itemId) {
R.id.menu_edit_source -> viewModel.rssSource?.sourceUrl?.let { R.id.menu_edit_source -> viewModel.rssSource?.sourceUrl?.let {
@ -58,9 +60,12 @@ class RssSortActivity : VMBaseActivity<RssSortViewModel>(R.layout.activity_rss_a
viewModel.clearArticles() viewModel.clearArticles()
} }
} }
<<<<<<< HEAD
R.id.menu_switch_layout -> { R.id.menu_switch_layout -> {
switchLayout() switchLayout()
} }
=======
>>>>>>> 6c28abcdcd7b57f40de92223ec9e6241805e2b7c
} }
return super.onCompatOptionsItemSelected(item) return super.onCompatOptionsItemSelected(item)
} }

Loading…
Cancel
Save