From b570626f3270abc76ae1d68c2bf663e87fa70cc5 Mon Sep 17 00:00:00 2001 From: atbest Date: Fri, 24 May 2019 01:23:23 -0400 Subject: [PATCH 0001/1997] Updated replace rule --- .../io/legado/app/data/dao/ReplaceRuleDao.kt | 7 +++++- .../app/ui/replacerule/ReplaceRuleActivity.kt | 23 +++++++++++++++++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt b/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt index 9b92e4c6a..919855143 100644 --- a/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt @@ -33,12 +33,17 @@ interface ReplaceRuleDao { @Query("SELECT * FROM replace_rules WHERE isEnabled = 1 AND scope LIKE '%' || :scope || '%'") fun findEnabledByScope(scope: String): List + @get:Query("SELECT COUNT(*) - SUM(isEnabled) FROM replace_rules") + val summary: Int + + @Query("UPDATE replace_rules SET isEnabled = :enable") + fun enableAll(enable: Boolean) + @Insert(onConflict = OnConflictStrategy.REPLACE) fun insert(vararg replaceRules: ReplaceRule) @Insert(onConflict = OnConflictStrategy.REPLACE) fun insert(replaceRule: ReplaceRule): Long - @Update fun update(vararg replaceRules: ReplaceRule) diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt index 304000c53..464c5746b 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt @@ -18,6 +18,7 @@ import org.jetbrains.anko.toast class ReplaceRuleActivity : AppCompatActivity() { private lateinit var adapter: ReplaceRuleAdapter private var rulesLiveData: LiveData>? = null + private var allEnabled = false override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -32,12 +33,23 @@ class ReplaceRuleActivity : AppCompatActivity() { adapter = ReplaceRuleAdapter(this) adapter.onClickListener = object: ReplaceRuleAdapter.OnClickListener { override fun update(rule: ReplaceRule) { - doAsync { App.db.replaceRuleDao().update(rule) } + doAsync { + App.db.replaceRuleDao().update(rule) + updateEnableAll() + } } override fun delete(rule: ReplaceRule) { - doAsync { App.db.replaceRuleDao().delete(rule) } + doAsync { + App.db.replaceRuleDao().delete(rule) + updateEnableAll() + } } override fun edit(rule: ReplaceRule) { + doAsync { + App.db.replaceRuleDao().enableAll(!allEnabled) + allEnabled = !allEnabled + } + toast("Edit function not implemented!") } } @@ -50,4 +62,11 @@ class ReplaceRuleActivity : AppCompatActivity() { rulesLiveData?.observe(this, Observer> { adapter.submitList(it) }) } + private fun updateEnableAll() { + doAsync { + App.db.replaceRuleDao().summary.let { + allEnabled = it == 0 + } + } + } } \ No newline at end of file From ab8da2e6a361f994be4d92f0dcb90b7d66aee4ad Mon Sep 17 00:00:00 2001 From: atbest Date: Fri, 24 May 2019 01:24:15 -0400 Subject: [PATCH 0002/1997] Added replace rule --- app/src/main/res/layout/activity_replace_rule.xml | 6 +++--- app/src/main/res/values/strings.xml | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/layout/activity_replace_rule.xml b/app/src/main/res/layout/activity_replace_rule.xml index 773e22242..5c5d4849e 100644 --- a/app/src/main/res/layout/activity_replace_rule.xml +++ b/app/src/main/res/layout/activity_replace_rule.xml @@ -5,14 +5,14 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context="io.legado.app.ui.search.SearchActivity"> + tools:context=".ui.replacerule.ReplaceRuleActivity"> + app:title="@string/replace"/> 阅读需要访问存储卡权限: 编辑 删除 + 净化替换 From 2c8a0c330a10177ab04879e0a7cea1a0d3575278 Mon Sep 17 00:00:00 2001 From: Invinciblelee <1760316362@qq.com> Date: Fri, 24 May 2019 15:28:42 +0800 Subject: [PATCH 0003/1997] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=9D=83=E9=99=90?= =?UTF-8?q?=E8=AF=B7=E6=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 1 - app/src/main/AndroidManifest.xml | 3 + .../app/help/permission/ActivitySource.kt | 20 ++ .../app/help/permission/FragmentSource.kt | 19 ++ .../permission/OnPermissionsDeniedCallback.kt | 5 + .../OnPermissionsGrantedCallback.kt | 7 + .../permission/OnPermissionsResultCallback.kt | 9 + .../OnRequestPermissionsResultCallback.kt | 11 + .../app/help/permission/PermissionActivity.kt | 77 +++++++ .../legado/app/help/permission/Permissions.kt | 72 +++++++ .../app/help/permission/PermissionsCompat.kt | 78 +++++++ .../io/legado/app/help/permission/Request.kt | 199 ++++++++++++++++++ .../app/help/permission/RequestManager.kt | 67 ++++++ .../app/help/permission/RequestPlugins.kt | 20 ++ .../app/help/permission/RequestSource.kt | 13 ++ .../io/legado/app/ui/main/MainActivity.kt | 78 ++++++- .../java/io/legado/app/ui/widget/TitleBar.kt | 2 +- app/src/main/res/layout/activity_search.xml | 6 +- app/src/main/res/layout/app_bar_main.xml | 2 +- app/src/main/res/values/strings.xml | 10 +- app/src/main/res/values/styles.xml | 15 +- 21 files changed, 704 insertions(+), 10 deletions(-) create mode 100644 app/src/main/java/io/legado/app/help/permission/ActivitySource.kt create mode 100644 app/src/main/java/io/legado/app/help/permission/FragmentSource.kt create mode 100644 app/src/main/java/io/legado/app/help/permission/OnPermissionsDeniedCallback.kt create mode 100644 app/src/main/java/io/legado/app/help/permission/OnPermissionsGrantedCallback.kt create mode 100644 app/src/main/java/io/legado/app/help/permission/OnPermissionsResultCallback.kt create mode 100644 app/src/main/java/io/legado/app/help/permission/OnRequestPermissionsResultCallback.kt create mode 100644 app/src/main/java/io/legado/app/help/permission/PermissionActivity.kt create mode 100644 app/src/main/java/io/legado/app/help/permission/Permissions.kt create mode 100644 app/src/main/java/io/legado/app/help/permission/PermissionsCompat.kt create mode 100644 app/src/main/java/io/legado/app/help/permission/Request.kt create mode 100644 app/src/main/java/io/legado/app/help/permission/RequestManager.kt create mode 100644 app/src/main/java/io/legado/app/help/permission/RequestPlugins.kt create mode 100644 app/src/main/java/io/legado/app/help/permission/RequestSource.kt diff --git a/app/build.gradle b/app/build.gradle index 966ba8516..215af4020 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -76,7 +76,6 @@ dependencies { implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.2.1' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.2.1' //规则相关 - implementation 'pub.devrel:easypermissions:3.0.0' implementation 'com.google.code.gson:gson:2.8.5' implementation 'com.jayway.jsonpath:json-path:2.4.0' implementation 'org.jsoup:jsoup:1.12.1' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7c5e32f4a..3bef8cc80 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -40,6 +40,9 @@ + + \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/help/permission/ActivitySource.kt b/app/src/main/java/io/legado/app/help/permission/ActivitySource.kt new file mode 100644 index 000000000..e0618067a --- /dev/null +++ b/app/src/main/java/io/legado/app/help/permission/ActivitySource.kt @@ -0,0 +1,20 @@ +package io.legado.app.help.permission + +import android.content.Context +import android.content.Intent +import androidx.appcompat.app.AppCompatActivity + +import java.lang.ref.WeakReference + +internal class ActivitySource(activity: AppCompatActivity) : RequestSource { + + private val actRef: WeakReference = WeakReference(activity) + + override val context: Context? + get() = actRef.get() + + override fun startActivity(intent: Intent) { + actRef.get()?.startActivity(intent) + } + +} diff --git a/app/src/main/java/io/legado/app/help/permission/FragmentSource.kt b/app/src/main/java/io/legado/app/help/permission/FragmentSource.kt new file mode 100644 index 000000000..b66e11b98 --- /dev/null +++ b/app/src/main/java/io/legado/app/help/permission/FragmentSource.kt @@ -0,0 +1,19 @@ +package io.legado.app.help.permission + +import android.content.Context +import android.content.Intent +import androidx.fragment.app.Fragment + +import java.lang.ref.WeakReference + +internal class FragmentSource(fragment: Fragment) : RequestSource { + + private val fragRef: WeakReference = WeakReference(fragment) + + override val context: Context? + get() = fragRef.get()?.requireContext() + + override fun startActivity(intent: Intent) { + fragRef.get()?.startActivity(intent) + } +} diff --git a/app/src/main/java/io/legado/app/help/permission/OnPermissionsDeniedCallback.kt b/app/src/main/java/io/legado/app/help/permission/OnPermissionsDeniedCallback.kt new file mode 100644 index 000000000..d6e81a68f --- /dev/null +++ b/app/src/main/java/io/legado/app/help/permission/OnPermissionsDeniedCallback.kt @@ -0,0 +1,5 @@ +package io.legado.app.help.permission + +interface OnPermissionsDeniedCallback { + fun onPermissionsDenied(requestCode: Int, deniedPermissions: Array) +} diff --git a/app/src/main/java/io/legado/app/help/permission/OnPermissionsGrantedCallback.kt b/app/src/main/java/io/legado/app/help/permission/OnPermissionsGrantedCallback.kt new file mode 100644 index 000000000..59f6977d4 --- /dev/null +++ b/app/src/main/java/io/legado/app/help/permission/OnPermissionsGrantedCallback.kt @@ -0,0 +1,7 @@ +package io.legado.app.help.permission + +interface OnPermissionsGrantedCallback { + + fun onPermissionsGranted(requestCode: Int) + +} diff --git a/app/src/main/java/io/legado/app/help/permission/OnPermissionsResultCallback.kt b/app/src/main/java/io/legado/app/help/permission/OnPermissionsResultCallback.kt new file mode 100644 index 000000000..3d7afa600 --- /dev/null +++ b/app/src/main/java/io/legado/app/help/permission/OnPermissionsResultCallback.kt @@ -0,0 +1,9 @@ +package io.legado.app.help.permission + +interface OnPermissionsResultCallback { + + fun onPermissionsGranted(requestCode: Int) + + fun onPermissionsDenied(requestCode: Int, deniedPermissions: Array) + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/help/permission/OnRequestPermissionsResultCallback.kt b/app/src/main/java/io/legado/app/help/permission/OnRequestPermissionsResultCallback.kt new file mode 100644 index 000000000..b86983fd9 --- /dev/null +++ b/app/src/main/java/io/legado/app/help/permission/OnRequestPermissionsResultCallback.kt @@ -0,0 +1,11 @@ +package io.legado.app.help.permission + +import android.content.Intent + +interface OnRequestPermissionsResultCallback { + + fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) + + + fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) +} diff --git a/app/src/main/java/io/legado/app/help/permission/PermissionActivity.kt b/app/src/main/java/io/legado/app/help/permission/PermissionActivity.kt new file mode 100644 index 000000000..98ecf5b67 --- /dev/null +++ b/app/src/main/java/io/legado/app/help/permission/PermissionActivity.kt @@ -0,0 +1,77 @@ +package io.legado.app.help.permission + +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import android.provider.Settings +import android.view.KeyEvent +import androidx.appcompat.app.AppCompatActivity +import androidx.core.app.ActivityCompat +import io.legado.app.R +import org.jetbrains.anko.toast + +class PermissionActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + val intent = intent + + when (intent.getIntExtra(KEY_INPUT_REQUEST_TYPE, Request.TYPE_REQUEST_PERMISSION)) { + Request.TYPE_REQUEST_PERMISSION//权限请求 + -> { + val requestCode = intent.getIntExtra(KEY_INPUT_PERMISSIONS_CODE, 1000) + val permissions = intent.getStringArrayExtra(KEY_INPUT_PERMISSIONS) + if (permissions != null) { + ActivityCompat.requestPermissions(this, permissions, requestCode) + } else { + finish() + } + } + Request.TYPE_REQUEST_SETTING//跳转到设置界面 + -> try { + val settingIntent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) + settingIntent.data = Uri.fromParts("package", packageName, null) + startActivityForResult(settingIntent, Request.TYPE_REQUEST_SETTING) + } catch (e: Exception) { + toast(R.string.tip_cannot_jump_setting_page) + finish() + } + + } + } + + override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults) + RequestPlugins.sRequestCallback?.onRequestPermissionsResult(requestCode, permissions, grantResults) + finish() + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + RequestPlugins.sRequestCallback?.onActivityResult(requestCode, resultCode, data) + finish() + } + + override fun startActivity(intent: Intent) { + super.startActivity(intent) + overridePendingTransition(0, 0) + } + + override fun finish() { + super.finish() + overridePendingTransition(0, 0) + } + + override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean { + return if (keyCode == KeyEvent.KEYCODE_BACK) { + true + } else super.onKeyDown(keyCode, event) + } + + companion object { + + const val KEY_INPUT_REQUEST_TYPE = "KEY_INPUT_REQUEST_TYPE" + const val KEY_INPUT_PERMISSIONS_CODE = "KEY_INPUT_PERMISSIONS_CODE" + const val KEY_INPUT_PERMISSIONS = "KEY_INPUT_PERMISSIONS" + } +} diff --git a/app/src/main/java/io/legado/app/help/permission/Permissions.kt b/app/src/main/java/io/legado/app/help/permission/Permissions.kt new file mode 100644 index 000000000..e1c0893e3 --- /dev/null +++ b/app/src/main/java/io/legado/app/help/permission/Permissions.kt @@ -0,0 +1,72 @@ +package io.legado.app.help.permission + +object Permissions { + + const val READ_CALENDAR = "android.permission.READ_CALENDAR" + const val WRITE_CALENDAR = "android.permission.WRITE_CALENDAR" + + const val CAMERA = "android.permission.CAMERA" + + const val READ_CONTACTS = "android.permission.READ_CONTACTS" + const val WRITE_CONTACTS = "android.permission.WRITE_CONTACTS" + const val GET_ACCOUNTS = "android.permission.GET_ACCOUNTS" + + const val ACCESS_FINE_LOCATION = "android.permission.ACCESS_FINE_LOCATION" + const val ACCESS_COARSE_LOCATION = "android.permission.ACCESS_COARSE_LOCATION" + + const val RECORD_AUDIO = "android.permission.RECORD_AUDIO" + + const val READ_PHONE_STATE = "android.permission.READ_PHONE_STATE" + const val CALL_PHONE = "android.permission.CALL_PHONE" + const val READ_CALL_LOG = "android.permission.READ_CALL_LOG" + const val WRITE_CALL_LOG = "android.permission.WRITE_CALL_LOG" + const val ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL" + const val USE_SIP = "android.permission.USE_SIP" + const val PROCESS_OUTGOING_CALLS = "android.permission.PROCESS_OUTGOING_CALLS" + + const val BODY_SENSORS = "android.permission.BODY_SENSORS" + + const val SEND_SMS = "android.permission.SEND_SMS" + const val RECEIVE_SMS = "android.permission.RECEIVE_SMS" + const val READ_SMS = "android.permission.READ_SMS" + const val RECEIVE_WAP_PUSH = "android.permission.RECEIVE_WAP_PUSH" + const val RECEIVE_MMS = "android.permission.RECEIVE_MMS" + + const val READ_EXTERNAL_STORAGE = "android.permission.READ_EXTERNAL_STORAGE" + const val WRITE_EXTERNAL_STORAGE = "android.permission.WRITE_EXTERNAL_STORAGE" + + object Group { + val CALENDAR = arrayOf(READ_CALENDAR, WRITE_CALENDAR) + + val CAMERA = arrayOf(Permissions.CAMERA) + + val CONTACTS = arrayOf(READ_CONTACTS, WRITE_CONTACTS, GET_ACCOUNTS) + + val LOCATION = arrayOf(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION) + + val MICROPHONE = arrayOf(RECORD_AUDIO) + + val PHONE = arrayOf( + READ_PHONE_STATE, + CALL_PHONE, + READ_CALL_LOG, + WRITE_CALL_LOG, + ADD_VOICEMAIL, + USE_SIP, + PROCESS_OUTGOING_CALLS + ) + + val SENSORS = arrayOf(BODY_SENSORS) + + val SMS = arrayOf( + SEND_SMS, + RECEIVE_SMS, + READ_SMS, + RECEIVE_WAP_PUSH, + RECEIVE_MMS + ) + + val STORAGE = arrayOf(READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE) + } + +} diff --git a/app/src/main/java/io/legado/app/help/permission/PermissionsCompat.kt b/app/src/main/java/io/legado/app/help/permission/PermissionsCompat.kt new file mode 100644 index 000000000..45ef0f885 --- /dev/null +++ b/app/src/main/java/io/legado/app/help/permission/PermissionsCompat.kt @@ -0,0 +1,78 @@ +package io.legado.app.help.permission + +import androidx.annotation.StringRes +import androidx.appcompat.app.AppCompatActivity +import androidx.fragment.app.Fragment + +class PermissionsCompat private constructor() { + + private var mRequest: Request? = null + + fun request() { + RequestManager.pushRequest(mRequest) + } + + class Builder { + private val mRequest: Request + + constructor(activity: AppCompatActivity) { + mRequest = Request(activity) + } + + constructor(fragment: Fragment) { + mRequest = Request(fragment) + } + + fun addPermissions(vararg permissions: String): Builder { + mRequest.addPermissions(*permissions) + return this + } + + fun requestCode(requestCode: Int): Builder { + mRequest.setRequestCode(requestCode) + return this + } + + fun onGranted(callback: (requestCode: Int) -> Unit): Builder { + mRequest.setOnGrantedCallback(object : OnPermissionsGrantedCallback { + override fun onPermissionsGranted(requestCode: Int) { + callback(requestCode) + } + }) + return this + } + + fun onDenied(callback: (requestCode: Int, deniedPermissions: Array) -> Unit): Builder { + mRequest.setOnDeniedCallback(object : OnPermissionsDeniedCallback { + override fun onPermissionsDenied(requestCode: Int, deniedPermissions: Array) { + callback(requestCode, deniedPermissions) + } + }) + return this + } + + fun rationale(rationale: CharSequence): Builder { + mRequest.setRationale(rationale) + return this + } + + fun rationale(@StringRes resId: Int): Builder { + mRequest.setRationale(resId) + return this + } + + fun build(): PermissionsCompat { + val compat = PermissionsCompat() + compat.mRequest = mRequest + return compat + } + + fun request(): PermissionsCompat { + val compat = build() + compat.mRequest = mRequest + compat.request() + return compat + } + } + +} diff --git a/app/src/main/java/io/legado/app/help/permission/Request.kt b/app/src/main/java/io/legado/app/help/permission/Request.kt new file mode 100644 index 000000000..c5d389fa6 --- /dev/null +++ b/app/src/main/java/io/legado/app/help/permission/Request.kt @@ -0,0 +1,199 @@ +package io.legado.app.help.permission + +import android.content.Intent +import android.content.pm.PackageManager +import android.os.Build +import androidx.annotation.StringRes +import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity +import androidx.core.content.ContextCompat +import androidx.fragment.app.Fragment +import io.legado.app.R +import org.jetbrains.anko.startActivity +import java.util.* + +internal class Request : OnRequestPermissionsResultCallback { + + var startTime: Long = 0 + private set + private var requestCode: Int = 0 + private var source: RequestSource? = null + private var permissions: ArrayList? = null + private var grantedCallback: OnPermissionsGrantedCallback? = null + private var deniedCallback: OnPermissionsDeniedCallback? = null + private var rationaleResId: Int = 0 + private var rationale: CharSequence? = null + + private var rationaleDialog: AlertDialog? = null + + private val deniedPermissions: Array? + get() { + val permissions: Array? + val size = this.permissions?.size ?: 0 + if (size > 0) { + permissions = this.permissions?.toTypedArray() + } else { + permissions = null + } + return getDeniedPermissions(permissions) + } + + constructor(activity: AppCompatActivity) { + source = ActivitySource(activity) + permissions = ArrayList() + } + + constructor(fragment: Fragment) { + source = FragmentSource(fragment) + permissions = ArrayList() + } + + fun addPermissions(vararg permissions: String) { + this.permissions?.addAll(Arrays.asList(*permissions)) + } + + fun setRequestCode(requestCode: Int) { + this.requestCode = requestCode + } + + fun setOnGrantedCallback(callback: OnPermissionsGrantedCallback) { + grantedCallback = callback + } + + fun setOnDeniedCallback(callback: OnPermissionsDeniedCallback) { + deniedCallback = callback + } + + fun setRationale(@StringRes resId: Int) { + rationaleResId = resId + rationale = null + } + + fun setRationale(rationale: CharSequence) { + this.rationale = rationale + rationaleResId = 0 + } + + fun start() { + RequestPlugins.setOnRequestPermissionsCallback(this) + + val deniedPermissions = deniedPermissions + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + if (deniedPermissions == null) { + onPermissionsGranted(requestCode) + } else { + val rationale = if (rationaleResId != 0) source?.context?.getText(rationaleResId) else rationale + if (rationale != null) { + showSettingDialog(rationale) { onPermissionsDenied(requestCode, deniedPermissions) } + } else { + onPermissionsDenied(requestCode, deniedPermissions) + } + } + } else { + if (deniedPermissions != null) { + source?.context?.startActivity( + Pair(PermissionActivity.KEY_INPUT_REQUEST_TYPE, TYPE_REQUEST_PERMISSION), + Pair(PermissionActivity.KEY_INPUT_PERMISSIONS_CODE, requestCode), + Pair(PermissionActivity.KEY_INPUT_PERMISSIONS, deniedPermissions) + ) + } else { + onPermissionsGranted(requestCode) + } + } + + startTime = System.currentTimeMillis() + } + + fun clear() { + grantedCallback = null + deniedCallback = null + } + + private fun getDeniedPermissions(permissions: Array?): Array? { + if (permissions != null) { + val deniedPermissionList = ArrayList() + for (permission in permissions) { + if (source?.context?.let { + ContextCompat.checkSelfPermission( + it, + permission + ) + } != PackageManager.PERMISSION_GRANTED + ) { + deniedPermissionList.add(permission) + } + } + val size = deniedPermissionList.size + if (size > 0) { + return deniedPermissionList.toTypedArray() + } + } + return null + } + + private fun showSettingDialog(rationale: CharSequence, cancel: () -> Unit) { + rationaleDialog?.dismiss() + source?.context?.let { + rationaleDialog = AlertDialog.Builder(it) + .setTitle(R.string.dialog_title) + .setMessage(rationale) + .setPositiveButton(R.string.dialog_setting) { _, _ -> + it.startActivity( + Pair( + PermissionActivity.KEY_INPUT_REQUEST_TYPE, + TYPE_REQUEST_SETTING + ) + ) + } + .setNegativeButton(R.string.dialog_cancel) { _, _ -> cancel() } + .show() + } + } + + private fun onPermissionsGranted(requestCode: Int) { + try { + grantedCallback?.onPermissionsGranted(requestCode) + } catch (ignore: Exception) { + } + + RequestPlugins.sResultCallback?.onPermissionsGranted(requestCode) + } + + private fun onPermissionsDenied(requestCode: Int, deniedPermissions: Array) { + try { + deniedCallback?.onPermissionsDenied(requestCode, deniedPermissions) + } catch (ignore: Exception) { + } + + RequestPlugins.sResultCallback?.onPermissionsDenied(requestCode, deniedPermissions) + } + + override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { + val deniedPermissions = getDeniedPermissions(permissions) + if (deniedPermissions != null) { + val rationale = if (rationaleResId != 0) source?.context?.getText(rationaleResId) else rationale + if (rationale != null) { + showSettingDialog(rationale) { onPermissionsDenied(requestCode, deniedPermissions) } + } else { + onPermissionsDenied(requestCode, deniedPermissions) + } + } else { + onPermissionsGranted(requestCode) + } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + val deniedPermissions = deniedPermissions + if (deniedPermissions == null) { + onPermissionsGranted(this.requestCode) + } else { + onPermissionsDenied(this.requestCode, deniedPermissions) + } + } + + companion object { + const val TYPE_REQUEST_PERMISSION = 1 + const val TYPE_REQUEST_SETTING = 2 + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/help/permission/RequestManager.kt b/app/src/main/java/io/legado/app/help/permission/RequestManager.kt new file mode 100644 index 000000000..e7f0eca52 --- /dev/null +++ b/app/src/main/java/io/legado/app/help/permission/RequestManager.kt @@ -0,0 +1,67 @@ +package io.legado.app.help.permission + +import android.os.Handler +import java.util.* + +internal object RequestManager : OnPermissionsResultCallback { + + private var requests: Stack? = null + private var request: Request? = null + + private val handler = Handler() + + private val requestRunnable = Runnable { + request?.start() + } + + private val isCurrentRequestInvalid: Boolean + get() = request?.let { System.currentTimeMillis() - it.startTime > 5 * 1000L } ?: true + + init { + RequestPlugins.setOnPermissionsResultCallback(this) + } + + fun pushRequest(request: Request?) { + if (request == null) return + + if (requests == null) { + requests = Stack() + } + + requests?.let { + val index = it.indexOf(request) + if (index >= 0) { + val to = it.size - 1 + if (index != to) { + Collections.swap(requests, index, to) + } + } else { + it.push(request) + } + + if (isCurrentRequestInvalid) { + this.request = it.pop() + handler.post(requestRunnable) + } + } + } + + private fun startNextRequest() { + request?.clear() + request = null + + requests?.let { + request = if (it.empty()) null else it.pop() + request?.let { handler.post(requestRunnable) } + } + } + + override fun onPermissionsGranted(requestCode: Int) { + startNextRequest() + } + + override fun onPermissionsDenied(requestCode: Int, deniedPermissions: Array) { + startNextRequest() + } + +} diff --git a/app/src/main/java/io/legado/app/help/permission/RequestPlugins.kt b/app/src/main/java/io/legado/app/help/permission/RequestPlugins.kt new file mode 100644 index 000000000..16370193f --- /dev/null +++ b/app/src/main/java/io/legado/app/help/permission/RequestPlugins.kt @@ -0,0 +1,20 @@ +package io.legado.app.help.permission + +internal object RequestPlugins { + + @Volatile + var sRequestCallback: OnRequestPermissionsResultCallback? = null + + @Volatile + var sResultCallback: OnPermissionsResultCallback? = null + + fun setOnRequestPermissionsCallback(callback: OnRequestPermissionsResultCallback) { + sRequestCallback = callback + } + + fun setOnPermissionsResultCallback(callback: OnPermissionsResultCallback) { + sResultCallback = callback + } + + +} diff --git a/app/src/main/java/io/legado/app/help/permission/RequestSource.kt b/app/src/main/java/io/legado/app/help/permission/RequestSource.kt new file mode 100644 index 000000000..73c89df43 --- /dev/null +++ b/app/src/main/java/io/legado/app/help/permission/RequestSource.kt @@ -0,0 +1,13 @@ +package io.legado.app.help.permission + +import android.content.Context +import android.content.Intent +import androidx.fragment.app.FragmentManager + +interface RequestSource { + + val context: Context? + + fun startActivity(intent: Intent) + +} diff --git a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt index ce40a7e33..10bfe53c3 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt @@ -2,18 +2,32 @@ package io.legado.app.ui.main import android.content.Intent import android.os.Bundle +import android.util.Log import android.view.Menu import android.view.MenuItem import androidx.appcompat.app.ActionBarDrawerToggle import androidx.core.view.GravityCompat import androidx.drawerlayout.widget.DrawerLayout import com.google.android.material.navigation.NavigationView +import com.jayway.jsonpath.Configuration +import com.jayway.jsonpath.JsonPath +import com.jayway.jsonpath.Option +import io.legado.app.App import io.legado.app.R import io.legado.app.base.BaseActivity +import io.legado.app.constant.AppConst.APP_TAG +import io.legado.app.data.entities.ReplaceRule +import io.legado.app.help.permission.Permissions +import io.legado.app.help.permission.PermissionsCompat +import io.legado.app.ui.replacerule.ReplaceRuleActivity import io.legado.app.ui.search.SearchActivity -import io.legado.app.utils.getViewModel +import io.legado.app.utils.* import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.app_bar_main.* +import org.jetbrains.anko.doAsync +import org.jetbrains.anko.startActivity +import org.jetbrains.anko.uiThread +import java.io.File class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedListener { override val viewModel: MainViewModel @@ -26,7 +40,7 @@ class MainActivity : BaseActivity(), NavigationV fab.setOnClickListener { startActivity(Intent(this, SearchActivity::class.java)) } val toggle = ActionBarDrawerToggle( - this, drawer_layout, titleBar.toolbar, + this, drawer_layout, title_bar.toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close ) @@ -58,6 +72,20 @@ class MainActivity : BaseActivity(), NavigationV override fun onNavigationItemSelected(item: MenuItem): Boolean { // Handle navigation view item clicks here. when (item.itemId) { + R.id.nav_backup -> { + // Handle the camera action + } + R.id.nav_import -> { + + } + R.id.nav_import_old -> PermissionsCompat.Builder(this) + .addPermissions(*Permissions.Group.STORAGE) + .rationale(R.string.tip_perm_request_storage) + .onGranted { importYueDu() }.request() + R.id.nav_import_github -> { + + } + R.id.nav_replace_rule -> startActivity() R.id.nav_send -> { } @@ -66,4 +94,50 @@ class MainActivity : BaseActivity(), NavigationV drawerLayout.closeDrawer(GravityCompat.START) return true } + + /* + * import from YueDu backup data + * */ + fun importYueDu() { + val yuedu = File(getSdPath(), "YueDu") + val jsonPath = JsonPath.using( + Configuration.builder() + .options(Option.SUPPRESS_EXCEPTIONS) + .build() + ) + + // Replace rules + val rFile = File(yuedu, "myBookReplaceRule.json") + val replaceRules = mutableListOf() + if (rFile.exists()) try { + val items: List> = jsonPath.parse(rFile.readText()).read("$.*") + for (item in items) { + val jsonItem = jsonPath.parse(item) + val rRule = ReplaceRule() + rRule.name = jsonItem.readString("$.replaceSummary") + rRule.pattern = jsonItem.readString("$.regex") + rRule.replacement = jsonItem.readString("$.replacement") + rRule.isRegex = jsonItem.readBool("$.isRegex") + rRule.scope = jsonItem.readString("$.useTo") + rRule.isEnabled = jsonItem.readBool("$.enable") + rRule.order = jsonItem.readInt("$.serialNumber") + replaceRules.add(rRule) + // Log.e(APP_TAG, rRule.toString()) + } + + doAsync { + App.db.replaceRuleDao().insert(*replaceRules.toTypedArray()) + val count = App.db.replaceRuleDao().all.size + val maxId = App.db.replaceRuleDao().maxOrder + uiThread { + Log.e(APP_TAG, "$count records were inserted to database, and max id is $maxId.") + } + } + + } catch (e: Exception) { + Log.e(APP_TAG, e.localizedMessage) + } + } + + } diff --git a/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt b/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt index 548c22ec5..74226b58c 100644 --- a/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt +++ b/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt @@ -37,7 +37,6 @@ class TitleBar(context: Context, attrs: AttributeSet?) : AppBarLayout(context, a val attachToActivity = a.getBoolean(R.styleable.TitleBar_attachToActivity, true) val titleText = a.getString(R.styleable.TitleBar_title) val subtitleText = a.getString(R.styleable.TitleBar_subtitle) - a.recycle() toolbar.apply { if(showNavigationIcon){ @@ -71,6 +70,7 @@ class TitleBar(context: Context, attrs: AttributeSet?) : AppBarLayout(context, a } } + a.recycle() if (attachToActivity) { attachToActivity(context) diff --git a/app/src/main/res/layout/activity_search.xml b/app/src/main/res/layout/activity_search.xml index 9e2a9e07c..4b23ca3d4 100644 --- a/app/src/main/res/layout/activity_search.xml +++ b/app/src/main/res/layout/activity_search.xml @@ -12,7 +12,7 @@ tools:context="io.legado.app.ui.search.SearchActivity"> + app:layout_constraintTop_toBottomOf="@id/title_bar"> diff --git a/app/src/main/res/layout/app_bar_main.xml b/app/src/main/res/layout/app_bar_main.xml index ae86cf117..5eb482eab 100644 --- a/app/src/main/res/layout/app_bar_main.xml +++ b/app/src/main/res/layout/app_bar_main.xml @@ -8,7 +8,7 @@ tools:context=".ui.main.MainActivity"> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 05315f8a9..29f6c8036 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -15,9 +15,17 @@ Send + 提示 + 取消 + 确定 + 去设置 + + 无法跳转至设置界面 + 阅读需要访问存储卡权限,请前往“设置”—”应用权限“—打开所需权限 + 点击重试 正在加载 - 阅读需要访问存储卡权限: + 编辑 删除 diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 09ffdee29..5e0976fa8 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -1,4 +1,4 @@ - + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 8194c2ece..43af45038 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -7,4 +7,96 @@ #66666666 + #eb4333 + #439b53 + + #00000000 + + @color/md_grey_100 + #dedede + #fcfcfc + #00000000 + + #30000000 + + #d3321b + + #80ACACAC + #80858585 + #88000000 + + #737373 + #adadad + + #de000000 + #b2000000 + #8a000000 + #dfdfdf + #383838 + + + #efefef + + #23000000 + #EEEEEE + #aaaaaaaa + + + #FFD4D4D4 + + #64000000 + #f4f4f4 + + + #99343434 + #000000 + #ffffff + + + + + + #1F000000 + #1F000000 + + #43000000 + #43000000 + #43000000 + + #61000000 + + #8A000000 + #8A000000 + #8A000000 + + #DE000000 + + #FFFAFAFA + + #FFBDBDBD + + #E8E8E8 + + + + #1AFFFFFF + + #1F000000 + + #4DFFFFFF + #4DFFFFFF + #4DFFFFFF + #4DFFFFFF + + #B3FFFFFF + #B3FFFFFF + #B3FFFFFF + + #FFFFFFFF + + #FFBDBDBD + + #FF424242 + + #202020 diff --git a/app/src/main/res/values/colors_material_design.xml b/app/src/main/res/values/colors_material_design.xml new file mode 100644 index 000000000..a00ddac9e --- /dev/null +++ b/app/src/main/res/values/colors_material_design.xml @@ -0,0 +1,338 @@ + + + + + + + @color/md_grey_50 + + #1F000000 + + #61000000 + + #8A000000 + #8A000000 + + #DE000000 + + @color/md_grey_300 + @color/md_grey_100 + @color/md_white_1000 + @color/md_white_1000 + + + @color/md_grey_850 + + #1FFFFFFF + + #4DFFFFFF + + #B3FFFFFF + #B3FFFFFF + + #FFFFFFFF + + @color/md_black_1000 + @color/md_grey_900 + @color/md_grey_800 + @color/md_grey_800 + + + #FFEBEE + #FFCDD2 + #EF9A9A + #E57373 + #EF5350 + #F44336 + #E53935 + #D32F2F + #C62828 + #B71C1C + #FF8A80 + #FF5252 + #FF1744 + #D50000 + + + #FCE4EC + #F8BBD0 + #F48FB1 + #F06292 + #EC407A + #E91E63 + #D81B60 + #C2185B + #AD1457 + #880E4F + #FF80AB + #FF4081 + #F50057 + #C51162 + + + #F3E5F5 + #E1BEE7 + #CE93D8 + #BA68C8 + #AB47BC + #9C27B0 + #8E24AA + #7B1FA2 + #6A1B9A + #4A148C + #EA80FC + #E040FB + #D500F9 + #AA00FF + + + #EDE7F6 + #D1C4E9 + #B39DDB + #9575CD + #7E57C2 + #673AB7 + #5E35B1 + #512DA8 + #4527A0 + #311B92 + #B388FF + #7C4DFF + #651FFF + #6200EA + + + #E8EAF6 + #C5CAE9 + #9FA8DA + #7986CB + #5C6BC0 + #3F51B5 + #3949AB + #303F9F + #283593 + #1A237E + #8C9EFF + #536DFE + #3D5AFE + #304FFE + + + #E3F2FD + #BBDEFB + #90CAF9 + #64B5F6 + #42A5F5 + #2196F3 + #1E88E5 + #1976D2 + #1565C0 + #0D47A1 + #82B1FF + #448AFF + #2979FF + #2962FF + + + #E1F5FE + #B3E5FC + #81D4FA + #4FC3F7 + #29B6F6 + #03A9F4 + #039BE5 + #0288D1 + #0277BD + #01579B + #80D8FF + #40C4FF + #00B0FF + #0091EA + + + #E0F7FA + #B2EBF2 + #80DEEA + #4DD0E1 + #26C6DA + #00BCD4 + #00ACC1 + #0097A7 + #00838F + #006064 + #84FFFF + #18FFFF + #00E5FF + #00B8D4 + + + #E0F2F1 + #B2DFDB + #80CBC4 + #4DB6AC + #26A69A + #009688 + #00897B + #00796B + #00695C + #004D40 + #A7FFEB + #64FFDA + #1DE9B6 + #00BFA5 + + + #E8F5E9 + #C8E6C9 + #A5D6A7 + #81C784 + #66BB6A + #4CAF50 + #43A047 + #388E3C + #2E7D32 + #1B5E20 + #B9F6CA + #69F0AE + #00E676 + #00C853 + + + #F1F8E9 + #DCEDC8 + #C5E1A5 + #AED581 + #9CCC65 + #8BC34A + #7CB342 + #689F38 + #558B2F + #33691E + #CCFF90 + #B2FF59 + #76FF03 + #64DD17 + + + #F9FBE7 + #F0F4C3 + #E6EE9C + #DCE775 + #D4E157 + #CDDC39 + #C0CA33 + #AFB42B + #9E9D24 + #827717 + #F4FF81 + #EEFF41 + #C6FF00 + #AEEA00 + + + #FFFDE7 + #FFF9C4 + #FFF59D + #FFF176 + #FFEE58 + #FFEB3B + #FDD835 + #FBC02D + #F9A825 + #F57F17 + #FFFF8D + #FFFF00 + #FFEA00 + #FFD600 + + + #FFF8E1 + #FFECB3 + #FFE082 + #FFD54F + #FFCA28 + #FFC107 + #FFB300 + #FFA000 + #FF8F00 + #FF6F00 + #FFE57F + #FFD740 + #FFC400 + #FFAB00 + + + #FFF3E0 + #FFE0B2 + #FFCC80 + #FFB74D + #FFA726 + #FF9800 + #FB8C00 + #F57C00 + #EF6C00 + #E65100 + #FFD180 + #FFAB40 + #FF9100 + #FF6D00 + + + #FBE9E7 + #FFCCBC + #FFAB91 + #FF8A65 + #FF7043 + #FF5722 + #F4511E + #E64A19 + #D84315 + #BF360C + #FF9E80 + #FF6E40 + #FF3D00 + #DD2C00 + + + #EFEBE9 + #D7CCC8 + #BCAAA4 + #A1887F + #8D6E63 + #795548 + #6D4C41 + #5D4037 + #4E342E + #3E2723 + + + #FAFAFA + #F5F5F5 + #EEEEEE + #E0E0E0 + #BDBDBD + #9E9E9E + #757575 + #616161 + #424242 + #303030 + #212121 + + + #ECEFF1 + #CFD8DC + #B0BEC5 + #90A4AE + #78909C + #607D8B + #546E7A + #455A64 + #37474F + #263238 + + + #000000 + #FFFFFF + + From 5f2991373b0ef21cabd3d15a53c11700d93b9b86 Mon Sep 17 00:00:00 2001 From: atbest Date: Sun, 26 May 2019 00:06:45 -0400 Subject: [PATCH 0026/1997] Added importing book shelf from YueDu --- .../jsonpath/spi/json/GsonJsonProvider.java | 4 +- .../java/io/legado/app/data/dao/BookDao.kt | 11 +++ .../java/io/legado/app/data/entities/Book.kt | 4 +- .../io/legado/app/ui/main/MainActivity.kt | 92 +++++++++++++++---- .../app/ui/replacerule/ReplaceRuleActivity.kt | 14 ++- .../app/ui/replacerule/ReplaceRuleAdapter.kt | 14 +-- .../io/legado/app/utils/MiscExtensions.kt | 5 +- app/src/main/res/drawable/ic_divider.xml | 6 ++ .../main/res/layout/activity_replace_rule.xml | 4 +- app/src/main/res/layout/item_relace_rule.xml | 12 +-- 10 files changed, 128 insertions(+), 38 deletions(-) create mode 100644 app/src/main/res/drawable/ic_divider.xml diff --git a/app/src/main/java/com/jayway/jsonpath/spi/json/GsonJsonProvider.java b/app/src/main/java/com/jayway/jsonpath/spi/json/GsonJsonProvider.java index 0828b2951..ab0ffc9ae 100644 --- a/app/src/main/java/com/jayway/jsonpath/spi/json/GsonJsonProvider.java +++ b/app/src/main/java/com/jayway/jsonpath/spi/json/GsonJsonProvider.java @@ -247,8 +247,8 @@ public class GsonJsonProvider extends AbstractJsonProvider { } } - throw new JsonPathException("length operation can not applied to " + obj != null ? obj.getClass().getName() - : "null"); + throw new JsonPathException("length operation can not applied to " + (obj != null ? obj.getClass().getName() + : "null")); } @Override diff --git a/app/src/main/java/io/legado/app/data/dao/BookDao.kt b/app/src/main/java/io/legado/app/data/dao/BookDao.kt index aae85f47f..0ea2baac1 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookDao.kt @@ -3,6 +3,8 @@ package io.legado.app.data.dao import androidx.lifecycle.LiveData import androidx.paging.DataSource import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy import androidx.room.Query import io.legado.app.data.entities.Book @@ -19,4 +21,13 @@ interface BookDao { @Query("SELECT * FROM books WHERE `name` in (:names)") fun findByName(vararg names: String): List + @get:Query("SELECT descUrl FROM books") + val allBookUrls: List + + @get:Query("SELECT COUNT(*) FROM books") + val allBookCount: Int + + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun insert(vararg books: Book) + } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/data/entities/Book.kt b/app/src/main/java/io/legado/app/data/entities/Book.kt index 1efd170c3..c883ff956 100644 --- a/app/src/main/java/io/legado/app/data/entities/Book.kt +++ b/app/src/main/java/io/legado/app/data/entities/Book.kt @@ -30,11 +30,13 @@ data class Book(@PrimaryKey var lastCheckTime: Long = 0, // 最近一次更新书籍信息的时间 var lastCheckCount: Int = 0, // 最近一次发现新章节的数量 var totalChapterNum: Int = 0, // 书籍目录总数 - var durChapterTitle: String? = null, // 当前章节名称 + var durChapterTitle: String? = null, // 当前章节名称 var durChapterIndex: Int = 0, // 当前章节索引 var durChapterPos: Int = 0, // 当前阅读的进度(首行字符的索引位置) var durChapterTime: Long = 0, // 最近一次阅读书籍的时间(打开正文的时间) var canUpdate: Boolean = true, // 刷新书架时更新书籍信息 + var order: Int = 0, // 手动排序 + var useReplaceRule: Boolean = true, // 正文使用净化替换规则 var variable: String? = null // 自定义书籍变量信息(用于书源规则检索书籍信息) ) : Parcelable { diff --git a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt index f6fb83294..46cb0096b 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt @@ -16,6 +16,7 @@ import io.legado.app.App import io.legado.app.R import io.legado.app.base.BaseActivity import io.legado.app.constant.AppConst.APP_TAG +import io.legado.app.data.entities.Book import io.legado.app.data.entities.ReplaceRule import io.legado.app.help.permission.Permissions import io.legado.app.help.permission.PermissionsCompat @@ -107,30 +108,85 @@ class MainActivity : BaseActivity(), NavigationV .build() ) - // Replace rules - val rFile = File(yuedu, "myBookReplaceRule.json") - val replaceRules = mutableListOf() - if (rFile.exists()) try { - val items: List> = jsonPath.parse(rFile.readText()).read("$.*") - for (item in items) { - val jsonItem = jsonPath.parse(item) - val rRule = ReplaceRule() - rRule.name = jsonItem.readString("$.replaceSummary") - rRule.pattern = jsonItem.readString("$.regex") - rRule.replacement = jsonItem.readString("$.replacement") - rRule.isRegex = jsonItem.readBool("$.isRegex") - rRule.scope = jsonItem.readString("$.useTo") - rRule.isEnabled = jsonItem.readBool("$.enable") - rRule.order = jsonItem.readInt("$.serialNumber") - replaceRules.add(rRule) + // 导入书架 + val shelfFile = File(yuedu, "myBookShelf.json") + val books = mutableListOf() + if (shelfFile.exists()) try { + doAsync { + val items: List> = jsonPath.parse(shelfFile.readText()).read("$") + val existingBooks = App.db.bookDao().allBookUrls.toSet() + for (item in items) { + val jsonItem = jsonPath.parse(item) + val book = Book() + book.descUrl = jsonItem.readString("$.noteUrl") ?: "" + if (book.descUrl.isBlank()) continue + book.name = jsonItem.readString("$.bookInfoBean.name") + if (book.descUrl in existingBooks) { + Log.d(APP_TAG, "Found existing book: ${book.name}") + continue + } + book.author = jsonItem.readString("$.bookInfoBean.author") + book.type = if (jsonItem.readString("$.bookInfoBean.bookSourceType") == "AUDIO") 1 else 0 + book.tocUrl = jsonItem.readString("$.bookInfoBean.chapterUrl") ?: book.descUrl + book.coverUrl = jsonItem.readString("$.bookInfoBean.coverUrl") + book.customCoverUrl = jsonItem.readString("$.customCoverPath") + book.lastCheckTime = jsonItem.readLong("$.bookInfoBean.finalRefreshData") ?: 0 + book.canUpdate = jsonItem.readBool("$.allowUpdate") == true + book.totalChapterNum = jsonItem.readInt("$.chapterListSize") ?: 0 + book.durChapterIndex = jsonItem.readInt("$.durChapter") ?: 0 + book.durChapterTitle = jsonItem.readString("$.durChapterName") + book.durChapterPos = jsonItem.readInt("$.durChapterPage") ?: 0 + book.durChapterTime = jsonItem.readLong("$.finalDate") ?: 0 + book.group = jsonItem.readInt("$.group") ?: 0 + // book. = jsonItem.readString("$.hasUpdate") + // book. = jsonItem.readString("$.isLoading") + book.latestChapterTitle = jsonItem.readString("$.lastChapterName") + book.lastCheckCount = jsonItem.readInt("$.newChapters") ?: 0 + book.order = jsonItem.readInt("$.serialNumber") ?: 0 + book.useReplaceRule = jsonItem.readBool("$.useReplaceRule") == true + book.variable = jsonItem.readString("$.variable") + books.add(book) + Log.d(APP_TAG, "Added ${book.name}") + } + App.db.bookDao().insert(*books.toTypedArray()) + val count = books.size + + uiThread { + toast(if (count > 0) "成功地导入 $count 本新书和音频" else "没有发现新书或音频") + } + } + } catch (e: Exception) { + Log.e(APP_TAG, "Failed to import book shelf.", e) + toast("Unable to import books:\n${e.localizedMessage}") + } + + // Replace rules + val ruleFile = File(yuedu, "myBookReplaceRule.json") + val replaceRules = mutableListOf() + if (ruleFile.exists()) try { doAsync { + val items: List> = jsonPath.parse(ruleFile.readText()).read("$") + val existingRules = App.db.replaceRuleDao().all.map { it.pattern }.toSet() + for (item in items) { + val jsonItem = jsonPath.parse(item) + val rRule = ReplaceRule() + rRule.pattern = jsonItem.readString("$.regex") + if (rRule.pattern.isNullOrEmpty() || rRule.pattern in existingRules) continue + rRule.name = jsonItem.readString("$.replaceSummary") + rRule.replacement = jsonItem.readString("$.replacement") + rRule.isRegex = jsonItem.readBool("$.isRegex") == true + rRule.scope = jsonItem.readString("$.useTo") + rRule.isEnabled = jsonItem.readBool("$.enable") == true + rRule.order = jsonItem.readInt("$.serialNumber") ?: 0 + replaceRules.add(rRule) + } App.db.replaceRuleDao().insert(*replaceRules.toTypedArray()) - val count = items.size + val count = replaceRules.size val maxId = App.db.replaceRuleDao().maxOrder uiThread { - toast("成功地导入 $count 条净化替换规则") + toast(if (count > 0) "成功地导入 $count 条净化替换规则" else "没有发现新的净化替换规则") } } diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt index 8f6077c96..5d0ebadc6 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt @@ -1,11 +1,14 @@ package io.legado.app.ui.replacerule import android.os.Bundle +import android.util.Log import androidx.appcompat.app.AppCompatActivity +import androidx.core.content.ContextCompat import androidx.lifecycle.LiveData import androidx.lifecycle.Observer import androidx.paging.LivePagedListBuilder import androidx.paging.PagedList +import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.App import io.legado.app.R @@ -15,6 +18,8 @@ import org.jetbrains.anko.doAsync import org.jetbrains.anko.toast import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.ItemTouchHelper +import io.legado.app.constant.AppConst.APP_TAG +import kotlinx.android.synthetic.main.item_relace_rule.* class ReplaceRuleActivity : AppCompatActivity() { @@ -25,7 +30,6 @@ class ReplaceRuleActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_replace_rule) - rv_replace_rule.layoutManager = LinearLayoutManager(this) initRecyclerView() initDataObservers() initSwipeToDelete() @@ -57,6 +61,12 @@ class ReplaceRuleActivity : AppCompatActivity() { } } rv_replace_rule.adapter = adapter + rv_replace_rule.addItemDecoration( + DividerItemDecoration(this, DividerItemDecoration.VERTICAL).apply { + ContextCompat.getDrawable(baseContext, R.drawable.ic_divider)?.let { + Log.e(APP_TAG, it.toString()) + this.setDrawable(it) } + }) } private fun initDataObservers() { @@ -90,7 +100,7 @@ class ReplaceRuleActivity : AppCompatActivity() { override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { toast("You swiped the item!") - TODO() + // TODO() // remove((viewHolder as TodoViewHolder).todo) } }).attachToRecyclerView(rv_replace_rule) diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt index a767cee52..d9befdd97 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt @@ -1,6 +1,7 @@ package io.legado.app.ui.replacerule import android.content.Context +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -9,6 +10,7 @@ import androidx.paging.PagedListAdapter import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import io.legado.app.R +import io.legado.app.constant.AppConst.APP_TAG import io.legado.app.data.entities.ReplaceRule import kotlinx.android.synthetic.main.item_relace_rule.view.* import org.jetbrains.anko.sdk27.listeners.onClick @@ -45,16 +47,16 @@ class ReplaceRuleAdapter(context: Context) : } override fun onBindViewHolder(holder: MyViewHolder, pos: Int) { - getItem(pos)?.let { holder.bind(it, onClickListener, pos == itemCount - 1) } + getItem(pos)?.let { holder.bind(it, onClickListener) } } class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { - fun bind(rule: ReplaceRule, listener: OnClickListener?, hideDivider: Boolean) = with(itemView) { + fun bind(rule: ReplaceRule, listener: OnClickListener?) = with(itemView) { tv_name.text = rule.name - swt_enabled.isChecked = rule.isEnabled - divider.isGone = hideDivider - iv_delete.isGone = true - iv_edit.isGone = true + swt_enabled.isChecked = rule.isEnabled + // divider.isGone = hideDivider + iv_delete.isGone = true + iv_edit.isGone = true // iv_delete.onClick { listener?.delete(rule) } // iv_edit.onClick { listener?.edit(rule) } swt_enabled.onClick { diff --git a/app/src/main/java/io/legado/app/utils/MiscExtensions.kt b/app/src/main/java/io/legado/app/utils/MiscExtensions.kt index 1f47d2af9..84665cd8c 100644 --- a/app/src/main/java/io/legado/app/utils/MiscExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/MiscExtensions.kt @@ -6,4 +6,7 @@ fun ReadContext.readString(path: String): String? = this.read(path, String::clas fun ReadContext.readBool(path: String): Boolean? = this.read(path, Boolean::class.java) -fun ReadContext.readInt(path: String): Int? = this.read(path, Int::class.java) \ No newline at end of file +fun ReadContext.readInt(path: String): Int? = this.read(path, Int::class.java) + +fun ReadContext.readLong(path: String): Long? = this.read(path, Long::class.java) + diff --git a/app/src/main/res/drawable/ic_divider.xml b/app/src/main/res/drawable/ic_divider.xml new file mode 100644 index 000000000..7515c3960 --- /dev/null +++ b/app/src/main/res/drawable/ic_divider.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/app/src/main/res/layout/activity_replace_rule.xml b/app/src/main/res/layout/activity_replace_rule.xml index d2d3d92e8..c16af5b11 100644 --- a/app/src/main/res/layout/activity_replace_rule.xml +++ b/app/src/main/res/layout/activity_replace_rule.xml @@ -18,8 +18,8 @@ android:id="@+id/rv_replace_rule" android:layout_width="match_parent" android:layout_height="match_parent" - android:paddingStart="8dp" - android:paddingEnd="8dp" + android:paddingStart="16dp" + android:paddingEnd="16dp" android:layout_marginBottom="8dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" diff --git a/app/src/main/res/layout/item_relace_rule.xml b/app/src/main/res/layout/item_relace_rule.xml index c739121b9..34e28b5c9 100644 --- a/app/src/main/res/layout/item_relace_rule.xml +++ b/app/src/main/res/layout/item_relace_rule.xml @@ -4,9 +4,7 @@ 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:paddingStart="8dp" - android:paddingEnd="8dp"> + android:layout_height="wrap_content"> - + From b06e6cd831ed8598576726f7db8c02dd7dcb31e5 Mon Sep 17 00:00:00 2001 From: atbest Date: Sun, 26 May 2019 00:41:22 -0400 Subject: [PATCH 0027/1997] Created backup and restore objects --- .../java/io/legado/app/help/storage/Backup.kt | 12 ++ .../io/legado/app/help/storage/Restore.kt | 121 ++++++++++++++++ .../app/lib/theme/ThemeStorePrefKeys.java | 2 +- .../io/legado/app/ui/main/MainActivity.kt | 133 ++---------------- .../main/res/menu/activity_main_drawer.xml | 2 +- 5 files changed, 146 insertions(+), 124 deletions(-) create mode 100644 app/src/main/java/io/legado/app/help/storage/Backup.kt create mode 100644 app/src/main/java/io/legado/app/help/storage/Restore.kt diff --git a/app/src/main/java/io/legado/app/help/storage/Backup.kt b/app/src/main/java/io/legado/app/help/storage/Backup.kt new file mode 100644 index 000000000..0f55ac786 --- /dev/null +++ b/app/src/main/java/io/legado/app/help/storage/Backup.kt @@ -0,0 +1,12 @@ +package io.legado.app.help.storage + +object Backup { + + fun backup() { + + } + + fun autoBackup() { + + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/help/storage/Restore.kt b/app/src/main/java/io/legado/app/help/storage/Restore.kt new file mode 100644 index 000000000..aafb71f5c --- /dev/null +++ b/app/src/main/java/io/legado/app/help/storage/Restore.kt @@ -0,0 +1,121 @@ +package io.legado.app.help.storage + +import android.content.Context +import android.util.Log +import com.jayway.jsonpath.Configuration +import com.jayway.jsonpath.JsonPath +import com.jayway.jsonpath.Option +import io.legado.app.App +import io.legado.app.constant.AppConst +import io.legado.app.data.entities.Book +import io.legado.app.data.entities.ReplaceRule +import io.legado.app.utils.* +import org.jetbrains.anko.doAsync +import org.jetbrains.anko.toast +import org.jetbrains.anko.uiThread +import java.io.File + +object Restore { + + fun restore() { + + } + + fun importFromGithub() { + + } + + fun importYueDuData(context: Context) { + val yuedu = File(getSdPath(), "YueDu") + val jsonPath = JsonPath.using( + Configuration.builder() + .options(Option.SUPPRESS_EXCEPTIONS) + .build() + ) + + // 导入书架 + val shelfFile = File(yuedu, "myBookShelf.json") + val books = mutableListOf() + if (shelfFile.exists()) try { + doAsync { + val items: List> = jsonPath.parse(shelfFile.readText()).read("$") + val existingBooks = App.db.bookDao().allBookUrls.toSet() + for (item in items) { + val jsonItem = jsonPath.parse(item) + val book = Book() + book.descUrl = jsonItem.readString("$.noteUrl") ?: "" + if (book.descUrl.isBlank()) continue + book.name = jsonItem.readString("$.bookInfoBean.name") + if (book.descUrl in existingBooks) { + Log.d(AppConst.APP_TAG, "Found existing book: ${book.name}") + continue + } + book.author = jsonItem.readString("$.bookInfoBean.author") + book.type = if (jsonItem.readString("$.bookInfoBean.bookSourceType") == "AUDIO") 1 else 0 + book.tocUrl = jsonItem.readString("$.bookInfoBean.chapterUrl") ?: book.descUrl + book.coverUrl = jsonItem.readString("$.bookInfoBean.coverUrl") + book.customCoverUrl = jsonItem.readString("$.customCoverPath") + book.lastCheckTime = jsonItem.readLong("$.bookInfoBean.finalRefreshData") ?: 0 + book.canUpdate = jsonItem.readBool("$.allowUpdate") == true + book.totalChapterNum = jsonItem.readInt("$.chapterListSize") ?: 0 + book.durChapterIndex = jsonItem.readInt("$.durChapter") ?: 0 + book.durChapterTitle = jsonItem.readString("$.durChapterName") + book.durChapterPos = jsonItem.readInt("$.durChapterPage") ?: 0 + book.durChapterTime = jsonItem.readLong("$.finalDate") ?: 0 + book.group = jsonItem.readInt("$.group") ?: 0 + // book. = jsonItem.readString("$.hasUpdate") + // book. = jsonItem.readString("$.isLoading") + book.latestChapterTitle = jsonItem.readString("$.lastChapterName") + book.lastCheckCount = jsonItem.readInt("$.newChapters") ?: 0 + book.order = jsonItem.readInt("$.serialNumber") ?: 0 + book.useReplaceRule = jsonItem.readBool("$.useReplaceRule") == true + book.variable = jsonItem.readString("$.variable") + books.add(book) + Log.d(AppConst.APP_TAG, "Added ${book.name}") + } + App.db.bookDao().insert(*books.toTypedArray()) + val count = books.size + + uiThread { + context.toast(if (count > 0) "成功地导入 $count 本新书和音频" else "没有发现新书或音频") + } + + } + + } catch (e: Exception) { + Log.e(AppConst.APP_TAG, "Failed to import book shelf.", e) + context.toast("Unable to import books:\n${e.localizedMessage}") + } + + // Replace rules + val ruleFile = File(yuedu, "myBookReplaceRule.json") + val replaceRules = mutableListOf() + if (ruleFile.exists()) try { + doAsync { + val items: List> = jsonPath.parse(ruleFile.readText()).read("$") + val existingRules = App.db.replaceRuleDao().all.map { it.pattern }.toSet() + for (item in items) { + val jsonItem = jsonPath.parse(item) + val rule = ReplaceRule() + rule.pattern = jsonItem.readString("$.regex") + if (rule.pattern.isNullOrEmpty() || rule.pattern in existingRules) continue + rule.name = jsonItem.readString("$.replaceSummary") + rule.replacement = jsonItem.readString("$.replacement") + rule.isRegex = jsonItem.readBool("$.isRegex") == true + rule.scope = jsonItem.readString("$.useTo") + rule.isEnabled = jsonItem.readBool("$.enable") == true + rule.order = jsonItem.readInt("$.serialNumber") ?: 0 + replaceRules.add(rule) + } + App.db.replaceRuleDao().insert(*replaceRules.toTypedArray()) + val count = replaceRules.size + uiThread { + context.toast(if (count > 0) "成功地导入 $count 条净化替换规则" else "没有发现新的净化替换规则") + } + } + + } catch (e: Exception) { + Log.e(AppConst.APP_TAG, e.localizedMessage) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/lib/theme/ThemeStorePrefKeys.java b/app/src/main/java/io/legado/app/lib/theme/ThemeStorePrefKeys.java index 9a8286f9e..dc09388cc 100644 --- a/app/src/main/java/io/legado/app/lib/theme/ThemeStorePrefKeys.java +++ b/app/src/main/java/io/legado/app/lib/theme/ThemeStorePrefKeys.java @@ -5,7 +5,7 @@ package io.legado.app.lib.theme; */ interface ThemeStorePrefKeys { - String CONFIG_PREFS_KEY_DEFAULT = "[[kabouzeid_app-theme-helper]]"; + String CONFIG_PREFS_KEY_DEFAULT = "app_themes"; String IS_CONFIGURED_KEY = "is_configured"; String IS_CONFIGURED_VERSION_KEY = "is_configured_version"; String VALUES_CHANGED = "values_changed"; diff --git a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt index 46cb0096b..8e9de7e29 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt @@ -2,34 +2,24 @@ package io.legado.app.ui.main import android.content.Intent import android.os.Bundle -import android.util.Log import android.view.Menu import android.view.MenuItem import androidx.appcompat.app.ActionBarDrawerToggle import androidx.core.view.GravityCompat import androidx.drawerlayout.widget.DrawerLayout import com.google.android.material.navigation.NavigationView -import com.jayway.jsonpath.Configuration -import com.jayway.jsonpath.JsonPath -import com.jayway.jsonpath.Option -import io.legado.app.App import io.legado.app.R import io.legado.app.base.BaseActivity -import io.legado.app.constant.AppConst.APP_TAG -import io.legado.app.data.entities.Book -import io.legado.app.data.entities.ReplaceRule import io.legado.app.help.permission.Permissions import io.legado.app.help.permission.PermissionsCompat +import io.legado.app.help.storage.Backup +import io.legado.app.help.storage.Restore import io.legado.app.ui.replacerule.ReplaceRuleActivity import io.legado.app.ui.search.SearchActivity import io.legado.app.utils.* import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.app_bar_main.* -import org.jetbrains.anko.doAsync import org.jetbrains.anko.startActivity -import org.jetbrains.anko.toast -import org.jetbrains.anko.uiThread -import java.io.File class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedListener { override val viewModel: MainViewModel @@ -74,19 +64,10 @@ class MainActivity : BaseActivity(), NavigationV override fun onNavigationItemSelected(item: MenuItem): Boolean { // Handle navigation view item clicks here. when (item.itemId) { - R.id.nav_backup -> { - // Handle the camera action - } - R.id.nav_import -> { - - } - R.id.nav_import_old -> PermissionsCompat.Builder(this) - .addPermissions(*Permissions.Group.STORAGE) - .rationale(R.string.tip_perm_request_storage) - .onGranted { importYueDu() }.request() - R.id.nav_import_github -> { - - } + R.id.nav_backup -> Backup.backup() + R.id.nav_restore -> Restore.restore() + R.id.nav_import_old -> importYueDu() + R.id.nav_import_github -> Restore.importFromGithub() R.id.nav_replace_rule -> startActivity() R.id.nav_send -> { @@ -97,103 +78,11 @@ class MainActivity : BaseActivity(), NavigationV return true } - /* - * import from YueDu backup data - * */ - fun importYueDu() { - val yuedu = File(getSdPath(), "YueDu") - val jsonPath = JsonPath.using( - Configuration.builder() - .options(Option.SUPPRESS_EXCEPTIONS) - .build() - ) - - // 导入书架 - val shelfFile = File(yuedu, "myBookShelf.json") - val books = mutableListOf() - if (shelfFile.exists()) try { - doAsync { - val items: List> = jsonPath.parse(shelfFile.readText()).read("$") - val existingBooks = App.db.bookDao().allBookUrls.toSet() - for (item in items) { - val jsonItem = jsonPath.parse(item) - val book = Book() - book.descUrl = jsonItem.readString("$.noteUrl") ?: "" - if (book.descUrl.isBlank()) continue - book.name = jsonItem.readString("$.bookInfoBean.name") - if (book.descUrl in existingBooks) { - Log.d(APP_TAG, "Found existing book: ${book.name}") - continue - } - book.author = jsonItem.readString("$.bookInfoBean.author") - book.type = if (jsonItem.readString("$.bookInfoBean.bookSourceType") == "AUDIO") 1 else 0 - book.tocUrl = jsonItem.readString("$.bookInfoBean.chapterUrl") ?: book.descUrl - book.coverUrl = jsonItem.readString("$.bookInfoBean.coverUrl") - book.customCoverUrl = jsonItem.readString("$.customCoverPath") - book.lastCheckTime = jsonItem.readLong("$.bookInfoBean.finalRefreshData") ?: 0 - book.canUpdate = jsonItem.readBool("$.allowUpdate") == true - book.totalChapterNum = jsonItem.readInt("$.chapterListSize") ?: 0 - book.durChapterIndex = jsonItem.readInt("$.durChapter") ?: 0 - book.durChapterTitle = jsonItem.readString("$.durChapterName") - book.durChapterPos = jsonItem.readInt("$.durChapterPage") ?: 0 - book.durChapterTime = jsonItem.readLong("$.finalDate") ?: 0 - book.group = jsonItem.readInt("$.group") ?: 0 - // book. = jsonItem.readString("$.hasUpdate") - // book. = jsonItem.readString("$.isLoading") - book.latestChapterTitle = jsonItem.readString("$.lastChapterName") - book.lastCheckCount = jsonItem.readInt("$.newChapters") ?: 0 - book.order = jsonItem.readInt("$.serialNumber") ?: 0 - book.useReplaceRule = jsonItem.readBool("$.useReplaceRule") == true - book.variable = jsonItem.readString("$.variable") - books.add(book) - Log.d(APP_TAG, "Added ${book.name}") - } - App.db.bookDao().insert(*books.toTypedArray()) - val count = books.size - - uiThread { - toast(if (count > 0) "成功地导入 $count 本新书和音频" else "没有发现新书或音频") - } - - } - - } catch (e: Exception) { - Log.e(APP_TAG, "Failed to import book shelf.", e) - toast("Unable to import books:\n${e.localizedMessage}") - } - - // Replace rules - val ruleFile = File(yuedu, "myBookReplaceRule.json") - val replaceRules = mutableListOf() - if (ruleFile.exists()) try { - doAsync { - val items: List> = jsonPath.parse(ruleFile.readText()).read("$") - val existingRules = App.db.replaceRuleDao().all.map { it.pattern }.toSet() - for (item in items) { - val jsonItem = jsonPath.parse(item) - val rRule = ReplaceRule() - rRule.pattern = jsonItem.readString("$.regex") - if (rRule.pattern.isNullOrEmpty() || rRule.pattern in existingRules) continue - rRule.name = jsonItem.readString("$.replaceSummary") - rRule.replacement = jsonItem.readString("$.replacement") - rRule.isRegex = jsonItem.readBool("$.isRegex") == true - rRule.scope = jsonItem.readString("$.useTo") - rRule.isEnabled = jsonItem.readBool("$.enable") == true - rRule.order = jsonItem.readInt("$.serialNumber") ?: 0 - replaceRules.add(rRule) - } - App.db.replaceRuleDao().insert(*replaceRules.toTypedArray()) - val count = replaceRules.size - val maxId = App.db.replaceRuleDao().maxOrder - uiThread { - toast(if (count > 0) "成功地导入 $count 条净化替换规则" else "没有发现新的净化替换规则") - } - } - - } catch (e: Exception) { - Log.e(APP_TAG, e.localizedMessage) - } + private fun importYueDu() { + PermissionsCompat.Builder(this) + .addPermissions(*Permissions.Group.STORAGE) + .rationale(R.string.tip_perm_request_storage) + .onGranted { Restore.importYueDuData(this) }.request() } - } diff --git a/app/src/main/res/menu/activity_main_drawer.xml b/app/src/main/res/menu/activity_main_drawer.xml index 665919c41..7aa2f3126 100644 --- a/app/src/main/res/menu/activity_main_drawer.xml +++ b/app/src/main/res/menu/activity_main_drawer.xml @@ -9,7 +9,7 @@ android:icon="@drawable/ic_menu_camera" android:title="@string/menu_backup"/> Date: Wed, 29 May 2019 11:17:23 +0800 Subject: [PATCH 0028/1997] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 6 ------ .../io/legado/app/help/permission/Request.kt | 16 ++++------------ .../io/legado/app/ui/search/SearchActivity.kt | 1 - 3 files changed, 4 insertions(+), 19 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index f1c81febc..c3d0fa13c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -41,12 +41,6 @@ kapt { } } -kotlin{ - experimental{ - coroutines "enable" - } -} - dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" diff --git a/app/src/main/java/io/legado/app/help/permission/Request.kt b/app/src/main/java/io/legado/app/help/permission/Request.kt index c5d389fa6..60db12240 100644 --- a/app/src/main/java/io/legado/app/help/permission/Request.kt +++ b/app/src/main/java/io/legado/app/help/permission/Request.kt @@ -14,8 +14,7 @@ import java.util.* internal class Request : OnRequestPermissionsResultCallback { - var startTime: Long = 0 - private set + val startTime: Long private var requestCode: Int = 0 private var source: RequestSource? = null private var permissions: ArrayList? = null @@ -28,22 +27,17 @@ internal class Request : OnRequestPermissionsResultCallback { private val deniedPermissions: Array? get() { - val permissions: Array? - val size = this.permissions?.size ?: 0 - if (size > 0) { - permissions = this.permissions?.toTypedArray() - } else { - permissions = null - } - return getDeniedPermissions(permissions) + return getDeniedPermissions(this.permissions?.toTypedArray()) } constructor(activity: AppCompatActivity) { + startTime = System.currentTimeMillis() source = ActivitySource(activity) permissions = ArrayList() } constructor(fragment: Fragment) { + startTime = System.currentTimeMillis() source = FragmentSource(fragment) permissions = ArrayList() } @@ -101,8 +95,6 @@ internal class Request : OnRequestPermissionsResultCallback { onPermissionsGranted(requestCode) } } - - startTime = System.currentTimeMillis() } fun clear() { diff --git a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt index c58c611a9..95f4c3be9 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt @@ -17,7 +17,6 @@ class SearchActivity : BaseActivity() { override fun onViewModelCreated(viewModel: SearchViewModel, savedInstanceState: Bundle?) { - startActivity() } } From 9720622da8a0cea0e7d1908b959eb07d72fa4fa2 Mon Sep 17 00:00:00 2001 From: GKF Date: Wed, 29 May 2019 14:15:16 +0800 Subject: [PATCH 0029/1997] =?UTF-8?q?=E4=BF=AE=E6=94=B9Rule?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/io/legado/app/App.kt | 82 +++++ app/src/main/res/values/strings.xml | 437 +++++++++++++++++++++++++ 2 files changed, 519 insertions(+) diff --git a/app/src/main/java/io/legado/app/App.kt b/app/src/main/java/io/legado/app/App.kt index 6ef0e877d..e62d513bc 100644 --- a/app/src/main/java/io/legado/app/App.kt +++ b/app/src/main/java/io/legado/app/App.kt @@ -1,7 +1,20 @@ package io.legado.app import android.app.Application +import android.app.NotificationChannel +import android.app.NotificationManager +import android.content.Context +import android.os.Build +import androidx.annotation.RequiresApi +import androidx.appcompat.app.AppCompatDelegate +import io.legado.app.constant.AppConst.channelIdDownload +import io.legado.app.constant.AppConst.channelIdReadAloud +import io.legado.app.constant.AppConst.channelIdWeb import io.legado.app.data.AppDatabase +import io.legado.app.lib.theme.ThemeStore +import io.legado.app.utils.getPrefBoolean +import io.legado.app.utils.getPrefInt +import java.util.* class App : Application() { @@ -19,5 +32,74 @@ class App : Application() { super.onCreate() INSTANCE = this db = AppDatabase.createDatabase(INSTANCE) + initNightTheme() + upThemeStore() + } + + fun initNightTheme() { + if (getPrefBoolean("isNightTheme", false)) { + AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES) + } else { + AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) + } + } + + fun upThemeStore() { + if (getPrefBoolean("isNightTheme", false)) { + ThemeStore.editTheme(this) + .primaryColor(getPrefInt("colorPrimaryNight", resources.getColor(R.color.md_grey_800))) + .accentColor(getPrefInt("colorAccentNight", resources.getColor(R.color.md_pink_800))) + .backgroundColor(getPrefInt("colorBackgroundNight", resources.getColor(R.color.md_grey_800))) + .apply() + } else { + ThemeStore.editTheme(this) + .primaryColor(getPrefInt("colorPrimary", resources.getColor(R.color.md_grey_100))) + .accentColor(getPrefInt("colorAccent", resources.getColor(R.color.md_pink_600))) + .backgroundColor(getPrefInt("colorBackground", resources.getColor(R.color.md_grey_100))) + .apply() + } + } + + /** + * 创建通知ID + */ + @RequiresApi(Build.VERSION_CODES.O) + private fun createChannelId() { + val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + //用唯一的ID创建渠道对象 + val downloadChannel = NotificationChannel( + channelIdDownload, + getString(R.string.download_offline), + NotificationManager.IMPORTANCE_LOW + ) + //初始化channel + downloadChannel.enableLights(false) + downloadChannel.enableVibration(false) + downloadChannel.setSound(null, null) + + //用唯一的ID创建渠道对象 + val readAloudChannel = NotificationChannel( + channelIdReadAloud, + getString(R.string.read_aloud), + NotificationManager.IMPORTANCE_LOW + ) + //初始化channel + readAloudChannel.enableLights(false) + readAloudChannel.enableVibration(false) + readAloudChannel.setSound(null, null) + + //用唯一的ID创建渠道对象 + val webChannel = NotificationChannel( + channelIdWeb, + getString(R.string.web_service), + NotificationManager.IMPORTANCE_LOW + ) + //初始化channel + webChannel.enableLights(false) + webChannel.enableVibration(false) + webChannel.setSound(null, null) + + //向notification manager 提交channel + notificationManager.createNotificationChannels(Arrays.asList(downloadChannel, readAloudChannel, webChannel)) } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 104e439e4..aaf582f1a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -31,4 +31,441 @@ 净化替换 暂无 启用 + + 书架 + 最后阅读 + 让阅读成为一种习惯。 + 更新日志 + 阅读·搜索 + 书架还空着,先去添加吧! + 搜索 + 下载任务 + 列表视图 + 网格视图 + 列表/网格 + 书城 + 添加本地 + 书源管理 + 设置 + 主题设置 + 关于 + 捐赠 + 退出 + 还未保存,是否继续编辑 + 阅读样式设置 + + 本地 + 搜索 + 没有网络 + 网络连接超时 + 数据解析失败 + 来源: %s + 最近: %s + 书名 + 最新: %s + 是否将《%s》放入书架? + 共%s个Text文件 + 加载中… + 获取数据失败! + 重试 + web服务 + web编辑书源 + http://%s:%d + 离线下载 + 离线下载 + 下载选择的章节到本地 + 换源 + + \u3000\u3000这是一款开源的阅读软件,你可以fork我们的代码自己编译APK。欢迎提交代码帮助改善应用。\n\u3000\u3000公众号[开源阅读软件]! + + Version %s + 自动刷新 + 打开软件时自动更新书籍 + 自动下载最新章节 + 更新书籍时自动下载最新章节 + 备份 + 恢复 + 备份请给与存储权限 + 恢复请给与存储权限 + 确认 + 取消 + 确认备份吗? + 新备份会替换原有备份。\n备份文件夹YueDu + 确认恢复吗? + 恢复书架会覆盖现有书架。 + 备份成功 + 备份失败 + 正在恢复 + 恢复成功 + 恢复失败 + 屏幕方向 + 跟随传感器 + 横向 + 竖向 + 跟随系统 + 免责声明 + 共%d章 + 界面 + 亮度 + 目录 + 下一章 + 上一章 + 隐藏状态栏 + 阅读界面隐藏状态栏 + 阅读行数调整 + 阅读行数减一行,如阅读界面显示不全可启用 + 朗读 + 正在朗读 + 点击打开阅读界面 + 返回 + 重新加载 + 开始 + 停止 + 暂停 + 继续 + 定时 + 朗读暂停 + 正在朗读(还剩%d分钟) + 阅读界面隐藏虚拟按键 + 隐藏导航栏 + 导航栏颜色 + GitHub + 评分 + 发送邮件 + 无法打开 + 无章节 + 添加网址 + 添加书籍网址 + 背景 + 作者 + 站点暂时不支持解析,请反馈 + 朗读停止 + 清除缓存 + 保存 + 编辑书源 + 禁用书源 + 新建书源 + 添加书籍 + 扫描 + 拷贝书源 + 粘贴书源 + 书源规则说明 + 检查更新 + 扫描二维码 + 扫描本地图片 + 规则说明 + 分享 + 软件分享 + 跟随系统 + 添加 + 导入书源 + 本地导入 + 网络导入 + 替换净化 + 替换规则编辑 + 替换规则 + 替换为 + 封面 + + 音量键翻页 + 点击翻页 + 点击总是翻下一页 + 翻页动画 + 屏幕超时 + 返回 + 菜单 + 调节 + 滚动条 + 清除缓存会删除所有已保存章节,是否确认删除? + 书源共享 + 替换规则名称 + 全选 + 夜间模式 + 启动页 + 开始下载 + 取消下载 + 暂无任务 + 导入选择书籍 + 更新和搜索线程数,如感觉卡顿请减小线程数,量力而行 + 切换图标 + 删除书籍 + 开始阅读 + 加载数据中… + 加载失败,点击重试 + 内容简介 + 打开外部书籍 + 来源 + 本地导入 + 网络导入 + 书架排序 + 检查更新间隔 + 按阅读时间排序 + 按更新时间排序 + 手动排序 + 阅读方式 + 删除所选 + 是否确认删除? + 默认字体 + 发现 + 发现管理 + 没有内容,去书源里自定义吧! + 删除所有 + 搜索历史 + 清除 + 正文显示标题 + 书源同步 + 无最新章节信息 + 显示时间和电量 + 显示分隔线 + 深色状态栏图标 + 内容 + 拷贝内容 + 一键缓存 + 这是一段测试文字\n\u3000\u3000只是让你看看效果的 + 文字颜色和背景(长按自定义) + 沉浸式状态栏 + 还剩%d章未下载 + 长按输入颜色值 + 加载中… + 追更区 + 养肥区 + 书签 + 添加书签 + 删除 + 加载超时 + 关注:%s + 已拷贝 + 整理书架 + 这将会删除所有书籍,请谨慎操作。 + 搜索书源 + 搜索(共%d个书源) + 目录(%d) + 加粗 + 字体 + 文字 + 软件主页 + + + + + 边距: + 上边距 + 下边距 + 左边距 + 右边距 + 校验书源 + 校验所选 + 进度 %d/%d + 请安装并选择中文TTS! + TTS初始化失败! + 简繁转换 + 关闭 + 简转繁 + 繁转简 + 翻页模式 + %1$d 项 + 存储卡: + 加入书架 + 加入书架(%1$d) + 成功添加%1$d本书 + 请将字体文件放到SD根目录Fonts文件夹下重新选择 + 默认字体 + 选择字体 + 字号 + 行距 + 段距 + 置顶 + 自动展开发现 + 默认展开第一组发现 + 当前线程数 %s + 朗读语速 + 自动翻页 + 停止自动翻页 + 自动翻页间隔 + 书籍信息 + 默认打开书架 + 自动跳转最近阅读 + 替换范围,选填书名或者源名 + 分组 + 内容缓存路径 + 系统文件选择器 + 新版本 + 下载更新 + 朗读时音量键翻页 + Tip边距跟随边距调整 + 禁止更新 + 允许更新 + 反转选择 + 搜索书名、作者 + 书名、作者、URL + 常见问题 + 显示所有发现 + 关闭则只显示勾选源的发现 + 更新目录 + txt目录正则 + 设置编码 + 倒序-顺序 + 排序 + 智能排序 + 手动排序 + 拼音排序 + 滚动到顶部 + 滚动到底部 + 已读: %s + 追更 + 养肥 + 完结 + 所有书籍 + 追更书籍 + 养肥书籍 + 完结书籍 + 本地书籍 + 状态栏颜色透明 + 导航栏变色 + 导航栏根据夜间模式变化 + 放入书架 + 继续阅读 + 封面地址 + 覆盖 + 仿真 + 滑动 + 滚动 + 无动画 + 此书源使用了高级功能,请到捐赠里点击支付宝红包搜索码领取红包开启。 + 后台更新换源最新章节 + 开启则会在软件打开1分钟后开始更新 + 书架ToolBar自动隐藏 + 滚动书架时ToolBar自动隐藏与显示 + 登录 + 登录%s + 成功 + 当前源没有配置登陆地址 + 书源名称(bookSourceName) + 书源URL(bookSourceUrl) + 书源分组(bookSourceGroup) + 登录URL(loginUrl) + 作者规则(ruleBookAuthor) + 正文规则(ruleBookContent) + 书名规则(ruleBookName) + 目录列表规则(ruleChapterList) + 章节名称规则(ruleChapterName) + 目录URL规则(ruleChapterUrl) + 目录下一页规则(ruleChapterUrlNext) + 章节URL规则(ruleContentUrl) + 封面规则(ruleCoverUrl) + 简介规则(ruleIntroduce) + 搜索作者规则(ruleSearchAuthor) + 发现作者规则(ruleFindAuthor) + 搜索封面规则(ruleSearchCoverUrl) + 发现封面规则(ruleFindCoverUrl) + 搜索分类规则(ruleSearchKind) + 发现分类规则(ruleFindKind) + 搜索最新章节规则(ruleSearchLastChapter) + 发现最新章节规则(ruleFindLastChapter) + 搜索列表规则(ruleSearchList) + 发现列表规则(ruleFindList) + 搜索书名规则(ruleSearchName) + 发现书名规则(ruleFindName) + 搜索书籍URL规则(ruleSearchNoteUrl) + 发现书籍URL规则(ruleFindNoteUrl) + 搜索简介规则(ruleSearchIntroduce) + 发现简介规则(ruleFindIntroduce) + 搜索地址(ruleSearchUrl) + 发现规则(ruleFindUrl) + 正文下一页URL规则(ruleContentUrlNext) + 书籍详情URL正则(ruleBookUrlPattern) + 书籍详情预处理规则(ruleBookInfoInit) + 分类规则(ruleBookKind) + 最新章节规则(ruleBookLastChapter) + HttpUserAgent + 调试书源 + 二维码导入 + 扫描二维码 + \@ + + 选中时点击可弹出菜单 + 主题 + 默认主题 + 恢复主题为默认配色 + 加入QQ群 + 文件读取失败 + 获取背景图片需存储权限 + 输入书源网址 + 删除文件 + 删除文件成功 + 确定删除文件吗? + 手机目录 + 智能导入 + 发现 + 切换显示样式 + 导入本地书籍需存储权限 + 点击可切换到白天模式 + 点击可切换到夜间模式 + 本软件需要存储权限来存储备份书籍信息 + 再按一次退出程序 + 导入本地书籍需存储权限 + 网络连接不可用 + + + 是否删除全部书籍? + 是否同时删除已下载的书籍目录? + 扫描二维码需相机权限 + 朗读正在运行,不能自动翻页 + 输入编码 + TXT目录规则 + 打开外部书籍需获取存储权限 + 书籍信息获取失败 + 内容获取失败 + 目录获取失败 + 访问网站失败:%s + 未获取到书名 + 输入替换规则网址 + 搜索列表获取成功%d + 书源名称和URL不能为空 + 图库 + 领支付宝红包 + 没有获取到更新地址 + 正在打开首页,成功自动返回主界面 + 登录成功后请点击右上角图标进行首页访问测试 + + 章节: + + 使用正则表达式 + 缩进 + 无缩进 + 一字符缩进 + 二字符缩进 + 三字符缩进 + 四字符缩进 + 选择SD卡 + 没有发现,可以在书源里添加。 + 恢复默认 + 自定义缓存路径需要存储权限 + 黑色 + 文章内容为空 + 正在换源请等待… + 目录列表为空 + 加载失败\n%s + 正文边距 + Tip边距 + 字距 + + E-Ink 模式 + 去除动画,优化电纸书使用体验 + Web服务 + web端口 + 当前端口 %s + 二维码分享 + wifi分享 + 请给于存储权限 + 上一个 + 下一个 + 音乐 + 音频 + 启用 + 全部书源 + 输入不能为空 + 清空发现缓存 + 编辑发现 + 切换软件显示在桌面的图标 From 90a1ada010a0b8a5f05e254b4741d50e4e34a11b Mon Sep 17 00:00:00 2001 From: GKF Date: Wed, 29 May 2019 14:46:54 +0800 Subject: [PATCH 0030/1997] up App --- app/src/main/java/io/legado/app/App.kt | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/App.kt b/app/src/main/java/io/legado/app/App.kt index e62d513bc..868748389 100644 --- a/app/src/main/java/io/legado/app/App.kt +++ b/app/src/main/java/io/legado/app/App.kt @@ -4,6 +4,7 @@ import android.app.Application import android.app.NotificationChannel import android.app.NotificationManager import android.content.Context +import android.content.pm.PackageManager import android.os.Build import androidx.annotation.RequiresApi import androidx.appcompat.app.AppCompatDelegate @@ -28,12 +29,24 @@ class App : Application() { private set } + private var versionCode = 0 + override fun onCreate() { super.onCreate() INSTANCE = this db = AppDatabase.createDatabase(INSTANCE) + versionCode = try { + packageManager.getPackageInfo(packageName, 0).versionCode + } catch (e: PackageManager.NameNotFoundException) { + 0 + } initNightTheme() - upThemeStore() + if (!ThemeStore.isConfigured(this, versionCode)) { + upThemeStore() + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + createChannelId() + } } fun initNightTheme() { @@ -44,6 +57,9 @@ class App : Application() { } } + /** + * 更新主题 + */ fun upThemeStore() { if (getPrefBoolean("isNightTheme", false)) { ThemeStore.editTheme(this) @@ -63,6 +79,7 @@ class App : Application() { /** * 创建通知ID */ + @RequiresApi(Build.VERSION_CODES.O) private fun createChannelId() { val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager From 9bbe7dd7d53ba25266890cee8ce8bacfe7b2bf26 Mon Sep 17 00:00:00 2001 From: GKF Date: Thu, 30 May 2019 13:49:25 +0800 Subject: [PATCH 0031/1997] remove dataBinding --- .../java/io/legado/app/base/BaseActivity.kt | 10 +-- .../io/legado/app/ui/main/MainActivity.kt | 4 +- .../app/ui/replacerule/ReplaceRuleActivity.kt | 21 ++--- .../ui/replacerule/ReplaceRuleViewModel.java | 11 +++ .../io/legado/app/ui/search/SearchActivity.kt | 3 +- app/src/main/res/drawable-v21/bg_ib_pre.xml | 5 ++ .../main/res/drawable-v21/bg_ib_pre_round.xml | 3 + .../res/drawable/bg_chapter_item_divider.xml | 10 +++ app/src/main/res/drawable/bg_edit.xml | 6 ++ app/src/main/res/drawable/bg_ib_pre.xml | 5 ++ .../main/res/drawable/bg_shadow_bottom.png | Bin 0 -> 3127 bytes .../res/drawable/bg_shadow_bottom_night.png | Bin 0 -> 418 bytes app/src/main/res/drawable/bg_shadow_top.png | Bin 0 -> 340 bytes .../main/res/drawable/bg_shadow_top_night.png | Bin 0 -> 424 bytes .../main/res/drawable/bg_textfield_search.xml | 10 +++ .../main/res/drawable/fastscroll_bubble.xml | 39 +++++++++ .../main/res/drawable/fastscroll_handle.xml | 31 ++++++++ .../main/res/drawable/fastscroll_track.xml | 27 +++++++ app/src/main/res/drawable/ic_about.xml | 11 +++ app/src/main/res/drawable/ic_add.xml | 11 +++ app/src/main/res/drawable/ic_add_online.xml | 11 +++ app/src/main/res/drawable/ic_arrange.xml | 17 ++++ app/src/main/res/drawable/ic_arrow_back.xml | 9 +++ .../main/res/drawable/ic_arrow_drop_down.xml | 9 +++ .../main/res/drawable/ic_arrow_drop_up.xml | 9 +++ app/src/main/res/drawable/ic_author.xml | 12 +++ app/src/main/res/drawable/ic_auto_page.xml | 14 ++++ .../main/res/drawable/ic_auto_page_stop.xml | 17 ++++ app/src/main/res/drawable/ic_back_last.xml | 11 +++ app/src/main/res/drawable/ic_backup.xml | 29 +++++++ app/src/main/res/drawable/ic_book_has.xml | 14 ++++ app/src/main/res/drawable/ic_book_last.xml | 15 ++++ .../res/drawable/ic_book_source_manage.xml | 20 +++++ app/src/main/res/drawable/ic_bookmark.xml | 11 +++ app/src/main/res/drawable/ic_brightness.xml | 11 +++ app/src/main/res/drawable/ic_cancel.xml | 14 ++++ app/src/main/res/drawable/ic_chapter_list.xml | 20 +++++ app/src/main/res/drawable/ic_check.xml | 9 +++ app/src/main/res/drawable/ic_check_source.xml | 14 ++++ app/src/main/res/drawable/ic_copy.xml | 17 ++++ app/src/main/res/drawable/ic_daytime.xml | 35 ++++++++ app/src/main/res/drawable/ic_disclaimer.xml | 17 ++++ app/src/main/res/drawable/ic_donate.xml | 11 +++ app/src/main/res/drawable/ic_download.xml | 9 +++ .../main/res/drawable/ic_download_line.xml | 14 ++++ app/src/main/res/drawable/ic_exchange.xml | 17 ++++ .../main/res/drawable/ic_expand_less_24dp.xml | 9 +++ .../main/res/drawable/ic_expand_more_24dp.xml | 9 +++ app/src/main/res/drawable/ic_faq.xml | 17 ++++ app/src/main/res/drawable/ic_find_replace.xml | 14 ++++ app/src/main/res/drawable/ic_folder.xml | 10 +++ .../res/drawable/ic_format_line_spacing.xml | 20 +++++ app/src/main/res/drawable/ic_groups.xml | 20 +++++ app/src/main/res/drawable/ic_history.xml | 12 +++ app/src/main/res/drawable/ic_import.xml | 19 +++++ .../res/drawable/ic_interface_setting.xml | 14 ++++ app/src/main/res/drawable/ic_last_read.xml | 7 ++ app/src/main/res/drawable/ic_launch.xml | 14 ++++ app/src/main/res/drawable/ic_list.xml | 26 ++++++ app/src/main/res/drawable/ic_mail.xml | 11 +++ app/src/main/res/drawable/ic_more_vert.xml | 9 +++ .../main/res/drawable/ic_network_check.xml | 9 +++ app/src/main/res/drawable/ic_pause_24dp.xml | 9 +++ .../res/drawable/ic_pause_outline_24dp.xml | 14 ++++ app/src/main/res/drawable/ic_play_24dp.xml | 9 +++ .../res/drawable/ic_play_outline_24dp.xml | 11 +++ app/src/main/res/drawable/ic_qq_group.xml | 11 +++ app/src/main/res/drawable/ic_read_aloud.xml | 11 +++ .../res/drawable/ic_refresh_black_24dp.xml | 14 ++++ .../res/drawable/ic_refresh_white_24dp.xml | 9 +++ app/src/main/res/drawable/ic_restore.xml | 26 ++++++ app/src/main/res/drawable/ic_save.xml | 14 ++++ app/src/main/res/drawable/ic_scan.xml | 11 +++ app/src/main/res/drawable/ic_scoring.xml | 11 +++ app/src/main/res/drawable/ic_search.xml | 17 ++++ app/src/main/res/drawable/ic_select_all.xml | 23 ++++++ app/src/main/res/drawable/ic_settings.xml | 14 ++++ app/src/main/res/drawable/ic_share.xml | 14 ++++ app/src/main/res/drawable/ic_skip_next.xml | 9 +++ .../main/res/drawable/ic_skip_previous.xml | 9 +++ .../main/res/drawable/ic_stop_black_24dp.xml | 9 +++ .../res/drawable/ic_swap_outline_24dp.xml | 20 +++++ app/src/main/res/drawable/ic_theme.xml | 20 +++++ .../main/res/drawable/ic_time_add_24dp.xml | 10 +++ .../main/res/drawable/ic_timer_black_24dp.xml | 20 +++++ app/src/main/res/drawable/ic_toc.xml | 26 ++++++ app/src/main/res/drawable/ic_top_source.xml | 14 ++++ app/src/main/res/drawable/ic_translate.xml | 14 ++++ app/src/main/res/drawable/ic_tune.xml | 17 ++++ app/src/main/res/drawable/ic_update.xml | 14 ++++ app/src/main/res/drawable/ic_version.xml | 11 +++ app/src/main/res/drawable/ic_view_quilt.xml | 26 ++++++ app/src/main/res/drawable/ic_volume_up.xml | 9 +++ app/src/main/res/drawable/ic_web_outline.xml | 13 +++ .../main/res/drawable/ic_web_service_noti.xml | 10 +++ .../res/drawable/ic_web_service_phone.xml | 17 ++++ app/src/main/res/drawable/icon_read_book.png | Bin 0 -> 10462 bytes app/src/main/res/drawable/image_welcome.xml | 75 ++++++++++++++++++ app/src/main/res/drawable/image_yue_du.webp | Bin 0 -> 7540 bytes .../main/res/drawable/img_cover_default.jpg | Bin 0 -> 6927 bytes app/src/main/res/drawable/img_cover_gs.jpg | Bin 0 -> 3753 bytes .../main/res/drawable/selector_common_bg.xml | 10 +++ .../res/drawable/selector_fillet_btn_bg.xml | 5 ++ .../main/res/drawable/selector_tv_black.xml | 6 ++ app/src/main/res/drawable/shape_card_view.xml | 6 ++ .../main/res/drawable/shape_fillet_btn.xml | 6 ++ .../res/drawable/shape_fillet_btn_press.xml | 6 ++ .../drawable/shape_pop_checkaddshelf_bg.xml | 6 ++ .../main/res/drawable/shape_radius_1dp.xml | 7 ++ .../main/res/drawable/shape_space_divider.xml | 8 ++ .../main/res/drawable/shape_text_cursor.xml | 7 ++ app/src/main/res/layout/activity_main.xml | 43 +++++----- app/src/main/res/layout/activity_search.xml | 51 +++++------- app/src/main/res/values/dimens.xml | 25 ++++++ 114 files changed, 1486 insertions(+), 74 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.java create mode 100644 app/src/main/res/drawable-v21/bg_ib_pre.xml create mode 100644 app/src/main/res/drawable-v21/bg_ib_pre_round.xml create mode 100644 app/src/main/res/drawable/bg_chapter_item_divider.xml create mode 100644 app/src/main/res/drawable/bg_edit.xml create mode 100644 app/src/main/res/drawable/bg_ib_pre.xml create mode 100644 app/src/main/res/drawable/bg_shadow_bottom.png create mode 100644 app/src/main/res/drawable/bg_shadow_bottom_night.png create mode 100644 app/src/main/res/drawable/bg_shadow_top.png create mode 100644 app/src/main/res/drawable/bg_shadow_top_night.png create mode 100644 app/src/main/res/drawable/bg_textfield_search.xml create mode 100644 app/src/main/res/drawable/fastscroll_bubble.xml create mode 100644 app/src/main/res/drawable/fastscroll_handle.xml create mode 100644 app/src/main/res/drawable/fastscroll_track.xml create mode 100644 app/src/main/res/drawable/ic_about.xml create mode 100644 app/src/main/res/drawable/ic_add.xml create mode 100644 app/src/main/res/drawable/ic_add_online.xml create mode 100644 app/src/main/res/drawable/ic_arrange.xml create mode 100644 app/src/main/res/drawable/ic_arrow_back.xml create mode 100644 app/src/main/res/drawable/ic_arrow_drop_down.xml create mode 100644 app/src/main/res/drawable/ic_arrow_drop_up.xml create mode 100644 app/src/main/res/drawable/ic_author.xml create mode 100644 app/src/main/res/drawable/ic_auto_page.xml create mode 100644 app/src/main/res/drawable/ic_auto_page_stop.xml create mode 100644 app/src/main/res/drawable/ic_back_last.xml create mode 100644 app/src/main/res/drawable/ic_backup.xml create mode 100644 app/src/main/res/drawable/ic_book_has.xml create mode 100644 app/src/main/res/drawable/ic_book_last.xml create mode 100644 app/src/main/res/drawable/ic_book_source_manage.xml create mode 100644 app/src/main/res/drawable/ic_bookmark.xml create mode 100644 app/src/main/res/drawable/ic_brightness.xml create mode 100644 app/src/main/res/drawable/ic_cancel.xml create mode 100644 app/src/main/res/drawable/ic_chapter_list.xml create mode 100644 app/src/main/res/drawable/ic_check.xml create mode 100644 app/src/main/res/drawable/ic_check_source.xml create mode 100644 app/src/main/res/drawable/ic_copy.xml create mode 100644 app/src/main/res/drawable/ic_daytime.xml create mode 100644 app/src/main/res/drawable/ic_disclaimer.xml create mode 100644 app/src/main/res/drawable/ic_donate.xml create mode 100644 app/src/main/res/drawable/ic_download.xml create mode 100644 app/src/main/res/drawable/ic_download_line.xml create mode 100644 app/src/main/res/drawable/ic_exchange.xml create mode 100644 app/src/main/res/drawable/ic_expand_less_24dp.xml create mode 100644 app/src/main/res/drawable/ic_expand_more_24dp.xml create mode 100644 app/src/main/res/drawable/ic_faq.xml create mode 100644 app/src/main/res/drawable/ic_find_replace.xml create mode 100644 app/src/main/res/drawable/ic_folder.xml create mode 100644 app/src/main/res/drawable/ic_format_line_spacing.xml create mode 100644 app/src/main/res/drawable/ic_groups.xml create mode 100644 app/src/main/res/drawable/ic_history.xml create mode 100644 app/src/main/res/drawable/ic_import.xml create mode 100644 app/src/main/res/drawable/ic_interface_setting.xml create mode 100644 app/src/main/res/drawable/ic_last_read.xml create mode 100644 app/src/main/res/drawable/ic_launch.xml create mode 100644 app/src/main/res/drawable/ic_list.xml create mode 100644 app/src/main/res/drawable/ic_mail.xml create mode 100644 app/src/main/res/drawable/ic_more_vert.xml create mode 100644 app/src/main/res/drawable/ic_network_check.xml create mode 100644 app/src/main/res/drawable/ic_pause_24dp.xml create mode 100644 app/src/main/res/drawable/ic_pause_outline_24dp.xml create mode 100644 app/src/main/res/drawable/ic_play_24dp.xml create mode 100644 app/src/main/res/drawable/ic_play_outline_24dp.xml create mode 100644 app/src/main/res/drawable/ic_qq_group.xml create mode 100644 app/src/main/res/drawable/ic_read_aloud.xml create mode 100644 app/src/main/res/drawable/ic_refresh_black_24dp.xml create mode 100644 app/src/main/res/drawable/ic_refresh_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_restore.xml create mode 100644 app/src/main/res/drawable/ic_save.xml create mode 100644 app/src/main/res/drawable/ic_scan.xml create mode 100644 app/src/main/res/drawable/ic_scoring.xml create mode 100644 app/src/main/res/drawable/ic_search.xml create mode 100644 app/src/main/res/drawable/ic_select_all.xml create mode 100644 app/src/main/res/drawable/ic_settings.xml create mode 100644 app/src/main/res/drawable/ic_share.xml create mode 100644 app/src/main/res/drawable/ic_skip_next.xml create mode 100644 app/src/main/res/drawable/ic_skip_previous.xml create mode 100644 app/src/main/res/drawable/ic_stop_black_24dp.xml create mode 100644 app/src/main/res/drawable/ic_swap_outline_24dp.xml create mode 100644 app/src/main/res/drawable/ic_theme.xml create mode 100644 app/src/main/res/drawable/ic_time_add_24dp.xml create mode 100644 app/src/main/res/drawable/ic_timer_black_24dp.xml create mode 100644 app/src/main/res/drawable/ic_toc.xml create mode 100644 app/src/main/res/drawable/ic_top_source.xml create mode 100644 app/src/main/res/drawable/ic_translate.xml create mode 100644 app/src/main/res/drawable/ic_tune.xml create mode 100644 app/src/main/res/drawable/ic_update.xml create mode 100644 app/src/main/res/drawable/ic_version.xml create mode 100644 app/src/main/res/drawable/ic_view_quilt.xml create mode 100644 app/src/main/res/drawable/ic_volume_up.xml create mode 100644 app/src/main/res/drawable/ic_web_outline.xml create mode 100644 app/src/main/res/drawable/ic_web_service_noti.xml create mode 100644 app/src/main/res/drawable/ic_web_service_phone.xml create mode 100644 app/src/main/res/drawable/icon_read_book.png create mode 100644 app/src/main/res/drawable/image_welcome.xml create mode 100644 app/src/main/res/drawable/image_yue_du.webp create mode 100644 app/src/main/res/drawable/img_cover_default.jpg create mode 100644 app/src/main/res/drawable/img_cover_gs.jpg create mode 100644 app/src/main/res/drawable/selector_common_bg.xml create mode 100644 app/src/main/res/drawable/selector_fillet_btn_bg.xml create mode 100644 app/src/main/res/drawable/selector_tv_black.xml create mode 100644 app/src/main/res/drawable/shape_card_view.xml create mode 100644 app/src/main/res/drawable/shape_fillet_btn.xml create mode 100644 app/src/main/res/drawable/shape_fillet_btn_press.xml create mode 100644 app/src/main/res/drawable/shape_pop_checkaddshelf_bg.xml create mode 100644 app/src/main/res/drawable/shape_radius_1dp.xml create mode 100644 app/src/main/res/drawable/shape_space_divider.xml create mode 100644 app/src/main/res/drawable/shape_text_cursor.xml diff --git a/app/src/main/java/io/legado/app/base/BaseActivity.kt b/app/src/main/java/io/legado/app/base/BaseActivity.kt index c85db5b5c..0de007342 100644 --- a/app/src/main/java/io/legado/app/base/BaseActivity.kt +++ b/app/src/main/java/io/legado/app/base/BaseActivity.kt @@ -3,15 +3,9 @@ package io.legado.app.base import android.os.Bundle import android.view.MenuItem import androidx.appcompat.app.AppCompatActivity -import androidx.databinding.DataBindingUtil -import androidx.databinding.ViewDataBinding import androidx.lifecycle.ViewModel -import com.google.android.material.bottomnavigation.BottomNavigationView -abstract class BaseActivity : AppCompatActivity() { - - protected lateinit var dataBinding: BD - private set +abstract class BaseActivity : AppCompatActivity() { protected abstract val viewModel: VM @@ -19,7 +13,7 @@ abstract class BaseActivity : AppCompatAct override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - dataBinding = DataBindingUtil.setContentView(this, layoutID) + setContentView(layoutID) onViewModelCreated(viewModel, savedInstanceState) } diff --git a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt index 8e9de7e29..246533e56 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt @@ -16,12 +16,12 @@ import io.legado.app.help.storage.Backup import io.legado.app.help.storage.Restore import io.legado.app.ui.replacerule.ReplaceRuleActivity import io.legado.app.ui.search.SearchActivity -import io.legado.app.utils.* +import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.app_bar_main.* import org.jetbrains.anko.startActivity -class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedListener { +class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedListener { override val viewModel: MainViewModel get() = getViewModel(MainViewModel::class.java) diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt index 5d0ebadc6..2c282e458 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt @@ -2,34 +2,37 @@ package io.legado.app.ui.replacerule import android.os.Bundle import android.util.Log -import androidx.appcompat.app.AppCompatActivity import androidx.core.content.ContextCompat import androidx.lifecycle.LiveData import androidx.lifecycle.Observer import androidx.paging.LivePagedListBuilder import androidx.paging.PagedList import androidx.recyclerview.widget.DividerItemDecoration +import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView import io.legado.app.App import io.legado.app.R +import io.legado.app.base.BaseActivity +import io.legado.app.constant.AppConst.APP_TAG import io.legado.app.data.entities.ReplaceRule +import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_replace_rule.* import org.jetbrains.anko.doAsync import org.jetbrains.anko.toast -import androidx.recyclerview.widget.RecyclerView -import androidx.recyclerview.widget.ItemTouchHelper -import io.legado.app.constant.AppConst.APP_TAG -import kotlinx.android.synthetic.main.item_relace_rule.* -class ReplaceRuleActivity : AppCompatActivity() { +class ReplaceRuleActivity : BaseActivity() { + override val viewModel: ReplaceRuleViewModel + get() = getViewModel(ReplaceRuleViewModel::class.java) + override val layoutID: Int + get() = R.layout.activity_replace_rule private lateinit var adapter: ReplaceRuleAdapter private var rulesLiveData: LiveData>? = null private var allEnabled = false - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_replace_rule) + override fun onViewModelCreated(viewModel: ReplaceRuleViewModel, savedInstanceState: Bundle?) { + super.onViewModelCreated(viewModel, savedInstanceState) initRecyclerView() initDataObservers() initSwipeToDelete() diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.java b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.java new file mode 100644 index 000000000..fac35d61d --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.java @@ -0,0 +1,11 @@ +package io.legado.app.ui.replacerule; + +import android.app.Application; +import io.legado.app.base.BaseViewModel; +import org.jetbrains.annotations.NotNull; + +public class ReplaceRuleViewModel extends BaseViewModel { + public ReplaceRuleViewModel(@NotNull Application application) { + super(application); + } +} diff --git a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt index c58c611a9..da55af76a 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt @@ -3,11 +3,10 @@ package io.legado.app.ui.search import android.os.Bundle import io.legado.app.R import io.legado.app.base.BaseActivity -import io.legado.app.data.entities.rule.Rule import io.legado.app.utils.getViewModel import org.jetbrains.anko.startActivity -class SearchActivity : BaseActivity() { +class SearchActivity : BaseActivity() { override val viewModel: SearchViewModel get() = getViewModel(SearchViewModel::class.java) diff --git a/app/src/main/res/drawable-v21/bg_ib_pre.xml b/app/src/main/res/drawable-v21/bg_ib_pre.xml new file mode 100644 index 000000000..9fdfe8c17 --- /dev/null +++ b/app/src/main/res/drawable-v21/bg_ib_pre.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-v21/bg_ib_pre_round.xml b/app/src/main/res/drawable-v21/bg_ib_pre_round.xml new file mode 100644 index 000000000..c43b5c490 --- /dev/null +++ b/app/src/main/res/drawable-v21/bg_ib_pre_round.xml @@ -0,0 +1,3 @@ + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_chapter_item_divider.xml b/app/src/main/res/drawable/bg_chapter_item_divider.xml new file mode 100644 index 000000000..423a6bb03 --- /dev/null +++ b/app/src/main/res/drawable/bg_chapter_item_divider.xml @@ -0,0 +1,10 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_edit.xml b/app/src/main/res/drawable/bg_edit.xml new file mode 100644 index 000000000..8a3c4e59e --- /dev/null +++ b/app/src/main/res/drawable/bg_edit.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_ib_pre.xml b/app/src/main/res/drawable/bg_ib_pre.xml new file mode 100644 index 000000000..d44a8b2f0 --- /dev/null +++ b/app/src/main/res/drawable/bg_ib_pre.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_shadow_bottom.png b/app/src/main/res/drawable/bg_shadow_bottom.png new file mode 100644 index 0000000000000000000000000000000000000000..ac0124b670691689ed19d44fb1498230f91cbf68 GIT binary patch literal 3127 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 F699})m_h&m literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/bg_shadow_top.png b/app/src/main/res/drawable/bg_shadow_top.png new file mode 100644 index 0000000000000000000000000000000000000000..cb8fee03db41e424234fce1f138671c15d338c3d GIT binary patch literal 340 zcmeAS@N?(olHy`uVBq!ia0vp^M}XLlg&9b;HLg?#QbGYfA+8+iZY**Ztctck5`t!a zDt86SvXun+1&cEZvGQ`(?r9eRioEu8aSVw#{Pxnt%)<@>t{2;_3^EfW?=(o>IbgKv zfc4+)lcqLF$b711HrgeB`k$;^PmbC)O`RsKMK9M*7FrfRx5%}b_jmF!&+rXxZ#&oc zCq%l4rKtq9tmNs)xbgH_*R?f{vMiN5FY@{cCI-0P*(kepQMt%PkwX_me(>Zvl`!-2 z-U(ovTO@PedWz8eg)F^FZU&+U-)bbq&Qx@r;2~(~mZaGqre!zopr0Bb^kD*ylh literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/bg_shadow_top_night.png b/app/src/main/res/drawable/bg_shadow_top_night.png new file mode 100644 index 0000000000000000000000000000000000000000..7984c35dbd2cdb35c16cf7942de030ed4e225565 GIT binary patch literal 424 zcmeAS@N?(olHy`uVBq!ia0vp^M}XLlgAGWQtluI6q!^2X+?^QKos)S9a~60+7BevL9R^{>lk;;^Bllfrk9fQG{C_uv)`~2aO-8k* zOuKLEZ#dQRBZsA^?Z& zY!)NMJgG*Xj_Ym;!jEuF4af=70@2Ctw%C zHruCTGf2Zm!4oYOxhyrOgxc2ll=nJ>Et~A-pqOyt)DwQE4W5d7{_#q0_c3_FQ+S6X zCG}I0e9jslpsiL}Kw}TPDWrGo2f4)&X!f5>77-@4>+1|soZgr-sj=_?k*14W!cqZ) zB|PT@Hw1D>1a<5=&$0%n>a`FL7h|(_I736c&T0Oe4XlDe@&eO=q08Xu>gTe~DWM4f Du2h!N literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/bg_textfield_search.xml b/app/src/main/res/drawable/bg_textfield_search.xml new file mode 100644 index 000000000..9db913814 --- /dev/null +++ b/app/src/main/res/drawable/bg_textfield_search.xml @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/fastscroll_bubble.xml b/app/src/main/res/drawable/fastscroll_bubble.xml new file mode 100644 index 000000000..566919858 --- /dev/null +++ b/app/src/main/res/drawable/fastscroll_bubble.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/fastscroll_handle.xml b/app/src/main/res/drawable/fastscroll_handle.xml new file mode 100644 index 000000000..7cc91b9ea --- /dev/null +++ b/app/src/main/res/drawable/fastscroll_handle.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/fastscroll_track.xml b/app/src/main/res/drawable/fastscroll_track.xml new file mode 100644 index 000000000..d60893c04 --- /dev/null +++ b/app/src/main/res/drawable/fastscroll_track.xml @@ -0,0 +1,27 @@ + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_about.xml b/app/src/main/res/drawable/ic_about.xml new file mode 100644 index 000000000..1c6a7f643 --- /dev/null +++ b/app/src/main/res/drawable/ic_about.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_add.xml b/app/src/main/res/drawable/ic_add.xml new file mode 100644 index 000000000..67a246c89 --- /dev/null +++ b/app/src/main/res/drawable/ic_add.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_add_online.xml b/app/src/main/res/drawable/ic_add_online.xml new file mode 100644 index 000000000..1b1387f70 --- /dev/null +++ b/app/src/main/res/drawable/ic_add_online.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_arrange.xml b/app/src/main/res/drawable/ic_arrange.xml new file mode 100644 index 000000000..130079315 --- /dev/null +++ b/app/src/main/res/drawable/ic_arrange.xml @@ -0,0 +1,17 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_arrow_back.xml b/app/src/main/res/drawable/ic_arrow_back.xml new file mode 100644 index 000000000..e1d42df18 --- /dev/null +++ b/app/src/main/res/drawable/ic_arrow_back.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_arrow_drop_down.xml b/app/src/main/res/drawable/ic_arrow_drop_down.xml new file mode 100644 index 000000000..f7def8a08 --- /dev/null +++ b/app/src/main/res/drawable/ic_arrow_drop_down.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_arrow_drop_up.xml b/app/src/main/res/drawable/ic_arrow_drop_up.xml new file mode 100644 index 000000000..a6d5895e2 --- /dev/null +++ b/app/src/main/res/drawable/ic_arrow_drop_up.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_author.xml b/app/src/main/res/drawable/ic_author.xml new file mode 100644 index 000000000..d14ffaf39 --- /dev/null +++ b/app/src/main/res/drawable/ic_author.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_auto_page.xml b/app/src/main/res/drawable/ic_auto_page.xml new file mode 100644 index 000000000..f720abd23 --- /dev/null +++ b/app/src/main/res/drawable/ic_auto_page.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_auto_page_stop.xml b/app/src/main/res/drawable/ic_auto_page_stop.xml new file mode 100644 index 000000000..bebcd8680 --- /dev/null +++ b/app/src/main/res/drawable/ic_auto_page_stop.xml @@ -0,0 +1,17 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_back_last.xml b/app/src/main/res/drawable/ic_back_last.xml new file mode 100644 index 000000000..243d0386e --- /dev/null +++ b/app/src/main/res/drawable/ic_back_last.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_backup.xml b/app/src/main/res/drawable/ic_backup.xml new file mode 100644 index 000000000..8b17ca37c --- /dev/null +++ b/app/src/main/res/drawable/ic_backup.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_book_has.xml b/app/src/main/res/drawable/ic_book_has.xml new file mode 100644 index 000000000..0b7941616 --- /dev/null +++ b/app/src/main/res/drawable/ic_book_has.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_book_last.xml b/app/src/main/res/drawable/ic_book_last.xml new file mode 100644 index 000000000..3ee254c91 --- /dev/null +++ b/app/src/main/res/drawable/ic_book_last.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_book_source_manage.xml b/app/src/main/res/drawable/ic_book_source_manage.xml new file mode 100644 index 000000000..ac9acfc6c --- /dev/null +++ b/app/src/main/res/drawable/ic_book_source_manage.xml @@ -0,0 +1,20 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_bookmark.xml b/app/src/main/res/drawable/ic_bookmark.xml new file mode 100644 index 000000000..0eccdac3f --- /dev/null +++ b/app/src/main/res/drawable/ic_bookmark.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_brightness.xml b/app/src/main/res/drawable/ic_brightness.xml new file mode 100644 index 000000000..095df912f --- /dev/null +++ b/app/src/main/res/drawable/ic_brightness.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_cancel.xml b/app/src/main/res/drawable/ic_cancel.xml new file mode 100644 index 000000000..8b2b5cbb4 --- /dev/null +++ b/app/src/main/res/drawable/ic_cancel.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_chapter_list.xml b/app/src/main/res/drawable/ic_chapter_list.xml new file mode 100644 index 000000000..c667fa24e --- /dev/null +++ b/app/src/main/res/drawable/ic_chapter_list.xml @@ -0,0 +1,20 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_check.xml b/app/src/main/res/drawable/ic_check.xml new file mode 100644 index 000000000..a4f01346c --- /dev/null +++ b/app/src/main/res/drawable/ic_check.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_check_source.xml b/app/src/main/res/drawable/ic_check_source.xml new file mode 100644 index 000000000..7384b9986 --- /dev/null +++ b/app/src/main/res/drawable/ic_check_source.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_copy.xml b/app/src/main/res/drawable/ic_copy.xml new file mode 100644 index 000000000..54c020707 --- /dev/null +++ b/app/src/main/res/drawable/ic_copy.xml @@ -0,0 +1,17 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_daytime.xml b/app/src/main/res/drawable/ic_daytime.xml new file mode 100644 index 000000000..363491941 --- /dev/null +++ b/app/src/main/res/drawable/ic_daytime.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_disclaimer.xml b/app/src/main/res/drawable/ic_disclaimer.xml new file mode 100644 index 000000000..fd6ad6dd2 --- /dev/null +++ b/app/src/main/res/drawable/ic_disclaimer.xml @@ -0,0 +1,17 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_donate.xml b/app/src/main/res/drawable/ic_donate.xml new file mode 100644 index 000000000..b86f39cb5 --- /dev/null +++ b/app/src/main/res/drawable/ic_donate.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_download.xml b/app/src/main/res/drawable/ic_download.xml new file mode 100644 index 000000000..0e2c939be --- /dev/null +++ b/app/src/main/res/drawable/ic_download.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_download_line.xml b/app/src/main/res/drawable/ic_download_line.xml new file mode 100644 index 000000000..854a3ec99 --- /dev/null +++ b/app/src/main/res/drawable/ic_download_line.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_exchange.xml b/app/src/main/res/drawable/ic_exchange.xml new file mode 100644 index 000000000..2eb01190b --- /dev/null +++ b/app/src/main/res/drawable/ic_exchange.xml @@ -0,0 +1,17 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_expand_less_24dp.xml b/app/src/main/res/drawable/ic_expand_less_24dp.xml new file mode 100644 index 000000000..4ac9d39c4 --- /dev/null +++ b/app/src/main/res/drawable/ic_expand_less_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_expand_more_24dp.xml b/app/src/main/res/drawable/ic_expand_more_24dp.xml new file mode 100644 index 000000000..82e7ee5de --- /dev/null +++ b/app/src/main/res/drawable/ic_expand_more_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_faq.xml b/app/src/main/res/drawable/ic_faq.xml new file mode 100644 index 000000000..00835615d --- /dev/null +++ b/app/src/main/res/drawable/ic_faq.xml @@ -0,0 +1,17 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_find_replace.xml b/app/src/main/res/drawable/ic_find_replace.xml new file mode 100644 index 000000000..3e9c524b1 --- /dev/null +++ b/app/src/main/res/drawable/ic_find_replace.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_folder.xml b/app/src/main/res/drawable/ic_folder.xml new file mode 100644 index 000000000..7f16bd7c1 --- /dev/null +++ b/app/src/main/res/drawable/ic_folder.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_format_line_spacing.xml b/app/src/main/res/drawable/ic_format_line_spacing.xml new file mode 100644 index 000000000..b1586f195 --- /dev/null +++ b/app/src/main/res/drawable/ic_format_line_spacing.xml @@ -0,0 +1,20 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_groups.xml b/app/src/main/res/drawable/ic_groups.xml new file mode 100644 index 000000000..8a46a8295 --- /dev/null +++ b/app/src/main/res/drawable/ic_groups.xml @@ -0,0 +1,20 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_history.xml b/app/src/main/res/drawable/ic_history.xml new file mode 100644 index 000000000..7a17e5efd --- /dev/null +++ b/app/src/main/res/drawable/ic_history.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_import.xml b/app/src/main/res/drawable/ic_import.xml new file mode 100644 index 000000000..f2ebb9ced --- /dev/null +++ b/app/src/main/res/drawable/ic_import.xml @@ -0,0 +1,19 @@ + + + + + + + diff --git a/app/src/main/res/drawable/ic_interface_setting.xml b/app/src/main/res/drawable/ic_interface_setting.xml new file mode 100644 index 000000000..12377d124 --- /dev/null +++ b/app/src/main/res/drawable/ic_interface_setting.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_last_read.xml b/app/src/main/res/drawable/ic_last_read.xml new file mode 100644 index 000000000..b74e62b0b --- /dev/null +++ b/app/src/main/res/drawable/ic_last_read.xml @@ -0,0 +1,7 @@ + + + diff --git a/app/src/main/res/drawable/ic_launch.xml b/app/src/main/res/drawable/ic_launch.xml new file mode 100644 index 000000000..fd066a65a --- /dev/null +++ b/app/src/main/res/drawable/ic_launch.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_list.xml b/app/src/main/res/drawable/ic_list.xml new file mode 100644 index 000000000..447de0d25 --- /dev/null +++ b/app/src/main/res/drawable/ic_list.xml @@ -0,0 +1,26 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_mail.xml b/app/src/main/res/drawable/ic_mail.xml new file mode 100644 index 000000000..1a141c9ab --- /dev/null +++ b/app/src/main/res/drawable/ic_mail.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_more_vert.xml b/app/src/main/res/drawable/ic_more_vert.xml new file mode 100644 index 000000000..e708a4db1 --- /dev/null +++ b/app/src/main/res/drawable/ic_more_vert.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_network_check.xml b/app/src/main/res/drawable/ic_network_check.xml new file mode 100644 index 000000000..c6ef1b857 --- /dev/null +++ b/app/src/main/res/drawable/ic_network_check.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_pause_24dp.xml b/app/src/main/res/drawable/ic_pause_24dp.xml new file mode 100644 index 000000000..a4eba8213 --- /dev/null +++ b/app/src/main/res/drawable/ic_pause_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_pause_outline_24dp.xml b/app/src/main/res/drawable/ic_pause_outline_24dp.xml new file mode 100644 index 000000000..556cddae7 --- /dev/null +++ b/app/src/main/res/drawable/ic_pause_outline_24dp.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_play_24dp.xml b/app/src/main/res/drawable/ic_play_24dp.xml new file mode 100644 index 000000000..cf5976472 --- /dev/null +++ b/app/src/main/res/drawable/ic_play_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_play_outline_24dp.xml b/app/src/main/res/drawable/ic_play_outline_24dp.xml new file mode 100644 index 000000000..b41d03091 --- /dev/null +++ b/app/src/main/res/drawable/ic_play_outline_24dp.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_qq_group.xml b/app/src/main/res/drawable/ic_qq_group.xml new file mode 100644 index 000000000..e97350048 --- /dev/null +++ b/app/src/main/res/drawable/ic_qq_group.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_read_aloud.xml b/app/src/main/res/drawable/ic_read_aloud.xml new file mode 100644 index 000000000..f0ab5860a --- /dev/null +++ b/app/src/main/res/drawable/ic_read_aloud.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_refresh_black_24dp.xml b/app/src/main/res/drawable/ic_refresh_black_24dp.xml new file mode 100644 index 000000000..6f22d5f31 --- /dev/null +++ b/app/src/main/res/drawable/ic_refresh_black_24dp.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_refresh_white_24dp.xml b/app/src/main/res/drawable/ic_refresh_white_24dp.xml new file mode 100644 index 000000000..5c2f53873 --- /dev/null +++ b/app/src/main/res/drawable/ic_refresh_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_restore.xml b/app/src/main/res/drawable/ic_restore.xml new file mode 100644 index 000000000..12c95ce76 --- /dev/null +++ b/app/src/main/res/drawable/ic_restore.xml @@ -0,0 +1,26 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_save.xml b/app/src/main/res/drawable/ic_save.xml new file mode 100644 index 000000000..27c5b36ce --- /dev/null +++ b/app/src/main/res/drawable/ic_save.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_scan.xml b/app/src/main/res/drawable/ic_scan.xml new file mode 100644 index 000000000..ed5b5f201 --- /dev/null +++ b/app/src/main/res/drawable/ic_scan.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_scoring.xml b/app/src/main/res/drawable/ic_scoring.xml new file mode 100644 index 000000000..b716b3ef8 --- /dev/null +++ b/app/src/main/res/drawable/ic_scoring.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_search.xml b/app/src/main/res/drawable/ic_search.xml new file mode 100644 index 000000000..c7370b2d3 --- /dev/null +++ b/app/src/main/res/drawable/ic_search.xml @@ -0,0 +1,17 @@ + + + + diff --git a/app/src/main/res/drawable/ic_select_all.xml b/app/src/main/res/drawable/ic_select_all.xml new file mode 100644 index 000000000..6e73c7002 --- /dev/null +++ b/app/src/main/res/drawable/ic_select_all.xml @@ -0,0 +1,23 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_settings.xml b/app/src/main/res/drawable/ic_settings.xml new file mode 100644 index 000000000..fe8892929 --- /dev/null +++ b/app/src/main/res/drawable/ic_settings.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_share.xml b/app/src/main/res/drawable/ic_share.xml new file mode 100644 index 000000000..0ed7a1688 --- /dev/null +++ b/app/src/main/res/drawable/ic_share.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_skip_next.xml b/app/src/main/res/drawable/ic_skip_next.xml new file mode 100644 index 000000000..4ad2389e0 --- /dev/null +++ b/app/src/main/res/drawable/ic_skip_next.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_skip_previous.xml b/app/src/main/res/drawable/ic_skip_previous.xml new file mode 100644 index 000000000..1f558a617 --- /dev/null +++ b/app/src/main/res/drawable/ic_skip_previous.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_stop_black_24dp.xml b/app/src/main/res/drawable/ic_stop_black_24dp.xml new file mode 100644 index 000000000..27eec317a --- /dev/null +++ b/app/src/main/res/drawable/ic_stop_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_swap_outline_24dp.xml b/app/src/main/res/drawable/ic_swap_outline_24dp.xml new file mode 100644 index 000000000..52e3355c1 --- /dev/null +++ b/app/src/main/res/drawable/ic_swap_outline_24dp.xml @@ -0,0 +1,20 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_theme.xml b/app/src/main/res/drawable/ic_theme.xml new file mode 100644 index 000000000..7af5b372e --- /dev/null +++ b/app/src/main/res/drawable/ic_theme.xml @@ -0,0 +1,20 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_time_add_24dp.xml b/app/src/main/res/drawable/ic_time_add_24dp.xml new file mode 100644 index 000000000..9114c9848 --- /dev/null +++ b/app/src/main/res/drawable/ic_time_add_24dp.xml @@ -0,0 +1,10 @@ + + + + diff --git a/app/src/main/res/drawable/ic_timer_black_24dp.xml b/app/src/main/res/drawable/ic_timer_black_24dp.xml new file mode 100644 index 000000000..a7338a31f --- /dev/null +++ b/app/src/main/res/drawable/ic_timer_black_24dp.xml @@ -0,0 +1,20 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_toc.xml b/app/src/main/res/drawable/ic_toc.xml new file mode 100644 index 000000000..e21bcf95c --- /dev/null +++ b/app/src/main/res/drawable/ic_toc.xml @@ -0,0 +1,26 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_top_source.xml b/app/src/main/res/drawable/ic_top_source.xml new file mode 100644 index 000000000..2c973959a --- /dev/null +++ b/app/src/main/res/drawable/ic_top_source.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_translate.xml b/app/src/main/res/drawable/ic_translate.xml new file mode 100644 index 000000000..0d5f42df1 --- /dev/null +++ b/app/src/main/res/drawable/ic_translate.xml @@ -0,0 +1,14 @@ + + + + + + diff --git a/app/src/main/res/drawable/ic_tune.xml b/app/src/main/res/drawable/ic_tune.xml new file mode 100644 index 000000000..b9bd12b85 --- /dev/null +++ b/app/src/main/res/drawable/ic_tune.xml @@ -0,0 +1,17 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_update.xml b/app/src/main/res/drawable/ic_update.xml new file mode 100644 index 000000000..0d0e1fe81 --- /dev/null +++ b/app/src/main/res/drawable/ic_update.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_version.xml b/app/src/main/res/drawable/ic_version.xml new file mode 100644 index 000000000..0eccdac3f --- /dev/null +++ b/app/src/main/res/drawable/ic_version.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_view_quilt.xml b/app/src/main/res/drawable/ic_view_quilt.xml new file mode 100644 index 000000000..30f5e324c --- /dev/null +++ b/app/src/main/res/drawable/ic_view_quilt.xml @@ -0,0 +1,26 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_volume_up.xml b/app/src/main/res/drawable/ic_volume_up.xml new file mode 100644 index 000000000..e1e30c7c1 --- /dev/null +++ b/app/src/main/res/drawable/ic_volume_up.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_web_outline.xml b/app/src/main/res/drawable/ic_web_outline.xml new file mode 100644 index 000000000..7bcbe7ca6 --- /dev/null +++ b/app/src/main/res/drawable/ic_web_outline.xml @@ -0,0 +1,13 @@ + + + diff --git a/app/src/main/res/drawable/ic_web_service_noti.xml b/app/src/main/res/drawable/ic_web_service_noti.xml new file mode 100644 index 000000000..edb48575d --- /dev/null +++ b/app/src/main/res/drawable/ic_web_service_noti.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_web_service_phone.xml b/app/src/main/res/drawable/ic_web_service_phone.xml new file mode 100644 index 000000000..4c8c83a40 --- /dev/null +++ b/app/src/main/res/drawable/ic_web_service_phone.xml @@ -0,0 +1,17 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/icon_read_book.png b/app/src/main/res/drawable/icon_read_book.png new file mode 100644 index 0000000000000000000000000000000000000000..016b8cf1677585100b3a89252402b4524e17cd7f GIT binary patch literal 10462 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 GVgC;_7WV=G literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/image_welcome.xml b/app/src/main/res/drawable/image_welcome.xml new file mode 100644 index 000000000..4f5b613b8 --- /dev/null +++ b/app/src/main/res/drawable/image_welcome.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/image_yue_du.webp b/app/src/main/res/drawable/image_yue_du.webp new file mode 100644 index 0000000000000000000000000000000000000000..2d3652cdb529062dd27818be7d2958b33cfb37cf GIT binary patch literal 7540 zcmV-)9gE^pNk&F&9RL7VMM6+kP&go99RL8ZlmMLpDh2{90X~sPo=hdABB&yi={W!r z32AO~?>wjmSLsIsANKR}mA}hQM|KxgvemDHr{IB-^++Xlq zLR#nhFV^p1k7a&~{}23st2fU1!S+}FN4N*_uk3&Ky?y_A;U)Or`98pZ)ql_Ww10K~ z+x>r^udF|8J^??T|91bG>(T6c(g0L0OnpHQs3G+PKA?xx5c+NJ8nR&8;i4Adx%C7- zpoi2D`hp)&L+S{9K@X@Q^#lo}TJfs)3<^nBylTC}0+Lm)mRux?jd<02h6N<6UNv6f zfl2q=G*`eMX=2Eny-=5dQ*`D+hS`FH4uMN3+bGg`k&zy7Q7I)_@v8YJ0fo4JhpJ(o zDhaf`n+#;X2~-ghxIg)w1n}%o11qw$q5oxmB7e&=;iAn4$>%NLc%Xmba%1VcXJ|2y zl$LEWdF4l&j%F zd~PTi8CSLL7!;DNe6r!pXcgt*dQMS71W`b&3vUEp$0Af|_oFn{ie;C}G?s#OL6@sT z_D?zKGL6I;U-K5s^7(a@FiDK$m2PfrynO3;MSs}U{W*;@=#(3qjU6MDPh{yj*GT*s zCfmCYj!r$ zBXpH0O7Yfk7jcYJfaX1shf#rGz33{kGPFCkX0* z2L1e2@ikS`CDq(m!0?*YD};ciXH5P&Tn$3_7UOn_$CL4qS}@0z^it~5$;IZ^%nfIb zLhPCWDqM-wqBC>{-a%b9n|CBLWo(`2FuIy@H=iSv6^B2Xrtbu$=)IXQT1_8I!U+VFIseVrds!m9=*U!`@+8?DV zqQxWffx;uA++Fh=O|0AKGc;2}iL`UdkW%hQ0092^Z~y=R0Hpu`00QOVw%cvC+ikYn zZMGl)01G_(7b4s!mMYZxe>E|-eYF}9& zf44mIhnZNDlUY!43slb5$Q@`fOzw{a_p&*8KBpujOE!jeczwmxCB4h>HTZb30`AH` z#>+f4m5J3XeUrp;Uuid*3x~ZBHC9(>#|%dHO-+YvC9izob1yYoi5E*D;Fur}lvQye zk8ht+=;F1}{eS~Jt=|&(rUZrAAtN**amxUa`$a`8>z6MiA7)5dcpoOI(AUf~&S9imP#=hbH^FJ?k{f)}^8e zPAg;$38Pc%{;+7<%@B&`mIiCgVWy}_pDSS+x+xaxVB`Kpcch~jq6s; zstrJEfzT@RbpNoSKz0#PzuR?I#XWzuv0k09@eO+Yi$+)fY5;~Ja-X)Y9~T$aOdG24 z$e58qskWZGv_V{)Fe6SJ$oAQe7$Qlt3q#`8cxnk<$qUzvmJ7$e0S9w0kxgZ4UZb7|;thbIo zhkTqQQnWFyV=EyKzB(pABRWYeyP=O48n>}I*R=pv{-RNLxzFc%TnfVf+eV}H3ElsS ziYk5N^r3-HGi!Ipk6`dl(rn#V!f5TR_>X4DWT3hDgox`#BVUy(XXw$?-kzta>W0f{ zV<=bg+}vvD|BOLN#0*K3HA=*;3J5g2LlnO&l>Pvl^v*D=l6!q)8iJ>W z7%7ax-(D=x43E<6RY>|WXiJYb<#iQgjr%`A!rzSwjs;piPFiapYIGv!HTu|z=kguI z7K+9*xht|g{COUu5camE;06k0D=;(RN`2|)v`C{n7v5~F^09yfH9z=y6)?L7ILJf| zcA3XGkvKcTOPHm&b{x&N-`nL*F>wQsEu%bm+JXL2>~HRQ&nTT8>!d%;_PvtSA&W@a z3{M<&b78|xIE_M*fIqI!)m!P+FMbnSz-^Y5sU@NoMrJnY7?ltMj-(4Y!iWE;fkL>$c}1NiFYI#?Q=l|1u3}M&snPCy;wv;7vUA zDSaeEwR)5gdmGp7E#Lt5ZP=hx**9aJ%F85aAvuMfnF0BdG1D@y96IY9pXOoJ04Lhe z8h?9`so36I=*#d6c6MjL$sGy(&_FherBsF~(Ks*uj3L6{EKk8#ZF)lykXr`|+`%*C zpO-yf;}DgTi1J|BxV@Y}P#}!!_g~PM)DVPR-b0*MZeO3graM+81PXib>-Sf`m&n+H z)S@pxZ1$Ym*(my(W~5tF`nHZh(iZO?)P;TPZ+)uzDy9nr(6h{$8=0i%W#%-fc8nf7 zhMm6sym41SHwC zAdU*jZU4`!N!nwq?Zz%M6QoG!TP%#(>2^5_qi|Gth~<~c@89LDdV4ncy=>u{l%ym( zZUOdz))e~O38U1}6su(NRUM-1_tS^q&X5T|ZlcgaQS5>R@|u+Ap$9-Ch_h=e*vnAq zUaF7xCrENgjJlOBjxPW( zwXgiwYpT+~n$4$r&qUs?5xC7#W9uIeqRrf*CquKBz~11cUYqqaz@x1&*e_8Q5JoE- zX0ij*{ntBwmWeD8dussN|Fd0MjEO|%97OPQb}%A;8|Y{dbH^MnCJ~gh|IXu!{n(`W z^#2zz^C2GwlGY|ANM&E=qwnX{4L_@`DN}x|q zJ`M!T?YiTd0Fj*X|3Hypk%Q$A%aue$Ujdx}Z0h#0I{oEaXQKe?wW-WinyfPrN%zJP zwB2H)m!hN*0&jY70ao<`CVqJNB-KK(b8|mxf4ZT*Au`E^88eN?50V@yMqe*1+yg)6 zb;iH=PYOu$!~2=syD7Kto7OfEAZ0cZsA3}8<@LT!T5XmW65+^o1OZb?lNfDc6wovn zj75!EG>$EoTYVzJbKbX~kM`I4OhXdE*+0Ml|5aYkMdWjx+|Ok}9F=2XmAf6HbW6j5pO4M_U-|?o1=Dwg881oxI-dK8A1qc-HBhmHEyziJ7+q z`l=knbBVBqvIWFxUcIbR>%WmDn`JFCuQSABi4wYW;->Xtx!ar%5z#?gcCe~`dR3Yr zjGbU-F#v)(LSn7{y`k;|+7EF!6UQ9?r`SQg>^}Aks0$Yn5I0Bk5N{NiD=#Pe3QokB zRHF~~oP&;4(V%MJQY3yj)0|Y5O-GspSdPk8JmaoJ_RyGd7u)>XMVY>pUL>Ie&+Sf# z+yP^pXrj6&L2)+7U}@aRekQW`w6%sX@Gl#*6mj3vi8fXBX;?*B&ca2DckuNyD?xjDb~zEWnpz%v?o+bf4^ zJEc*QWUckT`CeaS`TZWB(q;`Q&fZULc59=Vb4xQ zXgvt_Bsn+TO!8+@(xya`15K_#qav>`e1}#CFS(latR;8~FVH!EHnQK-1pwktVuUub zrg=$4fAsXLLh-g>=Q@rH_sQjz=(f@W>kDEZ0ePj%M`=s5HwIi2UE~jBL^^P;U){Ew zAaVp-^WrSc!RNk(vO4!K&0YGC7M`Peyh#{5PbJkI$g~(y0;#su10FRH$Ieu_y!9=fHLw^B3%QB#GM@g6!!b9ON=1sjsB-jP5Ae zPr6$hZad$|Os%uF+)1$mDZ|l{{Tt>MdSjDh`RmZ7y4)MQ=k%Ky$Cg_gk-)<#r%duc zNJNwIf9I8G(Xg=)VCx-_p4~vL_1`5p(6b^eHt^5zndh=oC+TQr)x8p@A{qpXc&Ir0M|p`4J~uYtjiIWw z{bhdHPQ21eQZeDrGs8V5Ry&nTVdIo~gaAKbQ_xqK^khSLrJ&f73L=L-SnLwm%%V?0 zpo;OAOE^5%0*m0oyG>)i(Kag)KCC}`4DB8R*GWnR$=$dC%%J>9N=CEQp)Ek%7Tm!o z&$p6mJ}7-WO4o!62ZzM3EBmF@rp-*N`CN9c+1i`qjy=xG31lfogN;XPv6sD5Y=+2f zM}-FSoDYi&Mp_t@f9e#jd!N7$xwybmhv7V3pg!Ij57CmI|L-K7WzC*JtBPal_ZT`W zvRgi=9N9aubY_~Tp2P3RT9f7sp%0?M>EP8-4eK_rt{AqFLh2oVodfnz{3=IMy1Iv&w3zAnkuesS7-NK%Uelp1HQg5C!c! zz39d`*rkLCYcVAt19@>MPd{%q0Kon*eUnkU{>o0{{-51Itg_=^PHqqQgg18jZSR9& z-Y;2L?B?YU=Y+*Nt%@rNUCm(V$ct_$KcSr67vdndHVE39TmI4m9D$+nMyO8Ovr;tm z3p*b}A>l&?`E#?dBaT0(@%OK0OR>KbMO>cx1Itwp-LlO!mWlc&Pvvut>NSWGEykuw&pVz%fE9FLJ%49{CTTHrTvwrb7M7bF%;CFp*pJlgSJ79;*<-f7 z-TozTC>}XmM%3jBAJJp;Q1D(usCz~W>MoH%yi3;?1bE|iQtm{_Nr#QSxzw+svlHxq z8WH)-Vx-piFBs#Q+3gE4eSN0V%tlPF? zM_<+ZzE}Iy{^nDDW93&7k+kD>bGwp`#Mn40|13Qh+IUSu&4cTB0InbmcL^8Hen|^4g%L2brt<`H(App)O8>=(^aCoeGd@U|4A@8rpBlW6Zih_w7_vuL|qhL z)$)u07u0{&?#4?+R`C&akX!IX*^gFv#C}pHdA;!vPIK`xI|6hsjH0x=*Aoqm;4;=; ze+5|o59Z}Pe7~#+n1UU4hpE3;UsJ0(p70$0-)Pq5<8;dZ$h-HHo$0Zq+uIn~(eOkA z{oBb7B!DF|xsitMU?Rd+)Q#rl&!tHeRyR3_VXr%h((cqHaq`{d){yTC{rbu z{%=o6G4^XZ2vk)e0kImKk-XMtFjvYYiIIto_v}_2AD|;%a{AELeMa+A!m%887o!ez zf0uR)FXB{Ey1pXNyaRrmnvb1a;E>2y8m?D}giEj7;vZqEV^lY%#n*5#C+tqCRT+M7us2{{mgq;jK64W zs)PWgeb~w{`(#Ojfc-jhcsMkR9LWUG)|dj$WI$3ZZ&EK-LrA39SxyN}jvM&>n;u~} z+?9>ZS`zG+Fy}+h{1dflxL;8Q{lMb#%}OvpS)8M$2r^pw8cu94T@}{krYbv$4INzH zkLdqg4At9gh*Hk2f16G<3)`nV5iAkEqS+n+LCg%^Bd-7P#2M9@=eI|&c0)1nN{?)K zk3Qm-iOBK_n*;Up&L$Il3{8tWwlFTnf5sCF#lGTBzc!R2Tg_5=J&l%-n;Y~AgGO$2 zn!f}%K;=0Jo2E_WCbun7Vj|7TH?#M4BOTf;!4flCHHr3MH)-zQZy`^#nL42_GRMSZ z-UY#t2SL;`Ag|nsp*)lz1`1LKSaw^O7pg#-O z)r~9U6T4O=AtW#*R>?S-qMC>06}A6xKtXMp&!+v_aLYN(mTeg2;doKhpeCgUk;(Wr zeqBn#_dz=xX_+A0t-x~i6UGH$$rc%Y_RwM~|eYgoup zc4(ejRnDlHUL%f#8@xuN8gFFy9j=}l^%rRWACgM&^a(6_U84Z_o}1YZbYOv{`8=5# zYCMn}$8@?_p8rSavWcgn>^s}1N)K65%GGb1J*7@2-;CMnzQf&ZrVqq6_&4QdId$pZ zZs4uBD^U-gyt|>Q`a^?>sfmV?V5;4}8oN#2R=09jef@>p6-7O8g6;odmuc?H47W4X z)avWU1)Hg10_sa~!Te<%f8fTgy$y?|3PrB+qNvhM8YI`9C#N)o4XmIw#{+hKjr2PyK}e&yxieSjw# z*LRL!gn72$=B5k$9vlb@kqrdN>HYH;CeOXZrm*W`N|I<53qiRTr~U4y{O5w=*KG+P z*}?7mq}D@DMT+HQdbv+#RNJO7cyvI17G28hR=*ebz!5ZD&?TN__mA#qeJ;+bc~O`+ z>EV2rfsi`#2?p=~Bi{6uuO{g?yzt7;nDkfIgs43|j-OLK_gKJCVss5yJTyK)hyCG= zp-6E_97(Iyb-zz0r|9Ki7*+CeR}1R&&wO1~%5VL5@VG$DQU4b2^8IHqui}nJs0RL6 z!2vX(0{=W^Nm!+Vv-MYj7oOaj**&Nbd;HGh4M_UbxDPnQx}U5=bxO|lFC%-J?o7)wo^3Z<9Gi1?7IZ24r$A|%~c=L}$7B}ZGtow(Y7{XtL7+I@f z<-PgG2ofC2H>T6(2XM1qVx#Lc5rJpF98v!rm9yu)xt6FLkRDXPlr#9RgK9hgOEkG2 z>IND~H`&XAecCX(+56TDdr>b8aCL-TT+_hN**XG1_?Hvo3e&;_raxYNVJX4rsV0A4 z;btb2-f?=mBK+;cWk{3XHx{$}N<~HR7~(pVM@Oy6G3%TJz8PL;`QtsASB6>(skWAc z;=#!}Eam@C_{VeodseD?+hUF%Eugf@&fTL+CV)D(zt-;pZJc8HJUIt3XWozp11G$G z$X@o2U&*k+zYxwBra`kbPV&|2mhT<&92${eK?*d7g<7C4x(}uf!3VE_?Wa#U)B+2k ze#VB>tMS+HZInWNIkvZ%Vh*3JecTwoB4SXZAIIm?L2vN{woM|HNArC@Vl@lwQ`6Tc z4Y1_ceucpWA4#$u$z$Z(w?^;99yujHlyy$H%TykxLM;SB&n4a9pMr`33lk}TX<6x) z-8~oFrbnJM0RtFcR~|U-TXi7Dv41VyQYUsKC3t_)QzfJ(FZ(@Sdoi!qtaWEZ6<#9e z0`B;oCTA}2gvqF>tUnSmF`_%?dBG@jpYuO3tl(6-!7=aQp#~Ig2H2qkXSN);Al^*_ zJ;kD9`bEcl;HUarqaSdV@w%gyPXY;_x}mBfM&#wT6Hyg6MlEq7Irlacac-H?+ZsmG zFaJuFs)@*RqSI!#&n|OG^|WRF!^q$xbd3#KPlU8(&M9ha@XuPX_?2*mrLw!)N2rv1 zgOrC>p44HsAaMQ@9ClWvKM8@d5NBFc2N(tT|3zPu#3JQtasRDhSM#O9FK7xy&)QE0 KC-mJCKmY)CblHIb literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/img_cover_default.jpg b/app/src/main/res/drawable/img_cover_default.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6504a4e7e8857ff417e2564aec97897265ef3289 GIT binary patch literal 6927 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 + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_fillet_btn_bg.xml b/app/src/main/res/drawable/selector_fillet_btn_bg.xml new file mode 100644 index 000000000..817bb3499 --- /dev/null +++ b/app/src/main/res/drawable/selector_fillet_btn_bg.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_tv_black.xml b/app/src/main/res/drawable/selector_tv_black.xml new file mode 100644 index 000000000..eab98a451 --- /dev/null +++ b/app/src/main/res/drawable/selector_tv_black.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_card_view.xml b/app/src/main/res/drawable/shape_card_view.xml new file mode 100644 index 000000000..20d4d7656 --- /dev/null +++ b/app/src/main/res/drawable/shape_card_view.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_fillet_btn.xml b/app/src/main/res/drawable/shape_fillet_btn.xml new file mode 100644 index 000000000..5a29bf37e --- /dev/null +++ b/app/src/main/res/drawable/shape_fillet_btn.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_fillet_btn_press.xml b/app/src/main/res/drawable/shape_fillet_btn_press.xml new file mode 100644 index 000000000..417341636 --- /dev/null +++ b/app/src/main/res/drawable/shape_fillet_btn_press.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_pop_checkaddshelf_bg.xml b/app/src/main/res/drawable/shape_pop_checkaddshelf_bg.xml new file mode 100644 index 000000000..951803c38 --- /dev/null +++ b/app/src/main/res/drawable/shape_pop_checkaddshelf_bg.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_radius_1dp.xml b/app/src/main/res/drawable/shape_radius_1dp.xml new file mode 100644 index 000000000..ffcc8c82c --- /dev/null +++ b/app/src/main/res/drawable/shape_radius_1dp.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_space_divider.xml b/app/src/main/res/drawable/shape_space_divider.xml new file mode 100644 index 000000000..9a699b89d --- /dev/null +++ b/app/src/main/res/drawable/shape_space_divider.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_text_cursor.xml b/app/src/main/res/drawable/shape_text_cursor.xml new file mode 100644 index 000000000..721c358c6 --- /dev/null +++ b/app/src/main/res/drawable/shape_text_cursor.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 92789a7fb..8e1943029 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,29 +1,24 @@ - - - - - + + + + - - - - + app:headerLayout="@layout/nav_header_main" + app:menu="@menu/activity_main_drawer"/> - - + diff --git a/app/src/main/res/layout/activity_search.xml b/app/src/main/res/layout/activity_search.xml index 4b23ca3d4..33b3b9ddb 100644 --- a/app/src/main/res/layout/activity_search.xml +++ b/app/src/main/res/layout/activity_search.xml @@ -1,39 +1,32 @@ - - - - + + + - + android:layout_height="0dp" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintTop_toBottomOf="@id/title_bar"> - - - - - - + android:layout_height="match_parent"/> - - + - + diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 68b3b25a3..9f8946337 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -10,4 +10,29 @@ 14sp 16sp 18sp + + 24dp + + 0.8dp + 10dp + + 18sp + + 4dp + + 44dp + 88dp + 48sp + 16dp + + 40dp + 8dp + 0dp + + 2dp + + 8dp + 8dp + 8dp + 8dp \ No newline at end of file From 9c5f7f9716f59e7819cc9bdb54c74c9161f6c25f Mon Sep 17 00:00:00 2001 From: GKF Date: Thu, 30 May 2019 13:51:00 +0800 Subject: [PATCH 0032/1997] remove dataBinding --- app/build.gradle | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index f1c81febc..e90ef8109 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,9 +9,6 @@ androidExtensions { android { compileSdkVersion 28 - dataBinding { - enabled = true - } defaultConfig { applicationId "io.legado.app" minSdkVersion 21 From 61a32247376e5308728cfc08a4ba540ab1203651 Mon Sep 17 00:00:00 2001 From: GKF Date: Thu, 30 May 2019 13:58:25 +0800 Subject: [PATCH 0033/1997] up build.gradle --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index e90ef8109..64de5fe3b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -85,6 +85,6 @@ dependencies { implementation 'com.squareup.retrofit2:retrofit:2.5.0' testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test:runner:1.1.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' + androidTestImplementation 'androidx.test:runner:1.2.0' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' } From 5b5c660e02bf36ec249a3afb512bf92fb58461d1 Mon Sep 17 00:00:00 2001 From: GKF Date: Thu, 30 May 2019 14:22:35 +0800 Subject: [PATCH 0034/1997] =?UTF-8?q?=E6=9B=B4=E6=94=B9=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=E5=9B=BE=E6=A0=87=E9=A2=9C=E8=89=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/io/legado/app/base/BaseActivity.kt | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/app/src/main/java/io/legado/app/base/BaseActivity.kt b/app/src/main/java/io/legado/app/base/BaseActivity.kt index 0de007342..a1e6d5cc7 100644 --- a/app/src/main/java/io/legado/app/base/BaseActivity.kt +++ b/app/src/main/java/io/legado/app/base/BaseActivity.kt @@ -1,9 +1,17 @@ package io.legado.app.base +import android.annotation.SuppressLint +import android.graphics.PorterDuff import android.os.Bundle +import android.view.Menu import android.view.MenuItem import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.ViewModel +import io.legado.app.R +import io.legado.app.lib.theme.ColorUtil +import io.legado.app.lib.theme.MaterialValueHelper +import io.legado.app.lib.theme.ThemeStore +import java.util.* abstract class BaseActivity : AppCompatActivity() { @@ -21,6 +29,52 @@ abstract class BaseActivity : AppCompatActivity() { } + /** + * 设置MENU图标颜色 + */ + override fun onCreateOptionsMenu(menu: Menu): Boolean { + val primaryTextColor = + MaterialValueHelper.getPrimaryTextColor(this, ColorUtil.isColorLight(ThemeStore.primaryColor(this))) + for (i in 0 until menu.size()) { + val drawable = menu.getItem(i).icon + if (drawable != null) { + drawable.mutate() + drawable.setColorFilter(primaryTextColor, PorterDuff.Mode.SRC_ATOP) + } + } + return super.onCreateOptionsMenu(menu) + } + + @SuppressLint("PrivateApi") + override fun onMenuOpened(featureId: Int, menu: Menu?): Boolean { + if (menu != null) { + //展开菜单显示图标 + if (menu.javaClass.simpleName.equals("MenuBuilder", ignoreCase = true)) { + try { + var method = menu.javaClass.getDeclaredMethod("setOptionalIconsVisible", java.lang.Boolean.TYPE) + method.isAccessible = true + method.invoke(menu, true) + method = menu.javaClass.getDeclaredMethod("getNonActionItems") + val menuItems = method.invoke(menu) as ArrayList + if (!menuItems.isEmpty()) { + for (menuItem in menuItems) { + val drawable = menuItem.icon + if (drawable != null) { + drawable.mutate() + drawable.setColorFilter( + resources.getColor(R.color.tv_text_default), + PorterDuff.Mode.SRC_ATOP + ) + } + } + } + } catch (ignored: Exception) { + } + } + } + return super.onMenuOpened(featureId, menu) + } + override fun onOptionsItemSelected(item: MenuItem?): Boolean { item?.let { if (it.itemId == android.R.id.home) { From f87efa47cad838b5ec07cbad647b78eeb2bdd330 Mon Sep 17 00:00:00 2001 From: GKF Date: Thu, 30 May 2019 14:25:41 +0800 Subject: [PATCH 0035/1997] =?UTF-8?q?=E6=9B=B4=E6=94=B9=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=E5=9B=BE=E6=A0=87=E9=A2=9C=E8=89=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/io/legado/app/base/BaseActivity.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/base/BaseActivity.kt b/app/src/main/java/io/legado/app/base/BaseActivity.kt index a1e6d5cc7..368f60519 100644 --- a/app/src/main/java/io/legado/app/base/BaseActivity.kt +++ b/app/src/main/java/io/legado/app/base/BaseActivity.kt @@ -33,8 +33,8 @@ abstract class BaseActivity : AppCompatActivity() { * 设置MENU图标颜色 */ override fun onCreateOptionsMenu(menu: Menu): Boolean { - val primaryTextColor = - MaterialValueHelper.getPrimaryTextColor(this, ColorUtil.isColorLight(ThemeStore.primaryColor(this))) + val primaryTextColor = MaterialValueHelper + .getPrimaryTextColor(this, ColorUtil.isColorLight(ThemeStore.primaryColor(this))) for (i in 0 until menu.size()) { val drawable = menu.getItem(i).icon if (drawable != null) { @@ -56,7 +56,7 @@ abstract class BaseActivity : AppCompatActivity() { method.invoke(menu, true) method = menu.javaClass.getDeclaredMethod("getNonActionItems") val menuItems = method.invoke(menu) as ArrayList - if (!menuItems.isEmpty()) { + if (menuItems.isNotEmpty()) { for (menuItem in menuItems) { val drawable = menuItem.icon if (drawable != null) { From 369663073e3d67568b3871c38db5cb3d60d04d37 Mon Sep 17 00:00:00 2001 From: GKF Date: Thu, 30 May 2019 16:16:11 +0800 Subject: [PATCH 0036/1997] Theme View --- .../lib/theme/prefs/ATEPreferenceCategory.kt | 36 +++++++ .../lib/theme/prefs/ATESwitchPreference.kt | 52 ++++++++++ .../app/lib/theme/prefs/IconListPreference.kt | 95 +++++++++++++++++++ .../app/lib/theme/view/ATEAccentBgTextView.kt | 33 +++++++ .../lib/theme/view/ATEAccentStrokeTextView.kt | 39 ++++++++ .../lib/theme/view/ATEAutoCompleteTextView.kt | 33 +++++++ .../legado/app/lib/theme/view/ATECheckBox.kt | 29 ++++++ .../legado/app/lib/theme/view/ATEEditText.kt | 29 ++++++ .../app/lib/theme/view/ATEPrimaryTextView.kt | 28 ++++++ .../app/lib/theme/view/ATEProgressBar.kt | 41 ++++++++ .../app/lib/theme/view/ATERadioButton.kt | 29 ++++++ .../app/lib/theme/view/ATERadioNoButton.kt | 37 ++++++++ .../lib/theme/view/ATESecondaryTextView.kt | 28 ++++++ .../legado/app/lib/theme/view/ATESeekBar.kt | 29 ++++++ .../app/lib/theme/view/ATEStockSwitch.kt | 34 +++++++ .../app/lib/theme/view/ATEStrokeTextView.kt | 41 ++++++++ .../io/legado/app/lib/theme/view/ATESwitch.kt | 34 +++++++ .../app/lib/theme/view/ATETextInputLayout.kt | 31 ++++++ .../io/legado/app/utils/FloatExtensions.kt | 16 ++++ .../java/io/legado/app/utils/IntExtensions.kt | 13 +++ .../main/res/layout/item_icon_preference.xml | 31 ++++++ app/src/main/res/layout/view_icon.xml | 5 + app/src/main/res/values/attrs.xml | 56 ++++++++++- 23 files changed, 798 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/io/legado/app/lib/theme/prefs/ATEPreferenceCategory.kt create mode 100644 app/src/main/java/io/legado/app/lib/theme/prefs/ATESwitchPreference.kt create mode 100644 app/src/main/java/io/legado/app/lib/theme/prefs/IconListPreference.kt create mode 100644 app/src/main/java/io/legado/app/lib/theme/view/ATEAccentBgTextView.kt create mode 100644 app/src/main/java/io/legado/app/lib/theme/view/ATEAccentStrokeTextView.kt create mode 100644 app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt create mode 100644 app/src/main/java/io/legado/app/lib/theme/view/ATECheckBox.kt create mode 100644 app/src/main/java/io/legado/app/lib/theme/view/ATEEditText.kt create mode 100644 app/src/main/java/io/legado/app/lib/theme/view/ATEPrimaryTextView.kt create mode 100644 app/src/main/java/io/legado/app/lib/theme/view/ATEProgressBar.kt create mode 100644 app/src/main/java/io/legado/app/lib/theme/view/ATERadioButton.kt create mode 100644 app/src/main/java/io/legado/app/lib/theme/view/ATERadioNoButton.kt create mode 100644 app/src/main/java/io/legado/app/lib/theme/view/ATESecondaryTextView.kt create mode 100644 app/src/main/java/io/legado/app/lib/theme/view/ATESeekBar.kt create mode 100644 app/src/main/java/io/legado/app/lib/theme/view/ATEStockSwitch.kt create mode 100644 app/src/main/java/io/legado/app/lib/theme/view/ATEStrokeTextView.kt create mode 100644 app/src/main/java/io/legado/app/lib/theme/view/ATESwitch.kt create mode 100644 app/src/main/java/io/legado/app/lib/theme/view/ATETextInputLayout.kt create mode 100644 app/src/main/java/io/legado/app/utils/FloatExtensions.kt create mode 100644 app/src/main/java/io/legado/app/utils/IntExtensions.kt create mode 100644 app/src/main/res/layout/item_icon_preference.xml create mode 100644 app/src/main/res/layout/view_icon.xml diff --git a/app/src/main/java/io/legado/app/lib/theme/prefs/ATEPreferenceCategory.kt b/app/src/main/java/io/legado/app/lib/theme/prefs/ATEPreferenceCategory.kt new file mode 100644 index 000000000..2029744ed --- /dev/null +++ b/app/src/main/java/io/legado/app/lib/theme/prefs/ATEPreferenceCategory.kt @@ -0,0 +1,36 @@ +package io.legado.app.lib.theme.prefs + +import android.content.Context +import android.os.Build +import android.preference.PreferenceCategory +import android.util.AttributeSet +import android.view.View +import android.widget.TextView +import androidx.annotation.RequiresApi +import io.legado.app.lib.theme.ThemeStore + + +class ATEPreferenceCategory : PreferenceCategory { + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super( + context, + attrs, + defStyleAttr, + defStyleRes + ) + + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) + + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) + + constructor(context: Context) : super(context) + + override fun onBindView(view: View) { + super.onBindView(view) + if (view is TextView) { + view.setTextColor(ThemeStore.accentColor(view.getContext()))//设置title文本的颜色 + } + } + +} diff --git a/app/src/main/java/io/legado/app/lib/theme/prefs/ATESwitchPreference.kt b/app/src/main/java/io/legado/app/lib/theme/prefs/ATESwitchPreference.kt new file mode 100644 index 000000000..8d3ca5f56 --- /dev/null +++ b/app/src/main/java/io/legado/app/lib/theme/prefs/ATESwitchPreference.kt @@ -0,0 +1,52 @@ +package io.legado.app.lib.theme.prefs + +import android.content.Context +import android.os.Build +import android.preference.SwitchPreference +import android.util.AttributeSet +import android.view.View +import android.view.ViewGroup +import android.widget.Switch +import androidx.annotation.RequiresApi +import io.legado.app.lib.theme.ATH +import io.legado.app.lib.theme.ThemeStore +import java.util.* + +class ATESwitchPreference : SwitchPreference { + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super( + context, + attrs, + defStyleAttr, + defStyleRes + ) + + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) + + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) + + constructor(context: Context) : super(context) + + override fun onBindView(view: View) { + super.onBindView(view) + + if (view is ViewGroup) { + val queue = LinkedList() + queue.add(view) + while (!queue.isEmpty()) { + val current = queue.removeFirst() + for (i in 0 until current.childCount) { + if (current.getChildAt(i) is Switch) { + ATH.setTint(current.getChildAt(i), ThemeStore.accentColor(view.getContext())) + return + } else if (current.getChildAt(i) is ViewGroup) { + queue.addLast(current.getChildAt(i) as ViewGroup) + } + } + } + } + + } + +} diff --git a/app/src/main/java/io/legado/app/lib/theme/prefs/IconListPreference.kt b/app/src/main/java/io/legado/app/lib/theme/prefs/IconListPreference.kt new file mode 100644 index 000000000..f1389a989 --- /dev/null +++ b/app/src/main/java/io/legado/app/lib/theme/prefs/IconListPreference.kt @@ -0,0 +1,95 @@ +package io.legado.app.lib.theme.prefs + +import android.annotation.SuppressLint +import android.app.Activity +import android.app.AlertDialog.Builder +import android.content.Context +import android.graphics.drawable.Drawable +import android.preference.ListPreference +import android.util.AttributeSet +import android.view.View +import android.view.ViewGroup +import android.widget.ArrayAdapter +import android.widget.CheckedTextView +import android.widget.ImageView +import android.widget.ListAdapter +import io.legado.app.R +import java.util.* + + +class IconListPreference(context: Context, attrs: AttributeSet) : ListPreference(context, attrs) { + + private val mEntryDrawables = ArrayList() + + init { + + val a = context.theme.obtainStyledAttributes(attrs, R.styleable.IconListPreference, 0, 0) + + val drawables: Array + + try { + drawables = a.getTextArray(R.styleable.IconListPreference_icons) + } finally { + a.recycle() + } + + for (drawable in drawables) { + val resId = context.resources.getIdentifier(drawable.toString(), "mipmap", context.packageName) + + val d = context.resources.getDrawable(resId) + + mEntryDrawables.add(d) + } + + widgetLayoutResource = R.layout.view_icon + } + + protected fun createListAdapter(): ListAdapter { + val selectedValue = value + val selectedIndex = findIndexOfValue(selectedValue) + return AppArrayAdapter(context, R.layout.item_icon_preference, entries, mEntryDrawables, selectedIndex) + } + + override fun onBindView(view: View) { + super.onBindView(view) + + val selectedValue = value + val selectedIndex = findIndexOfValue(selectedValue) + + val drawable = mEntryDrawables[selectedIndex] + + (view.findViewById(R.id.preview) as ImageView).setImageDrawable(drawable) + } + + override fun onPrepareDialogBuilder(builder: Builder) { + builder.setAdapter(createListAdapter(), this) + super.onPrepareDialogBuilder(builder) + } + + inner class AppArrayAdapter( + context: Context, textViewResourceId: Int, + objects: Array, imageDrawables: List, + selectedIndex: Int + ) : ArrayAdapter(context, textViewResourceId, objects) { + private var mImageDrawables: List? = null + private var mSelectedIndex = 0 + + init { + mSelectedIndex = selectedIndex + mImageDrawables = imageDrawables + } + + @SuppressLint("ViewHolder") + override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { + val inflater = (context as Activity).layoutInflater + val view = inflater.inflate(R.layout.item_icon_preference, parent, false) + val textView = view.findViewById(R.id.label) as CheckedTextView + textView.text = getItem(position) + textView.isChecked = position == mSelectedIndex + + val imageView = view.findViewById(R.id.icon) as ImageView + imageView.setImageDrawable(mImageDrawables!![position]) + return view + } + } +} diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATEAccentBgTextView.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATEAccentBgTextView.kt new file mode 100644 index 000000000..ae66905dd --- /dev/null +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATEAccentBgTextView.kt @@ -0,0 +1,33 @@ +package io.legado.app.lib.theme.view + +import android.content.Context +import android.graphics.Color +import android.util.AttributeSet +import androidx.appcompat.widget.AppCompatTextView +import io.legado.app.lib.theme.ColorUtil +import io.legado.app.lib.theme.Selector +import io.legado.app.lib.theme.ThemeStore +import io.legado.app.utils.dp + +class ATEAccentBgTextView : AppCompatTextView { + constructor(context: Context) : super(context) { + init(context, null) + } + + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { + init(context, attrs) + } + + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { + init(context, attrs) + } + + private fun init(context: Context, attrs: AttributeSet?) { + background = Selector.shapeBuild() + .setCornerRadius(3.dp) + .setDefaultBgColor(ThemeStore.accentColor(context)) + .setPressedBgColor(ColorUtil.darkenColor(ThemeStore.accentColor(context))) + .create() + setTextColor(Color.WHITE) + } +} diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATEAccentStrokeTextView.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATEAccentStrokeTextView.kt new file mode 100644 index 000000000..def0146f3 --- /dev/null +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATEAccentStrokeTextView.kt @@ -0,0 +1,39 @@ +package io.legado.app.lib.theme.view + +import android.content.Context +import android.util.AttributeSet +import androidx.appcompat.widget.AppCompatTextView +import io.legado.app.R +import io.legado.app.lib.theme.Selector +import io.legado.app.lib.theme.ThemeStore +import io.legado.app.utils.dp + +class ATEAccentStrokeTextView : AppCompatTextView { + constructor(context: Context) : super(context) { + init(context, null) + } + + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { + init(context, attrs) + } + + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { + init(context, attrs) + } + + private fun init(context: Context, attrs: AttributeSet?) { + background = Selector.shapeBuild() + .setCornerRadius(3.dp) + .setStrokeWidth(1.dp) + .setDisabledStrokeColor(context.resources.getColor(R.color.md_grey_500)) + .setDefaultStrokeColor(ThemeStore.accentColor(context)) + .setPressedBgColor(context.resources.getColor(R.color.transparent30)) + .create() + setTextColor( + Selector.colorBuild() + .setDefaultColor(ThemeStore.accentColor(context)) + .setDisabledColor(context.resources.getColor(R.color.md_grey_500)) + .create() + ) + } +} diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt new file mode 100644 index 000000000..4a4688fbb --- /dev/null +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt @@ -0,0 +1,33 @@ +package io.legado.app.lib.theme.view + +import android.content.Context +import android.os.Build +import android.util.AttributeSet +import androidx.appcompat.widget.AppCompatAutoCompleteTextView +import io.legado.app.lib.theme.Selector +import io.legado.app.lib.theme.ThemeStore + + +class ATEAutoCompleteTextView : AppCompatAutoCompleteTextView { + + constructor(context: Context) : super(context) { + init(context) + } + + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { + init(context) + } + + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { + init(context) + } + + private fun init(context: Context) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + backgroundTintList = Selector.colorBuild() + .setFocusedColor(ThemeStore.accentColor(context)) + .setDefaultColor(ThemeStore.textColorPrimary(context)) + .create() + } + } +} diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATECheckBox.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATECheckBox.kt new file mode 100644 index 000000000..15e3b5f14 --- /dev/null +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATECheckBox.kt @@ -0,0 +1,29 @@ +package io.legado.app.lib.theme.view + +import android.content.Context +import android.util.AttributeSet +import androidx.appcompat.widget.AppCompatCheckBox +import io.legado.app.lib.theme.ATH +import io.legado.app.lib.theme.ThemeStore + +/** + * @author Aidan Follestad (afollestad) + */ +class ATECheckBox : AppCompatCheckBox { + + constructor(context: Context) : super(context) { + init(context, null) + } + + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { + init(context, attrs) + } + + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { + init(context, attrs) + } + + private fun init(context: Context, attrs: AttributeSet?) { + ATH.setTint(this, ThemeStore.accentColor(context)) + } +} diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATEEditText.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATEEditText.kt new file mode 100644 index 000000000..c70ea4eda --- /dev/null +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATEEditText.kt @@ -0,0 +1,29 @@ +package io.legado.app.lib.theme.view + +import android.content.Context +import android.util.AttributeSet +import androidx.appcompat.widget.AppCompatEditText +import io.legado.app.lib.theme.ATH +import io.legado.app.lib.theme.ThemeStore + +/** + * @author Aidan Follestad (afollestad) + */ +class ATEEditText : AppCompatEditText { + + constructor(context: Context) : super(context) { + init(context, null) + } + + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { + init(context, attrs) + } + + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { + init(context, attrs) + } + + private fun init(context: Context, attrs: AttributeSet?) { + ATH.setTint(this, ThemeStore.accentColor(context)) + } +} diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATEPrimaryTextView.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATEPrimaryTextView.kt new file mode 100644 index 000000000..b39385688 --- /dev/null +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATEPrimaryTextView.kt @@ -0,0 +1,28 @@ +package io.legado.app.lib.theme.view + +import android.content.Context +import android.util.AttributeSet +import androidx.appcompat.widget.AppCompatTextView +import io.legado.app.lib.theme.ThemeStore + +/** + * @author Aidan Follestad (afollestad) + */ +class ATEPrimaryTextView : AppCompatTextView { + + constructor(context: Context) : super(context) { + init(context, null) + } + + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { + init(context, attrs) + } + + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { + init(context, attrs) + } + + private fun init(context: Context, attrs: AttributeSet?) { + setTextColor(ThemeStore.textColorPrimary(context)) + } +} diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATEProgressBar.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATEProgressBar.kt new file mode 100644 index 000000000..3a1809f16 --- /dev/null +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATEProgressBar.kt @@ -0,0 +1,41 @@ +package io.legado.app.lib.theme.view + +import android.annotation.TargetApi +import android.content.Context +import android.os.Build +import android.util.AttributeSet +import android.widget.ProgressBar +import io.legado.app.lib.theme.ATH +import io.legado.app.lib.theme.ThemeStore + +/** + * @author Aidan Follestad (afollestad) + */ +class ATEProgressBar : ProgressBar { + + constructor(context: Context) : super(context) { + init(context, null) + } + + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { + init(context, attrs) + } + + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { + init(context, attrs) + } + + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super( + context, + attrs, + defStyleAttr, + defStyleRes + ) { + init(context, attrs) + } + + private fun init(context: Context, attrs: AttributeSet?) { + ATH.setTint(this, ThemeStore.accentColor(context)) + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATERadioButton.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATERadioButton.kt new file mode 100644 index 000000000..583d5e054 --- /dev/null +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATERadioButton.kt @@ -0,0 +1,29 @@ +package io.legado.app.lib.theme.view + +import android.content.Context +import android.util.AttributeSet +import androidx.appcompat.widget.AppCompatRadioButton +import io.legado.app.lib.theme.ATH +import io.legado.app.lib.theme.ThemeStore + +/** + * @author Aidan Follestad (afollestad) + */ +class ATERadioButton : AppCompatRadioButton { + + constructor(context: Context) : super(context) { + init(context, null) + } + + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { + init(context, attrs) + } + + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { + init(context, attrs) + } + + private fun init(context: Context, attrs: AttributeSet?) { + ATH.setTint(this, ThemeStore.accentColor(context)) + } +} diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATERadioNoButton.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATERadioNoButton.kt new file mode 100644 index 000000000..138f05992 --- /dev/null +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATERadioNoButton.kt @@ -0,0 +1,37 @@ +package io.legado.app.lib.theme.view + +import android.content.Context +import android.graphics.Color +import android.util.AttributeSet +import androidx.appcompat.widget.AppCompatRadioButton +import io.legado.app.lib.theme.Selector +import io.legado.app.lib.theme.ThemeStore +import io.legado.app.utils.dp + +/** + * @author Aidan Follestad (afollestad) + */ +class ATERadioNoButton : AppCompatRadioButton { + + constructor(context: Context) : super(context) { + init(context, null) + } + + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { + init(context, attrs) + } + + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { + init(context, attrs) + } + + private fun init(context: Context, attrs: AttributeSet?) { + background = Selector.shapeBuild() + .setCornerRadius(3.dp) + .setStrokeWidth(3.dp) + .setCheckedBgColor(ThemeStore.accentColor(context)) + .setCheckedStrokeColor(ThemeStore.accentColor(context)) + .setDefaultStrokeColor(Color.WHITE) + .create() + } +} diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATESecondaryTextView.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATESecondaryTextView.kt new file mode 100644 index 000000000..dec5d938e --- /dev/null +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATESecondaryTextView.kt @@ -0,0 +1,28 @@ +package io.legado.app.lib.theme.view + +import android.content.Context +import android.util.AttributeSet +import androidx.appcompat.widget.AppCompatTextView +import io.legado.app.lib.theme.ThemeStore + +/** + * @author Aidan Follestad (afollestad) + */ +class ATESecondaryTextView : AppCompatTextView { + + constructor(context: Context) : super(context) { + init(context, null) + } + + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { + init(context, attrs) + } + + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { + init(context, attrs) + } + + private fun init(context: Context, attrs: AttributeSet?) { + setTextColor(ThemeStore.textColorSecondary(context)) + } +} diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATESeekBar.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATESeekBar.kt new file mode 100644 index 000000000..4a49b34f3 --- /dev/null +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATESeekBar.kt @@ -0,0 +1,29 @@ +package io.legado.app.lib.theme.view + +import android.content.Context +import android.util.AttributeSet +import androidx.appcompat.widget.AppCompatSeekBar +import io.legado.app.lib.theme.ATH +import io.legado.app.lib.theme.ThemeStore + +/** + * @author Aidan Follestad (afollestad) + */ +class ATESeekBar : AppCompatSeekBar { + + constructor(context: Context) : super(context) { + init(context, null) + } + + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { + init(context, attrs) + } + + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { + init(context, attrs) + } + + private fun init(context: Context, attrs: AttributeSet?) { + ATH.setTint(this, ThemeStore.accentColor(context)) + } +} diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATEStockSwitch.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATEStockSwitch.kt new file mode 100644 index 000000000..a22f3ee47 --- /dev/null +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATEStockSwitch.kt @@ -0,0 +1,34 @@ +package io.legado.app.lib.theme.view + +import android.content.Context +import android.util.AttributeSet +import android.view.View +import android.widget.Switch +import io.legado.app.lib.theme.ATH +import io.legado.app.lib.theme.ThemeStore + +/** + * @author Aidan Follestad (afollestad) + */ +class ATEStockSwitch : Switch { + + constructor(context: Context) : super(context) { + init(context, null) + } + + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { + init(context, attrs) + } + + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { + init(context, attrs) + } + + private fun init(context: Context, attrs: AttributeSet?) { + ATH.setTint(this, ThemeStore.accentColor(context)) + } + + override fun isShown(): Boolean { + return parent != null && visibility == View.VISIBLE + } +} diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATEStrokeTextView.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATEStrokeTextView.kt new file mode 100644 index 000000000..ee6697224 --- /dev/null +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATEStrokeTextView.kt @@ -0,0 +1,41 @@ +package io.legado.app.lib.theme.view + +import android.content.Context +import android.util.AttributeSet +import androidx.appcompat.widget.AppCompatTextView +import io.legado.app.R +import io.legado.app.lib.theme.Selector +import io.legado.app.lib.theme.ThemeStore +import io.legado.app.utils.dp + +class ATEStrokeTextView : AppCompatTextView { + constructor(context: Context) : super(context) { + init(context, null) + } + + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { + init(context, attrs) + } + + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { + init(context, attrs) + } + + private fun init(context: Context, attrs: AttributeSet?) { + background = Selector.shapeBuild() + .setCornerRadius(1.dp) + .setStrokeWidth(1.dp) + .setDisabledStrokeColor(context.resources.getColor(R.color.md_grey_500)) + .setDefaultStrokeColor(ThemeStore.textColorSecondary(context)) + .setSelectedStrokeColor(ThemeStore.accentColor(context)) + .setPressedBgColor(context.resources.getColor(R.color.transparent30)) + .create() + setTextColor( + Selector.colorBuild() + .setDefaultColor(ThemeStore.textColorSecondary(context)) + .setSelectedColor(ThemeStore.accentColor(context)) + .setDisabledColor(context.resources.getColor(R.color.md_grey_500)) + .create() + ) + } +} diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATESwitch.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATESwitch.kt new file mode 100644 index 000000000..6a718559e --- /dev/null +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATESwitch.kt @@ -0,0 +1,34 @@ +package io.legado.app.lib.theme.view + +import android.content.Context +import android.util.AttributeSet +import android.view.View +import android.widget.Switch +import io.legado.app.lib.theme.ATH +import io.legado.app.lib.theme.ThemeStore + +/** + * @author Aidan Follestad (afollestad) + */ +class ATESwitch : Switch { + + constructor(context: Context) : super(context) { + init(context, null) + } + + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { + init(context, attrs) + } + + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { + init(context, attrs) + } + + private fun init(context: Context, attrs: AttributeSet?) { + ATH.setTint(this, ThemeStore.accentColor(context)) + } + + override fun isShown(): Boolean { + return parent != null && visibility == View.VISIBLE + } +} diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATETextInputLayout.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATETextInputLayout.kt new file mode 100644 index 000000000..e09b03e2c --- /dev/null +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATETextInputLayout.kt @@ -0,0 +1,31 @@ +package io.legado.app.lib.theme.view + +import android.content.Context +import android.graphics.Canvas +import android.util.AttributeSet +import com.google.android.material.textfield.TextInputLayout +import io.legado.app.lib.theme.Selector +import io.legado.app.lib.theme.ThemeStore + +class ATETextInputLayout : TextInputLayout { + constructor(context: Context) : super(context) { + init(context) + } + + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { + init(context) + } + + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { + init(context) + } + + private fun init(context: Context) { + defaultHintTextColor = Selector.colorBuild().setDefaultColor(ThemeStore.accentColor(context)).create() + } + + override fun draw(canvas: Canvas) { + + super.draw(canvas) + } +} diff --git a/app/src/main/java/io/legado/app/utils/FloatExtensions.kt b/app/src/main/java/io/legado/app/utils/FloatExtensions.kt new file mode 100644 index 000000000..af9576c00 --- /dev/null +++ b/app/src/main/java/io/legado/app/utils/FloatExtensions.kt @@ -0,0 +1,16 @@ +package io.legado.app.utils + +import android.content.res.Resources + + +val Float.dp: Float // [xxhdpi](360 -> 1080) + get() = android.util.TypedValue.applyDimension( + android.util.TypedValue.COMPLEX_UNIT_DIP, this, Resources.getSystem().displayMetrics + ) + + +val Float.sp: Float // [xxhdpi](360 -> 1080) + get() = android.util.TypedValue.applyDimension( + android.util.TypedValue.COMPLEX_UNIT_SP, this, Resources.getSystem().displayMetrics + ) + diff --git a/app/src/main/java/io/legado/app/utils/IntExtensions.kt b/app/src/main/java/io/legado/app/utils/IntExtensions.kt new file mode 100644 index 000000000..11946c14a --- /dev/null +++ b/app/src/main/java/io/legado/app/utils/IntExtensions.kt @@ -0,0 +1,13 @@ +package io.legado.app.utils + +import android.content.res.Resources + +val Int.dp: Int + get() = android.util.TypedValue.applyDimension( + android.util.TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), Resources.getSystem().displayMetrics + ).toInt() + +val Int.sp: Int + get() = android.util.TypedValue.applyDimension( + android.util.TypedValue.COMPLEX_UNIT_SP, this.toFloat(), Resources.getSystem().displayMetrics + ).toInt() \ No newline at end of file diff --git a/app/src/main/res/layout/item_icon_preference.xml b/app/src/main/res/layout/item_icon_preference.xml new file mode 100644 index 000000000..a2063a71f --- /dev/null +++ b/app/src/main/res/layout/item_icon_preference.xml @@ -0,0 +1,31 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_icon.xml b/app/src/main/res/layout/view_icon.xml new file mode 100644 index 000000000..d0247c6ef --- /dev/null +++ b/app/src/main/res/layout/view_icon.xml @@ -0,0 +1,5 @@ + + \ No newline at end of file diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index fc861ecca..7bbabf7f6 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -44,5 +44,59 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 97f549dc931e229afcf6a3be2ee3834ed68b6efb Mon Sep 17 00:00:00 2001 From: GKF Date: Thu, 30 May 2019 16:34:38 +0800 Subject: [PATCH 0037/1997] Theme --- app/src/main/AndroidManifest.xml | 4 +- app/src/main/res/values-v21/styles.xml | 2 +- app/src/main/res/values/styles.xml | 83 ++++++++++++++++++++++++-- 3 files changed, 80 insertions(+), 9 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3bef8cc80..9d4cfaca1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -23,7 +23,7 @@ android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" - android:theme="@style/AppTheme" + android:theme="@style/CAppTheme" tools:ignore="AllowBackup,GoogleAppIndexingWarning"> @@ -32,7 +32,7 @@ + android:theme="@style/CAppTheme.NoActionBar"> diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml index e54680451..16b48ec19 100644 --- a/app/src/main/res/values-v21/styles.xml +++ b/app/src/main/res/values-v21/styles.xml @@ -1,5 +1,5 @@ - + + + + + + + + + + - + + + + + + + + + + - + + + + + + + + + - - - @@ -27,41 +29,54 @@ @color/colorPrimary @color/colorPrimaryDark @color/colorAccent - @style/PopupMenu - @style/MenuItemTextStyle - @style/PopupMenu + @style/Style.PopupMenu + @style/Style.MenuItemText + @style/Style.PopupMenu - + + - + + + + //**************************************************************System Style******************************************************************************// + - + + - - - - + //**************************************************************Widget Style******************************************************************************// - - - - - - From cd211f87a9b640beaa5e8dfdd52b9d443473cd53 Mon Sep 17 00:00:00 2001 From: Invinciblelee <1760316362@qq.com> Date: Fri, 31 May 2019 18:36:37 +0800 Subject: [PATCH 0049/1997] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/io/legado/app/base/BaseActivity.kt | 37 ++++++---- .../io/legado/app/lib/theme/DrawableUtils.kt | 24 ++++--- .../io/legado/app/ui/main/MainActivity.kt | 5 +- .../java/io/legado/app/ui/widget/TitleBar.kt | 11 +-- app/src/main/res/menu/main.xml | 7 ++ app/src/main/res/values/attrs.xml | 72 +++++++++---------- app/src/main/res/values/styles.xml | 2 +- 7 files changed, 92 insertions(+), 66 deletions(-) diff --git a/app/src/main/java/io/legado/app/base/BaseActivity.kt b/app/src/main/java/io/legado/app/base/BaseActivity.kt index c58318df1..652976bcf 100644 --- a/app/src/main/java/io/legado/app/base/BaseActivity.kt +++ b/app/src/main/java/io/legado/app/base/BaseActivity.kt @@ -4,6 +4,7 @@ import android.os.Bundle import android.view.Menu import android.view.MenuItem import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.view.menu.MenuBuilder import androidx.appcompat.view.menu.MenuItemImpl import androidx.core.content.ContextCompat import androidx.lifecycle.ViewModel @@ -30,17 +31,29 @@ abstract class BaseActivity : AppCompatActivity() { } - /** - * 设置MENU图标颜色 - */ - override fun onCreateOptionsMenu(menu: Menu): Boolean { - val primaryTextColor = getPrimaryTextColor(ColorUtils.isColorLight(ThemeStore.primaryColor(this))) - val defaultTextColor = ContextCompat.getColor(this, R.color.tv_text_default) - for (i in 0 until menu.size()) { - (menu.getItem(i) as MenuItemImpl).let {//overflow:展开的item - DrawableUtils.setTint(it.icon, if (it.requiresOverflow()) defaultTextColor else primaryTextColor) + override fun onCreateOptionsMenu(menu: Menu?): Boolean { + return menu?.let { + if (it is MenuBuilder) { + it.setOptionalIconsVisible(true) } - } + val bool = onCompatCreateOptionsMenu(it) + val primaryTextColor = getPrimaryTextColor(ColorUtils.isColorLight(ThemeStore.primaryColor(this))) + val defaultTextColor = ContextCompat.getColor(this, R.color.tv_text_default) + for (i in 0 until menu.size()) { + (menu.getItem(i) as MenuItemImpl).let { item -> + //overflow:展开的item + DrawableUtils.setTint( + item.icon, + if (item.requiresOverflow()) defaultTextColor else primaryTextColor + ) + } + } + bool + } ?: super.onCreateOptionsMenu(menu) + } + + + open fun onCompatCreateOptionsMenu(menu: Menu): Boolean { return super.onCreateOptionsMenu(menu) } @@ -74,7 +87,7 @@ abstract class BaseActivity : AppCompatActivity() { // return super.onMenuOpened(featureId, menu) // } - override fun onOptionsItemSelected(item: MenuItem?): Boolean { + final override fun onOptionsItemSelected(item: MenuItem?): Boolean { item?.let { if (it.itemId == android.R.id.home) { supportFinishAfterTransition() @@ -85,7 +98,7 @@ abstract class BaseActivity : AppCompatActivity() { } open fun onCompatOptionsItemSelected(item: MenuItem): Boolean { - return true + return super.onOptionsItemSelected(item) } protected fun initTheme() { diff --git a/app/src/main/java/io/legado/app/lib/theme/DrawableUtils.kt b/app/src/main/java/io/legado/app/lib/theme/DrawableUtils.kt index 08b43fc82..660448088 100644 --- a/app/src/main/java/io/legado/app/lib/theme/DrawableUtils.kt +++ b/app/src/main/java/io/legado/app/lib/theme/DrawableUtils.kt @@ -26,18 +26,22 @@ object DrawableUtils { return TransitionDrawable(drawables) } - fun setTintList(drawable: Drawable, tint: ColorStateList, tintMode: PorterDuff.Mode = PorterDuff.Mode.SRC_ATOP) { - val wrappedDrawable = DrawableCompat.wrap(drawable) - wrappedDrawable.mutate() - DrawableCompat.setTintMode(wrappedDrawable, tintMode) - DrawableCompat.setTintList(wrappedDrawable, tint) + fun setTintList(drawable: Drawable?, tint: ColorStateList, tintMode: PorterDuff.Mode = PorterDuff.Mode.SRC_ATOP) { + drawable?.let { + val wrappedDrawable = DrawableCompat.wrap(it) + wrappedDrawable.mutate() + DrawableCompat.setTintMode(wrappedDrawable, tintMode) + DrawableCompat.setTintList(wrappedDrawable, tint) + } } - fun setTint(drawable: Drawable, @ColorInt tint: Int, tintMode: PorterDuff.Mode = PorterDuff.Mode.SRC_ATOP) { - val wrappedDrawable = DrawableCompat.wrap(drawable) - wrappedDrawable.mutate() - DrawableCompat.setTintMode(wrappedDrawable, tintMode) - DrawableCompat.setTint(wrappedDrawable, tint) + fun setTint(drawable: Drawable?, @ColorInt tint: Int, tintMode: PorterDuff.Mode = PorterDuff.Mode.SRC_ATOP) { + drawable?.let { + val wrappedDrawable = DrawableCompat.wrap(it) + wrappedDrawable.mutate() + DrawableCompat.setTintMode(wrappedDrawable, tintMode) + DrawableCompat.setTint(wrappedDrawable, tint) + } } } diff --git a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt index 246533e56..b147d44df 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt @@ -51,10 +51,9 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationI } } - override fun onCreateOptionsMenu(menu: Menu): Boolean { - // Inflate the menu; this adds items to the action bar if it is present. + override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { menuInflater.inflate(R.menu.main, menu) - return true + return super.onCompatCreateOptionsMenu(menu) } override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { diff --git a/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt b/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt index 75fa15765..428500b6e 100644 --- a/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt +++ b/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt @@ -33,6 +33,8 @@ class TitleBar(context: Context, attrs: AttributeSet?) : AppBarLayout(context, a toolbar.subtitle = subtitle } + private val mDisplayHomeAsUp: Boolean + init { inflate(context, R.layout.view_titlebar, this) toolbar = findViewById(R.id.toolbar) @@ -44,14 +46,15 @@ class TitleBar(context: Context, attrs: AttributeSet?) : AppBarLayout(context, a val navigationContentDescription = a.getText(R.styleable.TitleBar_navigationContentDescription) val navigationIconTint = a.getColorStateList(R.styleable.TitleBar_navigationIconTint) val navigationIconTintMode = a.getInt(R.styleable.TitleBar_navigationIconTintMode, 9) - val showNavigationIcon = a.getBoolean(R.styleable.TitleBar_showNavigationIcon, true) val attachToActivity = a.getBoolean(R.styleable.TitleBar_attachToActivity, true) val titleText = a.getString(R.styleable.TitleBar_title) val subtitleText = a.getString(R.styleable.TitleBar_subtitle) + mDisplayHomeAsUp = a.getBoolean(R.styleable.TitleBar_displayHomeAsUp, true) + toolbar.apply { - if (showNavigationIcon) { - this.navigationIcon = navigationIcon + navigationIcon?.let { + this.navigationIcon = it this.navigationContentDescription = navigationContentDescription wrapDrawableTint(this.navigationIcon, navigationIconTint, navigationIconTintMode) } @@ -120,7 +123,7 @@ class TitleBar(context: Context, attrs: AttributeSet?) : AppBarLayout(context, a val activity = getCompatActivity(context) activity?.let { activity.setSupportActionBar(toolbar) - activity.supportActionBar?.setDisplayHomeAsUpEnabled(true) + activity.supportActionBar?.setDisplayHomeAsUpEnabled(mDisplayHomeAsUp) } } diff --git a/app/src/main/res/menu/main.xml b/app/src/main/res/menu/main.xml index d579f6feb..ffa80409c 100644 --- a/app/src/main/res/menu/main.xml +++ b/app/src/main/res/menu/main.xml @@ -5,4 +5,11 @@ android:title="@string/action_settings" android:orderInCategory="100" app:showAsAction="never"/> + + + diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index 7bbabf7f6..b60fcb652 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -1,48 +1,48 @@ - + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - + - - - - - + + + + + diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index c7cf14a15..0cf68e183 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -25,13 +25,13 @@ + + + //**************************************************************Widget Style******************************************************************************// - - - - //**************************************************************System Style******************************************************************************// + //**************************************************************System + Style******************************************************************************// - //**************************************************************Widget Style******************************************************************************// + //**************************************************************Widget + Style******************************************************************************// - + From fa543ccaf80a13459345a0c72f0c1ad5af159cfe Mon Sep 17 00:00:00 2001 From: Administrator <1760316362@qq.com> Date: Tue, 30 Jul 2019 17:29:50 +0800 Subject: [PATCH 0475/1997] update --- .../main/java/io/legado/app/lib/theme/ATH.kt | 15 + .../io/legado/app/ui/about/AboutFragment.kt | 6 + .../io/legado/app/ui/about/DonateActivity.kt | 2 + .../app/ui/bookshelf/BookshelfActivity.kt | 2 + .../app/ui/booksource/BookSourceActivity.kt | 2 + .../io/legado/app/ui/config/ConfigFragment.kt | 7 + .../app/ui/config/ThemeConfigFragment.kt | 7 + .../app/ui/config/WebDavConfigFragment.kt | 7 + .../app/ui/replacerule/ReplaceRuleActivity.kt | 2 + .../io/legado/app/ui/search/SearchActivity.kt | 7 + .../app/ui/sourcedebug/SourceDebugActivity.kt | 2 + .../app/ui/sourceedit/SourceEditActivity.kt | 2 + app/src/main/res/layout/activity_donate.xml | 272 +++++++++--------- 13 files changed, 199 insertions(+), 134 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/theme/ATH.kt b/app/src/main/java/io/legado/app/lib/theme/ATH.kt index 7553da7b8..62a8cad34 100644 --- a/app/src/main/java/io/legado/app/lib/theme/ATH.kt +++ b/app/src/main/java/io/legado/app/lib/theme/ATH.kt @@ -8,6 +8,7 @@ import android.os.Build import android.view.View import android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR import android.widget.EdgeEffect +import android.widget.ScrollView import androidx.annotation.ColorInt import androidx.appcompat.app.AlertDialog import androidx.recyclerview.widget.RecyclerView @@ -146,10 +147,24 @@ object ATH { } } + fun setEdgeEffectColor(scrollView: ScrollView?, @ColorInt color: Int) { + try { + val clazz = ScrollView::class.java + for (name in arrayOf("mEdgeGlowTop", "mEdgeGlowBottom")) { + val field = clazz.getDeclaredField(name) + field.isAccessible = true + val edge = field.get(scrollView) + (edge as EdgeEffect).color = color + } + } catch (ignored: Exception) { + } + } + fun applyEdgeEffectColor(view: View?) { when (view) { is RecyclerView -> view.edgeEffectFactory = DEFAULT_EFFECT_FACTORY is ViewPager -> setEdgeEffectColor(view, ThemeStore.primaryColor(view.context)) + is ScrollView -> setEdgeEffectColor(view, ThemeStore.primaryColor(view.context)) } } diff --git a/app/src/main/java/io/legado/app/ui/about/AboutFragment.kt b/app/src/main/java/io/legado/app/ui/about/AboutFragment.kt index db9285137..5f2220b07 100644 --- a/app/src/main/java/io/legado/app/ui/about/AboutFragment.kt +++ b/app/src/main/java/io/legado/app/ui/about/AboutFragment.kt @@ -3,6 +3,7 @@ package io.legado.app.ui.about import android.content.Intent import android.net.Uri import android.os.Bundle +import android.view.View import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat import io.legado.app.App @@ -22,6 +23,11 @@ class AboutFragment : PreferenceFragmentCompat() { return super.onPreferenceTreeClick(preference) } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + listView.overScrollMode = View.OVER_SCROLL_NEVER + } + private fun openIntent(intentName: String, address: String) { try { val intent = Intent(intentName) diff --git a/app/src/main/java/io/legado/app/ui/about/DonateActivity.kt b/app/src/main/java/io/legado/app/ui/about/DonateActivity.kt index b27bfb654..c5bb90704 100644 --- a/app/src/main/java/io/legado/app/ui/about/DonateActivity.kt +++ b/app/src/main/java/io/legado/app/ui/about/DonateActivity.kt @@ -11,6 +11,7 @@ import android.widget.Toast import androidx.lifecycle.AndroidViewModel import io.legado.app.R import io.legado.app.base.BaseActivity +import io.legado.app.lib.theme.ATH import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_donate.* import kotlinx.android.synthetic.main.view_title_bar.* @@ -32,6 +33,7 @@ class DonateActivity : BaseActivity() { override fun onActivityCreated(viewModel: AndroidViewModel, savedInstanceState: Bundle?) { setSupportActionBar(toolbar) + ATH.applyEdgeEffectColor(scroll_view) vw_zfb_tz.setOnClickListener { aliDonate(this) } cv_wx_gzh.setOnClickListener { val clipboard = this.getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager diff --git a/app/src/main/java/io/legado/app/ui/bookshelf/BookshelfActivity.kt b/app/src/main/java/io/legado/app/ui/bookshelf/BookshelfActivity.kt index 15a920dca..a6cda3975 100644 --- a/app/src/main/java/io/legado/app/ui/bookshelf/BookshelfActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookshelf/BookshelfActivity.kt @@ -12,6 +12,7 @@ import io.legado.app.App import io.legado.app.R import io.legado.app.base.BaseActivity import io.legado.app.data.entities.Book +import io.legado.app.lib.theme.ATH import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_bookshelf.* @@ -36,6 +37,7 @@ class BookshelfActivity : BaseActivity() { } private fun initRecyclerView() { + ATH.applyEdgeEffectColor(rv_bookshelf) rv_bookshelf.layoutManager = LinearLayoutManager(this) rv_bookshelf.addItemDecoration(DividerItemDecoration(this, LinearLayout.VERTICAL)) bookshelfAdapter = BookshelfAdapter() diff --git a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt index bdc43ffeb..25690f258 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt @@ -17,6 +17,7 @@ import io.legado.app.R import io.legado.app.base.BaseActivity import io.legado.app.data.entities.BookSource import io.legado.app.help.ItemTouchCallback +import io.legado.app.lib.theme.ATH import io.legado.app.ui.bookshelf.BookshelfViewModel import io.legado.app.ui.qrcode.QrCodeActivity import io.legado.app.ui.sourceedit.SourceEditActivity @@ -73,6 +74,7 @@ class BookSourceActivity : BaseActivity(), BookSourceAdapter } private fun initRecyclerView() { + ATH.applyEdgeEffectColor(recycler_view) recycler_view.layoutManager = LinearLayoutManager(this) recycler_view.addItemDecoration( DividerItemDecoration( diff --git a/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt index efac58fbc..c33d584a5 100644 --- a/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt @@ -2,10 +2,12 @@ package io.legado.app.ui.config import android.content.SharedPreferences import android.os.Bundle +import android.view.View import androidx.preference.ListPreference import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat import io.legado.app.R +import io.legado.app.lib.theme.ATH import io.legado.app.utils.getPrefString @@ -16,6 +18,11 @@ class ConfigFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChange addPreferencesFromResource(R.xml.pref_config) } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + ATH.applyEdgeEffectColor(listView) + } + override fun onResume() { super.onResume() preferenceManager.sharedPreferences.registerOnSharedPreferenceChangeListener(this) diff --git a/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt index 07b60b065..0a727d354 100644 --- a/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt @@ -3,6 +3,7 @@ package io.legado.app.ui.config import android.content.SharedPreferences import android.os.Bundle import android.os.Handler +import android.view.View import androidx.appcompat.app.AlertDialog import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat @@ -11,6 +12,7 @@ import com.jeremyliao.liveeventbus.LiveEventBus import io.legado.app.App import io.legado.app.R import io.legado.app.constant.Bus +import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.ColorUtils import io.legado.app.utils.* @@ -21,6 +23,11 @@ class ThemeConfigFragment : PreferenceFragmentCompat(), SharedPreferences.OnShar addPreferencesFromResource(R.xml.pref_config_theme) } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + ATH.applyEdgeEffectColor(listView) + } + override fun onResume() { super.onResume() preferenceManager.sharedPreferences.registerOnSharedPreferenceChangeListener(this) diff --git a/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt index b6e8f778c..9faa87b39 100644 --- a/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt @@ -1,10 +1,12 @@ package io.legado.app.ui.config import android.os.Bundle +import android.view.View import androidx.preference.ListPreference import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat import io.legado.app.R +import io.legado.app.lib.theme.ATH import io.legado.app.utils.getPrefString class WebDavConfigFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChangeListener { @@ -15,6 +17,11 @@ class WebDavConfigFragment : PreferenceFragmentCompat(), Preference.OnPreference bindPreferenceSummaryToValue(findPreference("web_dav_account")) } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + ATH.applyEdgeEffectColor(listView) + } + override fun onPreferenceChange(preference: Preference?, newValue: Any?): Boolean { val stringValue = newValue.toString() diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt index eac5212ee..a6d206d36 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt @@ -16,6 +16,7 @@ import io.legado.app.R import io.legado.app.base.BaseActivity import io.legado.app.constant.AppConst.APP_TAG import io.legado.app.data.entities.ReplaceRule +import io.legado.app.lib.theme.ATH import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_replace_rule.* import org.jetbrains.anko.doAsync @@ -38,6 +39,7 @@ class ReplaceRuleActivity : BaseActivity() { } private fun initRecyclerView() { + ATH.applyEdgeEffectColor(rv_replace_rule) rv_replace_rule.layoutManager = LinearLayoutManager(this) adapter = ReplaceRuleAdapter(this) adapter.onClickListener = object : ReplaceRuleAdapter.OnClickListener { diff --git a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt index 644684e44..c2a420c6f 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt @@ -4,7 +4,9 @@ import android.os.Bundle import android.view.View import io.legado.app.R import io.legado.app.base.BaseActivity +import io.legado.app.lib.theme.ATH import io.legado.app.utils.getViewModel +import kotlinx.android.synthetic.main.activity_search.* import kotlinx.android.synthetic.main.view_title_bar.* class SearchActivity : BaseActivity() { @@ -17,6 +19,7 @@ class SearchActivity : BaseActivity() { override fun onActivityCreated(viewModel: SearchViewModel, savedInstanceState: Bundle?) { initSearchView() + initRecyclerView() viewModel.search() } @@ -31,4 +34,8 @@ class SearchActivity : BaseActivity() { } } + private fun initRecyclerView() { + ATH.applyEdgeEffectColor(rv_search_list) + } + } diff --git a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt index af7dfe808..a5543ff39 100644 --- a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt +++ b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt @@ -10,6 +10,7 @@ import io.legado.app.R import io.legado.app.base.BaseActivity import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookSource +import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.ThemeStore import io.legado.app.model.WebBook import io.legado.app.model.webbook.SourceDebug @@ -41,6 +42,7 @@ class SourceDebugActivity : BaseActivity(), SourceDebug.Callba } private fun initRecyclerView() { + ATH.applyEdgeEffectColor(recycler_view) adapter = SourceDebugAdapter() recycler_view.layoutManager = LinearLayoutManager(this) recycler_view.adapter = adapter diff --git a/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditActivity.kt index 787ee6868..a290ffd45 100644 --- a/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditActivity.kt @@ -15,6 +15,7 @@ import io.legado.app.R import io.legado.app.base.BaseActivity import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.rule.* +import io.legado.app.lib.theme.ATH import io.legado.app.ui.sourcedebug.SourceDebugActivity import io.legado.app.ui.widget.KeyboardToolPop import io.legado.app.utils.GSON @@ -89,6 +90,7 @@ class SourceEditActivity : BaseActivity(false), KeyboardToo } private fun initView() { + ATH.applyEdgeEffectColor(recycler_view) mSoftKeyboardTool = KeyboardToolPop(this, this) window.decorView.viewTreeObserver.addOnGlobalLayoutListener(KeyboardOnGlobalChangeListener()) recycler_view.layoutManager = LinearLayoutManager(this) diff --git a/app/src/main/res/layout/activity_donate.xml b/app/src/main/res/layout/activity_donate.xml index e485130be..0956dd71b 100644 --- a/app/src/main/res/layout/activity_donate.xml +++ b/app/src/main/res/layout/activity_donate.xml @@ -1,228 +1,232 @@ + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/ll_content" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + android:id="@+id/title_bar" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:title="@string/donate"/> - - + android:layout_height="match_parent" + android:overScrollMode="always" + android:fillViewport="true" + android:padding="5dp" + android:clipToPadding="false"> - + android:orientation="vertical"> - + android:layout_margin="5dp" + app:cardBackgroundColor="@color/background_card"> - + android:orientation="vertical"> + + - - + android:layout_margin="5dp" + android:clickable="true" + android:focusable="true" + android:foreground="?attr/selectableItemBackground" + app:cardBackgroundColor="@color/background_card"> - + android:orientation="vertical"> + + - - + android:layout_margin="5dp" + android:clickable="true" + android:focusable="true" + android:foreground="?attr/selectableItemBackground" + app:cardBackgroundColor="@color/background_card"> - + android:orientation="horizontal" + android:padding="5dp"> + + - - + android:layout_margin="5dp" + android:clickable="true" + android:focusable="true" + android:foreground="?attr/selectableItemBackground" + app:cardBackgroundColor="@color/background_card"> - + android:orientation="horizontal" + android:padding="5dp"> + + - - + android:layout_margin="5dp" + android:clickable="true" + android:focusable="true" + android:foreground="?attr/selectableItemBackground" + app:cardBackgroundColor="@color/background_card"> - + android:orientation="horizontal" + android:padding="5dp"> + + - - + android:layout_margin="5dp" + android:clickable="true" + android:focusable="true" + android:foreground="?attr/selectableItemBackground" + app:cardBackgroundColor="@color/background_card"> - + android:orientation="horizontal" + android:padding="5dp"> + + - - + android:layout_margin="5dp" + android:clickable="true" + android:focusable="true" + android:foreground="?attr/selectableItemBackground" + app:cardBackgroundColor="@color/background_card"> - + android:orientation="horizontal" + android:padding="5dp"> + + - - + android:layout_margin="5dp" + android:clickable="true" + android:focusable="true" + android:foreground="?attr/selectableItemBackground" + app:cardBackgroundColor="@color/background_card"> - + android:orientation="horizontal" + android:padding="5dp"> + + From 39bd21ecff0ff9428f7d7af8c1cd345117152a15 Mon Sep 17 00:00:00 2001 From: Administrator <1760316362@qq.com> Date: Tue, 30 Jul 2019 18:17:01 +0800 Subject: [PATCH 0476/1997] update --- app/src/main/java/io/legado/app/App.kt | 2 +- .../app/ui/config/ThemeConfigFragment.kt | 6 ----- .../io/legado/app/ui/main/MainActivity.kt | 5 ++-- .../java/io/legado/app/utils/EventBusKt.kt | 24 ++++++++++++------- 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/io/legado/app/App.kt b/app/src/main/java/io/legado/app/App.kt index 580d2359f..64d4d9371 100644 --- a/app/src/main/java/io/legado/app/App.kt +++ b/app/src/main/java/io/legado/app/App.kt @@ -51,7 +51,7 @@ class App : Application() { .autoClear(false) } - fun initNightTheme() { + fun initNightTheme() {//对整个应用生效,不要手动调用recreate if (getPrefBoolean("isNightTheme")) { AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES) } else { diff --git a/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt index 0a727d354..2b709ec4b 100644 --- a/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt @@ -7,8 +7,6 @@ import android.view.View import androidx.appcompat.app.AlertDialog import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat -import com.jaredrummler.android.colorpicker.ColorPreferenceCompat -import com.jeremyliao.liveeventbus.LiveEventBus import io.legado.app.App import io.legado.app.R import io.legado.app.constant.Bus @@ -106,8 +104,6 @@ class ThemeConfigFragment : PreferenceFragmentCompat(), SharedPreferences.OnShar .putInt("colorBackgroundNight", App.INSTANCE.getCompatColor(R.color.md_grey_800)) .apply() App.INSTANCE.upThemeStore() - LiveEventBus.get().with(Bus.RECREATE).post("") - Handler().postDelayed({ activity?.recreate() }, 100) } .setNegativeButton(R.string.cancel, null) .show().upTint() @@ -138,8 +134,6 @@ class ThemeConfigFragment : PreferenceFragmentCompat(), SharedPreferences.OnShar private fun upTheme(isNightTheme: Boolean) { if (App.INSTANCE.getPrefBoolean("isNightTheme") == isNightTheme) { App.INSTANCE.upThemeStore() - LiveEventBus.get().with(Bus.RECREATE).post("") - Handler().postDelayed({ activity?.recreate() }, 100) } } diff --git a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt index efe3c82a1..b92d71a03 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt @@ -5,7 +5,6 @@ import android.view.MenuItem import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentPagerAdapter -import androidx.lifecycle.Observer import androidx.viewpager.widget.ViewPager import com.google.android.material.bottomnavigation.BottomNavigationView import io.legado.app.App @@ -112,8 +111,8 @@ class MainActivity : BaseActivity(), BottomNavigationView.OnNavig } override fun observeLiveBus() { - observeEvent(Bus.RECREATE, Observer { + observeEvent(Bus.RECREATE) { recreate() - }) + } } } diff --git a/app/src/main/java/io/legado/app/utils/EventBusKt.kt b/app/src/main/java/io/legado/app/utils/EventBusKt.kt index e4c505565..116540e75 100644 --- a/app/src/main/java/io/legado/app/utils/EventBusKt.kt +++ b/app/src/main/java/io/legado/app/utils/EventBusKt.kt @@ -13,18 +13,26 @@ inline fun postEvent(tag: String, event: EVENT) { return LiveEventBus.get().with(tag, EVENT::class.java).post(event) } -inline fun AppCompatActivity.observeEvent(tag: String, observer: Observer) { - return eventObservable(tag).observe(this, observer) +inline fun AppCompatActivity.observeEvent(tag: String, crossinline observer: (EVENT) -> Unit) { + return eventObservable(tag).observe(this, Observer { + observer(it) + }) } -inline fun AppCompatActivity.observeEventSticky(tag: String, observer: Observer) { - return eventObservable(tag).observeSticky(this, observer) +inline fun AppCompatActivity.observeEventSticky(tag: String, crossinline observer: (EVENT) -> Unit) { + return eventObservable(tag).observeSticky(this, Observer { + observer(it) + }) } -inline fun Fragment.observeEvent(tag: String, observer: Observer) { - return eventObservable(tag).observe(this, observer) +inline fun Fragment.observeEvent(tag: String, crossinline observer: (EVENT) -> Unit) { + return eventObservable(tag).observe(this, Observer { + observer(it) + }) } -inline fun Fragment.observeEventSticky(tag: String, observer: Observer) { - return eventObservable(tag).observeSticky(this, observer) +inline fun Fragment.observeEventSticky(tag: String, crossinline observer: (EVENT) -> Unit) { + return eventObservable(tag).observeSticky(this, Observer { + observer(it) + }) } \ No newline at end of file From cf4fb013ddffa8f4520a68ebec31e800d5e35fcb Mon Sep 17 00:00:00 2001 From: Administrator <1760316362@qq.com> Date: Tue, 30 Jul 2019 18:33:12 +0800 Subject: [PATCH 0477/1997] update --- app/src/main/java/io/legado/app/App.kt | 9 +++++---- .../java/io/legado/app/ui/config/ThemeConfigFragment.kt | 9 +++++++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/App.kt b/app/src/main/java/io/legado/app/App.kt index 64d4d9371..c6e4f40bc 100644 --- a/app/src/main/java/io/legado/app/App.kt +++ b/app/src/main/java/io/legado/app/App.kt @@ -51,12 +51,13 @@ class App : Application() { .autoClear(false) } - fun initNightTheme() {//对整个应用生效,不要手动调用recreate - if (getPrefBoolean("isNightTheme")) { - AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES) + fun initNightTheme() { + val targetMode = if (getPrefBoolean("isNightTheme")) { + AppCompatDelegate.MODE_NIGHT_YES } else { - AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) + AppCompatDelegate.MODE_NIGHT_NO } + AppCompatDelegate.setDefaultNightMode(targetMode) } /** diff --git a/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt index 2b709ec4b..89a698b54 100644 --- a/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt @@ -40,8 +40,7 @@ class ThemeConfigFragment : PreferenceFragmentCompat(), SharedPreferences.OnShar sharedPreferences ?: return when (key) { "transparentStatusBar" -> { - postEvent(Bus.RECREATE, "") - Handler().postDelayed({ activity?.recreate() }, 100) + recreateActivities() } "colorPrimary", "colorAccent", "colorBackground" -> { if (backgroundIsDark(sharedPreferences)) { @@ -104,6 +103,7 @@ class ThemeConfigFragment : PreferenceFragmentCompat(), SharedPreferences.OnShar .putInt("colorBackgroundNight", App.INSTANCE.getCompatColor(R.color.md_grey_800)) .apply() App.INSTANCE.upThemeStore() + recreateActivities() } .setNegativeButton(R.string.cancel, null) .show().upTint() @@ -134,7 +134,12 @@ class ThemeConfigFragment : PreferenceFragmentCompat(), SharedPreferences.OnShar private fun upTheme(isNightTheme: Boolean) { if (App.INSTANCE.getPrefBoolean("isNightTheme") == isNightTheme) { App.INSTANCE.upThemeStore() + recreateActivities() } } + private fun recreateActivities() { + postEvent(Bus.RECREATE, "") + Handler().postDelayed({ activity?.recreate() }, 100L) + } } \ No newline at end of file From 469370d8609954607363de685a35a344976a828a Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 30 Jul 2019 20:52:10 +0800 Subject: [PATCH 0478/1997] up --- .../java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt index a5543ff39..4b42e5d91 100644 --- a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt +++ b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt @@ -20,6 +20,7 @@ import kotlinx.android.synthetic.main.activity_source_debug.* import kotlinx.android.synthetic.main.view_title_bar.* import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.launch +import org.jetbrains.anko.toast class SourceDebugActivity : BaseActivity(), SourceDebug.Callback { @@ -85,7 +86,7 @@ class SourceDebugActivity : BaseActivity(), SourceDebug.Callba SourceDebug(WebBook(it), this) .searchDebug(key) } - } + } ?: toast("未获取到书源") } override fun printLog(state: Int, msg: String) { From c5dbbf7c9517ad8849b214c1a2282f5b95f21390 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 30 Jul 2019 21:17:36 +0800 Subject: [PATCH 0479/1997] up --- .../java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt index 4b42e5d91..be5966534 100644 --- a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt +++ b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt @@ -73,7 +73,7 @@ class SourceDebugActivity : BaseActivity(), SourceDebug.Callba adapter.notifyDataSetChanged() bookSource?.let { SourceDebug.debugSource = it.bookSourceUrl - rotate_loading.visibility = View.VISIBLE + rotate_loading.show() if (key.isAbsUrl()) { val book = Book() book.origin = it.bookSourceUrl @@ -95,7 +95,7 @@ class SourceDebugActivity : BaseActivity(), SourceDebug.Callba adapter.logList.add(msg) adapter.notifyItemChanged(adapter.logList.size - 1) if (state == -1 || state == 1000) { - rotate_loading.visibility = View.GONE + rotate_loading.hide() } } } From 5e63cceb2081a2e2a1bc9d659a1a6657c57d5aae Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 30 Jul 2019 21:33:58 +0800 Subject: [PATCH 0480/1997] up --- app/src/main/java/io/legado/app/model/webbook/BookList.kt | 2 +- app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt | 2 +- app/src/main/res/layout/activity_source_debug.xml | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookList.kt b/app/src/main/java/io/legado/app/model/webbook/BookList.kt index cdd91a146..ba28bf0d6 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookList.kt @@ -62,7 +62,7 @@ object BookList { val ruleKind = analyzeRule.splitSourceRule(bookListRule.kind ?: "") val ruleLastChapter = analyzeRule.splitSourceRule(bookListRule.lastChapter ?: "") val ruleWordCount = analyzeRule.splitSourceRule(bookListRule.wordCount ?: "") - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "列表书为${collections.size}") + SourceDebug.printLog(bookSource.bookSourceUrl, 1, "列表数为${collections.size}") for ((index, item) in collections.withIndex()) { getSearchItem( item, diff --git a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt index 4cf38e520..ec7a81c38 100644 --- a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt +++ b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt @@ -19,8 +19,8 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { private val startTime: Long = System.currentTimeMillis() fun printLog(source: String?, state: Int, msg: String, print: Boolean = true, isHtml: Boolean = false) { - if (!print) return if (debugSource != source) return + if (!print) return var printMsg = msg if (isHtml) { printMsg = printMsg.htmlFormat() diff --git a/app/src/main/res/layout/activity_source_debug.xml b/app/src/main/res/layout/activity_source_debug.xml index 7f8059f74..4a98208bd 100644 --- a/app/src/main/res/layout/activity_source_debug.xml +++ b/app/src/main/res/layout/activity_source_debug.xml @@ -16,8 +16,9 @@ + android:layout_height="0dp" + app:layout_constraintTop_toBottomOf="@+id/title_bar" + app:layout_constraintBottom_toBottomOf="parent" /> Date: Tue, 30 Jul 2019 21:35:57 +0800 Subject: [PATCH 0481/1997] up --- app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt index ec7a81c38..aef04abb1 100644 --- a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt +++ b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt @@ -18,8 +18,8 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { private val DEBUG_TIME_FORMAT = SimpleDateFormat("[mm:ss.SSS]", Locale.getDefault()) private val startTime: Long = System.currentTimeMillis() - fun printLog(source: String?, state: Int, msg: String, print: Boolean = true, isHtml: Boolean = false) { - if (debugSource != source) return + fun printLog(sourceUrl: String?, state: Int, msg: String, print: Boolean = true, isHtml: Boolean = false) { + if (debugSource != sourceUrl) return if (!print) return var printMsg = msg if (isHtml) { From 24b22ea2e142954088c61ae1f217d16312550462 Mon Sep 17 00:00:00 2001 From: Administrator <1760316362@qq.com> Date: Wed, 31 Jul 2019 10:21:31 +0800 Subject: [PATCH 0482/1997] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/base/adapter/CommonRecyclerAdapter.kt | 43 ++++++------ .../java/io/legado/app/help/EventMessage.kt | 50 ++++++++++++++ .../app/ui/sourcedebug/SourceDebugActivity.kt | 65 +++++-------------- .../app/ui/sourcedebug/SourceDebugAdapter.kt | 31 ++------- .../app/ui/sourcedebug/SourceDebugModel.kt | 51 +++++++++++++++ .../app/ui/sourceedit/SourceEditActivity.kt | 2 +- 6 files changed, 146 insertions(+), 96 deletions(-) create mode 100644 app/src/main/java/io/legado/app/help/EventMessage.kt create mode 100644 app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt diff --git a/app/src/main/java/io/legado/app/base/adapter/CommonRecyclerAdapter.kt b/app/src/main/java/io/legado/app/base/adapter/CommonRecyclerAdapter.kt index bd0cea427..30f8f794f 100644 --- a/app/src/main/java/io/legado/app/base/adapter/CommonRecyclerAdapter.kt +++ b/app/src/main/java/io/legado/app/base/adapter/CommonRecyclerAdapter.kt @@ -53,11 +53,11 @@ abstract class CommonRecyclerAdapter(protected val context: Context) : Rec } fun > addItemViewDelegate(viewType: Int, delegate: DELEGATE) { - itemDelegates.put(viewType, delegate) + itemDelegates[viewType] = delegate } fun > addItemViewDelegate(delegate: DELEGATE) { - itemDelegates.put(itemDelegates.size, delegate) + itemDelegates[itemDelegates.size] = delegate } fun > addItemViewDelegates(vararg delegates: DELEGATE) { @@ -148,26 +148,15 @@ abstract class CommonRecyclerAdapter(protected val context: Context) : Rec synchronized(lock) { val oldSize = getActualItemCount() if (this.items.add(item)) { - if (oldSize == 0) { - notifyDataSetChanged() - } else { - notifyItemInserted(oldSize + getHeaderCount()) - } + notifyItemInserted(oldSize + getHeaderCount()) } } } fun addItems(position: Int, newItems: List) { synchronized(lock) { - val oldSize = getActualItemCount() - if (position in 0 until oldSize) { - if (if (oldSize == 0) this.items.addAll(newItems) else this.items.addAll(position, newItems)) { - if (oldSize == 0) { - notifyDataSetChanged() - } else { - notifyItemRangeChanged(position + getHeaderCount(), newItems.size) - } - } + if (this.items.addAll(position, newItems)) { + notifyItemRangeInserted(position + getHeaderCount(), newItems.size) } } } @@ -176,33 +165,32 @@ abstract class CommonRecyclerAdapter(protected val context: Context) : Rec synchronized(lock) { val oldSize = getActualItemCount() if (this.items.addAll(newItems)) { - if (oldSize == 0) { - notifyDataSetChanged() - } else { - notifyItemRangeChanged(oldSize + getHeaderCount(), newItems.size) - } + notifyItemRangeInserted(oldSize + getHeaderCount(), newItems.size) } } } fun removeItem(position: Int) { synchronized(lock) { - if (this.items.removeAt(position) != null) + if (this.items.removeAt(position) != null) { notifyItemRemoved(position + getHeaderCount()) + } } } fun removeItem(item: ITEM) { synchronized(lock) { - if (this.items.remove(item)) + if (this.items.remove(item)) { notifyItemRemoved(this.items.indexOf(item) + getHeaderCount()) + } } } fun removeItems(items: List) { synchronized(lock) { - if (this.items.removeAll(items)) + if (this.items.removeAll(items)) { notifyDataSetChanged() + } } } @@ -234,6 +222,13 @@ abstract class CommonRecyclerAdapter(protected val context: Context) : Rec } } + fun clearItems() { + synchronized(lock) { + this.items.clear() + notifyDataSetChanged() + } + } + fun isEmpty(): Boolean { return items.isEmpty() } diff --git a/app/src/main/java/io/legado/app/help/EventMessage.kt b/app/src/main/java/io/legado/app/help/EventMessage.kt new file mode 100644 index 000000000..fe9c80994 --- /dev/null +++ b/app/src/main/java/io/legado/app/help/EventMessage.kt @@ -0,0 +1,50 @@ +package io.legado.app.help + +import android.text.TextUtils + +import java.util.Arrays + +class EventMessage { + + var what: Int?=null + var tag: String? = null + var obj: Any? = null + + fun isFrom(tag: String): Boolean { + return TextUtils.equals(this.tag, tag) + } + + fun maybeFrom(vararg tags: String): Boolean { + return listOf(*tags).contains(tag) + } + + companion object { + + fun obtain(tag: String): EventMessage { + val message = EventMessage() + message.tag = tag + return message + } + + fun obtain(what: Int): EventMessage { + val message = EventMessage() + message.what = what + return message + } + + fun obtain(what: Int, obj: Any): EventMessage { + val message = EventMessage() + message.what = what + message.obj = obj + return message + } + + fun obtain(tag: String, obj: Any): EventMessage { + val message = EventMessage() + message.tag = tag + message.obj = obj + return message + } + } + +} diff --git a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt index be5966534..3de2e2fd0 100644 --- a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt +++ b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt @@ -3,48 +3,43 @@ package io.legado.app.ui.sourcedebug import android.os.Bundle import android.view.View import androidx.appcompat.widget.SearchView -import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.Observer import androidx.recyclerview.widget.LinearLayoutManager -import io.legado.app.App import io.legado.app.R import io.legado.app.base.BaseActivity -import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookSource import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.ThemeStore -import io.legado.app.model.WebBook import io.legado.app.model.webbook.SourceDebug import io.legado.app.utils.getViewModel -import io.legado.app.utils.isAbsUrl import kotlinx.android.synthetic.main.activity_source_debug.* import kotlinx.android.synthetic.main.view_title_bar.* -import kotlinx.coroutines.Dispatchers.IO -import kotlinx.coroutines.launch import org.jetbrains.anko.toast -class SourceDebugActivity : BaseActivity(), SourceDebug.Callback { +class SourceDebugActivity : BaseActivity() { - override val viewModel: AndroidViewModel - get() = getViewModel(AndroidViewModel::class.java) + override val viewModel: SourceDebugModel + get() = getViewModel(SourceDebugModel::class.java) override val layoutID: Int get() = R.layout.activity_source_debug private lateinit var adapter: SourceDebugAdapter - private var bookSource: BookSource? = null - override fun onActivityCreated(viewModel: AndroidViewModel, savedInstanceState: Bundle?) { - launch(IO) { - intent.getStringExtra("key")?.let { - bookSource = App.db.bookSourceDao().findByKey(it) - } - } + override fun onActivityCreated(viewModel: SourceDebugModel, savedInstanceState: Bundle?) { + viewModel.init(intent.getStringExtra("key")) initRecyclerView() initSearchView() + viewModel.logs.observe(this, Observer { + adapter.addItem(it.obj as String) + if (it.what == -1 || it.what == 1000) { + rotate_loading.hide() + } + }) } private fun initRecyclerView() { ATH.applyEdgeEffectColor(recycler_view) - adapter = SourceDebugAdapter() + adapter = SourceDebugAdapter(this) recycler_view.layoutManager = LinearLayoutManager(this) recycler_view.adapter = adapter rotate_loading.loadingColor = ThemeStore.accentColor(this) @@ -69,36 +64,12 @@ class SourceDebugActivity : BaseActivity(), SourceDebug.Callba } private fun startSearch(key: String) { - adapter.logList.clear() - adapter.notifyDataSetChanged() - bookSource?.let { - SourceDebug.debugSource = it.bookSourceUrl + adapter.clearItems() + viewModel.startDebug(key, { rotate_loading.show() - if (key.isAbsUrl()) { - val book = Book() - book.origin = it.bookSourceUrl - book.bookUrl = key - SourceDebug.printLog(it.bookSourceUrl, 1, "开始访问$key") - SourceDebug(WebBook(it), this) - .infoDebug(book) - } else { - SourceDebug.printLog(it.bookSourceUrl, 1, "开始搜索关键字$key") - SourceDebug(WebBook(it), this) - .searchDebug(key) - } - } ?: toast("未获取到书源") - } - - override fun printLog(state: Int, msg: String) { - launch { - synchronized(this) { - adapter.logList.add(msg) - adapter.notifyItemChanged(adapter.logList.size - 1) - if (state == -1 || state == 1000) { - rotate_loading.hide() - } - } - } + }, { + toast("未获取到书源") + }) } override fun onDestroy() { diff --git a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugAdapter.kt b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugAdapter.kt index 0cde606b0..b8b821ea1 100644 --- a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugAdapter.kt @@ -1,32 +1,15 @@ package io.legado.app.ui.sourcedebug -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.recyclerview.widget.RecyclerView +import android.content.Context import io.legado.app.R +import io.legado.app.base.adapter.ItemViewHolder +import io.legado.app.base.adapter.SimpleRecyclerAdapter import kotlinx.android.synthetic.main.item_source_debug.view.* -class SourceDebugAdapter : RecyclerView.Adapter() { - - val logList = arrayListOf() - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { - return MyViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_source_debug, parent, false)) - } - - override fun onBindViewHolder(holder: MyViewHolder, position: Int) { - holder.bind(logList[position]) - } - - override fun getItemCount(): Int { - return logList.size - } - - class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { - - fun bind(log: String) = with(itemView) { - text_view.text = log +class SourceDebugAdapter(context: Context) : SimpleRecyclerAdapter(context, R.layout.item_source_debug) { + override fun convert(holder: ItemViewHolder, item: String, payloads: MutableList) { + holder.itemView.apply { + text_view.text = item } } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt new file mode 100644 index 000000000..fe3316548 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt @@ -0,0 +1,51 @@ +package io.legado.app.ui.sourcedebug + +import android.app.Application +import androidx.lifecycle.MutableLiveData +import io.legado.app.App +import io.legado.app.base.BaseViewModel +import io.legado.app.data.entities.Book +import io.legado.app.data.entities.BookSource +import io.legado.app.help.EventMessage +import io.legado.app.model.WebBook +import io.legado.app.model.webbook.SourceDebug +import io.legado.app.utils.isAbsUrl + +class SourceDebugModel(application: Application) : BaseViewModel(application), SourceDebug.Callback { + + val logs: MutableLiveData = MutableLiveData() + + private var bookSource: BookSource? = null + + fun init(sourceUrl: String?) { + sourceUrl?.let { + //优先使用这个,不会抛出异常 + execute { + bookSource = App.db.bookSourceDao().findByKey(sourceUrl) + } + } + } + + fun startDebug(key: String, start: (() -> Unit)? = null, error: (() -> Unit)? = null) { + bookSource?.let { + start?.let { it() } + SourceDebug.debugSource = it.bookSourceUrl + if (key.isAbsUrl()) { + val book = Book() + book.origin = it.bookSourceUrl + book.bookUrl = key + SourceDebug.printLog(it.bookSourceUrl, 1, "开始访问$key") + SourceDebug(WebBook(it), this) + .infoDebug(book) + } else { + SourceDebug.printLog(it.bookSourceUrl, 1, "开始搜索关键字$key") + SourceDebug(WebBook(it), this) + .searchDebug(key) + } + } ?: error?.let { it() } + } + + override fun printLog(state: Int, msg: String) { + logs.postValue(EventMessage.obtain(state, msg)) + } +} diff --git a/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditActivity.kt index a290ffd45..4f1e8a344 100644 --- a/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditActivity.kt @@ -81,7 +81,7 @@ class SourceEditActivity : BaseActivity(false), KeyboardToo toast("书源名称和URL不能为空") } else { viewModel.save(bookSource) { - startActivity(Pair("key", bookSource.bookSourceUrl)) + startActivity("key" to bookSource.bookSourceUrl) } } } From 1876c6f61216edfe930f4c8d4c3b83b60f9ec2d0 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 31 Jul 2019 10:40:34 +0800 Subject: [PATCH 0483/1997] up --- .../java/io/legado/app/model/webbook/SourceDebug.kt | 11 +++++++++++ .../legado/app/ui/sourcedebug/SourceDebugActivity.kt | 6 +++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt index aef04abb1..2155cf3c5 100644 --- a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt +++ b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt @@ -88,4 +88,15 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { printLog(debugSource, -1, it.localizedMessage) } } + + fun printLog( + sourceUrl: String?, + state: Int, + msg: String, + print: Boolean = true, + isHtml: Boolean = false + ): SourceDebug { + SourceDebug.printLog(sourceUrl, state, msg, print, isHtml) + return this + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt index be5966534..641aec977 100644 --- a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt +++ b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt @@ -78,12 +78,12 @@ class SourceDebugActivity : BaseActivity(), SourceDebug.Callba val book = Book() book.origin = it.bookSourceUrl book.bookUrl = key - SourceDebug.printLog(it.bookSourceUrl, 1, "开始访问$key") SourceDebug(WebBook(it), this) + .printLog(it.bookSourceUrl, 1, "开始访问$key") .infoDebug(book) } else { - SourceDebug.printLog(it.bookSourceUrl, 1, "开始搜索关键字$key") SourceDebug(WebBook(it), this) + .printLog(it.bookSourceUrl, 1, "开始搜索关键字$key") .searchDebug(key) } } ?: toast("未获取到书源") @@ -93,7 +93,7 @@ class SourceDebugActivity : BaseActivity(), SourceDebug.Callba launch { synchronized(this) { adapter.logList.add(msg) - adapter.notifyItemChanged(adapter.logList.size - 1) + adapter.notifyItemInserted(adapter.logList.size - 1) if (state == -1 || state == 1000) { rotate_loading.hide() } From 82e4f881e3778bff5bd77d6b35904222eb201da3 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 31 Jul 2019 10:44:48 +0800 Subject: [PATCH 0484/1997] up --- .../java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt index fe3316548..e7a9c920f 100644 --- a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt +++ b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt @@ -34,12 +34,12 @@ class SourceDebugModel(application: Application) : BaseViewModel(application), S val book = Book() book.origin = it.bookSourceUrl book.bookUrl = key - SourceDebug.printLog(it.bookSourceUrl, 1, "开始访问$key") SourceDebug(WebBook(it), this) + .printLog(it.bookSourceUrl, 1, "开始访问$key") .infoDebug(book) } else { - SourceDebug.printLog(it.bookSourceUrl, 1, "开始搜索关键字$key") SourceDebug(WebBook(it), this) + .printLog(it.bookSourceUrl, 1, "开始搜索关键字$key") .searchDebug(key) } } ?: error?.let { it() } From dec667dcdbc641bf36e5e702a406ec672622d0ff Mon Sep 17 00:00:00 2001 From: Administrator <1760316362@qq.com> Date: Wed, 31 Jul 2019 11:41:32 +0800 Subject: [PATCH 0485/1997] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/base/adapter/CommonRecyclerAdapter.kt | 17 ++- .../io/legado/app/help/coroutine/Coroutine.kt | 23 ++- .../main/java/io/legado/app/model/WebBook.kt | 3 + .../legado/app/model/webbook/SourceDebug.kt | 58 ++++++-- .../legado/app/ui/search/SearchViewModel.kt | 136 ++++++++---------- .../app/ui/sourcedebug/SourceDebugActivity.kt | 7 - .../app/ui/sourcedebug/SourceDebugModel.kt | 33 ++--- 7 files changed, 155 insertions(+), 122 deletions(-) diff --git a/app/src/main/java/io/legado/app/base/adapter/CommonRecyclerAdapter.kt b/app/src/main/java/io/legado/app/base/adapter/CommonRecyclerAdapter.kt index 30f8f794f..d39022f7e 100644 --- a/app/src/main/java/io/legado/app/base/adapter/CommonRecyclerAdapter.kt +++ b/app/src/main/java/io/legado/app/base/adapter/CommonRecyclerAdapter.kt @@ -198,8 +198,21 @@ abstract class CommonRecyclerAdapter(protected val context: Context) : Rec synchronized(lock) { val size = getActualItemCount() if (oldPosition in 0 until size && newPosition in 0 until size) { - Collections.swap(this.items, oldPosition + getHeaderCount(), newPosition + getHeaderCount()) - notifyDataSetChanged() + val srcPosition = oldPosition + getHeaderCount() + val targetPosition = newPosition + getHeaderCount() + Collections.swap(this.items, srcPosition, targetPosition) + notifyItemChanged(srcPosition) + notifyItemChanged(targetPosition) + } + } + } + + fun updateItem(item: ITEM) { + synchronized(lock) { + val index = this.items.indexOf(item) + if (index >= 0) { + this.items[index] = item + notifyItemChanged(index) } } } diff --git a/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt b/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt index 26d1c7c5e..030295275 100644 --- a/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt +++ b/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt @@ -30,6 +30,15 @@ class Coroutine() { private var errorReturn: Result? = null + val isCancelled: Boolean + get() = job?.isCancelled ?: false + + val isActive: Boolean + get() = job?.isActive ?: false + + val isCompleted: Boolean + get() = job?.isCompleted ?: false + private constructor( scope: CoroutineScope, block: suspend CoroutineScope.() -> T @@ -106,24 +115,24 @@ class Coroutine() { private suspend fun executeInternal(block: suspend CoroutineScope.() -> T) { tryCatch( { - start?.let { it() } + start?.invoke(this) val result = executeBlock(block, timeMillis ?: 0L) - success?.let { it(result) } + success?.invoke(this, result) }, { e -> val consume: Boolean = errorReturn?.value?.let { value -> - success?.let { it(value) } + success?.invoke(this, value) true } ?: false if (!consume) { - error?.let { it(e) } + error?.invoke(this, e) } }, { - finally?.let { it() } + finally?.invoke(this) }) } @@ -142,9 +151,9 @@ class Coroutine() { try { coroutineScope { tryBlock() } } catch (e: Throwable) { - coroutineScope { errorBlock?.let { it(e) } } + coroutineScope { errorBlock?.invoke(this, e) } } finally { - coroutineScope { finallyBlock?.let { it() } } + coroutineScope { finallyBlock?.invoke(this) } } } diff --git a/app/src/main/java/io/legado/app/model/WebBook.kt b/app/src/main/java/io/legado/app/model/WebBook.kt index 242510ee9..43882e881 100644 --- a/app/src/main/java/io/legado/app/model/WebBook.kt +++ b/app/src/main/java/io/legado/app/model/WebBook.kt @@ -13,6 +13,9 @@ import io.legado.app.model.webbook.BookList class WebBook(private val bookSource: BookSource) { + val sourceUrl: String + get() = bookSource.bookSourceUrl + fun searchBook(key: String, page: Int?, isSearch: Boolean = true): Coroutine> { return Coroutine.async { bookSource.getSearchRule().searchUrl?.let { searchUrl -> diff --git a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt index aef04abb1..0b276796b 100644 --- a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt +++ b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt @@ -4,16 +4,20 @@ import android.annotation.SuppressLint import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter import io.legado.app.help.BookHelp +import io.legado.app.help.coroutine.Coroutine import io.legado.app.model.WebBook import io.legado.app.utils.htmlFormat +import io.legado.app.utils.isAbsUrl import java.text.SimpleDateFormat import java.util.* class SourceDebug(private val webBook: WebBook, callback: Callback) { companion object { - var debugSource: String? = null - var callback: Callback? = null + private var debugSource: String? = null + private var callback: Callback? = null + private val tasks: MutableList> = mutableListOf() + @SuppressLint("ConstantLocale") private val DEBUG_TIME_FORMAT = SimpleDateFormat("[mm:ss.SSS]", Locale.getDefault()) private val startTime: Long = System.currentTimeMillis() @@ -29,18 +33,46 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { String.format("%s %s", DEBUG_TIME_FORMAT.format(Date(System.currentTimeMillis() - startTime)), printMsg) callback?.printLog(state, printMsg) } - } - interface Callback { - fun printLog(state: Int, msg: String) + fun cancelDebug() { + tasks.forEach { + if (!it.isCancelled) { + it.cancel() + } + } + tasks.clear() + } + + fun stopDebug(){ + cancelDebug() + debugSource = null + callback = null + } } init { + debugSource = webBook.sourceUrl SourceDebug.callback = callback } + fun startDebug(key: String) { + cancelDebug() + with(webBook) { + if (key.isAbsUrl()) { + val book = Book() + book.origin = sourceUrl + book.bookUrl = key + printLog(sourceUrl, 1, "开始访问$key") + infoDebug(book) + } else { + printLog(sourceUrl, 1, "开始搜索关键字$key") + searchDebug(key) + } + } + } + fun searchDebug(key: String) { - webBook.searchBook(key, 1) + val search = webBook.searchBook(key, 1) .onSuccess { searchBooks -> searchBooks?.let { if (searchBooks.isNotEmpty()) { @@ -51,20 +83,22 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { .onError { printLog(debugSource, -1, it.localizedMessage) } + tasks.add(search) } fun infoDebug(book: Book) { - webBook.getBookInfo(book) + val info = webBook.getBookInfo(book) .onSuccess { tocDebug(book) } .onError { printLog(debugSource, -1, it.localizedMessage) } + tasks.add(info) } private fun tocDebug(book: Book) { - webBook.getChapterList(book) + val chapterList = webBook.getChapterList(book) .onSuccess { chapterList -> chapterList?.let { if (it.isNotEmpty()) { @@ -75,10 +109,11 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { .onError { printLog(debugSource, -1, it.localizedMessage) } + tasks.add(chapterList) } private fun contentDebug(book: Book, bookChapter: BookChapter) { - webBook.getContent(book, bookChapter) + val content = webBook.getContent(book, bookChapter) .onSuccess { content -> content?.let { printLog(debugSource, 1000, it) @@ -87,5 +122,10 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { .onError { printLog(debugSource, -1, it.localizedMessage) } + tasks.add(content) + } + + interface Callback { + fun printLog(state: Int, msg: String) } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt b/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt index 3252e5112..d3dddb787 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt @@ -10,6 +10,8 @@ import io.legado.app.data.entities.SearchBook import io.legado.app.help.http.HttpHelper import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch import kotlinx.coroutines.withContext class SearchViewModel(application: Application) : BaseViewModel(application) { @@ -19,86 +21,68 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { private val channel = Channel()//协程之间通信 fun search(start: (() -> Unit)? = null, finally: (() -> Unit)? = null) { -// launch { -// repeat(1000) { -// channel.send(it) -// } -// } -// -// -// val c = execute { -// -// Log.e("TAG1", "start") -// -// val response: String = HttpHelper.getApiService( -// "http://www.baidu.com" -// ).get("http://www.baidu.com").await() -// -// Log.e("TAG1", "result: $response") -// -// delay(2000L) -// -// response -// } -// .onStart { -// Log.e("TAG!", "start") -// start?.let { it() } -// } + launch { + repeat(1000) { + channel.send(it) + } + } + + + val c = execute { + + val response: String = HttpHelper.getApiService( + "http://www.baidu.com" + ).get("http://www.baidu.com").await() + + delay(2000L) + + response + } + .onStart { + Log.e("TAG!", "start") + start?.let { it() } + } + .onSuccess { + Log.e("TAG!", "success: $it") + } + .onError { + Log.e("TAG!", "error: $it") + } + .onFinally { + Log.e("TAG!", "finally") + if (finally != null) { + finally() + } + } + + val c2 = plus(c) +// .timeout { 100L } +// .onErrorReturn { "error return2" } + .onStart { + //会拦截掉c的onStart + Log.e("TAG!", "start2") + start?.let { it() } + } // .onSuccess { -// Log.e("TAG!", "success: $it") -// } -// .onError { -// Log.e("TAG!", "error: $it") -// } -// .onFinally { -// Log.e("TAG!", "finally") -// if (finally != null) { -// finally() -// } -// } -// -// val c2 = plus(c) -//// .timeout { 100L } -//// .onErrorReturn { "error return2" } -// .onStart { -// //会拦截掉c的onStart -// Log.e("TAG!", "start2") -// start?.let { it() } -// } -//// .onSuccess { -//// Log.e("TAG!", "success2: $it") -//// } -// .onError { -// Log.e("TAG!", "error2: $it") +// Log.e("TAG!", "success2: $it") // } -// .onFinally { -// Log.e("TAG!", "finally2") -// if (finally != null) { -// finally() -// } -// -// Log.e("TAG!", "rec2: " + channel.receive()) -// } -// -// launch { -// delay(1500L) -//// c2.cancel() -// -//// c.cancel() -// } -// -// -// launch { -// val list = test() -// println("size: ${list.size} $list") -// } + .onError { + Log.e("TAG!", "error2: $it") + } + .onFinally { + Log.e("TAG!", "finally2") + if (finally != null) { + finally() + } + Log.e("TAG!", "rec2: " + channel.receive()) + } - execute { - test(this) - }.onSuccess { - println("size: ${it?.size} $it") - } +// execute { +// test(this) +// }.onSuccess { +// println("size: ${it?.size} $it") +// } } suspend fun test(scope: CoroutineScope): MutableList { diff --git a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt index 3de2e2fd0..400328f1f 100644 --- a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt +++ b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt @@ -7,10 +7,8 @@ import androidx.lifecycle.Observer import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.R import io.legado.app.base.BaseActivity -import io.legado.app.data.entities.BookSource import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.ThemeStore -import io.legado.app.model.webbook.SourceDebug import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_source_debug.* import kotlinx.android.synthetic.main.view_title_bar.* @@ -71,9 +69,4 @@ class SourceDebugActivity : BaseActivity() { toast("未获取到书源") }) } - - override fun onDestroy() { - SourceDebug.debugSource = null - super.onDestroy() - } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt index fe3316548..3223e9660 100644 --- a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt +++ b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt @@ -4,48 +4,39 @@ import android.app.Application import androidx.lifecycle.MutableLiveData import io.legado.app.App import io.legado.app.base.BaseViewModel -import io.legado.app.data.entities.Book -import io.legado.app.data.entities.BookSource import io.legado.app.help.EventMessage import io.legado.app.model.WebBook import io.legado.app.model.webbook.SourceDebug -import io.legado.app.utils.isAbsUrl class SourceDebugModel(application: Application) : BaseViewModel(application), SourceDebug.Callback { val logs: MutableLiveData = MutableLiveData() - private var bookSource: BookSource? = null + private var webBook: WebBook? = null fun init(sourceUrl: String?) { sourceUrl?.let { //优先使用这个,不会抛出异常 execute { - bookSource = App.db.bookSourceDao().findByKey(sourceUrl) + val bookSource = App.db.bookSourceDao().findByKey(sourceUrl) + bookSource?.let { webBook = WebBook(it) } } } } fun startDebug(key: String, start: (() -> Unit)? = null, error: (() -> Unit)? = null) { - bookSource?.let { - start?.let { it() } - SourceDebug.debugSource = it.bookSourceUrl - if (key.isAbsUrl()) { - val book = Book() - book.origin = it.bookSourceUrl - book.bookUrl = key - SourceDebug.printLog(it.bookSourceUrl, 1, "开始访问$key") - SourceDebug(WebBook(it), this) - .infoDebug(book) - } else { - SourceDebug.printLog(it.bookSourceUrl, 1, "开始搜索关键字$key") - SourceDebug(WebBook(it), this) - .searchDebug(key) - } - } ?: error?.let { it() } + webBook?.let { + start?.invoke() + SourceDebug(it, this).startDebug(key) + } ?: error?.invoke() } override fun printLog(state: Int, msg: String) { logs.postValue(EventMessage.obtain(state, msg)) } + + override fun onCleared() { + super.onCleared() + SourceDebug.stopDebug() + } } From e3c7e8d0c4bf904c7d990f25745b035d3b1e8369 Mon Sep 17 00:00:00 2001 From: Administrator <1760316362@qq.com> Date: Wed, 31 Jul 2019 11:58:22 +0800 Subject: [PATCH 0486/1997] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../legado/app/base/adapter/ItemViewDelegate.kt | 2 +- .../io/legado/app/model/webbook/SourceDebug.kt | 15 +++++++-------- .../legado/app/ui/sourcedebug/SourceDebugModel.kt | 2 +- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/io/legado/app/base/adapter/ItemViewDelegate.kt b/app/src/main/java/io/legado/app/base/adapter/ItemViewDelegate.kt index b4cd06a2f..2ac1090f2 100644 --- a/app/src/main/java/io/legado/app/base/adapter/ItemViewDelegate.kt +++ b/app/src/main/java/io/legado/app/base/adapter/ItemViewDelegate.kt @@ -7,7 +7,7 @@ import android.content.Context * * item代理, */ -abstract class ItemViewDelegate(protected val context: Context, val layoutId: Int) { +abstract class ItemViewDelegate(protected val context: Context, val layoutId: Int) { abstract fun convert(holder: ItemViewHolder, item: ITEM, payloads: MutableList) diff --git a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt index a4c8ff5a2..03e9d0446 100644 --- a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt +++ b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt @@ -23,8 +23,7 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { private val startTime: Long = System.currentTimeMillis() fun printLog(sourceUrl: String?, state: Int, msg: String, print: Boolean = true, isHtml: Boolean = false) { - if (debugSource != sourceUrl) return - if (!print) return + if (debugSource != sourceUrl || callback == null || !print) return var printMsg = msg if (isHtml) { printMsg = printMsg.htmlFormat() @@ -34,20 +33,20 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { callback?.printLog(state, printMsg) } - fun cancelDebug() { + fun cancelDebug(destroy: Boolean = false) { tasks.forEach { if (!it.isCancelled) { it.cancel() } } tasks.clear() - } - fun stopDebug(){ - cancelDebug() - debugSource = null - callback = null + if (destroy) { + debugSource = null + callback = null + } } + } init { diff --git a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt index 3223e9660..0a9732ad5 100644 --- a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt +++ b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt @@ -37,6 +37,6 @@ class SourceDebugModel(application: Application) : BaseViewModel(application), S override fun onCleared() { super.onCleared() - SourceDebug.stopDebug() + SourceDebug.cancelDebug(true) } } From 16532abd306d2ed5dd97056729a441c5a697b1df Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 31 Jul 2019 12:30:56 +0800 Subject: [PATCH 0487/1997] up --- app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt | 1 + app/src/main/java/io/legado/app/model/webbook/BookContent.kt | 1 + app/src/main/java/io/legado/app/model/webbook/BookInfo.kt | 1 + app/src/main/java/io/legado/app/model/webbook/BookList.kt | 1 + 4 files changed, 4 insertions(+) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt b/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt index 93307505e..3904700e0 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt @@ -31,6 +31,7 @@ object BookChapterList { baseUrl ) ) + SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取成功:$baseUrl") val tocRule = bookSource.getTocRule() val nextUrlList = arrayListOf(baseUrl) var reverse = false diff --git a/app/src/main/java/io/legado/app/model/webbook/BookContent.kt b/app/src/main/java/io/legado/app/model/webbook/BookContent.kt index e3e158296..a6ab5cff4 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookContent.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookContent.kt @@ -32,6 +32,7 @@ object BookContent { baseUrl ) ) + SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取成功:$baseUrl") val content = StringBuilder() val nextUrlList = arrayListOf(baseUrl) val contentRule = bookSource.getContentRule() diff --git a/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt b/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt index 2b53eaedb..6fb891736 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt @@ -23,6 +23,7 @@ object BookInfo { baseUrl ) ) + SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取成功:$baseUrl") val infoRule = bookSource.getBookInfoRule() val analyzeRule = AnalyzeRule(book) analyzeRule.setContent(body) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookList.kt b/app/src/main/java/io/legado/app/model/webbook/BookList.kt index ba28bf0d6..350a84a38 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookList.kt @@ -27,6 +27,7 @@ object BookList { baseUrl ) ) + SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取成功:$baseUrl") val analyzeRule = AnalyzeRule(null) analyzeRule.setContent(body, baseUrl) bookSource.bookUrlPattern?.let { From 68c8110caf9d4966c57782a9aab7cc97766e6c96 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 31 Jul 2019 14:01:43 +0800 Subject: [PATCH 0488/1997] up --- app/src/main/java/io/legado/app/model/WebBook.kt | 10 +++++----- .../java/io/legado/app/model/webbook/BookContent.kt | 5 +---- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/WebBook.kt b/app/src/main/java/io/legado/app/model/WebBook.kt index 43882e881..b8bafd83a 100644 --- a/app/src/main/java/io/legado/app/model/WebBook.kt +++ b/app/src/main/java/io/legado/app/model/WebBook.kt @@ -19,7 +19,7 @@ class WebBook(private val bookSource: BookSource) { fun searchBook(key: String, page: Int?, isSearch: Boolean = true): Coroutine> { return Coroutine.async { bookSource.getSearchRule().searchUrl?.let { searchUrl -> - val analyzeUrl = AnalyzeUrl(searchUrl, key, page, baseUrl = bookSource.bookSourceUrl) + val analyzeUrl = AnalyzeUrl(searchUrl, key, page, baseUrl = sourceUrl) val response = analyzeUrl.getResponseAsync().await() BookList.analyzeBookList(response, bookSource, analyzeUrl, isSearch) } ?: arrayListOf() @@ -28,7 +28,7 @@ class WebBook(private val bookSource: BookSource) { fun getBookInfo(book: Book): Coroutine { return Coroutine.async { - val analyzeUrl = AnalyzeUrl(book = book, ruleUrl = book.bookUrl) + val analyzeUrl = AnalyzeUrl(book = book, ruleUrl = book.bookUrl, baseUrl = sourceUrl) val response = analyzeUrl.getResponseAsync().await() BookInfo.analyzeBookInfo(book, response.body(), bookSource, analyzeUrl) book @@ -37,7 +37,7 @@ class WebBook(private val bookSource: BookSource) { fun getChapterList(book: Book): Coroutine> { return Coroutine.async { - val analyzeUrl = AnalyzeUrl(book = book, ruleUrl = book.tocUrl) + val analyzeUrl = AnalyzeUrl(book = book, ruleUrl = book.tocUrl, baseUrl = book.bookUrl) val response = analyzeUrl.getResponseAsync().await() BookChapterList.analyzeChapterList(this, book, response, bookSource, analyzeUrl) } @@ -45,9 +45,9 @@ class WebBook(private val bookSource: BookSource) { fun getContent(book: Book, bookChapter: BookChapter): Coroutine { return Coroutine.async { - val analyzeUrl = AnalyzeUrl(book = book, ruleUrl = bookChapter.url) + val analyzeUrl = AnalyzeUrl(book = book, ruleUrl = bookChapter.url, baseUrl = book.tocUrl) val response = analyzeUrl.getResponseAsync().await() - BookContent.analyzeContent(this, response, book, bookChapter, bookSource, analyzeUrl) + BookContent.analyzeContent(this, response, book, bookSource) } } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/model/webbook/BookContent.kt b/app/src/main/java/io/legado/app/model/webbook/BookContent.kt index a6ab5cff4..9d41cb4aa 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookContent.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookContent.kt @@ -3,7 +3,6 @@ package io.legado.app.model.webbook import io.legado.app.App import io.legado.app.R import io.legado.app.data.entities.Book -import io.legado.app.data.entities.BookChapter import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.rule.ContentRule import io.legado.app.model.analyzeRule.AnalyzeRule @@ -20,9 +19,7 @@ object BookContent { coroutineScope: CoroutineScope, response: Response, book: Book, - bookChapter: BookChapter, - bookSource: BookSource, - analyzeUrl: AnalyzeUrl + bookSource: BookSource ): String { val baseUrl: String = NetworkUtils.getUrl(response) val body: String? = response.body() From 3df45dec469b01222f0006b91f719f13e923be67 Mon Sep 17 00:00:00 2001 From: Administrator <1760316362@qq.com> Date: Wed, 31 Jul 2019 15:13:35 +0800 Subject: [PATCH 0489/1997] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/help/coroutine/CompositeCoroutine.kt | 85 +++++++++++++++++++ .../app/help/coroutine/CoroutineContainer.kt | 15 ++++ .../legado/app/model/webbook/SourceDebug.kt | 8 +- 3 files changed, 102 insertions(+), 6 deletions(-) create mode 100644 app/src/main/java/io/legado/app/help/coroutine/CompositeCoroutine.kt create mode 100644 app/src/main/java/io/legado/app/help/coroutine/CoroutineContainer.kt diff --git a/app/src/main/java/io/legado/app/help/coroutine/CompositeCoroutine.kt b/app/src/main/java/io/legado/app/help/coroutine/CompositeCoroutine.kt new file mode 100644 index 000000000..99c2df223 --- /dev/null +++ b/app/src/main/java/io/legado/app/help/coroutine/CompositeCoroutine.kt @@ -0,0 +1,85 @@ +package io.legado.app.help.coroutine + +class CompositeCoroutine : CoroutineContainer { + + private var resources: HashSet>? = null + + val size: Int + get() = resources?.size ?: 0 + + val isEmpty: Boolean + get() = size == 0 + + constructor() + + constructor(vararg coroutines: Coroutine<*>) { + this.resources = hashSetOf(*coroutines) + } + + constructor(coroutines: Iterable>) { + this.resources = hashSetOf() + for (d in coroutines) { + this.resources?.add(d) + } + } + + override fun add(coroutine: Coroutine<*>): Boolean { + synchronized(this) { + var set: HashSet>? = resources + if (resources == null) { + set = hashSetOf() + resources = set + } + return set!!.add(coroutine) + } + } + + override fun addAll(vararg coroutines: Coroutine<*>): Boolean { + synchronized(this) { + var set: HashSet>? = resources + if (resources == null) { + set = hashSetOf() + resources = set + } + for (coroutine in coroutines) { + val add = set!!.add(coroutine) + if (!add) { + return false + } + } + } + return true + } + + override fun remove(coroutine: Coroutine<*>): Boolean { + if (delete(coroutine)) { + coroutine.cancel() + return true + } + return false + } + + override fun delete(coroutine: Coroutine<*>): Boolean { + synchronized(this) { + val set = resources + if (set == null || !set.remove(coroutine)) { + return false + } + } + return true + } + + override fun clear() { + val set: HashSet>? + synchronized(this) { + set = resources + resources = null + } + + set?.forEach { + runCatching { + it.cancel() + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/help/coroutine/CoroutineContainer.kt b/app/src/main/java/io/legado/app/help/coroutine/CoroutineContainer.kt new file mode 100644 index 000000000..d98a2b8da --- /dev/null +++ b/app/src/main/java/io/legado/app/help/coroutine/CoroutineContainer.kt @@ -0,0 +1,15 @@ +package io.legado.app.help.coroutine + +interface CoroutineContainer { + + fun add(coroutine: Coroutine<*>): Boolean + + fun addAll(vararg coroutines: Coroutine<*>): Boolean + + fun remove(coroutine: Coroutine<*>): Boolean + + fun delete(coroutine: Coroutine<*>): Boolean + + fun clear() + +} diff --git a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt index 03e9d0446..919be87a6 100644 --- a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt +++ b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt @@ -4,6 +4,7 @@ import android.annotation.SuppressLint import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter import io.legado.app.help.BookHelp +import io.legado.app.help.coroutine.CompositeCoroutine import io.legado.app.help.coroutine.Coroutine import io.legado.app.model.WebBook import io.legado.app.utils.htmlFormat @@ -16,7 +17,7 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { companion object { private var debugSource: String? = null private var callback: Callback? = null - private val tasks: MutableList> = mutableListOf() + private val tasks: CompositeCoroutine = CompositeCoroutine() @SuppressLint("ConstantLocale") private val DEBUG_TIME_FORMAT = SimpleDateFormat("[mm:ss.SSS]", Locale.getDefault()) @@ -34,11 +35,6 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { } fun cancelDebug(destroy: Boolean = false) { - tasks.forEach { - if (!it.isCancelled) { - it.cancel() - } - } tasks.clear() if (destroy) { From c9f94d8a41041bbf23fdb9f73e13e76643bca92d Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 31 Jul 2019 15:15:56 +0800 Subject: [PATCH 0490/1997] up --- .../io/legado/app/model/webbook/BookList.kt | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookList.kt b/app/src/main/java/io/legado/app/model/webbook/BookList.kt index 350a84a38..dbc3c6af8 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookList.kt @@ -57,6 +57,7 @@ object BookList { } } else { val ruleName = analyzeRule.splitSourceRule(bookListRule.name ?: "") + val ruleBookUrl = analyzeRule.splitSourceRule(bookListRule.bookUrl ?: "") val ruleAuthor = analyzeRule.splitSourceRule(bookListRule.author ?: "") val ruleCoverUrl = analyzeRule.splitSourceRule(bookListRule.coverUrl ?: "") val ruleIntro = analyzeRule.splitSourceRule(bookListRule.intro ?: "") @@ -72,6 +73,7 @@ object BookList { baseUrl, index == 0, ruleName = ruleName, + ruleBookUrl = ruleBookUrl, ruleAuthor = ruleAuthor, ruleCoverUrl = ruleCoverUrl, ruleIntro = ruleIntro, @@ -127,6 +129,7 @@ object BookList { baseUrl: String, printLog: Boolean, ruleName: List, + ruleBookUrl: List, ruleAuthor: List, ruleKind: List, ruleCoverUrl: List, @@ -142,13 +145,28 @@ object BookList { SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取书名", printLog) searchBook.name = analyzeRule.getString(ruleName) SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.name ?: "", printLog) - searchBook.name?.let { + if (!searchBook.name.isNullOrEmpty()) { + SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取书籍Url", printLog) + searchBook.bookUrl = analyzeRule.getString(ruleBookUrl, true) + SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.bookUrl, printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取作者", printLog) searchBook.author = analyzeRule.getString(ruleAuthor) + SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.author ?: "", printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取分类", printLog) searchBook.kind = analyzeRule.getString(ruleKind) + SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.kind ?: "", printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取简介", printLog) searchBook.intro = analyzeRule.getString(ruleIntro) + SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.intro ?: "", printLog, true) + SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取字数", printLog) searchBook.wordCount = analyzeRule.getString(ruleWordCount) - searchBook.coverUrl = analyzeRule.getString(ruleCoverUrl) + SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.wordCount ?: "", printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取封面Url", printLog) + searchBook.coverUrl = analyzeRule.getString(ruleCoverUrl, true) + SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.coverUrl ?: "", printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取最新章节", printLog) searchBook.latestChapterTitle = analyzeRule.getString(ruleLastChapter) + SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.latestChapterTitle ?: "", printLog) return searchBook } return null From 3accf592995c02cd02447192d87d7ea3fedf5379 Mon Sep 17 00:00:00 2001 From: Administrator <1760316362@qq.com> Date: Wed, 31 Jul 2019 15:21:46 +0800 Subject: [PATCH 0491/1997] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../legado/app/ui/sourcedebug/SourceDebugActivity.kt | 4 ++-- .../io/legado/app/ui/sourcedebug/SourceDebugModel.kt | 10 +++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt index 400328f1f..eda5f392d 100644 --- a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt +++ b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt @@ -27,12 +27,12 @@ class SourceDebugActivity : BaseActivity() { viewModel.init(intent.getStringExtra("key")) initRecyclerView() initSearchView() - viewModel.logs.observe(this, Observer { + viewModel.observeLogs(this){ adapter.addItem(it.obj as String) if (it.what == -1 || it.what == 1000) { rotate_loading.hide() } - }) + } } private fun initRecyclerView() { diff --git a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt index 0a9732ad5..5b7716804 100644 --- a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt +++ b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt @@ -1,7 +1,9 @@ package io.legado.app.ui.sourcedebug import android.app.Application +import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.Observer import io.legado.app.App import io.legado.app.base.BaseViewModel import io.legado.app.help.EventMessage @@ -10,10 +12,16 @@ import io.legado.app.model.webbook.SourceDebug class SourceDebugModel(application: Application) : BaseViewModel(application), SourceDebug.Callback { - val logs: MutableLiveData = MutableLiveData() + private val logs: MutableLiveData = MutableLiveData() private var webBook: WebBook? = null + fun observeLogs(owner: LifecycleOwner, observer: (EventMessage) -> Unit) { + logs.observe(owner, Observer { + observer(it) + }) + } + fun init(sourceUrl: String?) { sourceUrl?.let { //优先使用这个,不会抛出异常 From 87523bba2dc96f567115ec8dbf1621968886a019 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 31 Jul 2019 22:55:32 +0800 Subject: [PATCH 0492/1997] up --- .../java/io/legado/app/model/webbook/SourceDebug.kt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt index 919be87a6..7ca534ed9 100644 --- a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt +++ b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt @@ -5,7 +5,6 @@ import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter import io.legado.app.help.BookHelp import io.legado.app.help.coroutine.CompositeCoroutine -import io.legado.app.help.coroutine.Coroutine import io.legado.app.model.WebBook import io.legado.app.utils.htmlFormat import io.legado.app.utils.isAbsUrl @@ -66,11 +65,12 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { } } - fun searchDebug(key: String) { + private fun searchDebug(key: String) { val search = webBook.searchBook(key, 1) .onSuccess { searchBooks -> searchBooks?.let { if (searchBooks.isNotEmpty()) { + callback?.printLog(1, "") infoDebug(BookHelp.toBook(searchBooks[0])) } } @@ -81,9 +81,11 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { tasks.add(search) } - fun infoDebug(book: Book) { + private fun infoDebug(book: Book) { + printLog(debugSource, 1, "开始获取详情页") val info = webBook.getBookInfo(book) .onSuccess { + callback?.printLog(1, "") tocDebug(book) } .onError { @@ -93,10 +95,12 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { } private fun tocDebug(book: Book) { + printLog(debugSource, 1, "开始获取目录页") val chapterList = webBook.getChapterList(book) .onSuccess { chapterList -> chapterList?.let { if (it.isNotEmpty()) { + callback?.printLog(1, "") contentDebug(book, it[0]) } } @@ -108,6 +112,7 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { } private fun contentDebug(book: Book, bookChapter: BookChapter) { + printLog(debugSource, 1, "开始获取内容") val content = webBook.getContent(book, bookChapter) .onSuccess { content -> content?.let { From 51d537fba355828558cc91a4731998d75bdc1762 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 31 Jul 2019 23:02:41 +0800 Subject: [PATCH 0493/1997] up --- app/src/main/java/io/legado/app/model/webbook/BookList.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookList.kt b/app/src/main/java/io/legado/app/model/webbook/BookList.kt index dbc3c6af8..1fcc447dc 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookList.kt @@ -48,6 +48,7 @@ object BookList { reverse = true ruleList = ruleList.substring(1) } + SourceDebug.printLog(bookSource.bookSourceUrl, 1, "解析书籍列表") collections = analyzeRule.getElements(ruleList) if (collections.isEmpty() && bookSource.bookUrlPattern.isNullOrEmpty()) { SourceDebug.printLog(bookSource.bookSourceUrl, 1, "列表为空,按详情页解析") From 821e56182bfc424bf20b067b9c5dbdeef3040c3e Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 1 Aug 2019 08:23:41 +0800 Subject: [PATCH 0494/1997] up --- app/build.gradle | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 578212db5..72945b3c7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -83,7 +83,7 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.1.0-rc01' implementation 'androidx.preference:preference:1.1.0-rc01' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' - implementation 'com.google.android.material:material:1.1.0-alpha08' + implementation 'com.google.android.material:material:1.1.0-alpha09' implementation 'com.google.android:flexbox:1.1.0' //lifecycle @@ -116,8 +116,6 @@ dependencies { implementation 'com.google.code.gson:gson:2.8.5' implementation 'org.jsoup:jsoup:1.12.1' implementation 'cn.wanghaomiao:JsoupXpath:2.3.2' - // implementation 'org.apache.commons:commons-text:1.6' - // Default json parser for jsonpath implementation 'com.jayway.jsonpath:json-path:2.4.0' //JS @@ -137,7 +135,7 @@ dependencies { implementation 'com.jaredrummler:colorpicker:1.1.0' //对话框 - implementation 'com.afollestad.material-dialogs:core:3.0.0-rc3' - implementation 'com.afollestad.material-dialogs:input:3.0.0-rc3' - implementation 'com.afollestad.material-dialogs:files:3.0.0-rc3' + implementation 'com.afollestad.material-dialogs:core:3.1.0' + implementation 'com.afollestad.material-dialogs:input:3.1.0' + implementation 'com.afollestad.material-dialogs:files:3.1.0' } From 50e4f72b8e094bc328257dfad7b2f56f21c8b8d6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 1 Aug 2019 09:22:20 +0800 Subject: [PATCH 0495/1997] up --- app/build.gradle | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 72945b3c7..7354986a4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -83,6 +83,7 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.1.0-rc01' implementation 'androidx.preference:preference:1.1.0-rc01' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0' implementation 'com.google.android.material:material:1.1.0-alpha09' implementation 'com.google.android:flexbox:1.1.0' @@ -108,7 +109,7 @@ dependencies { implementation 'com.jeremyliao:live-event-bus-x:1.4.4' //协程 - def coroutines_version = '1.2.1' + def coroutines_version = '1.2.2' implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" @@ -138,4 +139,5 @@ dependencies { implementation 'com.afollestad.material-dialogs:core:3.1.0' implementation 'com.afollestad.material-dialogs:input:3.1.0' implementation 'com.afollestad.material-dialogs:files:3.1.0' + } From 6a65b282f286433b03211c89311682831ee4ec04 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 1 Aug 2019 10:26:00 +0800 Subject: [PATCH 0496/1997] up --- .../main/java/io/legado/app/constant/Bus.kt | 1 + .../app/ui/sourcedebug/SourceDebugActivity.kt | 19 ++++++++++++------- .../app/ui/sourcedebug/SourceDebugModel.kt | 15 +++------------ 3 files changed, 16 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/io/legado/app/constant/Bus.kt b/app/src/main/java/io/legado/app/constant/Bus.kt index 94d41fafb..98acde903 100644 --- a/app/src/main/java/io/legado/app/constant/Bus.kt +++ b/app/src/main/java/io/legado/app/constant/Bus.kt @@ -2,4 +2,5 @@ package io.legado.app.constant object Bus { const val RECREATE = "RECREATE" + const val SOURCE_DEBUG_LOG = "sourceDebugLog" } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt index eda5f392d..81817b616 100644 --- a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt +++ b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt @@ -3,13 +3,15 @@ package io.legado.app.ui.sourcedebug import android.os.Bundle import android.view.View import androidx.appcompat.widget.SearchView -import androidx.lifecycle.Observer import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.R import io.legado.app.base.BaseActivity +import io.legado.app.constant.Bus +import io.legado.app.help.EventMessage import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.ThemeStore import io.legado.app.utils.getViewModel +import io.legado.app.utils.observeEvent import kotlinx.android.synthetic.main.activity_source_debug.* import kotlinx.android.synthetic.main.view_title_bar.* import org.jetbrains.anko.toast @@ -27,12 +29,6 @@ class SourceDebugActivity : BaseActivity() { viewModel.init(intent.getStringExtra("key")) initRecyclerView() initSearchView() - viewModel.observeLogs(this){ - adapter.addItem(it.obj as String) - if (it.what == -1 || it.what == 1000) { - rotate_loading.hide() - } - } } private fun initRecyclerView() { @@ -69,4 +65,13 @@ class SourceDebugActivity : BaseActivity() { toast("未获取到书源") }) } + + override fun observeLiveBus() { + observeEvent(Bus.SOURCE_DEBUG_LOG) { + adapter.addItem(it.obj as String) + if (it.what == -1 || it.what == 1000) { + rotate_loading.hide() + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt index 5b7716804..df76cda3b 100644 --- a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt +++ b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt @@ -1,27 +1,18 @@ package io.legado.app.ui.sourcedebug import android.app.Application -import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.Observer import io.legado.app.App import io.legado.app.base.BaseViewModel +import io.legado.app.constant.Bus import io.legado.app.help.EventMessage import io.legado.app.model.WebBook import io.legado.app.model.webbook.SourceDebug +import io.legado.app.utils.postEvent class SourceDebugModel(application: Application) : BaseViewModel(application), SourceDebug.Callback { - private val logs: MutableLiveData = MutableLiveData() - private var webBook: WebBook? = null - fun observeLogs(owner: LifecycleOwner, observer: (EventMessage) -> Unit) { - logs.observe(owner, Observer { - observer(it) - }) - } - fun init(sourceUrl: String?) { sourceUrl?.let { //优先使用这个,不会抛出异常 @@ -40,7 +31,7 @@ class SourceDebugModel(application: Application) : BaseViewModel(application), S } override fun printLog(state: Int, msg: String) { - logs.postValue(EventMessage.obtain(state, msg)) + postEvent(Bus.SOURCE_DEBUG_LOG, EventMessage.obtain(state, msg)) } override fun onCleared() { From e2a2bbd2b8297726a0d9389c3bb5e21f741168b9 Mon Sep 17 00:00:00 2001 From: Administrator <1760316362@qq.com> Date: Thu, 1 Aug 2019 10:37:54 +0800 Subject: [PATCH 0497/1997] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 5 - .../java/io/legado/app/base/BaseActivity.kt | 11 +- .../java/io/legado/app/base/BaseFragment.kt | 3 +- .../java/io/legado/app/base/VMBaseActivity.kt | 10 + .../java/io/legado/app/base/VMBaseFragment.kt | 9 + .../io/legado/app/lib/dialogs/AlertBuilder.kt | 103 ++++++++++ .../app/lib/dialogs/AndroidAlertBuilder.kt | 117 ++++++++++++ .../legado/app/lib/dialogs/AndroidDialogs.kt | 179 ++++++++++++++++++ .../app/lib/dialogs/AndroidSelectors.kt | 50 +++++ .../java/io/legado/app/lib/dialogs/Dialogs.kt | 103 ++++++++++ .../io/legado/app/lib/dialogs/Selectors.kt | 52 +++++ .../lib/theme/prefs/ATEEditTextPreference.kt | 4 +- .../model/analyzeRule/AnalyzeByJSonPath.kt | 8 +- .../io/legado/app/ui/about/AboutActivity.kt | 9 +- .../io/legado/app/ui/about/DonateActivity.kt | 10 +- .../app/ui/bookinfo/BookInfoActivity.kt | 9 +- .../app/ui/bookinfo/BookInfoEditActivity.kt | 8 +- .../app/ui/bookshelf/BookshelfActivity.kt | 8 +- .../app/ui/booksource/BookSourceActivity.kt | 9 +- .../io/legado/app/ui/config/ConfigActivity.kt | 8 +- .../app/ui/config/ThemeConfigFragment.kt | 6 +- .../io/legado/app/ui/main/MainActivity.kt | 10 +- .../ui/main/bookshelf/BookshelfFragment.kt | 61 +++--- .../ui/main/bookshelf/BookshelfViewModel.kt | 24 +++ .../io/legado/app/ui/qrcode/QrCodeActivity.kt | 10 +- .../app/ui/replacerule/ReplaceRuleActivity.kt | 8 +- .../io/legado/app/ui/search/SearchActivity.kt | 9 +- .../app/ui/sourcedebug/SourceDebugActivity.kt | 11 +- .../app/ui/sourceedit/SourceEditActivity.kt | 9 +- .../legado/app/ui/welcome/WelcomeActivity.kt | 10 +- .../legado/app/utils/AlertDialogExtensions.kt | 7 +- .../io/legado/app/utils/ViewExtensions.kt | 15 +- app/src/main/res/layout/dialog_edittext.xml | 18 ++ 33 files changed, 776 insertions(+), 137 deletions(-) create mode 100644 app/src/main/java/io/legado/app/base/VMBaseActivity.kt create mode 100644 app/src/main/java/io/legado/app/base/VMBaseFragment.kt create mode 100644 app/src/main/java/io/legado/app/lib/dialogs/AlertBuilder.kt create mode 100644 app/src/main/java/io/legado/app/lib/dialogs/AndroidAlertBuilder.kt create mode 100644 app/src/main/java/io/legado/app/lib/dialogs/AndroidDialogs.kt create mode 100644 app/src/main/java/io/legado/app/lib/dialogs/AndroidSelectors.kt create mode 100644 app/src/main/java/io/legado/app/lib/dialogs/Dialogs.kt create mode 100644 app/src/main/java/io/legado/app/lib/dialogs/Selectors.kt create mode 100644 app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt create mode 100644 app/src/main/res/layout/dialog_edittext.xml diff --git a/app/build.gradle b/app/build.gradle index 578212db5..4771d0825 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -135,9 +135,4 @@ dependencies { //颜色选择 implementation 'com.jaredrummler:colorpicker:1.1.0' - - //对话框 - implementation 'com.afollestad.material-dialogs:core:3.0.0-rc3' - implementation 'com.afollestad.material-dialogs:input:3.0.0-rc3' - implementation 'com.afollestad.material-dialogs:files:3.0.0-rc3' } diff --git a/app/src/main/java/io/legado/app/base/BaseActivity.kt b/app/src/main/java/io/legado/app/base/BaseActivity.kt index 4dfe09fb4..51f960788 100644 --- a/app/src/main/java/io/legado/app/base/BaseActivity.kt +++ b/app/src/main/java/io/legado/app/base/BaseActivity.kt @@ -7,7 +7,6 @@ import android.view.MenuItem import android.view.View import android.view.WindowManager import androidx.appcompat.app.AppCompatActivity -import androidx.lifecycle.ViewModel import io.legado.app.R import io.legado.app.lib.theme.ColorUtils import io.legado.app.lib.theme.ThemeStore @@ -17,20 +16,16 @@ import kotlinx.coroutines.MainScope import kotlinx.coroutines.cancel -abstract class BaseActivity(private val fullScreen: Boolean = true) : AppCompatActivity(), +abstract class BaseActivity(private val layoutID: Int, private val fullScreen: Boolean = true) : AppCompatActivity(), CoroutineScope by MainScope() { - protected abstract val viewModel: VM - - protected abstract val layoutID: Int - override fun onCreate(savedInstanceState: Bundle?) { window.decorView.disableAutoFill() initTheme() setupSystemBar() super.onCreate(savedInstanceState) setContentView(layoutID) - onActivityCreated(viewModel, savedInstanceState) + onActivityCreated(savedInstanceState) observeLiveBus() } @@ -39,7 +34,7 @@ abstract class BaseActivity(private val fullScreen: Boolean = tr cancel() } - abstract fun onActivityCreated(viewModel: VM, savedInstanceState: Bundle?) + abstract fun onActivityCreated(savedInstanceState: Bundle?) final override fun onCreateOptionsMenu(menu: Menu?): Boolean { return menu?.let { diff --git a/app/src/main/java/io/legado/app/base/BaseFragment.kt b/app/src/main/java/io/legado/app/base/BaseFragment.kt index 7c02f1bd3..f8314c44c 100644 --- a/app/src/main/java/io/legado/app/base/BaseFragment.kt +++ b/app/src/main/java/io/legado/app/base/BaseFragment.kt @@ -11,7 +11,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.MainScope import kotlinx.coroutines.cancel -abstract class BaseFragment(contentLayoutId: Int = 0) : Fragment(contentLayoutId), +abstract class BaseFragment(layoutID: Int) : Fragment(layoutID), CoroutineScope by MainScope() { var supportToolbar: Toolbar? = null @@ -20,6 +20,7 @@ abstract class BaseFragment(contentLayoutId: Int = 0) : Fragment(contentLayoutId val menuInflater: MenuInflater get() = SupportMenuInflater(requireContext()) + override fun onDestroy() { super.onDestroy() cancel() diff --git a/app/src/main/java/io/legado/app/base/VMBaseActivity.kt b/app/src/main/java/io/legado/app/base/VMBaseActivity.kt new file mode 100644 index 000000000..8267a2c8b --- /dev/null +++ b/app/src/main/java/io/legado/app/base/VMBaseActivity.kt @@ -0,0 +1,10 @@ +package io.legado.app.base + +import androidx.lifecycle.ViewModel + +abstract class VMBaseActivity(layoutID: Int, fullScreen: Boolean = true) : + BaseActivity(layoutID, fullScreen) { + + protected abstract val viewModel: VM + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/base/VMBaseFragment.kt b/app/src/main/java/io/legado/app/base/VMBaseFragment.kt new file mode 100644 index 000000000..cc78d19dd --- /dev/null +++ b/app/src/main/java/io/legado/app/base/VMBaseFragment.kt @@ -0,0 +1,9 @@ +package io.legado.app.base + +import androidx.lifecycle.ViewModel + +abstract class VMBaseFragment(layoutID: Int) : BaseFragment(layoutID) { + + protected abstract val viewModel: VM + +} diff --git a/app/src/main/java/io/legado/app/lib/dialogs/AlertBuilder.kt b/app/src/main/java/io/legado/app/lib/dialogs/AlertBuilder.kt new file mode 100644 index 000000000..4617e99f1 --- /dev/null +++ b/app/src/main/java/io/legado/app/lib/dialogs/AlertBuilder.kt @@ -0,0 +1,103 @@ +/* + * Copyright 2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:Suppress("NOTHING_TO_INLINE", "unused") +package io.legado.app.lib.dialogs + +import android.annotation.SuppressLint +import android.content.Context +import android.content.DialogInterface +import android.graphics.drawable.Drawable +import android.view.KeyEvent +import android.view.View +import android.view.ViewManager +import androidx.annotation.DrawableRes +import androidx.annotation.StringRes +import org.jetbrains.anko.UI +import org.jetbrains.anko.internals.AnkoInternals.NO_GETTER +import kotlin.DeprecationLevel.ERROR + +@SuppressLint("SupportAnnotationUsage") +interface AlertBuilder { + val ctx: Context + + var title: CharSequence + @Deprecated(NO_GETTER, level = ERROR) get + + var titleResource: Int + @Deprecated(NO_GETTER, level = ERROR) get + + var message: CharSequence + @Deprecated(NO_GETTER, level = ERROR) get + + var messageResource: Int + @Deprecated(NO_GETTER, level = ERROR) get + + var icon: Drawable + @Deprecated(NO_GETTER, level = ERROR) get + + @setparam:DrawableRes + var iconResource: Int + @Deprecated(NO_GETTER, level = ERROR) get + + var customTitle: View + @Deprecated(NO_GETTER, level = ERROR) get + + var customView: View + @Deprecated(NO_GETTER, level = ERROR) get + + var isCancelable: Boolean + @Deprecated(NO_GETTER, level = ERROR) get + + fun onCancelled(handler: (dialog: DialogInterface) -> Unit) + + fun onKeyPressed(handler: (dialog: DialogInterface, keyCode: Int, e: KeyEvent) -> Boolean) + + fun positiveButton(buttonText: String, onClicked: (dialog: DialogInterface) -> Unit) + fun positiveButton(@StringRes buttonTextResource: Int, onClicked: (dialog: DialogInterface) -> Unit) + + fun negativeButton(buttonText: String, onClicked: (dialog: DialogInterface) -> Unit) + fun negativeButton(@StringRes buttonTextResource: Int, onClicked: (dialog: DialogInterface) -> Unit) + + fun neutralPressed(buttonText: String, onClicked: (dialog: DialogInterface) -> Unit) + fun neutralPressed(@StringRes buttonTextResource: Int, onClicked: (dialog: DialogInterface) -> Unit) + + fun items(items: List, onItemSelected: (dialog: DialogInterface, index: Int) -> Unit) + fun items(items: List, onItemSelected: (dialog: DialogInterface, item: T, index: Int) -> Unit) + + fun build(): D + fun show(): D +} + +fun AlertBuilder<*>.customTitle(view: () -> View) { + customTitle = view() +} + +fun AlertBuilder<*>.customView(view: () -> View) { + customView = view() +} + +inline fun AlertBuilder<*>.okButton(noinline handler: (dialog: DialogInterface) -> Unit) = + positiveButton(android.R.string.ok, handler) + +inline fun AlertBuilder<*>.cancelButton(noinline handler: (dialog: DialogInterface) -> Unit) = + negativeButton(android.R.string.cancel, handler) + +inline fun AlertBuilder<*>.yesButton(noinline handler: (dialog: DialogInterface) -> Unit) = + positiveButton(android.R.string.yes, handler) + +inline fun AlertBuilder<*>.noButton(noinline handler: (dialog: DialogInterface) -> Unit) = + negativeButton(android.R.string.no, handler) \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/lib/dialogs/AndroidAlertBuilder.kt b/app/src/main/java/io/legado/app/lib/dialogs/AndroidAlertBuilder.kt new file mode 100644 index 000000000..38e03d573 --- /dev/null +++ b/app/src/main/java/io/legado/app/lib/dialogs/AndroidAlertBuilder.kt @@ -0,0 +1,117 @@ +/* + * Copyright 2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.legado.app.lib.dialogs + +import android.content.Context +import android.content.DialogInterface +import android.graphics.drawable.Drawable +import android.view.KeyEvent +import android.view.View +import androidx.appcompat.app.AlertDialog +import org.jetbrains.anko.internals.AnkoInternals +import org.jetbrains.anko.internals.AnkoInternals.NO_GETTER +import kotlin.DeprecationLevel.ERROR + +val Android: AlertBuilderFactory = ::AndroidAlertBuilder + +internal class AndroidAlertBuilder(override val ctx: Context) : AlertBuilder { + private val builder = AlertDialog.Builder(ctx) + + override var title: CharSequence + @Deprecated(NO_GETTER, level = ERROR) get() = AnkoInternals.noGetter() + set(value) { builder.setTitle(value) } + + override var titleResource: Int + @Deprecated(NO_GETTER, level = ERROR) get() = AnkoInternals.noGetter() + set(value) { builder.setTitle(value) } + + override var message: CharSequence + @Deprecated(NO_GETTER, level = ERROR) get() = AnkoInternals.noGetter() + set(value) { builder.setMessage(value) } + + override var messageResource: Int + @Deprecated(NO_GETTER, level = ERROR) get() = AnkoInternals.noGetter() + set(value) { builder.setMessage(value) } + + override var icon: Drawable + @Deprecated(NO_GETTER, level = ERROR) get() = AnkoInternals.noGetter() + set(value) { builder.setIcon(value) } + + override var iconResource: Int + @Deprecated(NO_GETTER, level = ERROR) get() = AnkoInternals.noGetter() + set(value) { builder.setIcon(value) } + + override var customTitle: View + @Deprecated(NO_GETTER, level = ERROR) get() = AnkoInternals.noGetter() + set(value) { builder.setCustomTitle(value) } + + override var customView: View + @Deprecated(NO_GETTER, level = ERROR) get() = AnkoInternals.noGetter() + set(value) { builder.setView(value) } + + override var isCancelable: Boolean + @Deprecated(NO_GETTER, level = ERROR) get() = AnkoInternals.noGetter() + set(value) { builder.setCancelable(value) } + + override fun onCancelled(handler: (DialogInterface) -> Unit) { + builder.setOnCancelListener(handler) + } + + override fun onKeyPressed(handler: (dialog: DialogInterface, keyCode: Int, e: KeyEvent) -> Boolean) { + builder.setOnKeyListener(handler) + } + + override fun positiveButton(buttonText: String, onClicked: (dialog: DialogInterface) -> Unit) { + builder.setPositiveButton(buttonText) { dialog, _ -> onClicked(dialog) } + } + + override fun positiveButton(buttonTextResource: Int, onClicked: (dialog: DialogInterface) -> Unit) { + builder.setPositiveButton(buttonTextResource) { dialog, _ -> onClicked(dialog) } + } + + override fun negativeButton(buttonText: String, onClicked: (dialog: DialogInterface) -> Unit) { + builder.setNegativeButton(buttonText) { dialog, _ -> onClicked(dialog) } + } + + override fun negativeButton(buttonTextResource: Int, onClicked: (dialog: DialogInterface) -> Unit) { + builder.setNegativeButton(buttonTextResource) { dialog, _ -> onClicked(dialog) } + } + + override fun neutralPressed(buttonText: String, onClicked: (dialog: DialogInterface) -> Unit) { + builder.setNeutralButton(buttonText) { dialog, _ -> onClicked(dialog) } + } + + override fun neutralPressed(buttonTextResource: Int, onClicked: (dialog: DialogInterface) -> Unit) { + builder.setNeutralButton(buttonTextResource) { dialog, _ -> onClicked(dialog) } + } + + override fun items(items: List, onItemSelected: (dialog: DialogInterface, index: Int) -> Unit) { + builder.setItems(Array(items.size) { i -> items[i].toString() }) { dialog, which -> + onItemSelected(dialog, which) + } + } + + override fun items(items: List, onItemSelected: (dialog: DialogInterface, item: T, index: Int) -> Unit) { + builder.setItems(Array(items.size) { i -> items[i].toString() }) { dialog, which -> + onItemSelected(dialog, items[which], which) + } + } + + override fun build(): AlertDialog = builder.create() + + override fun show(): AlertDialog = builder.show() +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/lib/dialogs/AndroidDialogs.kt b/app/src/main/java/io/legado/app/lib/dialogs/AndroidDialogs.kt new file mode 100644 index 000000000..c178ef75d --- /dev/null +++ b/app/src/main/java/io/legado/app/lib/dialogs/AndroidDialogs.kt @@ -0,0 +1,179 @@ +/* + * Copyright 2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:Suppress("NOTHING_TO_INLINE", "unused") + +package io.legado.app.lib.dialogs + +import android.app.ProgressDialog +import android.content.Context +import android.content.DialogInterface +import androidx.appcompat.app.AlertDialog +import androidx.fragment.app.Fragment +import org.jetbrains.anko.AnkoContext + +inline fun AnkoContext<*>.alert( + title: CharSequence? = null, + message: CharSequence? = null, + noinline init: (AlertBuilder.() -> Unit)? = null +) = ctx.alert(title, message, init) + +inline fun Fragment.alert( + title: CharSequence? = null, + message: CharSequence? = null, + noinline init: (AlertBuilder.() -> Unit)? = null +) = requireActivity().alert(title, message, init) + +fun Context.alert( + title: CharSequence? = null, + message: CharSequence? = null, + init: (AlertBuilder.() -> Unit)? = null +): AlertBuilder { + return AndroidAlertBuilder(this).apply { + if (title != null) { + this.title = title + } + if (message != null) { + this.message = message + } + if (init != null) init() + } +} + +inline fun AnkoContext<*>.alert( + titleResource: Int? = null, + messageResource: Int? = null, + noinline init: (AlertBuilder.() -> Unit)? = null +) = ctx.alert(titleResource, messageResource, init) + +inline fun Fragment.alert( + title: Int? = null, + message: Int? = null, + noinline init: (AlertBuilder.() -> Unit)? = null +) = requireActivity().alert(title, message, init) + +fun Context.alert( + titleResource: Int? = null, + messageResource: Int? = null, + init: (AlertBuilder.() -> Unit)? = null +): AlertBuilder { + return AndroidAlertBuilder(this).apply { + if (titleResource != null) { + this.titleResource = titleResource + } + if (messageResource != null) { + this.messageResource = messageResource + } + if (init != null) init() + } +} + + +inline fun AnkoContext<*>.alert(noinline init: AlertBuilder.() -> Unit) = ctx.alert(init) +inline fun Fragment.alert(noinline init: AlertBuilder.() -> Unit) = activity?.alert(init) + +fun Context.alert(init: AlertBuilder.() -> Unit): AlertBuilder = + AndroidAlertBuilder(this).apply { init() } + +inline fun AnkoContext<*>.progressDialog( + title: Int? = null, + message: Int? = null, + noinline init: (ProgressDialog.() -> Unit)? = null +) = ctx.progressDialog(title, message, init) + +inline fun Fragment.progressDialog( + title: Int? = null, + message: Int? = null, + noinline init: (ProgressDialog.() -> Unit)? = null +) = requireActivity().progressDialog(title, message, init) + +fun Context.progressDialog( + title: Int? = null, + message: Int? = null, + init: (ProgressDialog.() -> Unit)? = null +) = progressDialog(title?.let { getString(it) }, message?.let { getString(it) }, false, init) + + +inline fun AnkoContext<*>.indeterminateProgressDialog( + title: Int? = null, + message: Int? = null, + noinline init: (ProgressDialog.() -> Unit)? = null +) = ctx.indeterminateProgressDialog(title, message, init) + +inline fun Fragment.indeterminateProgressDialog( + title: Int? = null, + message: Int? = null, + noinline init: (ProgressDialog.() -> Unit)? = null +) = requireActivity().indeterminateProgressDialog(title, message, init) + +fun Context.indeterminateProgressDialog( + title: Int? = null, + message: Int? = null, + init: (ProgressDialog.() -> Unit)? = null +) = progressDialog(title?.let { getString(it) }, message?.let { getString(it) }, true, init) + + +inline fun AnkoContext<*>.progressDialog( + title: CharSequence? = null, + message: CharSequence? = null, + noinline init: (ProgressDialog.() -> Unit)? = null +) = ctx.progressDialog(title, message, init) + +inline fun Fragment.progressDialog( + title: CharSequence? = null, + message: CharSequence? = null, + noinline init: (ProgressDialog.() -> Unit)? = null +) = requireActivity().progressDialog(title, message, init) + +fun Context.progressDialog( + title: CharSequence? = null, + message: CharSequence? = null, + init: (ProgressDialog.() -> Unit)? = null +) = progressDialog(title, message, false, init) + + +inline fun AnkoContext<*>.indeterminateProgressDialog( + title: CharSequence? = null, + message: CharSequence? = null, + noinline init: (ProgressDialog.() -> Unit)? = null +) = ctx.indeterminateProgressDialog(title, message, init) + +inline fun Fragment.indeterminateProgressDialog( + title: CharSequence? = null, + message: CharSequence? = null, + noinline init: (ProgressDialog.() -> Unit)? = null +) = requireActivity().indeterminateProgressDialog(title, message, init) + +fun Context.indeterminateProgressDialog( + title: CharSequence? = null, + message: CharSequence? = null, + init: (ProgressDialog.() -> Unit)? = null +) = progressDialog(title, message, true, init) + + +private fun Context.progressDialog( + title: CharSequence? = null, + message: CharSequence? = null, + indeterminate: Boolean, + init: (ProgressDialog.() -> Unit)? = null +) = ProgressDialog(this).apply { + isIndeterminate = indeterminate + if (!indeterminate) setProgressStyle(ProgressDialog.STYLE_HORIZONTAL) + if (message != null) setMessage(message) + if (title != null) setTitle(title) + if (init != null) init() + show() +} diff --git a/app/src/main/java/io/legado/app/lib/dialogs/AndroidSelectors.kt b/app/src/main/java/io/legado/app/lib/dialogs/AndroidSelectors.kt new file mode 100644 index 000000000..f4d63e1a8 --- /dev/null +++ b/app/src/main/java/io/legado/app/lib/dialogs/AndroidSelectors.kt @@ -0,0 +1,50 @@ +/* + * Copyright 2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:Suppress("NOTHING_TO_INLINE", "unused") + +package io.legado.app.lib.dialogs + +import android.content.Context +import android.content.DialogInterface +import androidx.fragment.app.Fragment +import org.jetbrains.anko.AnkoContext + +inline fun AnkoContext<*>.selector( + title: CharSequence? = null, + items: List, + noinline onClick: (DialogInterface, Int) -> Unit +) = ctx.selector(title, items, onClick) + +inline fun Fragment.selector( + title: CharSequence? = null, + items: List, + noinline onClick: (DialogInterface, Int) -> Unit +) = activity?.selector(title, items, onClick) + +fun Context.selector( + title: CharSequence? = null, + items: List, + onClick: (DialogInterface, Int) -> Unit +) { + with(AndroidAlertBuilder(this)) { + if (title != null) { + this.title = title + } + items(items, onClick) + show() + } +} diff --git a/app/src/main/java/io/legado/app/lib/dialogs/Dialogs.kt b/app/src/main/java/io/legado/app/lib/dialogs/Dialogs.kt new file mode 100644 index 000000000..9f4c0c77b --- /dev/null +++ b/app/src/main/java/io/legado/app/lib/dialogs/Dialogs.kt @@ -0,0 +1,103 @@ +/* + * Copyright 2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:Suppress("NOTHING_TO_INLINE", "unused") + +package io.legado.app.lib.dialogs + +import android.content.Context +import android.content.DialogInterface +import androidx.fragment.app.Fragment +import org.jetbrains.anko.AnkoContext + +typealias AlertBuilderFactory = (Context) -> AlertBuilder + +inline fun AnkoContext<*>.alert( + noinline factory: AlertBuilderFactory, + title: String? = null, + message: String? = null, + noinline init: (AlertBuilder.() -> Unit)? = null +) = ctx.alert(factory, title, message, init) + +inline fun Fragment.alert( + noinline factory: AlertBuilderFactory, + title: String? = null, + message: String? = null, + noinline init: (AlertBuilder.() -> Unit)? = null +) = activity?.alert(factory, title, message, init) + +fun Context.alert( + factory: AlertBuilderFactory, + title: String? = null, + message: String? = null, + init: (AlertBuilder.() -> Unit)? = null +): AlertBuilder { + return factory(this).apply { + if (title != null) { + this.title = title + } + if (message != null) { + this.message = message + } + if (init != null) init() + } +} + +inline fun AnkoContext<*>.alert( + noinline factory: AlertBuilderFactory, + titleResource: Int? = null, + messageResource: Int? = null, + noinline init: (AlertBuilder.() -> Unit)? = null +) = ctx.alert(factory, titleResource, messageResource, init) + +inline fun Fragment.alert( + noinline factory: AlertBuilderFactory, + titleResource: Int? = null, + messageResource: Int? = null, + noinline init: (AlertBuilder.() -> Unit)? = null +) = requireActivity().alert(factory, titleResource, messageResource, init) + +fun Context.alert( + factory: AlertBuilderFactory, + titleResource: Int? = null, + messageResource: Int? = null, + init: (AlertBuilder.() -> Unit)? = null +): AlertBuilder { + return factory(this).apply { + if (titleResource != null) { + this.titleResource = titleResource + } + if (messageResource != null) { + this.messageResource = messageResource + } + if (init != null) init() + } +} + +inline fun AnkoContext<*>.alert( + noinline factory: AlertBuilderFactory, + noinline init: AlertBuilder.() -> Unit +) = ctx.alert(factory, init) + +inline fun Fragment.alert( + noinline factory: AlertBuilderFactory, + noinline init: AlertBuilder.() -> Unit +) = requireActivity().alert(factory, init) + +fun Context.alert( + factory: AlertBuilderFactory, + init: AlertBuilder.() -> Unit +): AlertBuilder = factory(this).apply { init() } diff --git a/app/src/main/java/io/legado/app/lib/dialogs/Selectors.kt b/app/src/main/java/io/legado/app/lib/dialogs/Selectors.kt new file mode 100644 index 000000000..485c6971c --- /dev/null +++ b/app/src/main/java/io/legado/app/lib/dialogs/Selectors.kt @@ -0,0 +1,52 @@ +/* + * Copyright 2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:Suppress("NOTHING_TO_INLINE", "unused") +package io.legado.app.lib.dialogs + +import android.content.Context +import android.content.DialogInterface +import androidx.fragment.app.Fragment +import org.jetbrains.anko.AnkoContext + +inline fun AnkoContext<*>.selector( + noinline factory: AlertBuilderFactory, + title: CharSequence? = null, + items: List, + noinline onClick: (DialogInterface, CharSequence, Int) -> Unit +) = ctx.selector(factory, title, items, onClick) + +inline fun Fragment.selector( + noinline factory: AlertBuilderFactory, + title: CharSequence? = null, + items: List, + noinline onClick: (DialogInterface, CharSequence, Int) -> Unit +) = requireActivity().selector(factory, title, items, onClick) + +fun Context.selector( + factory: AlertBuilderFactory, + title: CharSequence? = null, + items: List, + onClick: (DialogInterface, CharSequence, Int) -> Unit +) { + with(factory(this)) { + if (title != null) { + this.title = title + } + items(items, onClick) + show() + } +} diff --git a/app/src/main/java/io/legado/app/lib/theme/prefs/ATEEditTextPreference.kt b/app/src/main/java/io/legado/app/lib/theme/prefs/ATEEditTextPreference.kt index 639ccab86..935aa6289 100644 --- a/app/src/main/java/io/legado/app/lib/theme/prefs/ATEEditTextPreference.kt +++ b/app/src/main/java/io/legado/app/lib/theme/prefs/ATEEditTextPreference.kt @@ -18,7 +18,7 @@ import androidx.appcompat.app.AlertDialog import androidx.preference.EditTextPreference import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.ThemeStore -import io.legado.app.utils.upTint +import io.legado.app.utils.applyTint class ATEEditTextPreference(context: Context?, attrs: AttributeSet?) : EditTextPreference( context, @@ -72,7 +72,7 @@ class ATEEditTextPreference(context: Context?, attrs: AttributeSet?) : EditTextP requestInputMethod(dialog) dialog.setOnDismissListener(this) dialog.show() - dialog.upTint() + dialog.applyTint() } protected fun onCreateDialogView(): View? { diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSonPath.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSonPath.kt index e1f697acd..298c1d2fa 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSonPath.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSonPath.kt @@ -98,12 +98,12 @@ class AnalyzeByJSonPath { if (rules.size == 1) { if (!rule.contains("{$.")) { try { - val `object` = ctx!!.read(rule) ?: return result - if (`object` is List<*>) { - for (o in `object`) + val obj = ctx!!.read(rule) ?: return result + if (obj is List<*>) { + for (o in obj) result.add(o.toString()) } else { - result.add(`object`.toString()) + result.add(obj.toString()) } } catch (ignored: Exception) { } diff --git a/app/src/main/java/io/legado/app/ui/about/AboutActivity.kt b/app/src/main/java/io/legado/app/ui/about/AboutActivity.kt index 05eef3ad7..303e9de4b 100644 --- a/app/src/main/java/io/legado/app/ui/about/AboutActivity.kt +++ b/app/src/main/java/io/legado/app/ui/about/AboutActivity.kt @@ -8,16 +8,13 @@ import android.view.MenuItem import androidx.lifecycle.AndroidViewModel import io.legado.app.R import io.legado.app.base.BaseActivity +import io.legado.app.base.VMBaseActivity import io.legado.app.utils.getViewModel import org.jetbrains.anko.toast -class AboutActivity : BaseActivity() { - override val viewModel: AndroidViewModel - get() = getViewModel(AndroidViewModel::class.java) - override val layoutID: Int - get() = R.layout.activity_about +class AboutActivity : BaseActivity(R.layout.activity_about) { - override fun onActivityCreated(viewModel: AndroidViewModel, savedInstanceState: Bundle?) { + override fun onActivityCreated(savedInstanceState: Bundle?) { val fTag = "aboutFragment" var aboutFragment = supportFragmentManager.findFragmentByTag(fTag) if (aboutFragment == null) aboutFragment = AboutFragment() diff --git a/app/src/main/java/io/legado/app/ui/about/DonateActivity.kt b/app/src/main/java/io/legado/app/ui/about/DonateActivity.kt index c5bb90704..313a6bec6 100644 --- a/app/src/main/java/io/legado/app/ui/about/DonateActivity.kt +++ b/app/src/main/java/io/legado/app/ui/about/DonateActivity.kt @@ -23,15 +23,9 @@ import java.net.URLEncoder * 捐赠页面 */ -class DonateActivity : BaseActivity() { +class DonateActivity : BaseActivity(R.layout.activity_donate) { - override val viewModel: AndroidViewModel - get() = getViewModel(AndroidViewModel::class.java) - - override val layoutID: Int - get() = R.layout.activity_donate - - override fun onActivityCreated(viewModel: AndroidViewModel, savedInstanceState: Bundle?) { + override fun onActivityCreated(savedInstanceState: Bundle?) { setSupportActionBar(toolbar) ATH.applyEdgeEffectColor(scroll_view) vw_zfb_tz.setOnClickListener { aliDonate(this) } diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index 39adfaa01..314a76cf4 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -3,15 +3,10 @@ package io.legado.app.ui.bookinfo import android.os.Bundle import io.legado.app.R import io.legado.app.base.BaseActivity -import io.legado.app.utils.getViewModel -class BookInfoActivity : BaseActivity() { - override val viewModel: BookInfoViewModel - get() = getViewModel(BookInfoViewModel::class.java) - override val layoutID: Int - get() = R.layout.activity_book_info +class BookInfoActivity : BaseActivity(R.layout.activity_book_info) { - override fun onActivityCreated(viewModel: BookInfoViewModel, savedInstanceState: Bundle?) { + override fun onActivityCreated(savedInstanceState: Bundle?) { } diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoEditActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoEditActivity.kt index 8e3ed92c5..689398fdc 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoEditActivity.kt @@ -2,16 +2,14 @@ package io.legado.app.ui.bookinfo import android.os.Bundle import io.legado.app.R -import io.legado.app.base.BaseActivity +import io.legado.app.base.VMBaseActivity import io.legado.app.utils.getViewModel -class BookInfoEditActivity : BaseActivity() { +class BookInfoEditActivity : VMBaseActivity(R.layout.activity_book_info_edit) { override val viewModel: BookInfoViewModel get() = getViewModel(BookInfoViewModel::class.java) - override val layoutID: Int - get() = R.layout.activity_book_info_edit - override fun onActivityCreated(viewModel: BookInfoViewModel, savedInstanceState: Bundle?) { + override fun onActivityCreated(savedInstanceState: Bundle?) { } diff --git a/app/src/main/java/io/legado/app/ui/bookshelf/BookshelfActivity.kt b/app/src/main/java/io/legado/app/ui/bookshelf/BookshelfActivity.kt index a6cda3975..590699652 100644 --- a/app/src/main/java/io/legado/app/ui/bookshelf/BookshelfActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookshelf/BookshelfActivity.kt @@ -10,22 +10,20 @@ import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.App import io.legado.app.R -import io.legado.app.base.BaseActivity +import io.legado.app.base.VMBaseActivity import io.legado.app.data.entities.Book import io.legado.app.lib.theme.ATH import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_bookshelf.* -class BookshelfActivity : BaseActivity() { +class BookshelfActivity : VMBaseActivity(R.layout.activity_bookshelf) { override val viewModel: BookshelfViewModel get() = getViewModel(BookshelfViewModel::class.java) - override val layoutID: Int - get() = R.layout.activity_bookshelf private lateinit var bookshelfAdapter: BookshelfAdapter private var bookshelfLiveData: LiveData>? = null - override fun onActivityCreated(viewModel: BookshelfViewModel, savedInstanceState: Bundle?) { + override fun onActivityCreated(savedInstanceState: Bundle?) { if (viewModel.bookGroup == null) { viewModel.bookGroup = intent.getParcelableExtra("data") } diff --git a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt index 25690f258..66ff91a1d 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt @@ -14,7 +14,7 @@ import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.App import io.legado.app.R -import io.legado.app.base.BaseActivity +import io.legado.app.base.VMBaseActivity import io.legado.app.data.entities.BookSource import io.legado.app.help.ItemTouchCallback import io.legado.app.lib.theme.ATH @@ -28,17 +28,16 @@ import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.launch import org.jetbrains.anko.startActivity -class BookSourceActivity : BaseActivity(), BookSourceAdapter.CallBack, +class BookSourceActivity : VMBaseActivity(R.layout.activity_book_source), + BookSourceAdapter.CallBack, SearchView.OnQueryTextListener { override val viewModel: BookshelfViewModel get() = getViewModel(BookshelfViewModel::class.java) - override val layoutID: Int - get() = R.layout.activity_book_source private lateinit var adapter: BookSourceAdapter private var bookSourceLiveDate: LiveData>? = null - override fun onActivityCreated(viewModel: BookshelfViewModel, savedInstanceState: Bundle?) { + override fun onActivityCreated(savedInstanceState: Bundle?) { setSupportActionBar(toolbar) initRecyclerView() initDataObserve() diff --git a/app/src/main/java/io/legado/app/ui/config/ConfigActivity.kt b/app/src/main/java/io/legado/app/ui/config/ConfigActivity.kt index a8449be35..6329cb2e3 100644 --- a/app/src/main/java/io/legado/app/ui/config/ConfigActivity.kt +++ b/app/src/main/java/io/legado/app/ui/config/ConfigActivity.kt @@ -2,18 +2,16 @@ package io.legado.app.ui.config import android.os.Bundle import io.legado.app.R -import io.legado.app.base.BaseActivity +import io.legado.app.base.VMBaseActivity import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_config.* import kotlinx.android.synthetic.main.view_title_bar.* -class ConfigActivity : BaseActivity() { +class ConfigActivity : VMBaseActivity(R.layout.activity_config) { override val viewModel: ConfigViewModel get() = getViewModel(ConfigViewModel::class.java) - override val layoutID: Int - get() = R.layout.activity_config - override fun onActivityCreated(viewModel: ConfigViewModel, savedInstanceState: Bundle?) { + override fun onActivityCreated(savedInstanceState: Bundle?) { intent.getIntExtra("configType", -1).let { if (it != -1) viewModel.configType = it } diff --git a/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt index 89a698b54..778e6e15e 100644 --- a/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt @@ -56,7 +56,7 @@ class ThemeConfigFragment : PreferenceFragmentCompat(), SharedPreferences.OnShar upTheme(false) } .setNegativeButton(R.string.cancel) { _, _ -> upTheme(false) } - .show().upTint() + .show().applyTint() } } else { upTheme(false) @@ -76,7 +76,7 @@ class ThemeConfigFragment : PreferenceFragmentCompat(), SharedPreferences.OnShar upTheme(true) } .setNegativeButton(R.string.cancel) { _, _ -> upTheme(true) } - .show().upTint() + .show().applyTint() } } else { upTheme(true) @@ -106,7 +106,7 @@ class ThemeConfigFragment : PreferenceFragmentCompat(), SharedPreferences.OnShar recreateActivities() } .setNegativeButton(R.string.cancel, null) - .show().upTint() + .show().applyTint() } } } diff --git a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt index b92d71a03..bcb1d2fe3 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt @@ -9,7 +9,7 @@ import androidx.viewpager.widget.ViewPager import com.google.android.material.bottomnavigation.BottomNavigationView import io.legado.app.App import io.legado.app.R -import io.legado.app.base.BaseActivity +import io.legado.app.base.VMBaseActivity import io.legado.app.constant.Bus import io.legado.app.help.permission.Permissions import io.legado.app.help.permission.PermissionsCompat @@ -26,16 +26,14 @@ import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -class MainActivity : BaseActivity(), BottomNavigationView.OnNavigationItemSelectedListener, +class MainActivity : VMBaseActivity(R.layout.activity_main), + BottomNavigationView.OnNavigationItemSelectedListener, ViewPager.OnPageChangeListener { override val viewModel: MainViewModel get() = getViewModel(MainViewModel::class.java) - override val layoutID: Int - get() = R.layout.activity_main - - override fun onActivityCreated(viewModel: MainViewModel, savedInstanceState: Bundle?) { + override fun onActivityCreated(savedInstanceState: Bundle?) { ATH.applyEdgeEffectColor(view_pager_main) bottom_navigation_view.setBackgroundColor(ThemeStore.backgroundColor(this)) val colorStateList = Selector.colorBuild() diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index 6bd0a54df..fece79af1 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -3,6 +3,7 @@ package io.legado.app.ui.main.bookshelf import android.os.Bundle import android.view.Menu import android.view.View +import android.widget.EditText import androidx.appcompat.widget.SearchView import androidx.lifecycle.LiveData import androidx.lifecycle.Observer @@ -10,28 +11,32 @@ import androidx.paging.LivePagedListBuilder import androidx.paging.PagedList import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager -import com.afollestad.materialdialogs.MaterialDialog -import com.afollestad.materialdialogs.input.input import io.legado.app.App import io.legado.app.R -import io.legado.app.base.BaseFragment +import io.legado.app.base.VMBaseFragment import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookGroup +import io.legado.app.lib.dialogs.* import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.ThemeStore import io.legado.app.ui.bookshelf.BookshelfActivity import io.legado.app.ui.search.SearchActivity -import io.legado.app.utils.disableAutoFill +import io.legado.app.utils.applyTint +import io.legado.app.utils.getViewModel +import io.legado.app.utils.requestInputMethod +import kotlinx.android.synthetic.main.dialog_edittext.view.* import kotlinx.android.synthetic.main.fragment_bookshelf.* import kotlinx.android.synthetic.main.view_title_bar.* -import kotlinx.coroutines.Dispatchers.IO -import kotlinx.coroutines.launch import org.jetbrains.anko.startActivity import org.jetbrains.anko.textColor -class BookshelfFragment : BaseFragment(R.layout.fragment_bookshelf), SearchView.OnQueryTextListener, +class BookshelfFragment : VMBaseFragment(R.layout.fragment_bookshelf), + SearchView.OnQueryTextListener, BookGroupAdapter.CallBack { + override val viewModel: BookshelfViewModel + get() = getViewModel(BookshelfViewModel::class.java) + private lateinit var bookshelfAdapter: BookshelfAdapter private lateinit var bookGroupAdapter: BookGroupAdapter private var bookGroupLiveData: LiveData>? = null @@ -89,25 +94,7 @@ class BookshelfFragment : BaseFragment(R.layout.fragment_bookshelf), SearchView. override fun open(bookGroup: BookGroup) { when (bookGroup.groupId) { - -10 -> context?.let { - MaterialDialog(it).show { - window?.decorView?.disableAutoFill() - title(text = "新建分组") - input(hint = "分组名称") { _, charSequence -> - run { - launch(IO) { - App.db.bookGroupDao().insert( - BookGroup( - App.db.bookGroupDao().maxId + 1, - charSequence.toString() - ) - ) - } - } - } - positiveButton(R.string.ok) - } - } + -10 -> showGroupInputDialog() else -> context?.startActivity(Pair("data", bookGroup)) } } @@ -121,4 +108,26 @@ class BookshelfFragment : BaseFragment(R.layout.fragment_bookshelf), SearchView. return false } + private fun showGroupInputDialog() { + alert(title = "新建分组") { + var editText: EditText? = null + + customView { + layoutInflater.inflate(R.layout.dialog_edittext, null).apply { + editText = edit_view.apply { + ATH.setTint(this, ThemeStore.accentColor(ctx)) + hint = "分组名称" + } + } + } + + yesButton { + viewModel.saveBookGroup(editText?.text?.toString()) + } + + noButton { } + + }.show().applyTint().requestInputMethod() + } + } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt new file mode 100644 index 000000000..d47080cb4 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt @@ -0,0 +1,24 @@ +package io.legado.app.ui.main.bookshelf + +import android.app.Application +import io.legado.app.App +import io.legado.app.base.BaseViewModel +import io.legado.app.data.entities.BookGroup + +class BookshelfViewModel(application: Application) : BaseViewModel(application) { + + + fun saveBookGroup(group: String?) { + if (!group.isNullOrBlank()) { + execute { + App.db.bookGroupDao().insert( + BookGroup( + App.db.bookGroupDao().maxId + 1, + group + ) + ) + } + } + } + +} diff --git a/app/src/main/java/io/legado/app/ui/qrcode/QrCodeActivity.kt b/app/src/main/java/io/legado/app/ui/qrcode/QrCodeActivity.kt index deb50d3a9..dac723182 100644 --- a/app/src/main/java/io/legado/app/ui/qrcode/QrCodeActivity.kt +++ b/app/src/main/java/io/legado/app/ui/qrcode/QrCodeActivity.kt @@ -6,27 +6,21 @@ import android.os.Bundle import android.view.Menu import android.view.MenuItem import android.view.View -import androidx.lifecycle.AndroidViewModel import cn.bingoogolapple.qrcode.core.QRCodeView import io.legado.app.R import io.legado.app.base.BaseActivity import io.legado.app.help.permission.Permissions import io.legado.app.help.permission.PermissionsCompat import io.legado.app.utils.FileUtils -import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_qrcode_capture.* import kotlinx.android.synthetic.main.view_title_bar.* -class QrCodeActivity : BaseActivity(), QRCodeView.Delegate { - override val viewModel: AndroidViewModel - get() = getViewModel(AndroidViewModel::class.java) - override val layoutID: Int - get() = R.layout.activity_qrcode_capture +class QrCodeActivity : BaseActivity(R.layout.activity_qrcode_capture), QRCodeView.Delegate { private val requestQrImage = 202 private var flashlightIsOpen: Boolean = false - override fun onActivityCreated(viewModel: AndroidViewModel, savedInstanceState: Bundle?) { + override fun onActivityCreated(savedInstanceState: Bundle?) { setSupportActionBar(toolbar) zxingview.setDelegate(this) fab_flashlight.setOnClickListener { diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt index a6d206d36..6e82de8df 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt @@ -13,7 +13,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import io.legado.app.App import io.legado.app.R -import io.legado.app.base.BaseActivity +import io.legado.app.base.VMBaseActivity import io.legado.app.constant.AppConst.APP_TAG import io.legado.app.data.entities.ReplaceRule import io.legado.app.lib.theme.ATH @@ -23,16 +23,14 @@ import org.jetbrains.anko.doAsync import org.jetbrains.anko.toast -class ReplaceRuleActivity : BaseActivity() { +class ReplaceRuleActivity : VMBaseActivity(R.layout.activity_replace_rule) { override val viewModel: ReplaceRuleViewModel get() = getViewModel(ReplaceRuleViewModel::class.java) - override val layoutID: Int - get() = R.layout.activity_replace_rule private lateinit var adapter: ReplaceRuleAdapter private var rulesLiveData: LiveData>? = null private var allEnabled = false - override fun onActivityCreated(viewModel: ReplaceRuleViewModel, savedInstanceState: Bundle?) { + override fun onActivityCreated(savedInstanceState: Bundle?) { initRecyclerView() initDataObservers() initSwipeToDelete() diff --git a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt index c2a420c6f..cc9b7a76b 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt @@ -3,21 +3,18 @@ package io.legado.app.ui.search import android.os.Bundle import android.view.View import io.legado.app.R -import io.legado.app.base.BaseActivity +import io.legado.app.base.VMBaseActivity import io.legado.app.lib.theme.ATH import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_search.* import kotlinx.android.synthetic.main.view_title_bar.* -class SearchActivity : BaseActivity() { +class SearchActivity : VMBaseActivity(R.layout.activity_search) { override val viewModel: SearchViewModel get() = getViewModel(SearchViewModel::class.java) - override val layoutID: Int - get() = R.layout.activity_search - - override fun onActivityCreated(viewModel: SearchViewModel, savedInstanceState: Bundle?) { + override fun onActivityCreated(savedInstanceState: Bundle?) { initSearchView() initRecyclerView() viewModel.search() diff --git a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt index eda5f392d..82df34f83 100644 --- a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt +++ b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt @@ -3,10 +3,9 @@ package io.legado.app.ui.sourcedebug import android.os.Bundle import android.view.View import androidx.appcompat.widget.SearchView -import androidx.lifecycle.Observer import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.R -import io.legado.app.base.BaseActivity +import io.legado.app.base.VMBaseActivity import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.ThemeStore import io.legado.app.utils.getViewModel @@ -14,20 +13,18 @@ import kotlinx.android.synthetic.main.activity_source_debug.* import kotlinx.android.synthetic.main.view_title_bar.* import org.jetbrains.anko.toast -class SourceDebugActivity : BaseActivity() { +class SourceDebugActivity : VMBaseActivity(R.layout.activity_source_debug) { override val viewModel: SourceDebugModel get() = getViewModel(SourceDebugModel::class.java) - override val layoutID: Int - get() = R.layout.activity_source_debug private lateinit var adapter: SourceDebugAdapter - override fun onActivityCreated(viewModel: SourceDebugModel, savedInstanceState: Bundle?) { + override fun onActivityCreated(savedInstanceState: Bundle?) { viewModel.init(intent.getStringExtra("key")) initRecyclerView() initSearchView() - viewModel.observeLogs(this){ + viewModel.observeLogs(this) { adapter.addItem(it.obj as String) if (it.what == -1 || it.what == 1000) { rotate_loading.hide() diff --git a/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditActivity.kt index 4f1e8a344..cb9c3ed0f 100644 --- a/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditActivity.kt @@ -12,7 +12,7 @@ import androidx.lifecycle.Observer import androidx.recyclerview.widget.LinearLayoutManager import com.google.android.material.tabs.TabLayout import io.legado.app.R -import io.legado.app.base.BaseActivity +import io.legado.app.base.VMBaseActivity import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.rule.* import io.legado.app.lib.theme.ATH @@ -26,11 +26,10 @@ import org.jetbrains.anko.startActivity import org.jetbrains.anko.toast import kotlin.math.abs -class SourceEditActivity : BaseActivity(false), KeyboardToolPop.OnClickListener { +class SourceEditActivity : VMBaseActivity(R.layout.activity_source_edit, false), + KeyboardToolPop.OnClickListener { override val viewModel: SourceEditViewModel get() = getViewModel(SourceEditViewModel::class.java) - override val layoutID: Int - get() = R.layout.activity_source_edit private val adapter = SourceEditAdapter() private val sourceEditList: ArrayList = ArrayList() @@ -43,7 +42,7 @@ class SourceEditActivity : BaseActivity(false), KeyboardToo private var mSoftKeyboardTool: PopupWindow? = null private var mIsSoftKeyBoardShowing = false - override fun onActivityCreated(viewModel: SourceEditViewModel, savedInstanceState: Bundle?) { + override fun onActivityCreated(savedInstanceState: Bundle?) { initView() viewModel.sourceLiveData.observe(this, Observer { upRecyclerView(it) diff --git a/app/src/main/java/io/legado/app/ui/welcome/WelcomeActivity.kt b/app/src/main/java/io/legado/app/ui/welcome/WelcomeActivity.kt index f225bcd80..3295cb766 100644 --- a/app/src/main/java/io/legado/app/ui/welcome/WelcomeActivity.kt +++ b/app/src/main/java/io/legado/app/ui/welcome/WelcomeActivity.kt @@ -3,22 +3,16 @@ package io.legado.app.ui.welcome import android.animation.Animator import android.animation.ValueAnimator import android.os.Bundle -import androidx.lifecycle.AndroidViewModel import io.legado.app.R import io.legado.app.base.BaseActivity import io.legado.app.lib.theme.ThemeStore import io.legado.app.ui.main.MainActivity -import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_welcome.* import org.jetbrains.anko.startActivity -class WelcomeActivity : BaseActivity() { - override val viewModel: AndroidViewModel - get() = getViewModel(AndroidViewModel::class.java) - override val layoutID: Int - get() = R.layout.activity_welcome +class WelcomeActivity : BaseActivity(R.layout.activity_welcome) { - override fun onActivityCreated(viewModel: AndroidViewModel, savedInstanceState: Bundle?) { + override fun onActivityCreated(savedInstanceState: Bundle?) { iv_bg.setColorFilter(ThemeStore.accentColor(this)) val welAnimator = ValueAnimator.ofFloat(1f, 0f).setDuration(800) welAnimator.startDelay = 100 diff --git a/app/src/main/java/io/legado/app/utils/AlertDialogExtensions.kt b/app/src/main/java/io/legado/app/utils/AlertDialogExtensions.kt index e956f1368..2f261a2e7 100644 --- a/app/src/main/java/io/legado/app/utils/AlertDialogExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/AlertDialogExtensions.kt @@ -1,8 +1,13 @@ package io.legado.app.utils +import android.view.WindowManager import androidx.appcompat.app.AlertDialog import io.legado.app.lib.theme.ATH -fun AlertDialog.upTint(): AlertDialog { +fun AlertDialog.applyTint(): AlertDialog { return ATH.setAlertDialogTint(this) } + +fun AlertDialog.requestInputMethod(){ + window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE) +} diff --git a/app/src/main/java/io/legado/app/utils/ViewExtensions.kt b/app/src/main/java/io/legado/app/utils/ViewExtensions.kt index 0275e057e..4300ea2ae 100644 --- a/app/src/main/java/io/legado/app/utils/ViewExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/ViewExtensions.kt @@ -3,6 +3,7 @@ package io.legado.app.utils import android.content.Context import android.os.Build import android.view.View +import android.view.View.* import android.view.inputmethod.InputMethodManager import io.legado.app.App @@ -15,6 +16,18 @@ fun View.hideSoftInput() = run { fun View.disableAutoFill() = run { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - this.importantForAutofill = View.IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS + this.importantForAutofill = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS } +} + +fun View.gone() { + visibility = GONE +} + +fun View.invisible() { + visibility = INVISIBLE +} + +fun View.visible() { + visibility = VISIBLE } \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_edittext.xml b/app/src/main/res/layout/dialog_edittext.xml new file mode 100644 index 000000000..04dd314d0 --- /dev/null +++ b/app/src/main/res/layout/dialog_edittext.xml @@ -0,0 +1,18 @@ + + + + + \ No newline at end of file From aa1c412a55af97c24af8f0b99419b67ce8438209 Mon Sep 17 00:00:00 2001 From: Administrator <1760316362@qq.com> Date: Thu, 1 Aug 2019 10:43:35 +0800 Subject: [PATCH 0498/1997] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 6 ------ .../app/ui/sourcedebug/SourceDebugActivity.kt | 18 ++++++++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 7354986a4..90f626586 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -134,10 +134,4 @@ dependencies { //颜色选择 implementation 'com.jaredrummler:colorpicker:1.1.0' - - //对话框 - implementation 'com.afollestad.material-dialogs:core:3.1.0' - implementation 'com.afollestad.material-dialogs:input:3.1.0' - implementation 'com.afollestad.material-dialogs:files:3.1.0' - } diff --git a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt index 82df34f83..644843369 100644 --- a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt +++ b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt @@ -6,9 +6,12 @@ import androidx.appcompat.widget.SearchView import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.R import io.legado.app.base.VMBaseActivity +import io.legado.app.constant.Bus +import io.legado.app.help.EventMessage import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.ThemeStore import io.legado.app.utils.getViewModel +import io.legado.app.utils.observeEvent import kotlinx.android.synthetic.main.activity_source_debug.* import kotlinx.android.synthetic.main.view_title_bar.* import org.jetbrains.anko.toast @@ -24,12 +27,6 @@ class SourceDebugActivity : VMBaseActivity(R.layout.activity_s viewModel.init(intent.getStringExtra("key")) initRecyclerView() initSearchView() - viewModel.observeLogs(this) { - adapter.addItem(it.obj as String) - if (it.what == -1 || it.what == 1000) { - rotate_loading.hide() - } - } } private fun initRecyclerView() { @@ -66,4 +63,13 @@ class SourceDebugActivity : VMBaseActivity(R.layout.activity_s toast("未获取到书源") }) } + + override fun observeLiveBus() { + observeEvent(Bus.SOURCE_DEBUG_LOG){ + adapter.addItem(it.obj as String) + if (it.what == -1 || it.what == 1000) { + rotate_loading.hide() + } + } + } } \ No newline at end of file From 80866b1bad76748434961fb323b8bbbd67c9ff01 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 1 Aug 2019 11:09:57 +0800 Subject: [PATCH 0499/1997] up --- .../io/legado/app/model/webbook/BookList.kt | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookList.kt b/app/src/main/java/io/legado/app/model/webbook/BookList.kt index 1fcc447dc..096d6d83c 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookList.kt @@ -110,13 +110,24 @@ object BookList { searchBook.name = analyzeRule.getString(name ?: "") SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.name ?: "") if (!searchBook.name.isNullOrEmpty()) { + SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取作者") searchBook.author = analyzeRule.getString(author ?: "") - searchBook.coverUrl = analyzeRule.getString(coverUrl ?: "") - searchBook.intro = analyzeRule.getString(intro ?: "") - searchBook.latestChapterTitle = analyzeRule.getString(lastChapter ?: "") + SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.author ?: "") + SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取分类") searchBook.kind = analyzeRule.getString(kind ?: "") + SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.kind ?: "") + SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取简介") + searchBook.intro = analyzeRule.getString(intro ?: "") + SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.intro ?: "", isHtml = true) + SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取字数") searchBook.wordCount = analyzeRule.getString(wordCount ?: "") - + SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.wordCount ?: "") + SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取封面Url") + searchBook.coverUrl = analyzeRule.getString(coverUrl ?: "", true) + SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.coverUrl ?: "") + SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取最新章节") + searchBook.latestChapterTitle = analyzeRule.getString(lastChapter ?: "") + SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.latestChapterTitle ?: "") return searchBook } } From fa23d1de24f4b8ece586e4e486535ef1c7110b76 Mon Sep 17 00:00:00 2001 From: Administrator <1760316362@qq.com> Date: Thu, 1 Aug 2019 11:31:18 +0800 Subject: [PATCH 0500/1997] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/main/bookshelf/BookshelfFragment.kt | 5 +- .../app/ui/sourcedebug/SourceDebugActivity.kt | 2 +- .../java/io/legado/app/utils/EventBusKt.kt | 54 ++++++++++++++++--- 3 files changed, 53 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index fece79af1..ec4b22c5c 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -16,7 +16,10 @@ import io.legado.app.R import io.legado.app.base.VMBaseFragment import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookGroup -import io.legado.app.lib.dialogs.* +import io.legado.app.lib.dialogs.alert +import io.legado.app.lib.dialogs.customView +import io.legado.app.lib.dialogs.noButton +import io.legado.app.lib.dialogs.yesButton import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.ThemeStore import io.legado.app.ui.bookshelf.BookshelfActivity diff --git a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt index 644843369..a6345fe13 100644 --- a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt +++ b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt @@ -65,7 +65,7 @@ class SourceDebugActivity : VMBaseActivity(R.layout.activity_s } override fun observeLiveBus() { - observeEvent(Bus.SOURCE_DEBUG_LOG){ + observeEvent(Bus.SOURCE_DEBUG_LOG) { adapter.addItem(it.obj as String) if (it.what == -1 || it.what == 1000) { rotate_loading.hide() diff --git a/app/src/main/java/io/legado/app/utils/EventBusKt.kt b/app/src/main/java/io/legado/app/utils/EventBusKt.kt index 116540e75..fa6904ea3 100644 --- a/app/src/main/java/io/legado/app/utils/EventBusKt.kt +++ b/app/src/main/java/io/legado/app/utils/EventBusKt.kt @@ -10,29 +10,71 @@ inline fun eventObservable(tag: String): LiveEventBus.Observable } inline fun postEvent(tag: String, event: EVENT) { - return LiveEventBus.get().with(tag, EVENT::class.java).post(event) + LiveEventBus.get().with(tag, EVENT::class.java).post(event) } inline fun AppCompatActivity.observeEvent(tag: String, crossinline observer: (EVENT) -> Unit) { - return eventObservable(tag).observe(this, Observer { + eventObservable(tag).observe(this, Observer { observer(it) }) } +/** + * 只能观察相同类型的事件,可用EventMessage + */ +inline fun AppCompatActivity.observeEvents(vararg tags: String, crossinline observer: (EVENT) -> Unit) { + val o = Observer { + observer(it) + } + tags.forEach { + eventObservable(it).observe(this, o) + } +} + inline fun AppCompatActivity.observeEventSticky(tag: String, crossinline observer: (EVENT) -> Unit) { - return eventObservable(tag).observeSticky(this, Observer { + eventObservable(tag).observeSticky(this, Observer { observer(it) }) } +inline fun AppCompatActivity.observeEventsSticky( + vararg tags: String, + crossinline observer: (EVENT) -> Unit +) { + val o = Observer { + observer(it) + } + tags.forEach { + eventObservable(it).observeSticky(this, o) + } +} + inline fun Fragment.observeEvent(tag: String, crossinline observer: (EVENT) -> Unit) { - return eventObservable(tag).observe(this, Observer { + eventObservable(tag).observe(this, Observer { observer(it) }) } +inline fun Fragment.observeEvents(vararg tags: String, crossinline observer: (EVENT) -> Unit) { + val o = Observer { + observer(it) + } + tags.forEach { + eventObservable(it).observe(this, o) + } +} + inline fun Fragment.observeEventSticky(tag: String, crossinline observer: (EVENT) -> Unit) { - return eventObservable(tag).observeSticky(this, Observer { + eventObservable(tag).observeSticky(this, Observer { observer(it) }) -} \ No newline at end of file +} + +inline fun Fragment.observeEventsSticky(vararg tags: String, crossinline observer: (EVENT) -> Unit) { + val o = Observer { + observer(it) + } + tags.forEach { + eventObservable(it).observeSticky(this, o) + } +} From 07ac3acb1fa9b187412dc428ea63242b0a26b971 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 1 Aug 2019 11:43:37 +0800 Subject: [PATCH 0501/1997] up --- .../java/io/legado/app/model/webbook/BookInfo.kt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt b/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt index 6fb891736..988a1fa59 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt @@ -29,27 +29,43 @@ object BookInfo { analyzeRule.setContent(body) infoRule.init?.let { if (it.isNotEmpty()) { + SourceDebug.printLog(bookSource.bookSourceUrl, 1, "执行详情页初始化规则") analyzeRule.setContent(analyzeRule.getElement(it)) } } + SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取书名") analyzeRule.getString(infoRule.name ?: "")?.let { if (it.isNotEmpty()) book.name = it } + SourceDebug.printLog(bookSource.bookSourceUrl, 1, book.name ?: "") + SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取作者") analyzeRule.getString(infoRule.author ?: "")?.let { if (it.isNotEmpty()) book.author = it } + SourceDebug.printLog(bookSource.bookSourceUrl, 1, book.author ?: "") + SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取分类") analyzeRule.getString(infoRule.kind ?: "")?.let { if (it.isNotEmpty()) book.kind = it } + SourceDebug.printLog(bookSource.bookSourceUrl, 1, book.kind ?: "") + SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取简介") analyzeRule.getString(infoRule.intro ?: "")?.let { if (it.isNotEmpty()) book.intro = it } + SourceDebug.printLog(bookSource.bookSourceUrl, 1, book.intro ?: "", isHtml = true) + SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取字数") analyzeRule.getString(infoRule.wordCount ?: "")?.let { if (it.isNotEmpty()) book.wordCount = it } + SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取最新章节") analyzeRule.getString(infoRule.lastChapter ?: "")?.let { if (it.isNotEmpty()) book.latestChapterTitle = it } + SourceDebug.printLog(bookSource.bookSourceUrl, 1, book.latestChapterTitle ?: "") + SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取目录Url") + book.tocUrl = analyzeRule.getString(infoRule.tocUrl ?: "", true) ?: baseUrl + if (book.tocUrl.isEmpty()) book.tocUrl = baseUrl + SourceDebug.printLog(bookSource.bookSourceUrl, 1, book.tocUrl) } } \ No newline at end of file From 52bd3a473105302cd846a1678a49a88a436d8068 Mon Sep 17 00:00:00 2001 From: Administrator <1760316362@qq.com> Date: Thu, 1 Aug 2019 11:47:56 +0800 Subject: [PATCH 0502/1997] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../io/legado/app/lib/dialogs/AlertBuilder.kt | 27 ++++++++++--------- .../app/lib/dialogs/AndroidAlertBuilder.kt | 24 ++++++++--------- .../ui/main/bookshelf/BookshelfFragment.kt | 2 +- 3 files changed, 27 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/dialogs/AlertBuilder.kt b/app/src/main/java/io/legado/app/lib/dialogs/AlertBuilder.kt index 4617e99f1..0ab0db154 100644 --- a/app/src/main/java/io/legado/app/lib/dialogs/AlertBuilder.kt +++ b/app/src/main/java/io/legado/app/lib/dialogs/AlertBuilder.kt @@ -15,6 +15,7 @@ */ @file:Suppress("NOTHING_TO_INLINE", "unused") + package io.legado.app.lib.dialogs import android.annotation.SuppressLint @@ -52,7 +53,7 @@ interface AlertBuilder { @setparam:DrawableRes var iconResource: Int @Deprecated(NO_GETTER, level = ERROR) get - + var customTitle: View @Deprecated(NO_GETTER, level = ERROR) get @@ -62,18 +63,18 @@ interface AlertBuilder { var isCancelable: Boolean @Deprecated(NO_GETTER, level = ERROR) get - fun onCancelled(handler: (dialog: DialogInterface) -> Unit) + fun positiveButton(buttonText: String, onClicked: ((dialog: DialogInterface) -> Unit)? = null) + fun positiveButton(@StringRes buttonTextResource: Int, onClicked: ((dialog: DialogInterface) -> Unit)? = null) - fun onKeyPressed(handler: (dialog: DialogInterface, keyCode: Int, e: KeyEvent) -> Boolean) + fun negativeButton(buttonText: String, onClicked: ((dialog: DialogInterface) -> Unit)? = null) + fun negativeButton(@StringRes buttonTextResource: Int, onClicked: ((dialog: DialogInterface) -> Unit)?=null) - fun positiveButton(buttonText: String, onClicked: (dialog: DialogInterface) -> Unit) - fun positiveButton(@StringRes buttonTextResource: Int, onClicked: (dialog: DialogInterface) -> Unit) + fun neutralButton(buttonText: String, onClicked: ((dialog: DialogInterface) -> Unit)? = null) + fun neutralButton(@StringRes buttonTextResource: Int, onClicked: ((dialog: DialogInterface) -> Unit)? = null) - fun negativeButton(buttonText: String, onClicked: (dialog: DialogInterface) -> Unit) - fun negativeButton(@StringRes buttonTextResource: Int, onClicked: (dialog: DialogInterface) -> Unit) + fun onCancelled(handler: (dialog: DialogInterface) -> Unit) - fun neutralPressed(buttonText: String, onClicked: (dialog: DialogInterface) -> Unit) - fun neutralPressed(@StringRes buttonTextResource: Int, onClicked: (dialog: DialogInterface) -> Unit) + fun onKeyPressed(handler: (dialog: DialogInterface, keyCode: Int, e: KeyEvent) -> Boolean) fun items(items: List, onItemSelected: (dialog: DialogInterface, index: Int) -> Unit) fun items(items: List, onItemSelected: (dialog: DialogInterface, item: T, index: Int) -> Unit) @@ -90,14 +91,14 @@ fun AlertBuilder<*>.customView(view: () -> View) { customView = view() } -inline fun AlertBuilder<*>.okButton(noinline handler: (dialog: DialogInterface) -> Unit) = +inline fun AlertBuilder<*>.okButton(noinline handler: ((dialog: DialogInterface) -> Unit)? = null) = positiveButton(android.R.string.ok, handler) -inline fun AlertBuilder<*>.cancelButton(noinline handler: (dialog: DialogInterface) -> Unit) = +inline fun AlertBuilder<*>.cancelButton(noinline handler: ((dialog: DialogInterface) -> Unit)? = null) = negativeButton(android.R.string.cancel, handler) -inline fun AlertBuilder<*>.yesButton(noinline handler: (dialog: DialogInterface) -> Unit) = +inline fun AlertBuilder<*>.yesButton(noinline handler: ((dialog: DialogInterface) -> Unit)? = null) = positiveButton(android.R.string.yes, handler) -inline fun AlertBuilder<*>.noButton(noinline handler: (dialog: DialogInterface) -> Unit) = +inline fun AlertBuilder<*>.noButton(noinline handler: ((dialog: DialogInterface) -> Unit)? = null) = negativeButton(android.R.string.no, handler) \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/lib/dialogs/AndroidAlertBuilder.kt b/app/src/main/java/io/legado/app/lib/dialogs/AndroidAlertBuilder.kt index 38e03d573..52711a17a 100644 --- a/app/src/main/java/io/legado/app/lib/dialogs/AndroidAlertBuilder.kt +++ b/app/src/main/java/io/legado/app/lib/dialogs/AndroidAlertBuilder.kt @@ -75,28 +75,28 @@ internal class AndroidAlertBuilder(override val ctx: Context) : AlertBuilder Unit) { - builder.setPositiveButton(buttonText) { dialog, _ -> onClicked(dialog) } + override fun positiveButton(buttonText: String, onClicked: ((dialog: DialogInterface) -> Unit)?) { + builder.setPositiveButton(buttonText) { dialog, _ -> onClicked?.invoke(dialog) } } - override fun positiveButton(buttonTextResource: Int, onClicked: (dialog: DialogInterface) -> Unit) { - builder.setPositiveButton(buttonTextResource) { dialog, _ -> onClicked(dialog) } + override fun positiveButton(buttonTextResource: Int, onClicked: ((dialog: DialogInterface) -> Unit)?) { + builder.setPositiveButton(buttonTextResource) { dialog, _ -> onClicked?.invoke(dialog) } } - override fun negativeButton(buttonText: String, onClicked: (dialog: DialogInterface) -> Unit) { - builder.setNegativeButton(buttonText) { dialog, _ -> onClicked(dialog) } + override fun negativeButton(buttonText: String, onClicked: ((dialog: DialogInterface) -> Unit)?) { + builder.setNegativeButton(buttonText) { dialog, _ -> onClicked?.invoke(dialog) } } - override fun negativeButton(buttonTextResource: Int, onClicked: (dialog: DialogInterface) -> Unit) { - builder.setNegativeButton(buttonTextResource) { dialog, _ -> onClicked(dialog) } + override fun negativeButton(buttonTextResource: Int, onClicked: ((dialog: DialogInterface) -> Unit)?) { + builder.setNegativeButton(buttonTextResource) { dialog, _ -> onClicked?.invoke(dialog) } } - override fun neutralPressed(buttonText: String, onClicked: (dialog: DialogInterface) -> Unit) { - builder.setNeutralButton(buttonText) { dialog, _ -> onClicked(dialog) } + override fun neutralButton(buttonText: String, onClicked: ((dialog: DialogInterface) -> Unit)?) { + builder.setNeutralButton(buttonText) { dialog, _ -> onClicked?.invoke(dialog) } } - override fun neutralPressed(buttonTextResource: Int, onClicked: (dialog: DialogInterface) -> Unit) { - builder.setNeutralButton(buttonTextResource) { dialog, _ -> onClicked(dialog) } + override fun neutralButton(buttonTextResource: Int, onClicked: ((dialog: DialogInterface) -> Unit)?) { + builder.setNeutralButton(buttonTextResource) { dialog, _ -> onClicked?.invoke(dialog) } } override fun items(items: List, onItemSelected: (dialog: DialogInterface, index: Int) -> Unit) { diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index ec4b22c5c..a0aa86e4e 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -128,7 +128,7 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b viewModel.saveBookGroup(editText?.text?.toString()) } - noButton { } + noButton() }.show().applyTint().requestInputMethod() } From c7b7f6801d762cef3fbbbb5b143e8848103cdcf3 Mon Sep 17 00:00:00 2001 From: Administrator <1760316362@qq.com> Date: Thu, 1 Aug 2019 11:48:15 +0800 Subject: [PATCH 0503/1997] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/io/legado/app/lib/dialogs/AlertBuilder.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/lib/dialogs/AlertBuilder.kt b/app/src/main/java/io/legado/app/lib/dialogs/AlertBuilder.kt index 0ab0db154..19e12d427 100644 --- a/app/src/main/java/io/legado/app/lib/dialogs/AlertBuilder.kt +++ b/app/src/main/java/io/legado/app/lib/dialogs/AlertBuilder.kt @@ -15,7 +15,6 @@ */ @file:Suppress("NOTHING_TO_INLINE", "unused") - package io.legado.app.lib.dialogs import android.annotation.SuppressLint From ea1d32016a89c60625de56bf71c9394335d46acb Mon Sep 17 00:00:00 2001 From: Administrator <1760316362@qq.com> Date: Thu, 1 Aug 2019 11:48:29 +0800 Subject: [PATCH 0504/1997] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/io/legado/app/lib/dialogs/AlertBuilder.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/lib/dialogs/AlertBuilder.kt b/app/src/main/java/io/legado/app/lib/dialogs/AlertBuilder.kt index 19e12d427..60404b266 100644 --- a/app/src/main/java/io/legado/app/lib/dialogs/AlertBuilder.kt +++ b/app/src/main/java/io/legado/app/lib/dialogs/AlertBuilder.kt @@ -15,6 +15,7 @@ */ @file:Suppress("NOTHING_TO_INLINE", "unused") + package io.legado.app.lib.dialogs import android.annotation.SuppressLint @@ -66,7 +67,7 @@ interface AlertBuilder { fun positiveButton(@StringRes buttonTextResource: Int, onClicked: ((dialog: DialogInterface) -> Unit)? = null) fun negativeButton(buttonText: String, onClicked: ((dialog: DialogInterface) -> Unit)? = null) - fun negativeButton(@StringRes buttonTextResource: Int, onClicked: ((dialog: DialogInterface) -> Unit)?=null) + fun negativeButton(@StringRes buttonTextResource: Int, onClicked: ((dialog: DialogInterface) -> Unit)? = null) fun neutralButton(buttonText: String, onClicked: ((dialog: DialogInterface) -> Unit)? = null) fun neutralButton(@StringRes buttonTextResource: Int, onClicked: ((dialog: DialogInterface) -> Unit)? = null) From d6a09e04da8ddb79f061e85b15d643d90c9229e7 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 1 Aug 2019 14:24:21 +0800 Subject: [PATCH 0505/1997] up --- .../app/model/webbook/BookChapterList.kt | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt b/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt index 3904700e0..3bd4be757 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt @@ -1,5 +1,6 @@ package io.legado.app.model.webbook +import android.text.TextUtils import io.legado.app.App import io.legado.app.R import io.legado.app.data.entities.Book @@ -40,7 +41,7 @@ object BookChapterList { reverse = true listRule = listRule.substring(1) } - var chapterData = analyzeChapterList(body, baseUrl, tocRule, listRule, book) + var chapterData = analyzeChapterList(body, baseUrl, tocRule, listRule, book, bookSource, printLog = true) chapterData.chapterList?.let { chapterList.addAll(it) } @@ -50,7 +51,7 @@ object BookChapterList { nextUrlList.add(nextUrl) AnalyzeUrl(ruleUrl = nextUrl, book = book).getResponse().execute() .body()?.let { nextBody -> - chapterData = analyzeChapterList(nextBody, nextUrl, tocRule, listRule, book) + chapterData = analyzeChapterList(nextBody, nextUrl, tocRule, listRule, book, bookSource) nextUrl = if (chapterData.nextUrl.isNotEmpty()) chapterData.nextUrl[0] else "" chapterData.chapterList?.let { chapterList.addAll(it) @@ -72,7 +73,9 @@ object BookChapterList { item.nextUrl, tocRule, listRule, - book + book, + bookSource, + getNextUrl = false ) item.chapterList = nextChapterData.chapterList } @@ -93,14 +96,25 @@ object BookChapterList { baseUrl: String, tocRule: TocRule, listRule: String, - book: Book + book: Book, + bookSource: BookSource, + getNextUrl: Boolean = true, + printLog: Boolean = false ): ChapterData> { val chapterList = arrayListOf() val nextUrlList = arrayListOf() val analyzeRule = AnalyzeRule(book) analyzeRule.setContent(body, baseUrl) - analyzeRule.getStringList(tocRule.nextTocUrl ?: "", true)?.let { - nextUrlList.addAll(it) + if (getNextUrl) { + SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取目录下一页列表", printLog) + analyzeRule.getStringList(tocRule.nextTocUrl ?: "", true)?.let { + for (item in it) { + if (item != baseUrl) { + nextUrlList.add(item) + } + } + } + SourceDebug.printLog(bookSource.bookSourceUrl, 1, TextUtils.join(",", nextUrlList), printLog) } val elements = analyzeRule.getElements(listRule) if (elements.isNotEmpty()) { From 27133a11c8e4a155e9fc4282d2ad652a2e618542 Mon Sep 17 00:00:00 2001 From: Administrator <1760316362@qq.com> Date: Thu, 1 Aug 2019 15:57:39 +0800 Subject: [PATCH 0506/1997] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/io/legado/app/App.kt | 34 ++- .../java/io/legado/app/base/BaseActivity.kt | 6 +- .../main/java/io/legado/app/lib/theme/ATH.kt | 38 ++- .../app/lib/theme/MaterialValueHelper.kt | 80 +++--- .../app/ui/bookshelf/BookshelfAdapter.kt | 3 +- .../app/ui/config/ThemeConfigFragment.kt | 30 +- .../io/legado/app/ui/main/MainActivity.kt | 7 +- .../ui/main/bookshelf/BookshelfFragment.kt | 11 +- .../ui/main/bookshelf/BookshelfViewModel.kt | 1 - .../app/ui/sourcedebug/SourceDebugActivity.kt | 3 +- .../legado/app/ui/welcome/WelcomeActivity.kt | 3 +- .../java/io/legado/app/ui/widget/TitleBar.kt | 10 +- .../io/legado/app/utils/AnkoExtensions.kt | 63 ----- .../io/legado/app/utils/ContextExtensions.kt | 9 +- .../io/legado/app/utils/FragmentExtensions.kt | 57 ++++ .../io/legado/app/utils/MenuExtensions.kt | 3 +- .../java/io/legado/app/utils/Snackbars.kt | 257 ++++++++++++++++++ .../main/java/io/legado/app/utils/Toasts.kt | 80 ++++++ .../java/io/legado/app/utils/ViewModelKt.kt | 3 + 19 files changed, 544 insertions(+), 154 deletions(-) delete mode 100644 app/src/main/java/io/legado/app/utils/AnkoExtensions.kt create mode 100644 app/src/main/java/io/legado/app/utils/FragmentExtensions.kt create mode 100644 app/src/main/java/io/legado/app/utils/Snackbars.kt create mode 100644 app/src/main/java/io/legado/app/utils/Toasts.kt diff --git a/app/src/main/java/io/legado/app/App.kt b/app/src/main/java/io/legado/app/App.kt index c6e4f40bc..a6c6d9514 100644 --- a/app/src/main/java/io/legado/app/App.kt +++ b/app/src/main/java/io/legado/app/App.kt @@ -14,8 +14,8 @@ import io.legado.app.constant.AppConst.channelIdWeb import io.legado.app.data.AppDatabase import io.legado.app.lib.theme.ThemeStore import io.legado.app.utils.getCompatColor -import io.legado.app.utils.getPrefBoolean import io.legado.app.utils.getPrefInt +import io.legado.app.utils.isNightTheme @Suppress("DEPRECATION") class App : Application() { @@ -36,14 +36,18 @@ class App : Application() { override fun onCreate() { super.onCreate() INSTANCE = this + db = AppDatabase.createDatabase(INSTANCE) packageManager.getPackageInfo(packageName, 0)?.let { versionCode = it.versionCode versionName = it.versionName } - if (!ThemeStore.isConfigured(this, versionCode)) upThemeStore() + + if (!ThemeStore.isConfigured(this, versionCode)) applyTheme() initNightTheme() + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) createChannelId() + LiveEventBus.get() .config() .supportBroadcast(this) @@ -51,20 +55,11 @@ class App : Application() { .autoClear(false) } - fun initNightTheme() { - val targetMode = if (getPrefBoolean("isNightTheme")) { - AppCompatDelegate.MODE_NIGHT_YES - } else { - AppCompatDelegate.MODE_NIGHT_NO - } - AppCompatDelegate.setDefaultNightMode(targetMode) - } - /** * 更新主题 */ - fun upThemeStore() { - if (getPrefBoolean("isNightTheme")) { + fun applyTheme() { + if (isNightTheme) { ThemeStore.editTheme(this) .primaryColor(getPrefInt("colorPrimaryNight", getCompatColor(R.color.colorPrimary))) .accentColor(getPrefInt("colorAccentNight", getCompatColor(R.color.colorAccent))) @@ -80,10 +75,21 @@ class App : Application() { } fun applyDayNight() { - upThemeStore() + applyTheme() initNightTheme() } + + private fun initNightTheme() { + val targetMode = if (isNightTheme) { + AppCompatDelegate.MODE_NIGHT_YES + } else { + AppCompatDelegate.MODE_NIGHT_NO + } + AppCompatDelegate.setDefaultNightMode(targetMode) + } + + /** * 创建通知ID */ diff --git a/app/src/main/java/io/legado/app/base/BaseActivity.kt b/app/src/main/java/io/legado/app/base/BaseActivity.kt index 51f960788..c109d0e3b 100644 --- a/app/src/main/java/io/legado/app/base/BaseActivity.kt +++ b/app/src/main/java/io/legado/app/base/BaseActivity.kt @@ -8,8 +8,10 @@ import android.view.View import android.view.WindowManager import androidx.appcompat.app.AppCompatActivity import io.legado.app.R +import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.ColorUtils import io.legado.app.lib.theme.ThemeStore +import io.legado.app.lib.theme.primaryColor import io.legado.app.utils.* import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.MainScope @@ -64,8 +66,8 @@ abstract class BaseActivity(private val layoutID: Int, private val fullScreen: B } private fun initTheme() { - window.decorView.setBackgroundColor(ThemeStore.backgroundColor(this)) - if (ColorUtils.isColorLight(ThemeStore.primaryColor(this))) { + ATH.applyBackgroundTint(window.decorView) + if (ColorUtils.isColorLight(primaryColor)) { setTheme(R.style.AppTheme_Light) } else { setTheme(R.style.AppTheme_Dark) diff --git a/app/src/main/java/io/legado/app/lib/theme/ATH.kt b/app/src/main/java/io/legado/app/lib/theme/ATH.kt index 62a8cad34..e59d87149 100644 --- a/app/src/main/java/io/legado/app/lib/theme/ATH.kt +++ b/app/src/main/java/io/legado/app/lib/theme/ATH.kt @@ -13,7 +13,12 @@ import androidx.annotation.ColorInt import androidx.appcompat.app.AlertDialog import androidx.recyclerview.widget.RecyclerView import androidx.viewpager.widget.ViewPager -import io.legado.app.utils.getPrefBoolean +import com.google.android.material.bottomnavigation.BottomNavigationView +import io.legado.app.R +import io.legado.app.utils.getCompatColor +import io.legado.app.utils.isTransparentStatusBar +import kotlinx.android.synthetic.main.activity_main.view.* +import org.jetbrains.anko.backgroundColor /** @@ -32,7 +37,7 @@ object ATH { fun setStatusbarColorAuto(activity: Activity) { setStatusbarColor( activity, - ThemeStore.statusBarColor(activity, activity.getPrefBoolean("transparentStatusBar")) + ThemeStore.statusBarColor(activity, activity.isTransparentStatusBar) ) } @@ -160,6 +165,35 @@ object ATH { } } + //**************************************************************Directly*************************************************************// + + fun applyBottomNavigationColor(bottomBar: BottomNavigationView?) { + bottomBar?.apply { + setBackgroundColor(ThemeStore.backgroundColor(context)) + val colorStateList = Selector.colorBuild() + .setDefaultColor(context.getCompatColor(R.color.btn_bg_press_tp)) + .setSelectedColor(ThemeStore.primaryColor(bottom_navigation_view.context)).create() + itemIconTintList = colorStateList + itemTextColor = colorStateList + } + } + + fun applyTint(view: View?) { + view?.apply { + setTint(this, context.accentColor) + } + } + + fun applyBackgroundTint(view: View?) { + view?.apply { + if (background == null) { + backgroundColor = context.backgroundColor + } else { + setBackgroundTint(this, context.backgroundColor) + } + } + } + fun applyEdgeEffectColor(view: View?) { when (view) { is RecyclerView -> view.edgeEffectFactory = DEFAULT_EFFECT_FACTORY diff --git a/app/src/main/java/io/legado/app/lib/theme/MaterialValueHelper.kt b/app/src/main/java/io/legado/app/lib/theme/MaterialValueHelper.kt index 1dc767f39..ea37c7b00 100644 --- a/app/src/main/java/io/legado/app/lib/theme/MaterialValueHelper.kt +++ b/app/src/main/java/io/legado/app/lib/theme/MaterialValueHelper.kt @@ -75,52 +75,56 @@ fun Fragment.getSecondaryDisabledTextColor(dark: Boolean): Int { } else ContextCompat.getColor(requireContext(), R.color.secondary_text_disabled_material_dark) } +val Context.primaryColor: Int + get() = ThemeStore.primaryColor(this) -@ColorInt -fun Context.getPrimaryTextColor(): Int { - return getPrimaryTextColor(isDarkTheme()) -} +val Context.primaryColorDark: Int + get() = ThemeStore.primaryColorDark(this) -@ColorInt -fun Context.getSecondaryTextColor(): Int { - return getSecondaryTextColor(isDarkTheme()) -} +val Context.accentColor: Int + get() = ThemeStore.accentColor(this) -@ColorInt -fun Context.getPrimaryDisabledTextColor(): Int { - return getPrimaryDisabledTextColor(isDarkTheme()) -} +val Context.backgroundColor: Int + get() = ThemeStore.backgroundColor(this) -@ColorInt -fun Context.getSecondaryDisabledTextColor(): Int { - return getSecondaryDisabledTextColor(isDarkTheme()) -} +val Context.primaryTextColor: Int + get() = getPrimaryTextColor(isDarkTheme) +val Context.secondaryTextColor: Int + get() = getSecondaryTextColor(isDarkTheme) -@ColorInt -fun Fragment.getPrimaryTextColor(): Int { - return getPrimaryTextColor(isDarkTheme()) -} +val Context.primaryDisabledTextColor: Int + get() = getPrimaryDisabledTextColor(isDarkTheme) -@ColorInt -fun Fragment.getSecondaryTextColor(): Int { - return getSecondaryTextColor(isDarkTheme()) -} +val Context.secondaryDisabledTextColor: Int + get() = getSecondaryDisabledTextColor(isDarkTheme) -@ColorInt -fun Fragment.getPrimaryDisabledTextColor(): Int { - return getPrimaryDisabledTextColor(isDarkTheme()) -} +val Fragment.primaryColor: Int + get() = ThemeStore.primaryColor(requireContext()) -@ColorInt -fun Fragment.getSecondaryDisabledTextColor(): Int { - return getSecondaryDisabledTextColor(isDarkTheme()) -} +val Fragment.primaryColorDark: Int + get() = ThemeStore.primaryColorDark(requireContext()) -fun Context.isDarkTheme(): Boolean { - return ColorUtils.isColorLight(ThemeStore.primaryColor(this)) -} +val Fragment.accentColor: Int + get() = ThemeStore.accentColor(requireContext()) + +val Fragment.backgroundColor: Int + get() = ThemeStore.backgroundColor(requireContext()) + +val Fragment.primaryTextColor: Int + get() = getPrimaryTextColor(isDarkTheme) + +val Fragment.secondaryTextColor: Int + get() = getSecondaryTextColor(isDarkTheme) + +val Fragment.primaryDisabledTextColor: Int + get() = getPrimaryDisabledTextColor(isDarkTheme) + +val Fragment.secondaryDisabledTextColor: Int + get() = getSecondaryDisabledTextColor(isDarkTheme) + +val Context.isDarkTheme: Boolean + get() = ColorUtils.isColorLight(ThemeStore.primaryColor(this)) -fun Fragment.isDarkTheme(): Boolean { - return requireContext().isDarkTheme() -} \ No newline at end of file +val Fragment.isDarkTheme: Boolean + get() = requireContext().isDarkTheme \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/bookshelf/BookshelfAdapter.kt b/app/src/main/java/io/legado/app/ui/bookshelf/BookshelfAdapter.kt index fa3a945b5..4f8a20e7f 100644 --- a/app/src/main/java/io/legado/app/ui/bookshelf/BookshelfAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/bookshelf/BookshelfAdapter.kt @@ -9,6 +9,7 @@ import androidx.recyclerview.widget.RecyclerView import io.legado.app.R import io.legado.app.data.entities.Book import io.legado.app.help.ImageLoader +import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.ThemeStore import kotlinx.android.synthetic.main.item_bookshelf_list.view.* import kotlinx.android.synthetic.main.item_relace_rule.view.tv_name @@ -49,7 +50,7 @@ class BookshelfAdapter : PagedListAdapter(D class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { init { - itemView.setBackgroundColor(ThemeStore.backgroundColor(itemView.context)) + ATH.applyBackgroundTint(itemView) } fun bind(book: Book, callBack: CallBack?) = with(itemView) { diff --git a/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt index 778e6e15e..1a2dad761 100644 --- a/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt @@ -49,9 +49,9 @@ class ThemeConfigFragment : PreferenceFragmentCompat(), SharedPreferences.OnShar .setTitle("白天背景太暗") .setMessage("将会恢复默认背景?") .setPositiveButton(R.string.ok) { _, _ -> - App.INSTANCE.putPrefInt( + putPrefInt( "colorBackground", - App.INSTANCE.getCompatColor(R.color.md_grey_100) + getCompatColor(R.color.md_grey_100) ) upTheme(false) } @@ -69,9 +69,9 @@ class ThemeConfigFragment : PreferenceFragmentCompat(), SharedPreferences.OnShar .setTitle("夜间背景太亮") .setMessage("将会恢复默认背景?") .setPositiveButton(R.string.ok) { _, _ -> - App.INSTANCE.putPrefInt( + putPrefInt( "colorBackgroundNight", - App.INSTANCE.getCompatColor(R.color.md_grey_800) + getCompatColor(R.color.md_grey_800) ) upTheme(true) } @@ -95,14 +95,14 @@ class ThemeConfigFragment : PreferenceFragmentCompat(), SharedPreferences.OnShar .setMessage("是否确认恢复?") .setPositiveButton(R.string.ok) { _, _ -> preferenceManager.sharedPreferences.edit() - .putInt("colorPrimary", App.INSTANCE.getCompatColor(R.color.colorPrimary)) - .putInt("colorAccent", App.INSTANCE.getCompatColor(R.color.colorAccent)) - .putInt("colorBackground", App.INSTANCE.getCompatColor(R.color.md_grey_100)) - .putInt("colorPrimaryNight", App.INSTANCE.getCompatColor(R.color.colorPrimary)) - .putInt("colorAccentNight", App.INSTANCE.getCompatColor(R.color.colorAccent)) - .putInt("colorBackgroundNight", App.INSTANCE.getCompatColor(R.color.md_grey_800)) + .putInt("colorPrimary", getCompatColor(R.color.colorPrimary)) + .putInt("colorAccent", getCompatColor(R.color.colorAccent)) + .putInt("colorBackground", getCompatColor(R.color.md_grey_100)) + .putInt("colorPrimaryNight", getCompatColor(R.color.colorPrimary)) + .putInt("colorAccentNight", getCompatColor(R.color.colorAccent)) + .putInt("colorBackgroundNight", getCompatColor(R.color.md_grey_800)) .apply() - App.INSTANCE.upThemeStore() + App.INSTANCE.applyTheme() recreateActivities() } .setNegativeButton(R.string.cancel, null) @@ -117,7 +117,7 @@ class ThemeConfigFragment : PreferenceFragmentCompat(), SharedPreferences.OnShar return !ColorUtils.isColorLight( sharedPreferences.getInt( "colorBackground", - App.INSTANCE.getCompatColor(R.color.md_grey_100) + getCompatColor(R.color.md_grey_100) ) ) } @@ -126,14 +126,14 @@ class ThemeConfigFragment : PreferenceFragmentCompat(), SharedPreferences.OnShar return ColorUtils.isColorLight( sharedPreferences.getInt( "colorBackgroundNight", - App.INSTANCE.getCompatColor(R.color.md_grey_800) + getCompatColor(R.color.md_grey_800) ) ) } private fun upTheme(isNightTheme: Boolean) { - if (App.INSTANCE.getPrefBoolean("isNightTheme") == isNightTheme) { - App.INSTANCE.upThemeStore() + if (this.isNightTheme == isNightTheme) { + App.INSTANCE.applyTheme() recreateActivities() } } diff --git a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt index bcb1d2fe3..774c6f329 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt @@ -35,12 +35,7 @@ class MainActivity : VMBaseActivity(R.layout.activity_main), override fun onActivityCreated(savedInstanceState: Bundle?) { ATH.applyEdgeEffectColor(view_pager_main) - bottom_navigation_view.setBackgroundColor(ThemeStore.backgroundColor(this)) - val colorStateList = Selector.colorBuild() - .setDefaultColor(getCompatColor(R.color.btn_bg_press_tp)) - .setSelectedColor(ThemeStore.primaryColor(bottom_navigation_view.context)).create() - bottom_navigation_view.itemIconTintList = colorStateList - bottom_navigation_view.itemTextColor = colorStateList + ATH.applyBottomNavigationColor(bottom_navigation_view) view_pager_main.offscreenPageLimit = 3 view_pager_main.adapter = TabFragmentPageAdapter(supportFragmentManager) view_pager_main.addOnPageChangeListener(this) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index a0aa86e4e..24b67a9f2 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -1,6 +1,7 @@ package io.legado.app.ui.main.bookshelf import android.os.Bundle +import android.util.Log import android.view.Menu import android.view.View import android.widget.EditText @@ -22,11 +23,13 @@ import io.legado.app.lib.dialogs.noButton import io.legado.app.lib.dialogs.yesButton import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.ThemeStore +import io.legado.app.lib.theme.accentColor import io.legado.app.ui.bookshelf.BookshelfActivity import io.legado.app.ui.search.SearchActivity import io.legado.app.utils.applyTint import io.legado.app.utils.getViewModel import io.legado.app.utils.requestInputMethod +import io.legado.app.utils.visible import kotlinx.android.synthetic.main.dialog_edittext.view.* import kotlinx.android.synthetic.main.fragment_bookshelf.* import kotlinx.android.synthetic.main.view_title_bar.* @@ -58,7 +61,7 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b } private fun initSearchView() { - search_view.visibility = View.VISIBLE + search_view.visible() search_view.onActionViewExpanded() search_view.isSubmitButtonEnabled = true search_view.queryHint = getString(R.string.search_book_key) @@ -68,11 +71,11 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b private fun initRecyclerView() { ATH.applyEdgeEffectColor(rv_bookshelf) - refresh_layout.setColorSchemeColors(ThemeStore.accentColor(refresh_layout.context)) + refresh_layout.setColorSchemeColors(accentColor) refresh_layout.setOnRefreshListener { refresh_layout.isRefreshing = false } - tv_recent_reading.textColor = ThemeStore.accentColor(tv_recent_reading.context) + tv_recent_reading.textColor = accentColor rv_book_group.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) bookGroupAdapter = BookGroupAdapter() rv_book_group.adapter = bookGroupAdapter @@ -118,7 +121,7 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b customView { layoutInflater.inflate(R.layout.dialog_edittext, null).apply { editText = edit_view.apply { - ATH.setTint(this, ThemeStore.accentColor(ctx)) + ATH.applyTint(this) hint = "分组名称" } } diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt index d47080cb4..1bb9a3b64 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt @@ -7,7 +7,6 @@ import io.legado.app.data.entities.BookGroup class BookshelfViewModel(application: Application) : BaseViewModel(application) { - fun saveBookGroup(group: String?) { if (!group.isNullOrBlank()) { execute { diff --git a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt index a6345fe13..609689873 100644 --- a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt +++ b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt @@ -10,6 +10,7 @@ import io.legado.app.constant.Bus import io.legado.app.help.EventMessage import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.ThemeStore +import io.legado.app.lib.theme.accentColor import io.legado.app.utils.getViewModel import io.legado.app.utils.observeEvent import kotlinx.android.synthetic.main.activity_source_debug.* @@ -34,7 +35,7 @@ class SourceDebugActivity : VMBaseActivity(R.layout.activity_s adapter = SourceDebugAdapter(this) recycler_view.layoutManager = LinearLayoutManager(this) recycler_view.adapter = adapter - rotate_loading.loadingColor = ThemeStore.accentColor(this) + rotate_loading.loadingColor = accentColor } private fun initSearchView() { diff --git a/app/src/main/java/io/legado/app/ui/welcome/WelcomeActivity.kt b/app/src/main/java/io/legado/app/ui/welcome/WelcomeActivity.kt index 3295cb766..efe7a36ff 100644 --- a/app/src/main/java/io/legado/app/ui/welcome/WelcomeActivity.kt +++ b/app/src/main/java/io/legado/app/ui/welcome/WelcomeActivity.kt @@ -6,6 +6,7 @@ import android.os.Bundle import io.legado.app.R import io.legado.app.base.BaseActivity import io.legado.app.lib.theme.ThemeStore +import io.legado.app.lib.theme.accentColor import io.legado.app.ui.main.MainActivity import kotlinx.android.synthetic.main.activity_welcome.* import org.jetbrains.anko.startActivity @@ -13,7 +14,7 @@ import org.jetbrains.anko.startActivity class WelcomeActivity : BaseActivity(R.layout.activity_welcome) { override fun onActivityCreated(savedInstanceState: Bundle?) { - iv_bg.setColorFilter(ThemeStore.accentColor(this)) + iv_bg.setColorFilter(accentColor) val welAnimator = ValueAnimator.ofFloat(1f, 0f).setDuration(800) welAnimator.startDelay = 100 welAnimator.addUpdateListener { animation -> diff --git a/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt b/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt index 0ce45791b..0a36b6a58 100644 --- a/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt +++ b/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt @@ -16,10 +16,11 @@ import androidx.core.graphics.drawable.DrawableCompat import com.google.android.material.appbar.AppBarLayout import io.legado.app.R import io.legado.app.lib.theme.DrawableUtils -import io.legado.app.lib.theme.ThemeStore -import io.legado.app.lib.theme.getPrimaryTextColor +import io.legado.app.lib.theme.primaryColor +import io.legado.app.lib.theme.primaryTextColor import io.legado.app.utils.getNavigationBarHeight import io.legado.app.utils.getStatusBarHeight +import org.jetbrains.anko.backgroundColor import org.jetbrains.anko.bottomPadding import org.jetbrains.anko.topPadding @@ -48,7 +49,6 @@ class TitleBar(context: Context, attrs: AttributeSet?) : AppBarLayout(context, a init { inflate(context, R.layout.view_title_bar, this) - setBackgroundColor(ThemeStore.primaryColor(context)) toolbar = findViewById(R.id.toolbar) val a = context.obtainStyledAttributes( attrs, R.styleable.TitleBar, @@ -124,6 +124,8 @@ class TitleBar(context: Context, attrs: AttributeSet?) : AppBarLayout(context, a if (!subtitleText.isNullOrBlank()) { this.subtitle = subtitleText } + + backgroundColor = context.primaryColor } if (a.getBoolean(R.styleable.TitleBar_fitStatusBar, true)) { @@ -174,7 +176,7 @@ class TitleBar(context: Context, attrs: AttributeSet?) : AppBarLayout(context, a } private fun wrapAppTheme() { - val primaryTextColor = if (isInEditMode) Color.BLACK else context.getPrimaryTextColor() + val primaryTextColor = if (isInEditMode) Color.BLACK else context.primaryTextColor DrawableUtils.setTint(toolbar.overflowIcon, primaryTextColor) toolbar.setTitleTextColor(primaryTextColor) diff --git a/app/src/main/java/io/legado/app/utils/AnkoExtensions.kt b/app/src/main/java/io/legado/app/utils/AnkoExtensions.kt deleted file mode 100644 index 44bdf4f15..000000000 --- a/app/src/main/java/io/legado/app/utils/AnkoExtensions.kt +++ /dev/null @@ -1,63 +0,0 @@ -package io.legado.app.utils - -import android.content.res.ColorStateList -import android.graphics.drawable.Drawable -import android.view.View -import androidx.annotation.ColorRes -import androidx.annotation.DrawableRes -import androidx.annotation.StringRes -import androidx.fragment.app.Fragment -import com.google.android.material.snackbar.Snackbar -import org.jetbrains.anko.dip -import org.jetbrains.anko.longToast -import org.jetbrains.anko.toast - - -/** - * Display the Snackbar with the [Snackbar.LENGTH_SHORT] duration. - * - * @param message the message text resource. - */ -@JvmName("snackbar2") -fun View.snackbar(@StringRes message: Int) = Snackbar - .make(this, message, Snackbar.LENGTH_SHORT) - .apply { show() } - -/** - * Display Snackbar with the [Snackbar.LENGTH_LONG] duration. - * - * @param message the message text resource. - */ -@JvmName("longSnackbar2") -fun View.longSnackbar(@StringRes message: Int) = Snackbar - .make(this, message, Snackbar.LENGTH_LONG) - .apply { show() } - -/** - * Display Snackbar with the [Snackbar.LENGTH_LONG] duration. - * - * @param message the message text resource. - */ -@JvmName("longSnackbar2") -fun View.longSnackbar(@StringRes message: Int, @StringRes actionText: Int, action: (View) -> Unit) = Snackbar - .make(this, message, Snackbar.LENGTH_LONG) - .setAction(actionText, action) - .apply { show() } - -fun Fragment.toast(textResource: Int) = requireActivity().toast(textResource) - -fun Fragment.toast(text: CharSequence) = requireActivity().toast(text) - -fun Fragment.longToast(textResource: Int) = requireActivity().longToast(textResource) - -fun Fragment.longToast(text: CharSequence) = requireActivity().longToast(text) - -fun Fragment.dip(value: Int): Int = requireActivity().dip(value) - -fun Fragment.dip(value: Float): Int = requireActivity().dip(value) - -fun Fragment.getCompatColor(@ColorRes id: Int): Int = requireContext().getCompatColor(id) - -fun Fragment.getCompatDrawable(@DrawableRes id: Int): Drawable? = requireContext().getCompatDrawable(id) - -fun Fragment.getCompatColorStateList(@ColorRes id: Int): ColorStateList? = requireContext().getCompatColorStateList(id) \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/utils/ContextExtensions.kt b/app/src/main/java/io/legado/app/utils/ContextExtensions.kt index d5a4e74e3..7de826fbb 100644 --- a/app/src/main/java/io/legado/app/utils/ContextExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/ContextExtensions.kt @@ -8,6 +8,7 @@ import androidx.annotation.DrawableRes import androidx.appcompat.app.AppCompatActivity import androidx.core.content.ContextCompat import androidx.core.content.edit +import androidx.fragment.app.Fragment import com.jeremyliao.liveeventbus.LiveEventBus import io.legado.app.R import org.jetbrains.anko.connectivityManager @@ -64,4 +65,10 @@ fun Context.getStatusBarHeight(): Int { fun Context.getNavigationBarHeight(): Int { val resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android") return resources.getDimensionPixelSize(resourceId) -} \ No newline at end of file +} + +val Context.isNightTheme: Boolean + get() = getPrefBoolean("isNightTheme") + +val Context.isTransparentStatusBar: Boolean + get() = getPrefBoolean("transparentStatusBar") \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/utils/FragmentExtensions.kt b/app/src/main/java/io/legado/app/utils/FragmentExtensions.kt new file mode 100644 index 000000000..c81c734ad --- /dev/null +++ b/app/src/main/java/io/legado/app/utils/FragmentExtensions.kt @@ -0,0 +1,57 @@ +package io.legado.app.utils + +import android.content.res.ColorStateList +import android.graphics.drawable.Drawable +import androidx.annotation.ColorRes +import androidx.annotation.DrawableRes +import androidx.core.content.edit +import androidx.fragment.app.Fragment +import org.jetbrains.anko.connectivityManager +import org.jetbrains.anko.defaultSharedPreferences + +fun Fragment.isOnline() = requireContext().connectivityManager.activeNetworkInfo?.isConnected == true + +fun Fragment.getPrefBoolean(key: String, defValue: Boolean = false) = + requireContext().defaultSharedPreferences.getBoolean(key, defValue) + +fun Fragment.putPrefBoolean(key: String, value: Boolean = false) = + requireContext().defaultSharedPreferences.edit { putBoolean(key, value) } + +fun Fragment.getPrefInt(key: String, defValue: Int = 0) = + requireContext().defaultSharedPreferences.getInt(key, defValue) + +fun Fragment.putPrefInt(key: String, value: Int) = + requireContext().defaultSharedPreferences.edit { putInt(key, value) } + +fun Fragment.getPrefLong(key: String, defValue: Long = 0L) = + requireContext().defaultSharedPreferences.getLong(key, defValue) + +fun Fragment.putPrefLong(key: String, value: Long) = + requireContext().defaultSharedPreferences.edit { putLong(key, value) } + +fun Fragment.getPrefString(key: String, defValue: String? = null) = + requireContext().defaultSharedPreferences.getString(key, defValue) + +fun Fragment.putPrefString(key: String, value: String) = + requireContext().defaultSharedPreferences.edit { putString(key, value) } + +fun Fragment.getPrefStringSet(key: String, defValue: MutableSet? = null) = + requireContext().defaultSharedPreferences.getStringSet(key, defValue) + +fun Fragment.putPrefStringSet(key: String, value: MutableSet) = + requireContext().defaultSharedPreferences.edit { putStringSet(key, value) } + +fun Fragment.removePref(key: String) = + requireContext().defaultSharedPreferences.edit { remove(key) } + +fun Fragment.getCompatColor(@ColorRes id: Int): Int = requireContext().getCompatColor(id) + +fun Fragment.getCompatDrawable(@DrawableRes id: Int): Drawable? = requireContext().getCompatDrawable(id) + +fun Fragment.getCompatColorStateList(@ColorRes id: Int): ColorStateList? = requireContext().getCompatColorStateList(id) + +val Fragment.isNightTheme: Boolean + get() = getPrefBoolean("isNightTheme") + +val Fragment.isTransparentStatusBar: Boolean + get() = getPrefBoolean("transparentStatusBar") \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/utils/MenuExtensions.kt b/app/src/main/java/io/legado/app/utils/MenuExtensions.kt index 881d87867..8d97321af 100644 --- a/app/src/main/java/io/legado/app/utils/MenuExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/MenuExtensions.kt @@ -8,12 +8,13 @@ import androidx.core.view.forEach import io.legado.app.R import io.legado.app.lib.theme.DrawableUtils import io.legado.app.lib.theme.getPrimaryTextColor +import io.legado.app.lib.theme.primaryTextColor fun Menu.setIconColor(context: Context): Menu = this.let { menu -> if (menu is MenuBuilder) { menu.setOptionalIconsVisible(true) } - val primaryTextColor = context.getPrimaryTextColor() + val primaryTextColor = context.primaryTextColor val defaultTextColor = context.getCompatColor(R.color.tv_text_default) menu.forEach { item -> (item as MenuItemImpl).let { impl -> diff --git a/app/src/main/java/io/legado/app/utils/Snackbars.kt b/app/src/main/java/io/legado/app/utils/Snackbars.kt new file mode 100644 index 000000000..f60def01f --- /dev/null +++ b/app/src/main/java/io/legado/app/utils/Snackbars.kt @@ -0,0 +1,257 @@ +package io.legado.app.utils + +import android.view.View +import androidx.annotation.StringRes +import com.google.android.material.snackbar.Snackbar + +/** + * Display the Snackbar with the [Snackbar.LENGTH_SHORT] duration. + * + * @param message the message text resource. + */ +@Deprecated("Use 'View.snackbar(Int)' instead.", ReplaceWith("view.snackbar(message)")) +inline fun snackbar(view: View, message: Int) = Snackbar + .make(view, message, Snackbar.LENGTH_SHORT) + .apply { show() } + +/** + * Display Snackbar with the [Snackbar.LENGTH_LONG] duration. + * + * @param message the message text resource. + */ +@Deprecated("Use 'View.longSnackbar(Int)' instead.", ReplaceWith("view.longSnackbar(message)")) +inline fun longSnackbar(view: View, message: Int) = Snackbar + .make(view, message, Snackbar.LENGTH_LONG) + .apply { show() } + +/** + * Display Snackbar with the [Snackbar.LENGTH_INDEFINITE] duration. + * + * @param message the message text resource. + */ +@Deprecated("Use 'View.indefiniteSnackbar(Int)' instead.", ReplaceWith("view.indefiniteSnackbar(message)")) +inline fun indefiniteSnackbar(view: View, message: Int) = Snackbar + .make(view, message, Snackbar.LENGTH_INDEFINITE) + .apply { show() } + +/** + * Display the Snackbar with the [Snackbar.LENGTH_SHORT] duration. + * + * @param message the message text. + */ +@Deprecated("Use 'View.snackbar(CharSequence)' instead.", ReplaceWith("view.snackbar(message)")) +inline fun snackbar(view: View, message: CharSequence) = Snackbar + .make(view, message, Snackbar.LENGTH_SHORT) + .apply { show() } + +/** + * Display Snackbar with the [Snackbar.LENGTH_LONG] duration. + * + * @param message the message text. + */ +@Deprecated("Use 'View.longSnackbar(CharSequence)' instead.", ReplaceWith("view.longSnackbar(message)")) +inline fun longSnackbar(view: View, message: CharSequence) = Snackbar + .make(view, message, Snackbar.LENGTH_LONG) + .apply { show() } + +/** + * Display Snackbar with the [Snackbar.LENGTH_INDEFINITE] duration. + * + * @param message the message text. + */ +@Deprecated("Use 'View.indefiniteSnackbar(CharSequence)' instead.", ReplaceWith("view.indefiniteSnackbar(message)")) +inline fun indefiniteSnackbar(view: View, message: CharSequence) = Snackbar + .make(view, message, Snackbar.LENGTH_INDEFINITE) + .apply { show() } + +/** + * Display the Snackbar with the [Snackbar.LENGTH_SHORT] duration. + * + * @param message the message text resource. + */ +@Deprecated("Use 'View.snackbar(Int, Int, (View) -> Unit)' instead.", ReplaceWith("view.snackbar(message, actionText, action)")) +inline fun snackbar(view: View, message: Int, actionText: Int, noinline action: (View) -> Unit) = Snackbar + .make(view, message, Snackbar.LENGTH_SHORT) + .setAction(actionText, action) + .apply { show() } + +/** + * Display Snackbar with the [Snackbar.LENGTH_LONG] duration. + * + * @param message the message text resource. + */ +@Deprecated("Use 'View.longSnackbar(Int, Int, (View) -> Unit)' instead.", ReplaceWith("view.longSnackbar(message, actionText, action)")) +inline fun longSnackbar(view: View, message: Int, actionText: Int, noinline action: (View) -> Unit) = Snackbar + .make(view, message, Snackbar.LENGTH_LONG) + .setAction(actionText, action) + .apply { show() } + +/** + * Display Snackbar with the [Snackbar.LENGTH_INDEFINITE] duration. + * + * @param message the message text resource. + */ +@Deprecated("Use 'View.indefiniteSnackbar(Int, Int, (View) -> Unit)' instead.", ReplaceWith("view.indefiniteSnackbar(message, actionText, action)")) +inline fun indefiniteSnackbar(view: View, message: Int, actionText: Int, noinline action: (View) -> Unit) = Snackbar + .make(view, message, Snackbar.LENGTH_INDEFINITE) + .setAction(actionText, action) + .apply { show() } + +/** + * Display the Snackbar with the [Snackbar.LENGTH_SHORT] duration. + * + * @param message the message text. + */ +@Deprecated("Use 'View.snackbar(CharSequence, CharSequence, (View) -> Unit)' instead.", ReplaceWith("view.snackbar(message, actionText, action)")) +inline fun snackbar(view: View, message: CharSequence, actionText: CharSequence, noinline action: (View) -> Unit) = Snackbar + .make(view, message, Snackbar.LENGTH_SHORT) + .setAction(actionText, action) + .apply { show() } + +/** + * Display Snackbar with the [Snackbar.LENGTH_LONG] duration. + * + * @param message the message text. + */ +@Deprecated("Use 'View.longSnackbar(CharSequence, CharSequence, (View) -> Unit)' instead.", ReplaceWith("view.longSnackbar(message, actionText, action)")) +inline fun longSnackbar(view: View, message: CharSequence, actionText: CharSequence, noinline action: (View) -> Unit) = Snackbar + .make(view, message, Snackbar.LENGTH_LONG) + .setAction(actionText, action) + .apply { show() } + +/** + * Display Snackbar with the [Snackbar.LENGTH_INDEFINITE] duration. + * + * @param message the message text. + */ +@Deprecated("Use 'View.indefiniteSnackbar(CharSequence, CharSequence, (View) -> Unit)' instead.", ReplaceWith("view.indefiniteSnackbar(message, actionText, action)")) +inline fun indefiniteSnackbar(view: View, message: CharSequence, actionText: CharSequence, noinline action: (View) -> Unit) = Snackbar + .make(view, message, Snackbar.LENGTH_INDEFINITE) + .setAction(actionText, action) + .apply { show() } + +/** + * Display the Snackbar with the [Snackbar.LENGTH_SHORT] duration. + * + * @param message the message text resource. + */ +@JvmName("snackbar2") +inline fun View.snackbar(@StringRes message: Int) = Snackbar + .make(this, message, Snackbar.LENGTH_SHORT) + .apply { show() } + +/** + * Display Snackbar with the [Snackbar.LENGTH_LONG] duration. + * + * @param message the message text resource. + */ +@JvmName("longSnackbar2") +inline fun View.longSnackbar(@StringRes message: Int) = Snackbar + .make(this, message, Snackbar.LENGTH_LONG) + .apply { show() } + +/** + * Display Snackbar with the [Snackbar.LENGTH_INDEFINITE] duration. + * + * @param message the message text resource. + */ +@JvmName("indefiniteSnackbar2") +inline fun View.indefiniteSnackbar(@StringRes message: Int) = Snackbar + .make(this, message, Snackbar.LENGTH_INDEFINITE) + .apply { show() } + +/** + * Display the Snackbar with the [Snackbar.LENGTH_SHORT] duration. + * + * @param message the message text. + */ +@JvmName("snackbar2") +inline fun View.snackbar(message: CharSequence) = Snackbar + .make(this, message, Snackbar.LENGTH_SHORT) + .apply { show() } + +/** + * Display Snackbar with the [Snackbar.LENGTH_LONG] duration. + * + * @param message the message text. + */ +@JvmName("longSnackbar2") +inline fun View.longSnackbar(message: CharSequence) = Snackbar + .make(this, message, Snackbar.LENGTH_LONG) + .apply { show() } + +/** + * Display Snackbar with the [Snackbar.LENGTH_INDEFINITE] duration. + * + * @param message the message text. + */ +@JvmName("indefiniteSnackbar2") +inline fun View.indefiniteSnackbar(message: CharSequence) = Snackbar + .make(this, message, Snackbar.LENGTH_INDEFINITE) + .apply { show() } + +/** + * Display the Snackbar with the [Snackbar.LENGTH_SHORT] duration. + * + * @param message the message text resource. + */ +@JvmName("snackbar2") +inline fun View.snackbar(message: Int, @StringRes actionText: Int, noinline action: (View) -> Unit) = Snackbar + .make(this, message, Snackbar.LENGTH_SHORT) + .setAction(actionText, action) + .apply { show() } + +/** + * Display Snackbar with the [Snackbar.LENGTH_LONG] duration. + * + * @param message the message text resource. + */ +@JvmName("longSnackbar2") +inline fun View.longSnackbar(@StringRes message: Int, @StringRes actionText: Int, noinline action: (View) -> Unit) = Snackbar + .make(this, message, Snackbar.LENGTH_LONG) + .setAction(actionText, action) + .apply { show() } + +/** + * Display Snackbar with the [Snackbar.LENGTH_INDEFINITE] duration. + * + * @param message the message text resource. + */ +@JvmName("indefiniteSnackbar2") +inline fun View.indefiniteSnackbar(@StringRes message: Int, @StringRes actionText: Int, noinline action: (View) -> Unit) = Snackbar + .make(this, message, Snackbar.LENGTH_INDEFINITE) + .setAction(actionText, action) + .apply { show() } + +/** + * Display the Snackbar with the [Snackbar.LENGTH_SHORT] duration. + * + * @param message the message text. + */ +@JvmName("snackbar2") +inline fun View.snackbar(message: CharSequence, actionText: CharSequence, noinline action: (View) -> Unit) = Snackbar + .make(this, message, Snackbar.LENGTH_SHORT) + .setAction(actionText, action) + .apply { show() } + +/** + * Display Snackbar with the [Snackbar.LENGTH_LONG] duration. + * + * @param message the message text. + */ +@JvmName("longSnackbar2") +inline fun View.longSnackbar(message: CharSequence, actionText: CharSequence, noinline action: (View) -> Unit) = Snackbar + .make(this, message, Snackbar.LENGTH_LONG) + .setAction(actionText, action) + .apply { show() } + +/** + * Display Snackbar with the [Snackbar.LENGTH_INDEFINITE] duration. + * + * @param message the message text. + */ +@JvmName("indefiniteSnackbar2") +inline fun View.indefiniteSnackbar(message: CharSequence, actionText: CharSequence, noinline action: (View) -> Unit) = Snackbar + .make(this, message, Snackbar.LENGTH_INDEFINITE) + .setAction(actionText, action) + .apply { show() } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/utils/Toasts.kt b/app/src/main/java/io/legado/app/utils/Toasts.kt new file mode 100644 index 000000000..5fea5ad08 --- /dev/null +++ b/app/src/main/java/io/legado/app/utils/Toasts.kt @@ -0,0 +1,80 @@ +package io.legado.app.utils + +import android.content.Context +import android.widget.Toast +import androidx.fragment.app.Fragment +import org.jetbrains.anko.longToast +import org.jetbrains.anko.toast + + +/** + * Display the simple Toast message with the [Toast.LENGTH_SHORT] duration. + * + * @param message the message text resource. + */ +inline fun Fragment.toast(message: Int) = requireActivity().toast(message) + +/** + * Display the simple Toast message with the [Toast.LENGTH_SHORT] duration. + * + * @param message the message text resource. + */ +inline fun Context.toast(message: Int): Toast = Toast + .makeText(this, message, Toast.LENGTH_SHORT) + .apply { + show() + } + +/** + * Display the simple Toast message with the [Toast.LENGTH_SHORT] duration. + * + * @param message the message text. + */ +inline fun Fragment.toast(message: CharSequence) = requireActivity().toast(message) + +/** + * Display the simple Toast message with the [Toast.LENGTH_SHORT] duration. + * + * @param message the message text. + */ +inline fun Context.toast(message: CharSequence): Toast = Toast + .makeText(this, message, Toast.LENGTH_SHORT) + .apply { + show() + } + +/** + * Display the simple Toast message with the [Toast.LENGTH_LONG] duration. + * + * @param message the message text resource. + */ +inline fun Fragment.longToast(message: Int) = requireActivity().longToast(message) + +/** + * Display the simple Toast message with the [Toast.LENGTH_LONG] duration. + * + * @param message the message text resource. + */ +inline fun Context.longToast(message: Int): Toast = Toast + .makeText(this, message, Toast.LENGTH_LONG) + .apply { + show() + } + +/** + * Display the simple Toast message with the [Toast.LENGTH_LONG] duration. + * + * @param message the message text. + */ +inline fun Fragment.longToast(message: CharSequence) = requireActivity().longToast(message) + +/** + * Display the simple Toast message with the [Toast.LENGTH_LONG] duration. + * + * @param message the message text. + */ +inline fun Context.longToast(message: CharSequence): Toast = Toast + .makeText(this, message, Toast.LENGTH_LONG) + .apply { + show() + } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/utils/ViewModelKt.kt b/app/src/main/java/io/legado/app/utils/ViewModelKt.kt index c2ef64e53..b777c8bbf 100644 --- a/app/src/main/java/io/legado/app/utils/ViewModelKt.kt +++ b/app/src/main/java/io/legado/app/utils/ViewModelKt.kt @@ -9,5 +9,8 @@ fun AppCompatActivity.getViewModel(clazz: Class) = ViewModelP fun Fragment.getViewModel(clazz: Class) = ViewModelProviders.of(this).get(clazz) +/** + * 与activity数据同步 + */ fun Fragment.getViewModelOfActivity(clazz: Class) = ViewModelProviders.of(requireActivity()).get(clazz) \ No newline at end of file From 87f3bb9767754006e47900fe30af462258ac1099 Mon Sep 17 00:00:00 2001 From: Administrator <1760316362@qq.com> Date: Thu, 1 Aug 2019 16:18:26 +0800 Subject: [PATCH 0507/1997] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/io/legado/app/base/BaseActivity.kt | 4 ++-- .../java/io/legado/app/ui/config/ThemeConfigFragment.kt | 8 +++++++- app/src/main/java/io/legado/app/ui/widget/TitleBar.kt | 3 ++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/base/BaseActivity.kt b/app/src/main/java/io/legado/app/base/BaseActivity.kt index c109d0e3b..881323bc6 100644 --- a/app/src/main/java/io/legado/app/base/BaseActivity.kt +++ b/app/src/main/java/io/legado/app/base/BaseActivity.kt @@ -80,13 +80,13 @@ abstract class BaseActivity(private val layoutID: Int, private val fullScreen: B window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_STABLE window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) - if (getPrefBoolean("transparentStatusBar")) { + if (isTransparentStatusBar) { window.statusBarColor = Color.TRANSPARENT } else { window.statusBarColor = getCompatColor(R.color.status_bar_bag) } } else { - window.statusBarColor = ThemeStore.statusBarColor(this, getPrefBoolean("transparentStatusBar")) + window.statusBarColor = ThemeStore.statusBarColor(this, isTransparentStatusBar) } } diff --git a/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt index 1a2dad761..1b4bac585 100644 --- a/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt @@ -13,6 +13,8 @@ import io.legado.app.constant.Bus import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.ColorUtils import io.legado.app.utils.* +import kotlinx.coroutines.delay +import kotlinx.coroutines.runBlocking class ThemeConfigFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedPreferenceChangeListener { @@ -140,6 +142,10 @@ class ThemeConfigFragment : PreferenceFragmentCompat(), SharedPreferences.OnShar private fun recreateActivities() { postEvent(Bus.RECREATE, "") - Handler().postDelayed({ activity?.recreate() }, 100L) + runBlocking { + delay(100L) + activity?.recreate() + } } + } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt b/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt index 0a36b6a58..fd6b825d0 100644 --- a/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt +++ b/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt @@ -125,7 +125,6 @@ class TitleBar(context: Context, attrs: AttributeSet?) : AppBarLayout(context, a this.subtitle = subtitleText } - backgroundColor = context.primaryColor } if (a.getBoolean(R.styleable.TitleBar_fitStatusBar, true)) { @@ -136,6 +135,8 @@ class TitleBar(context: Context, attrs: AttributeSet?) : AppBarLayout(context, a bottomPadding = context.getNavigationBarHeight() } + backgroundColor = context.primaryColor + a.recycle() } From 9dfce08b589423a9a0df00203f2e9d5b177fe14d Mon Sep 17 00:00:00 2001 From: Administrator <1760316362@qq.com> Date: Thu, 1 Aug 2019 18:49:26 +0800 Subject: [PATCH 0508/1997] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../legado/app/lib/dialogs/AndroidDialogs.kt | 41 +---------- .../app/lib/dialogs/AndroidSelectors.kt | 19 ++---- .../java/io/legado/app/lib/dialogs/Dialogs.kt | 20 ------ .../io/legado/app/lib/dialogs/Selectors.kt | 9 +-- .../app/ui/config/ThemeConfigFragment.kt | 68 +++++++++---------- .../java/io/legado/app/ui/widget/TitleBar.kt | 16 +---- .../io/legado/app/utils/ViewExtensions.kt | 31 +++++++++ 7 files changed, 77 insertions(+), 127 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/dialogs/AndroidDialogs.kt b/app/src/main/java/io/legado/app/lib/dialogs/AndroidDialogs.kt index c178ef75d..e14a2730f 100644 --- a/app/src/main/java/io/legado/app/lib/dialogs/AndroidDialogs.kt +++ b/app/src/main/java/io/legado/app/lib/dialogs/AndroidDialogs.kt @@ -25,12 +25,6 @@ import androidx.appcompat.app.AlertDialog import androidx.fragment.app.Fragment import org.jetbrains.anko.AnkoContext -inline fun AnkoContext<*>.alert( - title: CharSequence? = null, - message: CharSequence? = null, - noinline init: (AlertBuilder.() -> Unit)? = null -) = ctx.alert(title, message, init) - inline fun Fragment.alert( title: CharSequence? = null, message: CharSequence? = null, @@ -53,12 +47,6 @@ fun Context.alert( } } -inline fun AnkoContext<*>.alert( - titleResource: Int? = null, - messageResource: Int? = null, - noinline init: (AlertBuilder.() -> Unit)? = null -) = ctx.alert(titleResource, messageResource, init) - inline fun Fragment.alert( title: Int? = null, message: Int? = null, @@ -83,17 +71,11 @@ fun Context.alert( inline fun AnkoContext<*>.alert(noinline init: AlertBuilder.() -> Unit) = ctx.alert(init) -inline fun Fragment.alert(noinline init: AlertBuilder.() -> Unit) = activity?.alert(init) +inline fun Fragment.alert(noinline init: AlertBuilder.() -> Unit) = requireContext().alert(init) -fun Context.alert(init: AlertBuilder.() -> Unit): AlertBuilder = +fun Context.alert(init: AlertBuilder.() -> Unit): AlertBuilder = AndroidAlertBuilder(this).apply { init() } -inline fun AnkoContext<*>.progressDialog( - title: Int? = null, - message: Int? = null, - noinline init: (ProgressDialog.() -> Unit)? = null -) = ctx.progressDialog(title, message, init) - inline fun Fragment.progressDialog( title: Int? = null, message: Int? = null, @@ -107,12 +89,6 @@ fun Context.progressDialog( ) = progressDialog(title?.let { getString(it) }, message?.let { getString(it) }, false, init) -inline fun AnkoContext<*>.indeterminateProgressDialog( - title: Int? = null, - message: Int? = null, - noinline init: (ProgressDialog.() -> Unit)? = null -) = ctx.indeterminateProgressDialog(title, message, init) - inline fun Fragment.indeterminateProgressDialog( title: Int? = null, message: Int? = null, @@ -125,13 +101,6 @@ fun Context.indeterminateProgressDialog( init: (ProgressDialog.() -> Unit)? = null ) = progressDialog(title?.let { getString(it) }, message?.let { getString(it) }, true, init) - -inline fun AnkoContext<*>.progressDialog( - title: CharSequence? = null, - message: CharSequence? = null, - noinline init: (ProgressDialog.() -> Unit)? = null -) = ctx.progressDialog(title, message, init) - inline fun Fragment.progressDialog( title: CharSequence? = null, message: CharSequence? = null, @@ -145,12 +114,6 @@ fun Context.progressDialog( ) = progressDialog(title, message, false, init) -inline fun AnkoContext<*>.indeterminateProgressDialog( - title: CharSequence? = null, - message: CharSequence? = null, - noinline init: (ProgressDialog.() -> Unit)? = null -) = ctx.indeterminateProgressDialog(title, message, init) - inline fun Fragment.indeterminateProgressDialog( title: CharSequence? = null, message: CharSequence? = null, diff --git a/app/src/main/java/io/legado/app/lib/dialogs/AndroidSelectors.kt b/app/src/main/java/io/legado/app/lib/dialogs/AndroidSelectors.kt index f4d63e1a8..17ed0dea8 100644 --- a/app/src/main/java/io/legado/app/lib/dialogs/AndroidSelectors.kt +++ b/app/src/main/java/io/legado/app/lib/dialogs/AndroidSelectors.kt @@ -21,24 +21,17 @@ package io.legado.app.lib.dialogs import android.content.Context import android.content.DialogInterface import androidx.fragment.app.Fragment -import org.jetbrains.anko.AnkoContext - -inline fun AnkoContext<*>.selector( - title: CharSequence? = null, - items: List, - noinline onClick: (DialogInterface, Int) -> Unit -) = ctx.selector(title, items, onClick) inline fun Fragment.selector( - title: CharSequence? = null, - items: List, - noinline onClick: (DialogInterface, Int) -> Unit + title: CharSequence? = null, + items: List, + noinline onClick: (DialogInterface, Int) -> Unit ) = activity?.selector(title, items, onClick) fun Context.selector( - title: CharSequence? = null, - items: List, - onClick: (DialogInterface, Int) -> Unit + title: CharSequence? = null, + items: List, + onClick: (DialogInterface, Int) -> Unit ) { with(AndroidAlertBuilder(this)) { if (title != null) { diff --git a/app/src/main/java/io/legado/app/lib/dialogs/Dialogs.kt b/app/src/main/java/io/legado/app/lib/dialogs/Dialogs.kt index 9f4c0c77b..6a1e28428 100644 --- a/app/src/main/java/io/legado/app/lib/dialogs/Dialogs.kt +++ b/app/src/main/java/io/legado/app/lib/dialogs/Dialogs.kt @@ -21,17 +21,9 @@ package io.legado.app.lib.dialogs import android.content.Context import android.content.DialogInterface import androidx.fragment.app.Fragment -import org.jetbrains.anko.AnkoContext typealias AlertBuilderFactory = (Context) -> AlertBuilder -inline fun AnkoContext<*>.alert( - noinline factory: AlertBuilderFactory, - title: String? = null, - message: String? = null, - noinline init: (AlertBuilder.() -> Unit)? = null -) = ctx.alert(factory, title, message, init) - inline fun Fragment.alert( noinline factory: AlertBuilderFactory, title: String? = null, @@ -56,13 +48,6 @@ fun Context.alert( } } -inline fun AnkoContext<*>.alert( - noinline factory: AlertBuilderFactory, - titleResource: Int? = null, - messageResource: Int? = null, - noinline init: (AlertBuilder.() -> Unit)? = null -) = ctx.alert(factory, titleResource, messageResource, init) - inline fun Fragment.alert( noinline factory: AlertBuilderFactory, titleResource: Int? = null, @@ -87,11 +72,6 @@ fun Context.alert( } } -inline fun AnkoContext<*>.alert( - noinline factory: AlertBuilderFactory, - noinline init: AlertBuilder.() -> Unit -) = ctx.alert(factory, init) - inline fun Fragment.alert( noinline factory: AlertBuilderFactory, noinline init: AlertBuilder.() -> Unit diff --git a/app/src/main/java/io/legado/app/lib/dialogs/Selectors.kt b/app/src/main/java/io/legado/app/lib/dialogs/Selectors.kt index 485c6971c..b8fe1e1b4 100644 --- a/app/src/main/java/io/legado/app/lib/dialogs/Selectors.kt +++ b/app/src/main/java/io/legado/app/lib/dialogs/Selectors.kt @@ -15,19 +15,12 @@ */ @file:Suppress("NOTHING_TO_INLINE", "unused") + package io.legado.app.lib.dialogs import android.content.Context import android.content.DialogInterface import androidx.fragment.app.Fragment -import org.jetbrains.anko.AnkoContext - -inline fun AnkoContext<*>.selector( - noinline factory: AlertBuilderFactory, - title: CharSequence? = null, - items: List, - noinline onClick: (DialogInterface, CharSequence, Int) -> Unit -) = ctx.selector(factory, title, items, onClick) inline fun Fragment.selector( noinline factory: AlertBuilderFactory, diff --git a/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt index 1b4bac585..7d9f4006a 100644 --- a/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt @@ -10,11 +10,12 @@ import androidx.preference.PreferenceFragmentCompat import io.legado.app.App import io.legado.app.R import io.legado.app.constant.Bus +import io.legado.app.lib.dialogs.alert +import io.legado.app.lib.dialogs.noButton +import io.legado.app.lib.dialogs.yesButton import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.ColorUtils import io.legado.app.utils.* -import kotlinx.coroutines.delay -import kotlinx.coroutines.runBlocking class ThemeConfigFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedPreferenceChangeListener { @@ -46,40 +47,42 @@ class ThemeConfigFragment : PreferenceFragmentCompat(), SharedPreferences.OnShar } "colorPrimary", "colorAccent", "colorBackground" -> { if (backgroundIsDark(sharedPreferences)) { - activity?.let { - AlertDialog.Builder(it) - .setTitle("白天背景太暗") - .setMessage("将会恢复默认背景?") - .setPositiveButton(R.string.ok) { _, _ -> - putPrefInt( - "colorBackground", - getCompatColor(R.color.md_grey_100) - ) - upTheme(false) - } - .setNegativeButton(R.string.cancel) { _, _ -> upTheme(false) } - .show().applyTint() - } + alert { + title = "白天背景太暗" + message = "将会恢复默认背景?" + yesButton { + putPrefInt( + "colorBackground", + getCompatColor(R.color.md_grey_100) + ) + upTheme(false) + } + + noButton { + upTheme(false) + } + }.show().applyTint() } else { upTheme(false) } } "colorPrimaryNight", "colorAccentNight", "colorBackgroundNight" -> { if (backgroundIsLight(sharedPreferences)) { - activity?.let { - AlertDialog.Builder(it) - .setTitle("夜间背景太亮") - .setMessage("将会恢复默认背景?") - .setPositiveButton(R.string.ok) { _, _ -> - putPrefInt( - "colorBackgroundNight", - getCompatColor(R.color.md_grey_800) - ) - upTheme(true) - } - .setNegativeButton(R.string.cancel) { _, _ -> upTheme(true) } - .show().applyTint() - } + alert { + title = "夜间背景太亮" + message = "将会恢复默认背景?" + yesButton { + putPrefInt( + "colorBackgroundNight", + getCompatColor(R.color.md_grey_800) + ) + upTheme(true) + } + + noButton { + upTheme(true) + } + }.show().applyTint() } else { upTheme(true) } @@ -142,10 +145,7 @@ class ThemeConfigFragment : PreferenceFragmentCompat(), SharedPreferences.OnShar private fun recreateActivities() { postEvent(Bus.RECREATE, "") - runBlocking { - delay(100L) - activity?.recreate() - } + Handler().postDelayed({ activity?.recreate() }, 100L) } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt b/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt index fd6b825d0..631356af0 100644 --- a/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt +++ b/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt @@ -18,6 +18,7 @@ import io.legado.app.R import io.legado.app.lib.theme.DrawableUtils import io.legado.app.lib.theme.primaryColor import io.legado.app.lib.theme.primaryTextColor +import io.legado.app.utils.activity import io.legado.app.utils.getNavigationBarHeight import io.legado.app.utils.getStatusBarHeight import org.jetbrains.anko.backgroundColor @@ -143,7 +144,7 @@ class TitleBar(context: Context, attrs: AttributeSet?) : AppBarLayout(context, a override fun onAttachedToWindow() { super.onAttachedToWindow() if (attachToActivity) { - attachToActivity(context) + attachToActivity() } wrapAppTheme() } @@ -188,24 +189,13 @@ class TitleBar(context: Context, attrs: AttributeSet?) : AppBarLayout(context, a } } - private fun attachToActivity(context: Context) { - val activity = getCompatActivity(context) + private fun attachToActivity() { activity?.let { it.setSupportActionBar(toolbar) it.supportActionBar?.setDisplayHomeAsUpEnabled(displayHomeAsUp) } } - private fun getCompatActivity(context: Context?): AppCompatActivity? { - if (context == null) return null - return when (context) { - is AppCompatActivity -> context - is androidx.appcompat.view.ContextThemeWrapper -> getCompatActivity(context.baseContext) - is android.view.ContextThemeWrapper -> getCompatActivity(context.baseContext) - else -> null - } - } - private fun wrapDrawableTint(drawable: Drawable?, tintList: ColorStateList?, tintMode: Int) { if (drawable == null || tintList == null) return val wrappedDrawable = DrawableCompat.wrap(drawable.mutate()) diff --git a/app/src/main/java/io/legado/app/utils/ViewExtensions.kt b/app/src/main/java/io/legado/app/utils/ViewExtensions.kt index 4300ea2ae..50944d224 100644 --- a/app/src/main/java/io/legado/app/utils/ViewExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/ViewExtensions.kt @@ -1,11 +1,32 @@ package io.legado.app.utils import android.content.Context +import android.graphics.Bitmap +import android.graphics.Canvas +import android.graphics.Rect import android.os.Build +import android.os.Handler +import android.view.PixelCopy import android.view.View import android.view.View.* import android.view.inputmethod.InputMethodManager +import androidx.appcompat.app.AppCompatActivity import io.legado.app.App +import android.opengl.ETC1.getHeight +import android.opengl.ETC1.getWidth + + +private tailrec fun getCompatActivity(context: Context?): AppCompatActivity? { + return when (context) { + is AppCompatActivity -> context + is androidx.appcompat.view.ContextThemeWrapper -> getCompatActivity(context.baseContext) + is android.view.ContextThemeWrapper -> getCompatActivity(context.baseContext) + else -> null + } +} + +val View.activity: AppCompatActivity? + get() = getCompatActivity(context) fun View.hideSoftInput() = run { val imm = App.INSTANCE.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager @@ -30,4 +51,14 @@ fun View.invisible() { fun View.visible() { visibility = VISIBLE +} + +fun View.screenshot(): Bitmap? { + return runCatching { + val screenshot = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565) + val c = Canvas(screenshot) + c.translate(-scrollX.toFloat(), -scrollY.toFloat()) + draw(c) + screenshot + }.getOrNull() } \ No newline at end of file From 64dc125897c8fc676ae32cd0c113de1ba40f07ca Mon Sep 17 00:00:00 2001 From: Administrator <1760316362@qq.com> Date: Fri, 2 Aug 2019 09:36:49 +0800 Subject: [PATCH 0509/1997] update --- .../java/io/legado/app/utils/EventBusKt.kt | 46 ++++++------------- 1 file changed, 15 insertions(+), 31 deletions(-) diff --git a/app/src/main/java/io/legado/app/utils/EventBusKt.kt b/app/src/main/java/io/legado/app/utils/EventBusKt.kt index fa6904ea3..82c3f0f30 100644 --- a/app/src/main/java/io/legado/app/utils/EventBusKt.kt +++ b/app/src/main/java/io/legado/app/utils/EventBusKt.kt @@ -13,16 +13,10 @@ inline fun postEvent(tag: String, event: EVENT) { LiveEventBus.get().with(tag, EVENT::class.java).post(event) } -inline fun AppCompatActivity.observeEvent(tag: String, crossinline observer: (EVENT) -> Unit) { - eventObservable(tag).observe(this, Observer { - observer(it) - }) -} - -/** - * 只能观察相同类型的事件,可用EventMessage - */ -inline fun AppCompatActivity.observeEvents(vararg tags: String, crossinline observer: (EVENT) -> Unit) { +inline fun AppCompatActivity.observeEvent( + vararg tags: String, + noinline observer: (EVENT) -> Unit +) { val o = Observer { observer(it) } @@ -31,15 +25,10 @@ inline fun AppCompatActivity.observeEvents(vararg tags: String, } } -inline fun AppCompatActivity.observeEventSticky(tag: String, crossinline observer: (EVENT) -> Unit) { - eventObservable(tag).observeSticky(this, Observer { - observer(it) - }) -} -inline fun AppCompatActivity.observeEventsSticky( +inline fun AppCompatActivity.observeEventSticky( vararg tags: String, - crossinline observer: (EVENT) -> Unit + noinline observer: (EVENT) -> Unit ) { val o = Observer { observer(it) @@ -49,13 +38,10 @@ inline fun AppCompatActivity.observeEventsSticky( } } -inline fun Fragment.observeEvent(tag: String, crossinline observer: (EVENT) -> Unit) { - eventObservable(tag).observe(this, Observer { - observer(it) - }) -} - -inline fun Fragment.observeEvents(vararg tags: String, crossinline observer: (EVENT) -> Unit) { +inline fun Fragment.observeEvent( + vararg tags: String, + noinline observer: (EVENT) -> Unit +) { val o = Observer { observer(it) } @@ -64,13 +50,10 @@ inline fun Fragment.observeEvents(vararg tags: String, crossinli } } -inline fun Fragment.observeEventSticky(tag: String, crossinline observer: (EVENT) -> Unit) { - eventObservable(tag).observeSticky(this, Observer { - observer(it) - }) -} - -inline fun Fragment.observeEventsSticky(vararg tags: String, crossinline observer: (EVENT) -> Unit) { +inline fun Fragment.observeEventSticky( + vararg tags: String, + noinline observer: (EVENT) -> Unit +) { val o = Observer { observer(it) } @@ -78,3 +61,4 @@ inline fun Fragment.observeEventsSticky(vararg tags: String, cro eventObservable(it).observeSticky(this, o) } } + From c662e74a206bea89973a5f1703d9dcd8a3f60deb Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 2 Aug 2019 10:01:26 +0800 Subject: [PATCH 0510/1997] up --- app/src/main/AndroidManifest.xml | 1 + .../java/io/legado/app/ui/read/ReadActivity.kt | 17 +++++++++++++++++ .../java/io/legado/app/ui/read/ReadViewModel.kt | 8 ++++++++ app/src/main/res/layout/activity_read.xml | 7 +++++++ 4 files changed, 33 insertions(+) create mode 100644 app/src/main/java/io/legado/app/ui/read/ReadActivity.kt create mode 100644 app/src/main/java/io/legado/app/ui/read/ReadViewModel.kt create mode 100644 app/src/main/res/layout/activity_read.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index db32747e6..9f73953a6 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -54,6 +54,7 @@ + diff --git a/app/src/main/java/io/legado/app/ui/read/ReadActivity.kt b/app/src/main/java/io/legado/app/ui/read/ReadActivity.kt new file mode 100644 index 000000000..ede69761d --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/read/ReadActivity.kt @@ -0,0 +1,17 @@ +package io.legado.app.ui.read + +import android.os.Bundle +import io.legado.app.R +import io.legado.app.base.VMBaseActivity +import io.legado.app.utils.getViewModel + +class ReadActivity : VMBaseActivity(R.layout.activity_read) { + override val viewModel: ReadViewModel + get() = getViewModel(ReadViewModel::class.java) + + override fun onActivityCreated(savedInstanceState: Bundle?) { + + } + + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/read/ReadViewModel.kt b/app/src/main/java/io/legado/app/ui/read/ReadViewModel.kt new file mode 100644 index 000000000..098ad52d7 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/read/ReadViewModel.kt @@ -0,0 +1,8 @@ +package io.legado.app.ui.read + +import android.app.Application +import io.legado.app.base.BaseViewModel + +class ReadViewModel(application: Application) : BaseViewModel(application) { + +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_read.xml b/app/src/main/res/layout/activity_read.xml new file mode 100644 index 000000000..d829e291c --- /dev/null +++ b/app/src/main/res/layout/activity_read.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file From c76ee0f55097d3630c6e93ade34c2e9c2649804c Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 2 Aug 2019 10:53:44 +0800 Subject: [PATCH 0511/1997] up --- .../app/ui/booksource/BookSourceActivity.kt | 18 +++++++++- .../app/ui/sourcedebug/SourceDebugActivity.kt | 34 ++++++++++++++++++- app/src/main/res/menu/source_debug.xml | 11 ++++++ 3 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 app/src/main/res/menu/source_debug.xml diff --git a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt index 66ff91a1d..affb09a1f 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt @@ -1,5 +1,6 @@ package io.legado.app.ui.booksource +import android.content.Intent import android.os.Bundle import android.view.Menu import android.view.MenuItem @@ -27,6 +28,7 @@ import kotlinx.android.synthetic.main.view_title_bar.* import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.launch import org.jetbrains.anko.startActivity +import org.jetbrains.anko.startActivityForResult class BookSourceActivity : VMBaseActivity(R.layout.activity_book_source), BookSourceAdapter.CallBack, @@ -36,6 +38,7 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity_ private lateinit var adapter: BookSourceAdapter private var bookSourceLiveDate: LiveData>? = null + val qrRequestCode = 101 override fun onActivityCreated(savedInstanceState: Bundle?) { setSupportActionBar(toolbar) @@ -55,7 +58,7 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity_ this.startActivity() } R.id.action_import_book_source_qr -> { - this.startActivity() + this.startActivityForResult(qrRequestCode) } R.id.action_select_all -> { launch(IO) { @@ -135,4 +138,17 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity_ override fun edit(bookSource: BookSource) { startActivity(Pair("data", bookSource.bookSourceUrl)) } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + when (requestCode) { + qrRequestCode -> { + if (resultCode == RESULT_OK) { + data?.getStringExtra("result")?.let { + + } + } + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt index 609689873..ee15278ea 100644 --- a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt +++ b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt @@ -1,6 +1,9 @@ package io.legado.app.ui.sourcedebug +import android.content.Intent import android.os.Bundle +import android.view.Menu +import android.view.MenuItem import android.view.View import androidx.appcompat.widget.SearchView import androidx.recyclerview.widget.LinearLayoutManager @@ -9,12 +12,13 @@ import io.legado.app.base.VMBaseActivity import io.legado.app.constant.Bus import io.legado.app.help.EventMessage import io.legado.app.lib.theme.ATH -import io.legado.app.lib.theme.ThemeStore import io.legado.app.lib.theme.accentColor +import io.legado.app.ui.qrcode.QrCodeActivity import io.legado.app.utils.getViewModel import io.legado.app.utils.observeEvent import kotlinx.android.synthetic.main.activity_source_debug.* import kotlinx.android.synthetic.main.view_title_bar.* +import org.jetbrains.anko.startActivityForResult import org.jetbrains.anko.toast class SourceDebugActivity : VMBaseActivity(R.layout.activity_source_debug) { @@ -23,6 +27,7 @@ class SourceDebugActivity : VMBaseActivity(R.layout.activity_s get() = getViewModel(SourceDebugModel::class.java) private lateinit var adapter: SourceDebugAdapter + val qrRequestCode = 101 override fun onActivityCreated(savedInstanceState: Bundle?) { viewModel.init(intent.getStringExtra("key")) @@ -65,6 +70,33 @@ class SourceDebugActivity : VMBaseActivity(R.layout.activity_s }) } + override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { + menuInflater.inflate(R.menu.source_debug, menu) + return super.onCompatCreateOptionsMenu(menu) + } + + override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.action_scan -> { + startActivityForResult(qrRequestCode) + } + } + return super.onCompatOptionsItemSelected(item) + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + when (requestCode) { + qrRequestCode -> { + if (resultCode == RESULT_OK) { + data?.getStringExtra("result")?.let { + startSearch(it) + } + } + } + } + } + override fun observeLiveBus() { observeEvent(Bus.SOURCE_DEBUG_LOG) { adapter.addItem(it.obj as String) diff --git a/app/src/main/res/menu/source_debug.xml b/app/src/main/res/menu/source_debug.xml new file mode 100644 index 000000000..5b8b467f2 --- /dev/null +++ b/app/src/main/res/menu/source_debug.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file From 9fbdb796861edec968dfc398f05debe28e025276 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 2 Aug 2019 11:02:23 +0800 Subject: [PATCH 0512/1997] up --- .../main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt | 2 +- app/src/main/java/io/legado/app/model/webbook/BookInfo.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt index 4c3545135..fead18fe8 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt @@ -195,7 +195,7 @@ class AnalyzeRule(private var book: BaseBook? = null) { Mode.Js -> result = evalJS(rule.rule, it) Mode.Json -> result = getAnalyzeByJSonPath(it).getString(rule.rule) Mode.XPath -> result = getAnalyzeByXPath(it).getString(rule.rule) - Mode.Default -> result = if (isUrl && !TextUtils.isEmpty(baseUrl)) { + Mode.Default -> result = if (isUrl) { getAnalyzeByJSoup(it).getString0(rule.rule) } else { getAnalyzeByJSoup(it).getString(rule.rule) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt b/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt index 988a1fa59..f678e5ed2 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt @@ -26,7 +26,7 @@ object BookInfo { SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取成功:$baseUrl") val infoRule = bookSource.getBookInfoRule() val analyzeRule = AnalyzeRule(book) - analyzeRule.setContent(body) + analyzeRule.setContent(body, baseUrl) infoRule.init?.let { if (it.isNotEmpty()) { SourceDebug.printLog(bookSource.bookSourceUrl, 1, "执行详情页初始化规则") From 5d81eb3233ac72c2fdc9b9a7511cfb93dcf309f5 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 2 Aug 2019 11:13:03 +0800 Subject: [PATCH 0513/1997] up --- .../main/java/io/legado/app/model/webbook/BookChapterList.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt b/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt index 3bd4be757..9f093df7a 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt @@ -116,8 +116,11 @@ object BookChapterList { } SourceDebug.printLog(bookSource.bookSourceUrl, 1, TextUtils.join(",", nextUrlList), printLog) } + SourceDebug.printLog(bookSource.bookSourceUrl, 1, "解析目录列表", printLog) val elements = analyzeRule.getElements(listRule) + SourceDebug.printLog(bookSource.bookSourceUrl, 1, "目录数${elements.size}", printLog) if (elements.isNotEmpty()) { + SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取目录", printLog) val nameRule = analyzeRule.splitSourceRule(tocRule.chapterName ?: "") val urlRule = analyzeRule.splitSourceRule(tocRule.chapterUrl ?: "") for (item in elements) { @@ -131,6 +134,7 @@ object BookChapterList { chapterList.add(bookChapter) } } + SourceDebug.printLog(bookSource.bookSourceUrl, 1, "${chapterList[0].title}${chapterList[0].url}", printLog) } return ChapterData(chapterList, nextUrlList) } From 5b91e44e064cbd1d5a5eb3b89d4c1a18c2b403d2 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 2 Aug 2019 11:24:29 +0800 Subject: [PATCH 0514/1997] up --- .../java/io/legado/app/ui/booksource/BookSourceActivity.kt | 2 +- .../java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt index affb09a1f..4be37daca 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt @@ -38,7 +38,7 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity_ private lateinit var adapter: BookSourceAdapter private var bookSourceLiveDate: LiveData>? = null - val qrRequestCode = 101 + private val qrRequestCode = 101 override fun onActivityCreated(savedInstanceState: Bundle?) { setSupportActionBar(toolbar) diff --git a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt index ee15278ea..66d25642d 100644 --- a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt +++ b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt @@ -15,6 +15,7 @@ import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.accentColor import io.legado.app.ui.qrcode.QrCodeActivity import io.legado.app.utils.getViewModel +import io.legado.app.utils.hideSoftInput import io.legado.app.utils.observeEvent import kotlinx.android.synthetic.main.activity_source_debug.* import kotlinx.android.synthetic.main.view_title_bar.* @@ -27,7 +28,7 @@ class SourceDebugActivity : VMBaseActivity(R.layout.activity_s get() = getViewModel(SourceDebugModel::class.java) private lateinit var adapter: SourceDebugAdapter - val qrRequestCode = 101 + private val qrRequestCode = 101 override fun onActivityCreated(savedInstanceState: Bundle?) { viewModel.init(intent.getStringExtra("key")) @@ -51,6 +52,7 @@ class SourceDebugActivity : VMBaseActivity(R.layout.activity_s search_view.clearFocus() search_view.setOnQueryTextListener(object : SearchView.OnQueryTextListener { override fun onQueryTextSubmit(query: String?): Boolean { + search_view.hideSoftInput() startSearch(query ?: "我的") return true } From b5f02bccf04242b5da79d5e7470af0013c090ab5 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 2 Aug 2019 11:30:18 +0800 Subject: [PATCH 0515/1997] up --- app/src/main/java/io/legado/app/help/storage/Restore.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/help/storage/Restore.kt b/app/src/main/java/io/legado/app/help/storage/Restore.kt index 74ec65055..62342bb9c 100644 --- a/app/src/main/java/io/legado/app/help/storage/Restore.kt +++ b/app/src/main/java/io/legado/app/help/storage/Restore.kt @@ -143,7 +143,7 @@ object Restore { ) source.ruleBookInfo = GSON.toJson(bookInfoRule) val chapterRule = TocRule( - chapterList = jsonItem.readString("ruleChapterUrlNext"), + chapterList = jsonItem.readString("ruleChapterList"), chapterName = jsonItem.readString("ruleChapterName"), chapterUrl = jsonItem.readString("ruleContentUrl"), nextTocUrl = jsonItem.readString("ruleChapterUrlNext") From 8ebe422cfd814bf481d358c6df2a063aa0084ea3 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 2 Aug 2019 11:46:54 +0800 Subject: [PATCH 0516/1997] up --- .../legado/app/model/webbook/SourceDebug.kt | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt index 7ca534ed9..d9dd7df69 100644 --- a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt +++ b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt @@ -22,14 +22,27 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { private val DEBUG_TIME_FORMAT = SimpleDateFormat("[mm:ss.SSS]", Locale.getDefault()) private val startTime: Long = System.currentTimeMillis() - fun printLog(sourceUrl: String?, state: Int, msg: String, print: Boolean = true, isHtml: Boolean = false) { + fun printLog( + sourceUrl: String?, + state: Int, + msg: String, + print: Boolean = true, + isHtml: Boolean = false, + showTime: Boolean = true + ) { if (debugSource != sourceUrl || callback == null || !print) return var printMsg = msg if (isHtml) { printMsg = printMsg.htmlFormat() } - printMsg = - String.format("%s %s", DEBUG_TIME_FORMAT.format(Date(System.currentTimeMillis() - startTime)), printMsg) + if (showTime) { + printMsg = + String.format( + "%s %s", + DEBUG_TIME_FORMAT.format(Date(System.currentTimeMillis() - startTime)), + printMsg + ) + } callback?.printLog(state, printMsg) } @@ -70,7 +83,7 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { .onSuccess { searchBooks -> searchBooks?.let { if (searchBooks.isNotEmpty()) { - callback?.printLog(1, "") + printLog(debugSource, 1, "", showTime = false) infoDebug(BookHelp.toBook(searchBooks[0])) } } @@ -85,7 +98,7 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { printLog(debugSource, 1, "开始获取详情页") val info = webBook.getBookInfo(book) .onSuccess { - callback?.printLog(1, "") + printLog(debugSource, 1, "", showTime = false) tocDebug(book) } .onError { @@ -100,7 +113,7 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { .onSuccess { chapterList -> chapterList?.let { if (it.isNotEmpty()) { - callback?.printLog(1, "") + printLog(debugSource, 1, "", showTime = false) contentDebug(book, it[0]) } } From fe73c04a78667481a439281c74f51b0213cd652a Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 2 Aug 2019 11:50:49 +0800 Subject: [PATCH 0517/1997] up --- app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt index d9dd7df69..c493709cf 100644 --- a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt +++ b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt @@ -142,7 +142,7 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { fun printLog(state: Int, msg: String) } - fun printLog( + private fun printLog( sourceUrl: String?, state: Int, msg: String, From b8eec9ef72365507b8c2eb1ab20d056e4b36598a Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 2 Aug 2019 11:52:43 +0800 Subject: [PATCH 0518/1997] up --- .../main/java/io/legado/app/model/webbook/SourceDebug.kt | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt index c493709cf..7767fe73d 100644 --- a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt +++ b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt @@ -36,12 +36,7 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { printMsg = printMsg.htmlFormat() } if (showTime) { - printMsg = - String.format( - "%s %s", - DEBUG_TIME_FORMAT.format(Date(System.currentTimeMillis() - startTime)), - printMsg - ) + printMsg = "${DEBUG_TIME_FORMAT.format(Date(System.currentTimeMillis() - startTime))} $printMsg" } callback?.printLog(state, printMsg) } From 579012632571c7cbd99aa60ca9764c90832cf0f3 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 2 Aug 2019 12:02:03 +0800 Subject: [PATCH 0519/1997] up --- app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt index 7767fe73d..511b499bf 100644 --- a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt +++ b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt @@ -80,6 +80,8 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { if (searchBooks.isNotEmpty()) { printLog(debugSource, 1, "", showTime = false) infoDebug(BookHelp.toBook(searchBooks[0])) + } else { + printLog(debugSource, -1, "未获取到书籍") } } } @@ -110,6 +112,8 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { if (it.isNotEmpty()) { printLog(debugSource, 1, "", showTime = false) contentDebug(book, it[0]) + } else { + printLog(debugSource, -1, "目录列表为空") } } } From a4052e61c0db627a18f102e24e695d7f83900684 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 2 Aug 2019 12:24:12 +0800 Subject: [PATCH 0520/1997] up --- .../io/legado/app/model/webbook/BookChapterList.kt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt b/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt index 9f093df7a..6719aff4c 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt @@ -23,7 +23,7 @@ object BookChapterList { bookSource: BookSource, analyzeUrl: AnalyzeUrl ): List { - val chapterList = arrayListOf() + var chapterList = arrayListOf() val baseUrl: String = NetworkUtils.getUrl(response) val body: String? = response.body() body ?: throw Exception( @@ -58,7 +58,6 @@ object BookChapterList { } } } - if (reverse) chapterList.reverse() } else if (chapterData.nextUrl.size > 1) { val chapterDataList = arrayListOf>() for (item in chapterData.nextUrl) { @@ -85,8 +84,14 @@ object BookChapterList { chapterList.addAll(it) } } - if (reverse) chapterList.reverse() } + //去重 + if (!reverse) { + chapterList.reverse() + } + val lh = LinkedHashSet(chapterList) + chapterList = ArrayList(lh) + chapterList.reverse() return chapterList } From 54395c1385a90af2fd16f21fb089ebf38401ceac Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 2 Aug 2019 15:03:53 +0800 Subject: [PATCH 0521/1997] up --- app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt index 511b499bf..de180529a 100644 --- a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt +++ b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt @@ -22,6 +22,7 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { private val DEBUG_TIME_FORMAT = SimpleDateFormat("[mm:ss.SSS]", Locale.getDefault()) private val startTime: Long = System.currentTimeMillis() + @Synchronized fun printLog( sourceUrl: String?, state: Int, From c7d20c2510f60cd7ade14083b08f044505b8911e Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 2 Aug 2019 15:33:55 +0800 Subject: [PATCH 0522/1997] up --- .../java/io/legado/app/model/webbook/SourceDebug.kt | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt index de180529a..304dad375 100644 --- a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt +++ b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt @@ -142,14 +142,4 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { fun printLog(state: Int, msg: String) } - private fun printLog( - sourceUrl: String?, - state: Int, - msg: String, - print: Boolean = true, - isHtml: Boolean = false - ): SourceDebug { - SourceDebug.printLog(sourceUrl, state, msg, print, isHtml) - return this - } } \ No newline at end of file From 60cd555a2dd91d0cec9e7cdfd1a594aa7d0a44b5 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 2 Aug 2019 15:38:24 +0800 Subject: [PATCH 0523/1997] up --- app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt index 304dad375..3adbfa906 100644 --- a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt +++ b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt @@ -79,6 +79,7 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { .onSuccess { searchBooks -> searchBooks?.let { if (searchBooks.isNotEmpty()) { + printLog(debugSource, -1, "搜索完成") printLog(debugSource, 1, "", showTime = false) infoDebug(BookHelp.toBook(searchBooks[0])) } else { @@ -96,6 +97,7 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { printLog(debugSource, 1, "开始获取详情页") val info = webBook.getBookInfo(book) .onSuccess { + printLog(debugSource, -1, "详情页完成") printLog(debugSource, 1, "", showTime = false) tocDebug(book) } @@ -111,6 +113,7 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { .onSuccess { chapterList -> chapterList?.let { if (it.isNotEmpty()) { + printLog(debugSource, -1, "目录完成") printLog(debugSource, 1, "", showTime = false) contentDebug(book, it[0]) } else { From b8775cbe29719fdb5719c27cca15dd09017b293b Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 2 Aug 2019 15:44:19 +0800 Subject: [PATCH 0524/1997] up --- .../main/java/io/legado/app/model/webbook/SourceDebug.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt index 3adbfa906..1729ed97f 100644 --- a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt +++ b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt @@ -79,7 +79,7 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { .onSuccess { searchBooks -> searchBooks?.let { if (searchBooks.isNotEmpty()) { - printLog(debugSource, -1, "搜索完成") + printLog(debugSource, 1, "搜索完成") printLog(debugSource, 1, "", showTime = false) infoDebug(BookHelp.toBook(searchBooks[0])) } else { @@ -97,7 +97,7 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { printLog(debugSource, 1, "开始获取详情页") val info = webBook.getBookInfo(book) .onSuccess { - printLog(debugSource, -1, "详情页完成") + printLog(debugSource, 1, "详情页完成") printLog(debugSource, 1, "", showTime = false) tocDebug(book) } @@ -113,7 +113,7 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { .onSuccess { chapterList -> chapterList?.let { if (it.isNotEmpty()) { - printLog(debugSource, -1, "目录完成") + printLog(debugSource, 1, "目录完成") printLog(debugSource, 1, "", showTime = false) contentDebug(book, it[0]) } else { From e107d47385a82b7ddd15423d746b27cb2dd74781 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 2 Aug 2019 15:50:18 +0800 Subject: [PATCH 0525/1997] up --- app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt index 1729ed97f..a7cd9c5e7 100644 --- a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt +++ b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt @@ -20,7 +20,7 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { @SuppressLint("ConstantLocale") private val DEBUG_TIME_FORMAT = SimpleDateFormat("[mm:ss.SSS]", Locale.getDefault()) - private val startTime: Long = System.currentTimeMillis() + private var startTime: Long = System.currentTimeMillis() @Synchronized fun printLog( @@ -60,6 +60,7 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { fun startDebug(key: String) { cancelDebug() + startTime = System.currentTimeMillis() with(webBook) { if (key.isAbsUrl()) { val book = Book() From 1c6fddd61c4d56d2a2da7ffd7fc68149ab514b3c Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 2 Aug 2019 15:51:00 +0800 Subject: [PATCH 0526/1997] up --- app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt index a7cd9c5e7..804572049 100644 --- a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt +++ b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt @@ -1,6 +1,7 @@ package io.legado.app.model.webbook import android.annotation.SuppressLint +import android.util.Log import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter import io.legado.app.help.BookHelp @@ -39,6 +40,7 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { if (showTime) { printMsg = "${DEBUG_TIME_FORMAT.format(Date(System.currentTimeMillis() - startTime))} $printMsg" } + Log.e("sourceDebugLog", printMsg) callback?.printLog(state, printMsg) } From 27bb0ea20a841b62cd3b2be5c8b54592297c48c5 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 2 Aug 2019 15:54:45 +0800 Subject: [PATCH 0527/1997] up --- app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt index 804572049..a7cd9c5e7 100644 --- a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt +++ b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt @@ -1,7 +1,6 @@ package io.legado.app.model.webbook import android.annotation.SuppressLint -import android.util.Log import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter import io.legado.app.help.BookHelp @@ -40,7 +39,6 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { if (showTime) { printMsg = "${DEBUG_TIME_FORMAT.format(Date(System.currentTimeMillis() - startTime))} $printMsg" } - Log.e("sourceDebugLog", printMsg) callback?.printLog(state, printMsg) } From d6a83ed3e09a52e2fe1fb9c0d5b20ed80d2d701e Mon Sep 17 00:00:00 2001 From: Administrator <1760316362@qq.com> Date: Fri, 2 Aug 2019 16:35:36 +0800 Subject: [PATCH 0528/1997] update --- .../app/ui/sourcedebug/SourceDebugActivity.kt | 15 ++++++--------- .../legado/app/ui/sourcedebug/SourceDebugModel.kt | 8 +++++++- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt index 609689873..a70924bed 100644 --- a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt +++ b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt @@ -28,6 +28,12 @@ class SourceDebugActivity : VMBaseActivity(R.layout.activity_s viewModel.init(intent.getStringExtra("key")) initRecyclerView() initSearchView() + viewModel.observe{state, msg-> + adapter.addItem(msg) + if (state == -1 || state == 1000) { + rotate_loading.hide() + } + } } private fun initRecyclerView() { @@ -64,13 +70,4 @@ class SourceDebugActivity : VMBaseActivity(R.layout.activity_s toast("未获取到书源") }) } - - override fun observeLiveBus() { - observeEvent(Bus.SOURCE_DEBUG_LOG) { - adapter.addItem(it.obj as String) - if (it.what == -1 || it.what == 1000) { - rotate_loading.hide() - } - } - } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt index df76cda3b..e5c800b20 100644 --- a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt +++ b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt @@ -13,6 +13,8 @@ class SourceDebugModel(application: Application) : BaseViewModel(application), S private var webBook: WebBook? = null + private var callback: ((Int, String)-> Unit)? = null + fun init(sourceUrl: String?) { sourceUrl?.let { //优先使用这个,不会抛出异常 @@ -23,6 +25,10 @@ class SourceDebugModel(application: Application) : BaseViewModel(application), S } } + fun observe(callback: (Int, String)-> Unit){ + this.callback = callback + } + fun startDebug(key: String, start: (() -> Unit)? = null, error: (() -> Unit)? = null) { webBook?.let { start?.invoke() @@ -31,7 +37,7 @@ class SourceDebugModel(application: Application) : BaseViewModel(application), S } override fun printLog(state: Int, msg: String) { - postEvent(Bus.SOURCE_DEBUG_LOG, EventMessage.obtain(state, msg)) + callback?.invoke(state, msg) } override fun onCleared() { From d6b249f823e6c6c5113b37a20362829ef4f185db Mon Sep 17 00:00:00 2001 From: Administrator <1760316362@qq.com> Date: Fri, 2 Aug 2019 16:38:25 +0800 Subject: [PATCH 0529/1997] update --- .../io/legado/app/ui/main/my/MyFragment.kt | 6 +- .../java/io/legado/app/ui/widget/PageView.kt | 77 +++++++++++++++++++ .../io/legado/app/utils/FragmentExtensions.kt | 23 +++++- .../io/legado/app/utils/ViewExtensions.kt | 2 +- app/src/main/res/layout/activity_read.xml | 16 +++- 5 files changed, 116 insertions(+), 8 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/widget/PageView.kt diff --git a/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt b/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt index 92b27f3ed..5c23674e2 100644 --- a/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt @@ -6,9 +6,9 @@ import android.view.MenuItem import android.view.View import io.legado.app.R import io.legado.app.base.BaseFragment -import io.legado.app.ui.search.SearchActivity +import io.legado.app.ui.read.ReadActivity +import io.legado.app.utils.startActivity import kotlinx.android.synthetic.main.view_title_bar.* -import org.jetbrains.anko.startActivity class MyFragment : BaseFragment(R.layout.fragment_my_config) { @@ -26,7 +26,7 @@ class MyFragment : BaseFragment(R.layout.fragment_my_config) { override fun onCompatOptionsItemSelected(item: MenuItem) { when (item.itemId) { - R.id.action_settings -> requireContext().startActivity() + R.id.action_settings -> startActivity() } } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/PageView.kt new file mode 100644 index 000000000..7844f7e3f --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/PageView.kt @@ -0,0 +1,77 @@ +package io.legado.app.ui.widget + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.Canvas +import android.graphics.Rect +import android.graphics.drawable.GradientDrawable +import android.util.AttributeSet +import android.util.Log +import android.view.MotionEvent +import androidx.appcompat.widget.AppCompatTextView +import io.legado.app.utils.screenshot +import kotlin.math.abs + +class PageView(context: Context, attrs: AttributeSet) : AppCompatTextView(context, attrs) { + + private var bitmap: Bitmap? = null + + private var downX: Float = 0.toFloat() + private var offset: Float = 0.toFloat() + + private val srcRect: Rect = Rect() + private val destRect: Rect = Rect() + private val shadowDrawable: GradientDrawable + + init { + val shadowColors = intArrayOf(0x66111111, 0x00000000) + shadowDrawable = GradientDrawable( + GradientDrawable.Orientation.LEFT_RIGHT, shadowColors + ) + shadowDrawable.gradientType = GradientDrawable.LINEAR_GRADIENT + } + + override fun onDraw(canvas: Canvas?) { + canvas?.save() + super.onDraw(canvas) + canvas?.restore() + + + bitmap?.let { + srcRect.set(0, 0, width, height) + destRect.set(-width + offset.toInt(), 0, offset.toInt(), height) + canvas?.drawBitmap(it, srcRect, destRect, null) + addShadow(offset.toInt(), canvas) + } + } + + //添加阴影 + private fun addShadow(left: Int, canvas: Canvas?) { + canvas?.let { + shadowDrawable.setBounds(left, 0, left + 30, height) + shadowDrawable.draw(it) + } + } + + override fun onTouchEvent(event: MotionEvent?): Boolean { + when (event?.action) { + MotionEvent.ACTION_DOWN -> { + bitmap = screenshot() + Log.e("TAG", "bitmap == null: " + (bitmap == null)) + downX = event.x + offset = 0.toFloat() + invalidate() + } + MotionEvent.ACTION_MOVE -> { + offset = abs(event.x - downX) + invalidate() + } + MotionEvent.ACTION_UP -> { + bitmap = null + invalidate() + } + } + + return true + } +} diff --git a/app/src/main/java/io/legado/app/utils/FragmentExtensions.kt b/app/src/main/java/io/legado/app/utils/FragmentExtensions.kt index c81c734ad..f233929fb 100644 --- a/app/src/main/java/io/legado/app/utils/FragmentExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/FragmentExtensions.kt @@ -1,5 +1,8 @@ package io.legado.app.utils +import android.app.Activity +import android.app.Service +import android.content.Intent import android.content.res.ColorStateList import android.graphics.drawable.Drawable import androidx.annotation.ColorRes @@ -8,6 +11,7 @@ import androidx.core.content.edit import androidx.fragment.app.Fragment import org.jetbrains.anko.connectivityManager import org.jetbrains.anko.defaultSharedPreferences +import org.jetbrains.anko.internals.AnkoInternals fun Fragment.isOnline() = requireContext().connectivityManager.activeNetworkInfo?.isConnected == true @@ -54,4 +58,21 @@ val Fragment.isNightTheme: Boolean get() = getPrefBoolean("isNightTheme") val Fragment.isTransparentStatusBar: Boolean - get() = getPrefBoolean("transparentStatusBar") \ No newline at end of file + get() = getPrefBoolean("transparentStatusBar") + + +inline fun Fragment.startActivity(vararg params: Pair) = + AnkoInternals.internalStartActivity(requireActivity(), T::class.java, params) + + +inline fun Fragment.startActivityForResult(requestCode: Int, vararg params: Pair) = + startActivityForResult(AnkoInternals.createIntent(requireActivity(), T::class.java, params), requestCode) + +inline fun Fragment.startService(vararg params: Pair) = + AnkoInternals.internalStartService(requireActivity(), T::class.java, params) + +inline fun Fragment.stopService(vararg params: Pair) = + AnkoInternals.internalStopService(requireActivity(), T::class.java, params) + +inline fun Fragment.intentFor(vararg params: Pair): Intent = + AnkoInternals.createIntent(requireActivity(), T::class.java, params) \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/utils/ViewExtensions.kt b/app/src/main/java/io/legado/app/utils/ViewExtensions.kt index 50944d224..cbde9e3f1 100644 --- a/app/src/main/java/io/legado/app/utils/ViewExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/ViewExtensions.kt @@ -55,7 +55,7 @@ fun View.visible() { fun View.screenshot(): Bitmap? { return runCatching { - val screenshot = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565) + val screenshot = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) val c = Canvas(screenshot) c.translate(-scrollX.toFloat(), -scrollY.toFloat()) draw(c) diff --git a/app/src/main/res/layout/activity_read.xml b/app/src/main/res/layout/activity_read.xml index d829e291c..fc9704d8b 100644 --- a/app/src/main/res/layout/activity_read.xml +++ b/app/src/main/res/layout/activity_read.xml @@ -1,7 +1,17 @@ + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + \ No newline at end of file From 461f5ec6d652a990ea6c90227edf8b933758713c Mon Sep 17 00:00:00 2001 From: Administrator <1760316362@qq.com> Date: Fri, 2 Aug 2019 16:39:24 +0800 Subject: [PATCH 0530/1997] update --- .../io/legado/app/ui/sourcedebug/SourceDebugActivity.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt index 1e0cd7fef..0dda06020 100644 --- a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt +++ b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt @@ -31,6 +31,12 @@ class SourceDebugActivity : VMBaseActivity(R.layout.activity_s viewModel.init(intent.getStringExtra("key")) initRecyclerView() initSearchView() + viewModel.observe{state, msg-> + adapter.addItem(msg) + if (state == -1 || state == 1000) { + rotate_loading.hide() + } + } } private fun initRecyclerView() { From 3b18762616e596db66a95a6568cac724c5be848e Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 2 Aug 2019 16:54:06 +0800 Subject: [PATCH 0531/1997] up --- .../java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt index df76cda3b..21dd988ac 100644 --- a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt +++ b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt @@ -8,6 +8,7 @@ import io.legado.app.help.EventMessage import io.legado.app.model.WebBook import io.legado.app.model.webbook.SourceDebug import io.legado.app.utils.postEvent +import kotlinx.coroutines.launch class SourceDebugModel(application: Application) : BaseViewModel(application), SourceDebug.Callback { @@ -31,7 +32,9 @@ class SourceDebugModel(application: Application) : BaseViewModel(application), S } override fun printLog(state: Int, msg: String) { - postEvent(Bus.SOURCE_DEBUG_LOG, EventMessage.obtain(state, msg)) + launch { + postEvent(Bus.SOURCE_DEBUG_LOG, EventMessage.obtain(state, msg)) + } } override fun onCleared() { From 728ba09679970e90b1f6da02ba07a9a221163297 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 2 Aug 2019 17:10:37 +0800 Subject: [PATCH 0532/1997] up --- .../io/legado/app/ui/sourcedebug/SourceDebugActivity.kt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt index 0dda06020..9049bbc75 100644 --- a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt +++ b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt @@ -16,6 +16,7 @@ import io.legado.app.utils.getViewModel import io.legado.app.utils.hideSoftInput import kotlinx.android.synthetic.main.activity_source_debug.* import kotlinx.android.synthetic.main.view_title_bar.* +import kotlinx.coroutines.launch import org.jetbrains.anko.startActivityForResult import org.jetbrains.anko.toast @@ -32,9 +33,11 @@ class SourceDebugActivity : VMBaseActivity(R.layout.activity_s initRecyclerView() initSearchView() viewModel.observe{state, msg-> - adapter.addItem(msg) - if (state == -1 || state == 1000) { - rotate_loading.hide() + launch { + adapter.addItem(msg) + if (state == -1 || state == 1000) { + rotate_loading.hide() + } } } } From 27f7af26152694ea87272b21bd3a7a3884dec643 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 2 Aug 2019 17:53:17 +0800 Subject: [PATCH 0533/1997] up --- .../main/java/io/legado/app/data/dao/BookSourceDao.kt | 3 +++ .../io/legado/app/ui/booksource/BookSourceActivity.kt | 11 +++++++---- .../io/legado/app/ui/booksource/BookSourceAdapter.kt | 3 ++- .../legado/app/ui/booksource/BookSourceViewModel.kt | 11 +++++++++++ 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt index d93baa8fb..832f877ea 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt @@ -48,4 +48,7 @@ interface BookSourceDao { @Delete fun delete(vararg bookSource: BookSource) + + @get:Query("select min(customOrder) from book_sources") + val minOrder: Int } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt index 4be37daca..cd824cf00 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt @@ -19,7 +19,6 @@ import io.legado.app.base.VMBaseActivity import io.legado.app.data.entities.BookSource import io.legado.app.help.ItemTouchCallback import io.legado.app.lib.theme.ATH -import io.legado.app.ui.bookshelf.BookshelfViewModel import io.legado.app.ui.qrcode.QrCodeActivity import io.legado.app.ui.sourceedit.SourceEditActivity import io.legado.app.utils.getViewModel @@ -30,11 +29,11 @@ import kotlinx.coroutines.launch import org.jetbrains.anko.startActivity import org.jetbrains.anko.startActivityForResult -class BookSourceActivity : VMBaseActivity(R.layout.activity_book_source), +class BookSourceActivity : VMBaseActivity(R.layout.activity_book_source), BookSourceAdapter.CallBack, SearchView.OnQueryTextListener { - override val viewModel: BookshelfViewModel - get() = getViewModel(BookshelfViewModel::class.java) + override val viewModel: BookSourceViewModel + get() = getViewModel(BookSourceViewModel::class.java) private lateinit var adapter: BookSourceAdapter private var bookSourceLiveDate: LiveData>? = null @@ -139,6 +138,10 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity_ startActivity(Pair("data", bookSource.bookSourceUrl)) } + override fun topSource(bookSource: BookSource) { + viewModel.topSource(bookSource) + } + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) when (requestCode) { diff --git a/app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt b/app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt index 60680e083..1d6869cb4 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt @@ -83,7 +83,7 @@ class BookSourceAdapter : PagedListAdapter Date: Sat, 3 Aug 2019 00:45:29 +0800 Subject: [PATCH 0534/1997] up --- .../app/model/analyzeRule/AnalyzeByRegex.kt | 46 +++--- .../app/model/analyzeRule/AnalyzeRule.kt | 147 +++++++++++------- .../app/model/webbook/BookChapterList.kt | 3 + .../io/legado/app/model/webbook/BookList.kt | 3 + 4 files changed, 125 insertions(+), 74 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByRegex.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByRegex.kt index 8aee0c218..714a91256 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByRegex.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByRegex.kt @@ -70,7 +70,9 @@ object AnalyzeByRegex { val len = str.length while (index < len) { if (str[index] == '$') { - if (str[index + 1] == '{') { + if (index + 1 >= len) { + break + } else if (str[index + 1] == '{') { if (index > start) { ruleParam.add(str.substring(start, index)) ruleType.add(0) @@ -106,10 +108,29 @@ object AnalyzeByRegex { start = index } } else { - ++index + index++ + } + } else if (str[index] == '{') { + if (index + 1 >= len) { + break + } else if (str[index + 1] == '{') { + if (index > start) { + ruleParam.add(str.substring(start, index)) + ruleType.add(0) + start = index + } + while (index + 1 < len) { + if (str[index] == '}' && str[index + 1] == '}') { + ruleParam.add(str.substring(start + 2, index)) + ruleType.add(-11) + start = index + 2 + break + } + index++ + } } } else { - ++index + index++ } } if (index > start) { @@ -118,25 +139,6 @@ object AnalyzeByRegex { } } - // 存取字符串中的put&get参数 - fun checkKeys(ruleStr: String, analyzer: AnalyzeRule): String { - var str = ruleStr - if (str.contains("@put:{")) { - val putMatcher = Pattern.compile("@put:\\{([^,]*):([^\\}]*)\\}").matcher(str) - while (putMatcher.find()) { - str = str.replace(putMatcher.group(0), "") - analyzer.put(putMatcher.group(1), putMatcher.group(2)) - } - } - if (str.contains("@get:{")) { - val getMatcher = Pattern.compile("@get:\\{([^\\}]*)\\}").matcher(str) - while (getMatcher.find()) { - str = str.replace(getMatcher.group(), analyzer[getMatcher.group(1)] ?: "") - } - } - return str - } - // String数字转int数字的高效方法(利用ASCII值判断) private fun string2Int(s: String): Int { var r = 0 diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt index fead18fe8..5c4fc6c7f 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt @@ -1,16 +1,15 @@ package io.legado.app.model.analyzeRule -import android.annotation.SuppressLint import android.text.TextUtils import androidx.annotation.Keep import io.legado.app.constant.AppConst.SCRIPT_ENGINE -import io.legado.app.constant.Pattern.EXP_PATTERN import io.legado.app.constant.Pattern.JS_PATTERN import io.legado.app.data.entities.BaseBook import io.legado.app.utils.* import java.util.* import java.util.regex.Pattern import javax.script.SimpleBindings +import kotlin.collections.HashMap /** @@ -18,6 +17,7 @@ import javax.script.SimpleBindings * 统一解析接口 */ @Keep +@Suppress("unused") class AnalyzeRule(private var book: BaseBook? = null) { private var content: Any? = null private var baseUrl: String? = null @@ -121,6 +121,8 @@ class AnalyzeRule(private var book: BaseBook? = null) { if (ruleList.isNotEmpty()) { if (ruleList.isNotEmpty()) result = o for (rule in ruleList) { + putRule(rule.putMap) + rule.makeUpRule(result) result?.let { if (rule.rule.isNotEmpty()) { when (rule.mode) { @@ -129,7 +131,9 @@ class AnalyzeRule(private var book: BaseBook? = null) { getAnalyzeByJSonPath(it).getStringList(rule.rule) Mode.XPath -> result = getAnalyzeByXPath(it).getStringList(rule.rule) - else -> result = getAnalyzeByJSoup(it).getStringList(rule.rule) + Mode.Default -> result = getAnalyzeByJSoup(it).getStringList(rule.rule) + else -> { + } } } if (rule.replaceRegex.isNotEmpty() && result is List<*>) { @@ -189,6 +193,8 @@ class AnalyzeRule(private var book: BaseBook? = null) { content?.let { o -> if (ruleList.isNotEmpty()) result = o for (rule in ruleList) { + putRule(rule.putMap) + rule.makeUpRule(result) result?.let { if (rule.rule.isNotBlank()) { when (rule.mode) { @@ -200,6 +206,8 @@ class AnalyzeRule(private var book: BaseBook? = null) { } else { getAnalyzeByJSoup(it).getString(rule.rule) } + else -> { + } } } if (rule.replaceRegex.isNotEmpty()) { @@ -228,8 +236,11 @@ class AnalyzeRule(private var book: BaseBook? = null) { content?.let { o -> if (ruleList.isNotEmpty()) result = o for (rule in ruleList) { + putRule(rule.putMap) result?.let { when (rule.mode) { + Mode.Regex -> result = + AnalyzeByRegex.getElement(result.toString(), rule.rule.splitNotBlank("&&")) Mode.Js -> result = evalJS(rule.rule, it) Mode.Json -> result = getAnalyzeByJSonPath(it).getObject(rule.rule) Mode.XPath -> result = getAnalyzeByXPath(it).getElements(rule.rule) @@ -255,12 +266,12 @@ class AnalyzeRule(private var book: BaseBook? = null) { content?.let { o -> if (ruleList.isNotEmpty()) result = o for (rule in ruleList) { + putRule(rule.putMap) result?.let { when (rule.mode) { - Mode.Js -> { - if (result == null) result = content - result = evalJS(rule.rule, result) - } + Mode.Regex -> result = + AnalyzeByRegex.getElements(result.toString(), rule.rule.splitNotBlank("&&")) + Mode.Js -> result = evalJS(rule.rule, result) Mode.Json -> result = getAnalyzeByJSonPath(it).getList(rule.rule) Mode.XPath -> result = getAnalyzeByXPath(it).getElements(rule.rule) else -> result = getAnalyzeByJSoup(it).getElements(rule.rule) @@ -291,16 +302,16 @@ class AnalyzeRule(private var book: BaseBook? = null) { } /** - * 分离并执行put规则 + * 分离put规则 */ @Throws(Exception::class) - private fun splitPutRule(ruleStr: String): String { + private fun splitPutRule(ruleStr: String, putMap: HashMap): String { var vRuleStr = ruleStr val putMatcher = putPattern.matcher(vRuleStr) while (putMatcher.find()) { vRuleStr = vRuleStr.replace(putMatcher.group(), "") val map = GSON.fromJsonObject>(putMatcher.group(1)) - map?.let { putRule(map) } + map?.let { putMap.putAll(map) } } return vRuleStr } @@ -308,7 +319,7 @@ class AnalyzeRule(private var book: BaseBook? = null) { /** * 替换@get */ - fun replaceGet(ruleStr: String): String { + private fun replaceGet(ruleStr: String): String { var vRuleStr = ruleStr val getMatcher = getPattern.matcher(vRuleStr) while (getMatcher.find()) { @@ -341,33 +352,33 @@ class AnalyzeRule(private var book: BaseBook? = null) { } return vResult } - - /** - * 替换JS - */ - @SuppressLint("DefaultLocale") - @Throws(Exception::class) - private fun replaceJs(ruleStr: String): String { - var vRuleStr = ruleStr - if (vRuleStr.contains("{{") && vRuleStr.contains("}}")) { - var jsEval: Any - val sb = StringBuffer(vRuleStr.length) - val expMatcher = EXP_PATTERN.matcher(vRuleStr) - while (expMatcher.find()) { - jsEval = evalJS(expMatcher.group(1), content) - if (jsEval is String) { - expMatcher.appendReplacement(sb, jsEval) - } else if (jsEval is Double && jsEval % 1.0 == 0.0) { - expMatcher.appendReplacement(sb, String.format("%.0f", jsEval)) - } else { - expMatcher.appendReplacement(sb, jsEval.toString()) - } - } - expMatcher.appendTail(sb) - vRuleStr = sb.toString() - } - return vRuleStr - } +// +// /** +// * 替换JS +// */ +// @SuppressLint("DefaultLocale") +// @Throws(Exception::class) +// private fun replaceJs(ruleStr: String): String { +// var vRuleStr = ruleStr +// if (vRuleStr.contains("{{") && vRuleStr.contains("}}")) { +// var jsEval: Any +// val sb = StringBuffer(vRuleStr.length) +// val expMatcher = EXP_PATTERN.matcher(vRuleStr) +// while (expMatcher.find()) { +// jsEval = evalJS(expMatcher.group(1), content) +// if (jsEval is String) { +// expMatcher.appendReplacement(sb, jsEval) +// } else if (jsEval is Double && jsEval % 1.0 == 0.0) { +// expMatcher.appendReplacement(sb, String.format("%.0f", jsEval)) +// } else { +// expMatcher.appendReplacement(sb, jsEval.toString()) +// } +// } +// expMatcher.appendTail(sb) +// vRuleStr = sb.toString() +// } +// return vRuleStr +// } /** * 分解规则生成规则列表 @@ -386,27 +397,27 @@ class AnalyzeRule(private var book: BaseBook? = null) { } vRuleStr.startsWith("@Json:", true) -> { mode = Mode.Json + isRegex = true vRuleStr = vRuleStr.substring(6) } - else -> mode = if (isJSON) { - Mode.Json - } else { - Mode.Default + vRuleStr.startsWith(":") -> { + mode = Mode.Regex + vRuleStr = vRuleStr.substring(1) } + else -> mode = + when { + isRegex -> Mode.Regex + isJSON -> Mode.Json + else -> Mode.Default + } } - //分离put规则 - vRuleStr = splitPutRule(vRuleStr) - //替换get值 - vRuleStr = replaceGet(vRuleStr) - //替换js - vRuleStr = replaceJs(vRuleStr) - //拆分为列表 + //拆分为规则列表 var start = 0 var tmp: String val jsMatcher = JS_PATTERN.matcher(vRuleStr) while (jsMatcher.find()) { if (jsMatcher.start() > start) { - tmp = vRuleStr.substring(start, jsMatcher.start()).replace("\n".toRegex(), "").trim { it <= ' ' } + tmp = vRuleStr.substring(start, jsMatcher.start()).replace("\n", "").trim { it <= ' ' } if (!TextUtils.isEmpty(tmp)) { ruleList.add(SourceRule(tmp, mode)) } @@ -415,7 +426,7 @@ class AnalyzeRule(private var book: BaseBook? = null) { start = jsMatcher.end() } if (vRuleStr.length > start) { - tmp = vRuleStr.substring(start).replace("\n".toRegex(), "").trim { it <= ' ' } + tmp = vRuleStr.substring(start).replace("\n", "").trim { it <= ' ' } if (!TextUtils.isEmpty(tmp)) { ruleList.add(SourceRule(tmp, mode)) } @@ -432,6 +443,9 @@ class AnalyzeRule(private var book: BaseBook? = null) { internal var replaceRegex = "" internal var replacement = "" internal var replaceFirst = false + internal val putMap = HashMap() + private val ruleParam = ArrayList() + private val ruleType = ArrayList() init { this.mode = mainMode @@ -475,12 +489,41 @@ class AnalyzeRule(private var book: BaseBook? = null) { if (ruleStrS.size > 3) { replaceFirst = true } + //分离put + rule = splitPutRule(rule, putMap) + rule = replaceGet(rule) + // 拆分表达式替换规则 + AnalyzeByRegex.splitRegexRule(rule, ruleParam, ruleType) + } + + fun makeUpRule(result: Any?) { + val infoVal = StringBuilder() + var j = ruleParam.size + while (j-- > 0) { + val regType = ruleType[j] + if (regType > 0) { + @Suppress("UNCHECKED_CAST") + infoVal.insert(0, (result as List)[regType]) + } else if (regType < 0) { + val jsEval: Any = evalJS(ruleParam[j], result) + if (jsEval is String) { + infoVal.insert(0, jsEval) + } else if (jsEval is Double && jsEval % 1.0 == 0.0) { + infoVal.insert(0, String.format("%.0f", jsEval)) + } else { + infoVal.insert(0, jsEval.toString()) + } + } else { + infoVal.insert(0, ruleParam[j]) + } + } + rule = infoVal.toString() } } enum class Mode { - XPath, Json, Default, Js + XPath, Json, Default, Js, Regex } fun put(key: String, value: String): String { diff --git a/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt b/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt index 6719aff4c..2bf02391e 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt @@ -41,6 +41,9 @@ object BookChapterList { reverse = true listRule = listRule.substring(1) } + if (listRule.startsWith("+")) { + listRule = listRule.substring(1) + } var chapterData = analyzeChapterList(body, baseUrl, tocRule, listRule, book, bookSource, printLog = true) chapterData.chapterList?.let { chapterList.addAll(it) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookList.kt b/app/src/main/java/io/legado/app/model/webbook/BookList.kt index 096d6d83c..06a8ea92d 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookList.kt @@ -48,6 +48,9 @@ object BookList { reverse = true ruleList = ruleList.substring(1) } + if (ruleList.startsWith("+")) { + ruleList = ruleList.substring(1) + } SourceDebug.printLog(bookSource.bookSourceUrl, 1, "解析书籍列表") collections = analyzeRule.getElements(ruleList) if (collections.isEmpty() && bookSource.bookUrlPattern.isNullOrEmpty()) { From 170007e89364b5dd9ec597edc19123f266b5c9ac Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 3 Aug 2019 00:47:05 +0800 Subject: [PATCH 0535/1997] up --- .../app/model/analyzeRule/AnalyzeRule.kt | 28 +------------------ 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt index 5c4fc6c7f..efb1c2f18 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt @@ -352,33 +352,6 @@ class AnalyzeRule(private var book: BaseBook? = null) { } return vResult } -// -// /** -// * 替换JS -// */ -// @SuppressLint("DefaultLocale") -// @Throws(Exception::class) -// private fun replaceJs(ruleStr: String): String { -// var vRuleStr = ruleStr -// if (vRuleStr.contains("{{") && vRuleStr.contains("}}")) { -// var jsEval: Any -// val sb = StringBuffer(vRuleStr.length) -// val expMatcher = EXP_PATTERN.matcher(vRuleStr) -// while (expMatcher.find()) { -// jsEval = evalJS(expMatcher.group(1), content) -// if (jsEval is String) { -// expMatcher.appendReplacement(sb, jsEval) -// } else if (jsEval is Double && jsEval % 1.0 == 0.0) { -// expMatcher.appendReplacement(sb, String.format("%.0f", jsEval)) -// } else { -// expMatcher.appendReplacement(sb, jsEval.toString()) -// } -// } -// expMatcher.appendTail(sb) -// vRuleStr = sb.toString() -// } -// return vRuleStr -// } /** * 分解规则生成规则列表 @@ -491,6 +464,7 @@ class AnalyzeRule(private var book: BaseBook? = null) { } //分离put rule = splitPutRule(rule, putMap) + //get替换 rule = replaceGet(rule) // 拆分表达式替换规则 AnalyzeByRegex.splitRegexRule(rule, ruleParam, ruleType) From 6b6beac16b96b42fef474f2373ea857134a03ba2 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 3 Aug 2019 09:00:37 +0800 Subject: [PATCH 0536/1997] up --- .../main/java/io/legado/app/help/http/HttpHelper.kt | 4 +--- .../main/java/io/legado/app/help/http/SSLHelper.kt | 12 ++++++++++++ .../java/io/legado/app/model/webbook/BookContent.kt | 3 ++- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/http/HttpHelper.kt b/app/src/main/java/io/legado/app/help/http/HttpHelper.kt index 81602c87e..342d0a1e3 100644 --- a/app/src/main/java/io/legado/app/help/http/HttpHelper.kt +++ b/app/src/main/java/io/legado/app/help/http/HttpHelper.kt @@ -41,6 +41,7 @@ object HttpHelper { .connectTimeout(15, TimeUnit.SECONDS) .writeTimeout(15, TimeUnit.SECONDS) .readTimeout(15, TimeUnit.SECONDS) + .sslSocketFactory(SSLHelper.unsafeSSLSocketFactory, SSLHelper.unsafeTrustManager) .retryOnConnectionFailure(true) .hostnameVerifier(SSLHelper.unsafeHostnameVerifier) .connectionSpecs(specs) @@ -49,9 +50,6 @@ object HttpHelper { .protocols(listOf(Protocol.HTTP_1_1)) .addInterceptor(getHeaderInterceptor()) - SSLHelper.getSslSocketFactory()?.let { - builder.sslSocketFactory(it.sSLSocketFactory, it.trustManager) - } return builder.build() } diff --git a/app/src/main/java/io/legado/app/help/http/SSLHelper.kt b/app/src/main/java/io/legado/app/help/http/SSLHelper.kt index c78fbdcd5..8fc40d27c 100644 --- a/app/src/main/java/io/legado/app/help/http/SSLHelper.kt +++ b/app/src/main/java/io/legado/app/help/http/SSLHelper.kt @@ -5,6 +5,7 @@ import java.io.InputStream import java.security.KeyManagementException import java.security.KeyStore import java.security.NoSuchAlgorithmException +import java.security.SecureRandom import java.security.cert.CertificateException import java.security.cert.CertificateFactory import java.security.cert.X509Certificate @@ -33,6 +34,17 @@ object SSLHelper { } } + val unsafeSSLSocketFactory: SSLSocketFactory + get() { + try { + val sslContext = SSLContext.getInstance("SSL") + sslContext.init(null, arrayOf(unsafeTrustManager), SecureRandom()) + return sslContext.socketFactory + } catch (e: Exception) { + throw RuntimeException(e) + } + } + /** * 此类是用于主机名验证的基接口。 在握手期间,如果 URL 的主机名和服务器的标识主机名不匹配, * 则验证机制可以回调此接口的实现程序来确定是否应该允许此连接。策略可以是基于证书的或依赖于其他验证方案。 diff --git a/app/src/main/java/io/legado/app/model/webbook/BookContent.kt b/app/src/main/java/io/legado/app/model/webbook/BookContent.kt index 9d41cb4aa..a85ccb28c 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookContent.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookContent.kt @@ -8,6 +8,7 @@ import io.legado.app.data.entities.rule.ContentRule import io.legado.app.model.analyzeRule.AnalyzeRule import io.legado.app.model.analyzeRule.AnalyzeUrl import io.legado.app.utils.NetworkUtils +import io.legado.app.utils.htmlFormat import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.withContext import retrofit2.Response @@ -83,7 +84,7 @@ object BookContent { analyzeRule.getStringList(contentRule.nextContentUrl ?: "", true)?.let { nextUrlList.addAll(it) } - val content = analyzeRule.getString(contentRule.content ?: "") ?: "" + val content = analyzeRule.getString(contentRule.content ?: "")?.htmlFormat() ?: "" return ContentData(content, nextUrlList) } } \ No newline at end of file From 4b9d68b3ba2cdf509502cf362e33fe35c2d28862 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 3 Aug 2019 09:05:58 +0800 Subject: [PATCH 0537/1997] up --- .../io/legado/app/ui/booksource/BookSourceActivity.kt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt index cd824cf00..fd849ad63 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt @@ -154,4 +154,12 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity } } } + + override fun finish() { + if (search_view.query.isNullOrEmpty()) { + super.finish() + } else { + search_view.setQuery("", true) + } + } } \ No newline at end of file From 077870db5778c2fbde189febf6b50f25333acae0 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 3 Aug 2019 09:37:52 +0800 Subject: [PATCH 0538/1997] up --- .../main/java/io/legado/app/model/analyzeRule/AnalyzeByXPath.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByXPath.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByXPath.kt index 8ba053f40..23030393c 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByXPath.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByXPath.kt @@ -49,7 +49,7 @@ class AnalyzeByXPath { } } if (rules.size == 1) { - return jxDocument!!.selN(rules[0]) + return jxDocument?.selN(rules[0]) } else { val results = ArrayList>() for (rl in rules) { From 0d2ee98480b29fc82bb1d449217da31eda0713b8 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 3 Aug 2019 09:55:40 +0800 Subject: [PATCH 0539/1997] up --- .../app/model/analyzeRule/AnalyzeUrl.kt | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt index f6b0b83fd..bb32ec0fa 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt @@ -46,8 +46,7 @@ class AnalyzeUrl( private set var path: String? = null private set - var queryStr: String? = null - private set + private var queryStr: String? = null private val fieldMap = LinkedHashMap() private val headerMap = HashMap() private var charset: String? = null @@ -153,10 +152,6 @@ class AnalyzeUrl( body = RequestBody.create(jsonType, it) } else { analyzeFields(it) - val builder = FormBody.Builder() - for (item in fieldMap) - builder.add(item.key, item.value) - body = builder.build() } } ?: let { body = FormBody.Builder().build() @@ -206,13 +201,21 @@ class AnalyzeUrl( fun getResponseAsync(): Deferred> { return when { - method == Method.POST -> HttpHelper.getApiService( - baseUrl - ).postBodyAsync( - url, - body, - headerMap - ) + method == Method.POST -> { + if (fieldMap.isNotEmpty()) { + HttpHelper.getApiService( + baseUrl + ).postMapAsync(url, fieldMap, headerMap) + } else { + HttpHelper.getApiService( + baseUrl + ).postBodyAsync( + url, + body, + headerMap + ) + } + } fieldMap.isEmpty() -> HttpHelper.getApiService( baseUrl ).getAsync(url, headerMap) From 26ffcc9a461db570d9f64ec8da2dcce32a9e872c Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 3 Aug 2019 11:15:35 +0800 Subject: [PATCH 0540/1997] up --- .../app/model/analyzeRule/AnalyzeRule.kt | 103 +++++++++--------- 1 file changed, 52 insertions(+), 51 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt index efb1c2f18..47c0bea3b 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt @@ -120,30 +120,29 @@ class AnalyzeRule(private var book: BaseBook? = null) { content?.let { o -> if (ruleList.isNotEmpty()) { if (ruleList.isNotEmpty()) result = o - for (rule in ruleList) { - putRule(rule.putMap) - rule.makeUpRule(result) + for (sourceRule in ruleList) { + putRule(sourceRule.putMap) + sourceRule.makeUpRule(result) result?.let { - if (rule.rule.isNotEmpty()) { - when (rule.mode) { - Mode.Js -> result = evalJS(rule.rule, result) + if (sourceRule.rule.isNotEmpty()) { + when (sourceRule.mode) { + Mode.Js -> result = evalJS(sourceRule.rule, result) Mode.Json -> result = - getAnalyzeByJSonPath(it).getStringList(rule.rule) + getAnalyzeByJSonPath(it).getStringList(sourceRule.rule) Mode.XPath -> result = - getAnalyzeByXPath(it).getStringList(rule.rule) - Mode.Default -> result = getAnalyzeByJSoup(it).getStringList(rule.rule) - else -> { - } + getAnalyzeByXPath(it).getStringList(sourceRule.rule) + Mode.Default -> result = getAnalyzeByJSoup(it).getStringList(sourceRule.rule) + else -> result = sourceRule.rule } } - if (rule.replaceRegex.isNotEmpty() && result is List<*>) { + if (sourceRule.replaceRegex.isNotEmpty() && result is List<*>) { val newList = ArrayList() for (item in result as List<*>) { - newList.add(replaceRegex(item.toString(), rule)) + newList.add(replaceRegex(item.toString(), sourceRule)) } result = newList - } else if (rule.replaceRegex.isNotEmpty()) { - result = replaceRegex(result.toString(), rule) + } else if (sourceRule.replaceRegex.isNotEmpty()) { + result = replaceRegex(result.toString(), sourceRule) } } } @@ -192,26 +191,25 @@ class AnalyzeRule(private var book: BaseBook? = null) { var result: Any? = null content?.let { o -> if (ruleList.isNotEmpty()) result = o - for (rule in ruleList) { - putRule(rule.putMap) - rule.makeUpRule(result) + for (sourceRule in ruleList) { + putRule(sourceRule.putMap) + sourceRule.makeUpRule(result) result?.let { - if (rule.rule.isNotBlank()) { - when (rule.mode) { - Mode.Js -> result = evalJS(rule.rule, it) - Mode.Json -> result = getAnalyzeByJSonPath(it).getString(rule.rule) - Mode.XPath -> result = getAnalyzeByXPath(it).getString(rule.rule) + if (sourceRule.rule.isNotBlank()) { + when (sourceRule.mode) { + Mode.Js -> result = evalJS(sourceRule.rule, it) + Mode.Json -> result = getAnalyzeByJSonPath(it).getString(sourceRule.rule) + Mode.XPath -> result = getAnalyzeByXPath(it).getString(sourceRule.rule) Mode.Default -> result = if (isUrl) { - getAnalyzeByJSoup(it).getString0(rule.rule) + getAnalyzeByJSoup(it).getString0(sourceRule.rule) } else { - getAnalyzeByJSoup(it).getString(rule.rule) - } - else -> { + getAnalyzeByJSoup(it).getString(sourceRule.rule) } + else -> result = sourceRule.rule } } - if (rule.replaceRegex.isNotEmpty()) { - result = replaceRegex(result.toString(), rule) + if (sourceRule.replaceRegex.isNotEmpty()) { + result = replaceRegex(result.toString(), sourceRule) } } } @@ -235,19 +233,19 @@ class AnalyzeRule(private var book: BaseBook? = null) { val ruleList = splitSourceRule(ruleStr) content?.let { o -> if (ruleList.isNotEmpty()) result = o - for (rule in ruleList) { - putRule(rule.putMap) + for (sourceRule in ruleList) { + putRule(sourceRule.putMap) result?.let { - when (rule.mode) { + when (sourceRule.mode) { Mode.Regex -> result = - AnalyzeByRegex.getElement(result.toString(), rule.rule.splitNotBlank("&&")) - Mode.Js -> result = evalJS(rule.rule, it) - Mode.Json -> result = getAnalyzeByJSonPath(it).getObject(rule.rule) - Mode.XPath -> result = getAnalyzeByXPath(it).getElements(rule.rule) - else -> result = getAnalyzeByJSoup(it).getElements(rule.rule) + AnalyzeByRegex.getElement(result.toString(), sourceRule.rule.splitNotBlank("&&")) + Mode.Js -> result = evalJS(sourceRule.rule, it) + Mode.Json -> result = getAnalyzeByJSonPath(it).getObject(sourceRule.rule) + Mode.XPath -> result = getAnalyzeByXPath(it).getElements(sourceRule.rule) + else -> result = getAnalyzeByJSoup(it).getElements(sourceRule.rule) } - if (rule.replaceRegex.isNotEmpty()) { - result = replaceRegex(result.toString(), rule) + if (sourceRule.replaceRegex.isNotEmpty()) { + result = replaceRegex(result.toString(), sourceRule) } } } @@ -265,19 +263,19 @@ class AnalyzeRule(private var book: BaseBook? = null) { val ruleList = splitSourceRule(ruleStr) content?.let { o -> if (ruleList.isNotEmpty()) result = o - for (rule in ruleList) { - putRule(rule.putMap) + for (sourceRule in ruleList) { + putRule(sourceRule.putMap) result?.let { - when (rule.mode) { + when (sourceRule.mode) { Mode.Regex -> result = - AnalyzeByRegex.getElements(result.toString(), rule.rule.splitNotBlank("&&")) - Mode.Js -> result = evalJS(rule.rule, result) - Mode.Json -> result = getAnalyzeByJSonPath(it).getList(rule.rule) - Mode.XPath -> result = getAnalyzeByXPath(it).getElements(rule.rule) - else -> result = getAnalyzeByJSoup(it).getElements(rule.rule) + AnalyzeByRegex.getElements(result.toString(), sourceRule.rule.splitNotBlank("&&")) + Mode.Js -> result = evalJS(sourceRule.rule, result) + Mode.Json -> result = getAnalyzeByJSonPath(it).getList(sourceRule.rule) + Mode.XPath -> result = getAnalyzeByXPath(it).getElements(sourceRule.rule) + else -> result = getAnalyzeByJSoup(it).getElements(sourceRule.rule) } - if (rule.replaceRegex.isNotEmpty()) { - result = replaceRegex(result.toString(), rule) + if (sourceRule.replaceRegex.isNotEmpty()) { + result = replaceRegex(result.toString(), sourceRule) } } } @@ -370,11 +368,11 @@ class AnalyzeRule(private var book: BaseBook? = null) { } vRuleStr.startsWith("@Json:", true) -> { mode = Mode.Json - isRegex = true vRuleStr = vRuleStr.substring(6) } vRuleStr.startsWith(":") -> { mode = Mode.Regex + isRegex = true vRuleStr = vRuleStr.substring(1) } else -> mode = @@ -477,7 +475,10 @@ class AnalyzeRule(private var book: BaseBook? = null) { val regType = ruleType[j] if (regType > 0) { @Suppress("UNCHECKED_CAST") - infoVal.insert(0, (result as List)[regType]) + val resultList = result as List + if (resultList.size > regType) { + infoVal.insert(0, resultList[regType]) + } } else if (regType < 0) { val jsEval: Any = evalJS(ruleParam[j], result) if (jsEval is String) { From 33fe5451ffcb328acb42f698d81efb5507235d24 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 3 Aug 2019 11:59:37 +0800 Subject: [PATCH 0541/1997] up --- .../main/java/io/legado/app/model/analyzeRule/AnalyzeByRegex.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByRegex.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByRegex.kt index 714a91256..ce0d385f7 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByRegex.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByRegex.kt @@ -128,6 +128,8 @@ object AnalyzeByRegex { } index++ } + } else { + index++ } } else { index++ From f48aee3bb29d2bd7ae62195ac23b3c609bb8dc0a Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 3 Aug 2019 12:09:39 +0800 Subject: [PATCH 0542/1997] up --- app/src/main/java/io/legado/app/model/webbook/BookInfo.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt b/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt index f678e5ed2..d3d043a0b 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt @@ -57,6 +57,7 @@ object BookInfo { analyzeRule.getString(infoRule.wordCount ?: "")?.let { if (it.isNotEmpty()) book.wordCount = it } + SourceDebug.printLog(bookSource.bookSourceUrl, 1, book.wordCount ?: "") SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取最新章节") analyzeRule.getString(infoRule.lastChapter ?: "")?.let { if (it.isNotEmpty()) book.latestChapterTitle = it From c785a08e81374857f99f93c15b44d3fdae99d7d0 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 3 Aug 2019 12:24:50 +0800 Subject: [PATCH 0543/1997] up --- .../java/io/legado/app/model/analyzeRule/AnalyzeByRegex.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByRegex.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByRegex.kt index ce0d385f7..7518aa57d 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByRegex.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByRegex.kt @@ -16,7 +16,7 @@ object AnalyzeByRegex { return if (vIndex + 1 == regs.size) { // 新建容器 val info = arrayListOf() - for (groupIndex in 0 until resM.groupCount()) { + for (groupIndex in 0..resM.groupCount()) { info.add(resM.group(groupIndex)) } info @@ -43,7 +43,7 @@ object AnalyzeByRegex { do { // 新建容器 val info = arrayListOf() - for (groupIndex in 0 until resM.groupCount()) { + for (groupIndex in 0..resM.groupCount()) { info.add(resM.group(groupIndex)) } books.add(info) From 43d73a8b42787ee2ee7d00566af44273525146e1 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 3 Aug 2019 18:18:36 +0800 Subject: [PATCH 0544/1997] up --- app/src/main/res/layout/item_search.xml | 89 +++++++++++++++++++++++-- 1 file changed, 83 insertions(+), 6 deletions(-) diff --git a/app/src/main/res/layout/item_search.xml b/app/src/main/res/layout/item_search.xml index 88303c6f6..ff3b1149b 100644 --- a/app/src/main/res/layout/item_search.xml +++ b/app/src/main/res/layout/item_search.xml @@ -1,18 +1,95 @@ + + android:layout_margin="8dp" + android:text="@string/app_name" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toEndOf="@+id/iv_cover" + app:layout_constraintTop_toTopOf="parent" /> + + + + + + + + + + + + + + + + + + \ No newline at end of file From c41ab2d8b9d77eb24d04d117d0686bd8c511546e Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 3 Aug 2019 20:59:24 +0800 Subject: [PATCH 0545/1997] up --- .../io/legado/app/data/dao/BookSourceDao.kt | 3 + .../io/legado/app/ui/search/SearchActivity.kt | 19 ++++- .../legado/app/ui/search/SearchViewModel.kt | 83 ++++--------------- 3 files changed, 39 insertions(+), 66 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt index 832f877ea..ddc2fdc1b 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt @@ -25,6 +25,9 @@ interface BookSourceDao { @get:Query("select * from book_sources order by customOrder asc") val all: List + @get:Query("select * from book_sources where enabled = 1 order by customOrder asc") + val allEnabled: List + @Query("select * from book_sources where bookSourceUrl = :key") fun findByKey(key: String): BookSource? diff --git a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt index cc9b7a76b..3d6dfb1dc 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt @@ -2,6 +2,7 @@ package io.legado.app.ui.search import android.os.Bundle import android.view.View +import androidx.appcompat.widget.SearchView import io.legado.app.R import io.legado.app.base.VMBaseActivity import io.legado.app.lib.theme.ATH @@ -17,7 +18,6 @@ class SearchActivity : VMBaseActivity(R.layout.activity_search) override fun onActivityCreated(savedInstanceState: Bundle?) { initSearchView() initRecyclerView() - viewModel.search() } private fun initSearchView() { @@ -26,6 +26,23 @@ class SearchActivity : VMBaseActivity(R.layout.activity_search) search_view.isSubmitButtonEnabled = true search_view.queryHint = getString(R.string.search_book_key) search_view.clearFocus() + search_view.setOnQueryTextListener(object : SearchView.OnQueryTextListener { + override fun onQueryTextSubmit(query: String?): Boolean { + query?.let { + viewModel.search(it, { + content_view.showProgressView() + }, { + + }) + } + return true + } + + override fun onQueryTextChange(newText: String?): Boolean { + return false + } + + }) intent.getStringExtra("key")?.let { search_view.setQuery(it, true) } diff --git a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt b/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt index d3dddb787..3ca042ad0 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt @@ -4,85 +4,38 @@ import android.app.Application import android.util.Log import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData +import io.legado.app.App import io.legado.app.base.BaseViewModel import io.legado.app.data.api.CommonHttpApi import io.legado.app.data.entities.SearchBook +import io.legado.app.help.coroutine.CompositeCoroutine import io.legado.app.help.http.HttpHelper +import io.legado.app.model.WebBook import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch import kotlinx.coroutines.withContext class SearchViewModel(application: Application) : BaseViewModel(application) { - - val searchBooks: LiveData> = MutableLiveData() - + val tasks: CompositeCoroutine = CompositeCoroutine() + val searchBookList = arrayListOf() + val searchBooksData: LiveData> = MutableLiveData() + var searchPage = 0 private val channel = Channel()//协程之间通信 - fun search(start: (() -> Unit)? = null, finally: (() -> Unit)? = null) { - launch { - repeat(1000) { - channel.send(it) + fun search(key: String, start: (() -> Unit)? = null, finally: (() -> Unit)? = null) { + if (key.isEmpty()) return + start?.invoke() + execute { + val bookSourceList = App.db.bookSourceDao().allEnabled + for (item in bookSourceList) { + val search = WebBook(item).searchBook(key, searchPage) + .onSuccess { searchBookS -> + searchBookS?.let { searchBookList.addAll(it) } + } + tasks.add(search) } - } - - - val c = execute { - val response: String = HttpHelper.getApiService( - "http://www.baidu.com" - ).get("http://www.baidu.com").await() - - delay(2000L) - - response } - .onStart { - Log.e("TAG!", "start") - start?.let { it() } - } - .onSuccess { - Log.e("TAG!", "success: $it") - } - .onError { - Log.e("TAG!", "error: $it") - } - .onFinally { - Log.e("TAG!", "finally") - if (finally != null) { - finally() - } - } - - val c2 = plus(c) -// .timeout { 100L } -// .onErrorReturn { "error return2" } - .onStart { - //会拦截掉c的onStart - Log.e("TAG!", "start2") - start?.let { it() } - } -// .onSuccess { -// Log.e("TAG!", "success2: $it") -// } - .onError { - Log.e("TAG!", "error2: $it") - } - .onFinally { - Log.e("TAG!", "finally2") - if (finally != null) { - finally() - } - - Log.e("TAG!", "rec2: " + channel.receive()) - } - -// execute { -// test(this) -// }.onSuccess { -// println("size: ${it?.size} $it") -// } } suspend fun test(scope: CoroutineScope): MutableList { From a707fefc798faf01e98c7b4e34887876ebb134ce Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 3 Aug 2019 21:09:33 +0800 Subject: [PATCH 0546/1997] up --- .../main/java/io/legado/app/ui/search/SearchActivity.kt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt index 3d6dfb1dc..bba1721af 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt @@ -3,6 +3,7 @@ package io.legado.app.ui.search import android.os.Bundle import android.view.View import androidx.appcompat.widget.SearchView +import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.R import io.legado.app.base.VMBaseActivity import io.legado.app.lib.theme.ATH @@ -15,9 +16,11 @@ class SearchActivity : VMBaseActivity(R.layout.activity_search) override val viewModel: SearchViewModel get() = getViewModel(SearchViewModel::class.java) + private lateinit var adapter: SearchAdapter + override fun onActivityCreated(savedInstanceState: Bundle?) { - initSearchView() initRecyclerView() + initSearchView() } private fun initSearchView() { @@ -50,6 +53,9 @@ class SearchActivity : VMBaseActivity(R.layout.activity_search) private fun initRecyclerView() { ATH.applyEdgeEffectColor(rv_search_list) + adapter = SearchAdapter(this) + rv_search_list.layoutManager = LinearLayoutManager(this) + rv_search_list.adapter = adapter } } From 892c53a825c2109ad2d46aa81ea7b459664c94d9 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 3 Aug 2019 21:12:40 +0800 Subject: [PATCH 0547/1997] up --- .../java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt index 6e82de8df..af66e4031 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt @@ -105,8 +105,6 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { toast("You swiped the item!") - // TODO() - // remove((viewHolder as TodoViewHolder).todo) } }).attachToRecyclerView(rv_replace_rule) From 0f0bd2587c235189094e12b075c62b1822930b3b Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 3 Aug 2019 21:15:23 +0800 Subject: [PATCH 0548/1997] up --- .../main/java/io/legado/app/ui/main/my/PreferenceFragment.kt | 3 ++- app/src/main/res/xml/pref_main.xml | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/main/my/PreferenceFragment.kt b/app/src/main/java/io/legado/app/ui/main/my/PreferenceFragment.kt index 4f24b9e75..5b6eabd1c 100644 --- a/app/src/main/java/io/legado/app/ui/main/my/PreferenceFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/my/PreferenceFragment.kt @@ -8,12 +8,12 @@ import androidx.preference.PreferenceFragmentCompat import io.legado.app.App import io.legado.app.R import io.legado.app.lib.theme.ATH -import io.legado.app.lib.theme.ThemeStore import io.legado.app.ui.about.AboutActivity import io.legado.app.ui.about.DonateActivity import io.legado.app.ui.booksource.BookSourceActivity import io.legado.app.ui.config.ConfigActivity import io.legado.app.ui.config.ConfigViewModel +import io.legado.app.ui.replacerule.ReplaceRuleActivity import org.jetbrains.anko.startActivity class PreferenceFragment : PreferenceFragmentCompat(), @@ -50,6 +50,7 @@ class PreferenceFragment : PreferenceFragmentCompat(), preference?.let { when (preference.key) { "bookSourceManage" -> context?.startActivity() + "replaceManage" -> context?.startActivity() "setting" -> context?.startActivity( Pair("configType", ConfigViewModel.TYPE_CONFIG) ) diff --git a/app/src/main/res/xml/pref_main.xml b/app/src/main/res/xml/pref_main.xml index c187a7199..cf9f19b53 100644 --- a/app/src/main/res/xml/pref_main.xml +++ b/app/src/main/res/xml/pref_main.xml @@ -7,6 +7,11 @@ android:title="书源管理" app:iconSpaceReserved="false" /> + + Date: Sat, 3 Aug 2019 21:19:47 +0800 Subject: [PATCH 0549/1997] up --- app/src/main/res/layout/item_relace_rule.xml | 6 +++--- app/src/main/res/values/colors.xml | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/app/src/main/res/layout/item_relace_rule.xml b/app/src/main/res/layout/item_relace_rule.xml index 9e0466b92..6f145f350 100644 --- a/app/src/main/res/layout/item_relace_rule.xml +++ b/app/src/main/res/layout/item_relace_rule.xml @@ -13,7 +13,7 @@ android:contentDescription="@string/edit" android:src="@drawable/ic_edit" android:visibility="gone" - app:tint="@color/text_default" + app:tint="@color/tv_text_default" app:layout_constraintEnd_toStartOf="@id/iv_delete" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintTop_toTopOf="parent" /> @@ -27,7 +27,7 @@ android:contentDescription="@string/delete" android:src="@drawable/ic_clear_all" android:visibility="gone" - app:tint="@color/text_default" + app:tint="@color/tv_text_default" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintTop_toTopOf="parent" /> @@ -54,7 +54,7 @@ android:paddingBottom="16dp" android:textSize="16sp" android:text="Item Name" - android:textColor="@color/text_default" + android:textColor="@color/tv_text_default" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toEndOf="@id/cb_selected" diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index e26e29ab2..06b21555d 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -3,10 +3,8 @@ @color/md_light_blue_500 @color/md_light_blue_600 @color/md_pink_A400 - #222222 #66666666 - #eb4333 #439b53 From fac2bb44a6b725fd4db66329d17e5d3d7cae6300 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 3 Aug 2019 21:20:22 +0800 Subject: [PATCH 0550/1997] up --- app/src/main/res/layout/activity_replace_rule.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/layout/activity_replace_rule.xml b/app/src/main/res/layout/activity_replace_rule.xml index 2d5f59c5e..116ac4aef 100644 --- a/app/src/main/res/layout/activity_replace_rule.xml +++ b/app/src/main/res/layout/activity_replace_rule.xml @@ -16,7 +16,7 @@ Date: Sat, 3 Aug 2019 21:54:31 +0800 Subject: [PATCH 0551/1997] up --- .../java/io/legado/app/data/AppDatabase.kt | 3 ++- .../io/legado/app/data/dao/RssSourceDao.kt | 16 ++++++++++++++ .../io/legado/app/data/entities/RssSource.kt | 3 ++- .../io/legado/app/ui/main/rss/RssAdapter.kt | 1 + .../io/legado/app/ui/main/rss/RssFragment.kt | 21 ++++++++++++++++++- 5 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt diff --git a/app/src/main/java/io/legado/app/data/AppDatabase.kt b/app/src/main/java/io/legado/app/data/AppDatabase.kt index 5c62c01dc..877054299 100644 --- a/app/src/main/java/io/legado/app/data/AppDatabase.kt +++ b/app/src/main/java/io/legado/app/data/AppDatabase.kt @@ -12,7 +12,7 @@ import io.legado.app.data.entities.* @Database( entities = [Book::class, BookGroup::class, BookSource::class, BookChapter::class, ReplaceRule::class, SearchBook::class, - SearchKeyword::class, SourceCookie::class], + SearchKeyword::class, SourceCookie::class, RssSourceDao::class], version = 1, exportSchema = true ) @@ -56,4 +56,5 @@ abstract class AppDatabase : RoomDatabase() { abstract fun searchBookDao(): SearchBookDao abstract fun searchKeywordDao(): SearchKeywordDao abstract fun sourceCookieDao(): SourceCookieDao + abstract fun rssSourceDao(): RssSourceDao } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt b/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt new file mode 100644 index 000000000..49532a846 --- /dev/null +++ b/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt @@ -0,0 +1,16 @@ +package io.legado.app.data.dao + +import androidx.paging.DataSource +import androidx.room.Dao +import androidx.room.Query +import io.legado.app.data.entities.RssSource + +@Dao +interface RssSourceDao { + + @Query("SELECT * FROM rssSources") + fun observeAll(): DataSource.Factory + + @Query("SELECT * FROM rssSources where enabled = 1") + fun observeEnabled(): DataSource.Factory +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/data/entities/RssSource.kt b/app/src/main/java/io/legado/app/data/entities/RssSource.kt index 028740ee0..f18df8b03 100644 --- a/app/src/main/java/io/legado/app/data/entities/RssSource.kt +++ b/app/src/main/java/io/legado/app/data/entities/RssSource.kt @@ -4,5 +4,6 @@ import androidx.room.Entity @Entity(tableName = "rssSources") data class RssSource( - var sourceName: String + var sourceName: String, + var enabled: Boolean = true ) \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/rss/RssAdapter.kt b/app/src/main/java/io/legado/app/ui/main/rss/RssAdapter.kt index bcf752a39..cbce98ce0 100644 --- a/app/src/main/java/io/legado/app/ui/main/rss/RssAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/rss/RssAdapter.kt @@ -8,5 +8,6 @@ class RssAdapter { class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt b/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt index d13c1d8e1..e00c9d00e 100644 --- a/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt @@ -2,19 +2,38 @@ package io.legado.app.ui.main.rss import android.os.Bundle import android.view.View +import androidx.lifecycle.LiveData +import androidx.lifecycle.Observer +import androidx.paging.LivePagedListBuilder +import androidx.paging.PagedList +import androidx.recyclerview.widget.GridLayoutManager +import io.legado.app.App import io.legado.app.R import io.legado.app.base.BaseFragment +import io.legado.app.data.entities.RssSource import io.legado.app.lib.theme.ATH -import io.legado.app.lib.theme.ThemeStore import kotlinx.android.synthetic.main.fragment_rss.* class RssFragment : BaseFragment(R.layout.fragment_rss) { + private lateinit var adapter: RssAdapter + private var rssLiveData: LiveData>? = null + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { initRecyclerView() + initData() } private fun initRecyclerView() { ATH.applyEdgeEffectColor(recycler_view) + adapter = RssAdapter() + recycler_view.layoutManager = GridLayoutManager(requireContext(), 4) + + } + + private fun initData() { + rssLiveData?.removeObservers(viewLifecycleOwner) + rssLiveData = LivePagedListBuilder(App.db.rssSourceDao().observeEnabled(), 50).build() + rssLiveData?.observe(viewLifecycleOwner, Observer { }) } } \ No newline at end of file From 1a75f5a59349417ed998d25b3612220449bf591e Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 3 Aug 2019 21:57:23 +0800 Subject: [PATCH 0552/1997] up --- app/src/main/java/io/legado/app/data/AppDatabase.kt | 2 +- app/src/main/java/io/legado/app/data/entities/RssSource.kt | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/AppDatabase.kt b/app/src/main/java/io/legado/app/data/AppDatabase.kt index 877054299..630763064 100644 --- a/app/src/main/java/io/legado/app/data/AppDatabase.kt +++ b/app/src/main/java/io/legado/app/data/AppDatabase.kt @@ -12,7 +12,7 @@ import io.legado.app.data.entities.* @Database( entities = [Book::class, BookGroup::class, BookSource::class, BookChapter::class, ReplaceRule::class, SearchBook::class, - SearchKeyword::class, SourceCookie::class, RssSourceDao::class], + SearchKeyword::class, SourceCookie::class, RssSource::class], version = 1, exportSchema = true ) diff --git a/app/src/main/java/io/legado/app/data/entities/RssSource.kt b/app/src/main/java/io/legado/app/data/entities/RssSource.kt index f18df8b03..99650060c 100644 --- a/app/src/main/java/io/legado/app/data/entities/RssSource.kt +++ b/app/src/main/java/io/legado/app/data/entities/RssSource.kt @@ -1,9 +1,12 @@ package io.legado.app.data.entities +import android.os.Parcelable import androidx.room.Entity +import kotlinx.android.parcel.Parcelize +@Parcelize @Entity(tableName = "rssSources") data class RssSource( var sourceName: String, var enabled: Boolean = true -) \ No newline at end of file +) : Parcelable \ No newline at end of file From e8219eeb10fb4645bd25086743479f9366ce415b Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 3 Aug 2019 21:59:32 +0800 Subject: [PATCH 0553/1997] up --- app/src/main/java/io/legado/app/data/entities/RssSource.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/java/io/legado/app/data/entities/RssSource.kt b/app/src/main/java/io/legado/app/data/entities/RssSource.kt index 99650060c..1f5cba92a 100644 --- a/app/src/main/java/io/legado/app/data/entities/RssSource.kt +++ b/app/src/main/java/io/legado/app/data/entities/RssSource.kt @@ -2,11 +2,14 @@ package io.legado.app.data.entities import android.os.Parcelable import androidx.room.Entity +import androidx.room.PrimaryKey import kotlinx.android.parcel.Parcelize @Parcelize @Entity(tableName = "rssSources") data class RssSource( var sourceName: String, + @PrimaryKey + var sourceUrl: String, var enabled: Boolean = true ) : Parcelable \ No newline at end of file From 743f6da9b5f2b6156c62e2298109d1c53a58facc Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 4 Aug 2019 15:01:17 +0800 Subject: [PATCH 0554/1997] up --- .../io/legado/app/data/dao/SearchBookDao.kt | 6 ++- .../io/legado/app/model/webbook/BookList.kt | 2 + .../io/legado/app/ui/search/SearchActivity.kt | 7 +++- .../legado/app/ui/search/SearchViewModel.kt | 42 ++++++------------- 4 files changed, 26 insertions(+), 31 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt b/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt index ff36e8afb..dfa6794e1 100644 --- a/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt @@ -2,6 +2,8 @@ package io.legado.app.data.dao import androidx.paging.DataSource import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy import androidx.room.Query import io.legado.app.data.entities.SearchBook @@ -11,8 +13,10 @@ interface SearchBookDao { @Query("SELECT * FROM searchBooks") fun observeAll(): DataSource.Factory - @Query("SELECT * FROM searchBooks where time >= :time") + @Query("SELECT name, author, '' bookUrl, '' origin, '' originName, min(time) time, max(intro) intro, max(kind) kind, max(coverUrl) coverUrl, max(latestChapterTitle) latestChapterTitle FROM searchBooks where time >= :time group by name and author") fun observeNew(time: Long): DataSource.Factory + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun insert(vararg searchBook: SearchBook) } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/model/webbook/BookList.kt b/app/src/main/java/io/legado/app/model/webbook/BookList.kt index 06a8ea92d..cea3c9f49 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookList.kt @@ -131,6 +131,7 @@ object BookList { SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取最新章节") searchBook.latestChapterTitle = analyzeRule.getString(lastChapter ?: "") SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.latestChapterTitle ?: "") + searchBook.time = System.currentTimeMillis() return searchBook } } @@ -182,6 +183,7 @@ object BookList { SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取最新章节", printLog) searchBook.latestChapterTitle = analyzeRule.getString(ruleLastChapter) SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.latestChapterTitle ?: "", printLog) + searchBook.time = System.currentTimeMillis() return searchBook } return null diff --git a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt index bba1721af..64978fe69 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt @@ -32,8 +32,9 @@ class SearchActivity : VMBaseActivity(R.layout.activity_search) search_view.setOnQueryTextListener(object : SearchView.OnQueryTextListener { override fun onQueryTextSubmit(query: String?): Boolean { query?.let { - viewModel.search(it, { + viewModel.search(it, { startTime -> content_view.showProgressView() + initData(startTime) }, { }) @@ -58,4 +59,8 @@ class SearchActivity : VMBaseActivity(R.layout.activity_search) rv_search_list.adapter = adapter } + private fun initData(startTime: Long) { + + } + } diff --git a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt b/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt index 3ca042ad0..8ea099c5f 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt @@ -1,36 +1,30 @@ package io.legado.app.ui.search import android.app.Application -import android.util.Log -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData import io.legado.app.App import io.legado.app.base.BaseViewModel -import io.legado.app.data.api.CommonHttpApi -import io.legado.app.data.entities.SearchBook import io.legado.app.help.coroutine.CompositeCoroutine -import io.legado.app.help.http.HttpHelper import io.legado.app.model.WebBook -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.withContext class SearchViewModel(application: Application) : BaseViewModel(application) { - val tasks: CompositeCoroutine = CompositeCoroutine() - val searchBookList = arrayListOf() - val searchBooksData: LiveData> = MutableLiveData() + private val tasks: CompositeCoroutine = CompositeCoroutine() var searchPage = 0 - private val channel = Channel()//协程之间通信 - fun search(key: String, start: (() -> Unit)? = null, finally: (() -> Unit)? = null) { + fun search(key: String, start: ((startTime: Long) -> Unit)? = null, finally: (() -> Unit)? = null) { if (key.isEmpty()) return - start?.invoke() + tasks.clear() + start?.invoke(System.currentTimeMillis()) execute { val bookSourceList = App.db.bookSourceDao().allEnabled for (item in bookSourceList) { val search = WebBook(item).searchBook(key, searchPage) .onSuccess { searchBookS -> - searchBookS?.let { searchBookList.addAll(it) } + searchBookS?.let { + for (searchBook in searchBookS) { + + } + App.db.searchBookDao().insert(*it.toTypedArray()) + } } tasks.add(search) } @@ -38,18 +32,8 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { } } - suspend fun test(scope: CoroutineScope): MutableList { - val list = mutableListOf() - repeat(10) { - withContext(scope.coroutineContext) { - Log.e("TAG3", Thread.currentThread().name) - val response: String = HttpHelper.getApiService( - "http://www.baidu.com" - ).get("http://www.baidu.com").await() - list.add(response) - } - } - return list + override fun onCleared() { + super.onCleared() + tasks.clear() } - } From 862d151365942a6da632641c583cc72de329b98b Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 4 Aug 2019 15:53:13 +0800 Subject: [PATCH 0555/1997] up --- app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt | 2 +- .../main/java/io/legado/app/data/entities/SearchBook.kt | 7 ++++++- app/src/main/java/io/legado/app/model/webbook/BookList.kt | 2 ++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt b/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt index dfa6794e1..3c3ea9288 100644 --- a/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt @@ -13,7 +13,7 @@ interface SearchBookDao { @Query("SELECT * FROM searchBooks") fun observeAll(): DataSource.Factory - @Query("SELECT name, author, '' bookUrl, '' origin, '' originName, min(time) time, max(intro) intro, max(kind) kind, max(coverUrl) coverUrl, max(latestChapterTitle) latestChapterTitle FROM searchBooks where time >= :time group by name and author") + @Query("SELECT name, author, '' bookUrl, '' origin, '' originName, count(origin) originCount, min(time) time, max(intro) intro, max(kind) kind, max(coverUrl) coverUrl, max(latestChapterTitle) latestChapterTitle FROM searchBooks where time >= :time group by name and author order by bookOrder and originOrder and time") fun observeNew(time: Long): DataSource.Factory diff --git a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt index 8b76eea87..d95c566c0 100644 --- a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt +++ b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt @@ -27,9 +27,14 @@ data class SearchBook( var latestChapterTitle: String? = null, var time: Long = 0L, var variable: String? = null, - var bookInfoHtml: String? = null + var bookInfoHtml: String? = null, + var originOrder: Int = 0, + var bookOrder: Int = 0 ) : Parcelable, BaseBook { + @Ignore + var originCount: Int = 0 + @IgnoredOnParcel @Ignore override var variableMap: HashMap? = null diff --git a/app/src/main/java/io/legado/app/model/webbook/BookList.kt b/app/src/main/java/io/legado/app/model/webbook/BookList.kt index cea3c9f49..295bfa3eb 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookList.kt @@ -132,6 +132,7 @@ object BookList { searchBook.latestChapterTitle = analyzeRule.getString(lastChapter ?: "") SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.latestChapterTitle ?: "") searchBook.time = System.currentTimeMillis() + searchBook.originOrder = bookSource.customOrder return searchBook } } @@ -184,6 +185,7 @@ object BookList { searchBook.latestChapterTitle = analyzeRule.getString(ruleLastChapter) SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.latestChapterTitle ?: "", printLog) searchBook.time = System.currentTimeMillis() + searchBook.originOrder = bookSource.customOrder return searchBook } return null From 49616f8d077b516b6dc99494a7800e27b5c8bb55 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 4 Aug 2019 16:58:25 +0800 Subject: [PATCH 0556/1997] up --- .../io/legado/app/ui/search/SearchActivity.kt | 2 +- .../io/legado/app/ui/search/SearchAdapter.kt | 48 ++++++++++++++----- 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt index 64978fe69..89ff581cb 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt @@ -54,7 +54,7 @@ class SearchActivity : VMBaseActivity(R.layout.activity_search) private fun initRecyclerView() { ATH.applyEdgeEffectColor(rv_search_list) - adapter = SearchAdapter(this) + adapter = SearchAdapter() rv_search_list.layoutManager = LinearLayoutManager(this) rv_search_list.adapter = adapter } diff --git a/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt b/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt index cbdf67def..202b37644 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt @@ -1,26 +1,52 @@ package io.legado.app.ui.search -import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.paging.PagedListAdapter +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.RecyclerView import io.legado.app.R -import io.legado.app.base.adapter.ItemViewDelegate -import io.legado.app.base.adapter.ItemViewHolder -import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.data.entities.SearchBook -class SearchAdapter(context: Context) : SimpleRecyclerAdapter(context, R.layout.item_search) { +class SearchAdapter : PagedListAdapter(DIFF_CALLBACK) { - init { - addItemViewDelegate(TestItemDelegate(context)) - } + companion object { + + @JvmField + val DIFF_CALLBACK = object : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: SearchBook, newItem: SearchBook): Boolean = + oldItem.name == newItem.name + && oldItem.author == newItem.author - override fun convert(holder: ItemViewHolder, item: SearchBook, payloads: MutableList) { + override fun areContentsTheSame(oldItem: SearchBook, newItem: SearchBook): Boolean = + oldItem.name == newItem.name + && oldItem.author == newItem.author + && oldItem.originCount == newItem.originCount + } } - internal class TestItemDelegate(context: Context) : ItemViewDelegate(context, R.layout.item_search) { + var callBack: CallBack? = null - override fun convert(holder: ItemViewHolder, item: SearchBook, payloads: MutableList) { + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { + return MyViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_search, parent, false)) + } + + override fun onBindViewHolder(holder: MyViewHolder, position: Int) { + getItem(position)?.let { + holder.bind(it, callBack) } + } + + class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { + + fun bind(searchBook: SearchBook, callBack: CallBack?) { + + } } + interface CallBack { + fun showBookInfo() + } } \ No newline at end of file From e7d404d217c1a330b41f409596bc0c062d8080bb Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 4 Aug 2019 17:29:54 +0800 Subject: [PATCH 0557/1997] up --- .../java/io/legado/app/ui/search/SearchActivity.kt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt index 89ff581cb..aec7b54a7 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt @@ -3,9 +3,15 @@ package io.legado.app.ui.search import android.os.Bundle import android.view.View import androidx.appcompat.widget.SearchView +import androidx.lifecycle.LiveData +import androidx.lifecycle.Observer +import androidx.paging.LivePagedListBuilder +import androidx.paging.PagedList import androidx.recyclerview.widget.LinearLayoutManager +import io.legado.app.App import io.legado.app.R import io.legado.app.base.VMBaseActivity +import io.legado.app.data.entities.SearchBook import io.legado.app.lib.theme.ATH import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_search.* @@ -17,6 +23,7 @@ class SearchActivity : VMBaseActivity(R.layout.activity_search) get() = getViewModel(SearchViewModel::class.java) private lateinit var adapter: SearchAdapter + private var searchBookData: LiveData>? = null override fun onActivityCreated(savedInstanceState: Bundle?) { initRecyclerView() @@ -60,7 +67,9 @@ class SearchActivity : VMBaseActivity(R.layout.activity_search) } private fun initData(startTime: Long) { - + searchBookData?.removeObservers(this) + searchBookData = LivePagedListBuilder(App.db.searchBookDao().observeNew(startTime), 30).build() + searchBookData?.observe(this, Observer { adapter.submitList(it) }) } } From a0553fba15f7afd3f79e6faa7ff13d148072a1f9 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 4 Aug 2019 19:36:24 +0800 Subject: [PATCH 0558/1997] up --- .../io/legado/app/ui/search/SearchAdapter.kt | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt b/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt index 202b37644..196b6edd0 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt @@ -8,6 +8,11 @@ import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import io.legado.app.R import io.legado.app.data.entities.SearchBook +import io.legado.app.help.ImageLoader +import kotlinx.android.synthetic.main.item_bookshelf_list.view.iv_cover +import kotlinx.android.synthetic.main.item_bookshelf_list.view.tv_name +import kotlinx.android.synthetic.main.item_search.view.* +import org.jetbrains.anko.sdk27.listeners.onClick class SearchAdapter : PagedListAdapter(DIFF_CALLBACK) { @@ -41,12 +46,24 @@ class SearchAdapter : PagedListAdapter(D class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { - fun bind(searchBook: SearchBook, callBack: CallBack?) { - + fun bind(searchBook: SearchBook, callBack: CallBack?) = with(itemView) { + tv_name.text = String.format("%s(%s)", searchBook.name, searchBook.author) + tv_lasted.text = context.getString(R.string.book_search_last, searchBook.latestChapterTitle) + tv_introduce.text = searchBook.intro + searchBook.coverUrl.let { + ImageLoader.load(context, it)//Glide自动识别http://和file:// + .placeholder(R.drawable.img_cover_default) + .error(R.drawable.img_cover_default) + .centerCrop() + .setAsDrawable(iv_cover) + } + onClick { + callBack?.showBookInfo(searchBook) + } } } interface CallBack { - fun showBookInfo() + fun showBookInfo(searchBook: SearchBook) } } \ No newline at end of file From d732701783b5f688b885ebbae569c664362e6978 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 4 Aug 2019 19:40:09 +0800 Subject: [PATCH 0559/1997] up --- app/src/main/java/io/legado/app/data/entities/SearchBook.kt | 2 +- .../main/java/io/legado/app/ui/search/SearchViewModel.kt | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt index d95c566c0..4404631a8 100644 --- a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt +++ b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt @@ -29,7 +29,7 @@ data class SearchBook( var variable: String? = null, var bookInfoHtml: String? = null, var originOrder: Int = 0, - var bookOrder: Int = 0 + var searchOrder: Int = 0 ) : Parcelable, BaseBook { @Ignore diff --git a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt b/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt index 8ea099c5f..179d4abb9 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt @@ -21,7 +21,11 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { .onSuccess { searchBookS -> searchBookS?.let { for (searchBook in searchBookS) { - + when (key) { + searchBook.name -> searchBook.searchOrder = 0 + searchBook.author -> searchBook.searchOrder = 1 + else -> searchBook.searchOrder = 1000 + } } App.db.searchBookDao().insert(*it.toTypedArray()) } From e7b536360be834ba0a918307dccecaf854c17bfd Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 4 Aug 2019 19:41:36 +0800 Subject: [PATCH 0560/1997] up --- app/src/main/java/io/legado/app/ui/search/SearchActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt index aec7b54a7..20ba266ef 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt @@ -40,7 +40,7 @@ class SearchActivity : VMBaseActivity(R.layout.activity_search) override fun onQueryTextSubmit(query: String?): Boolean { query?.let { viewModel.search(it, { startTime -> - content_view.showProgressView() + content_view.showContentView() initData(startTime) }, { From b9c62e2055df939ade9450713c3b5a605a3d8263 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 4 Aug 2019 19:44:15 +0800 Subject: [PATCH 0561/1997] up --- app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt b/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt index 3c3ea9288..68cd99981 100644 --- a/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt @@ -13,7 +13,7 @@ interface SearchBookDao { @Query("SELECT * FROM searchBooks") fun observeAll(): DataSource.Factory - @Query("SELECT name, author, '' bookUrl, '' origin, '' originName, count(origin) originCount, min(time) time, max(intro) intro, max(kind) kind, max(coverUrl) coverUrl, max(latestChapterTitle) latestChapterTitle FROM searchBooks where time >= :time group by name and author order by bookOrder and originOrder and time") + @Query("SELECT name, author, '' bookUrl, '' origin, '' originName, count(origin) originCount, min(time) time, max(intro) intro, max(kind) kind, max(coverUrl) coverUrl, max(latestChapterTitle) latestChapterTitle FROM searchBooks where time >= :time group by name and author order by searchOrder and originOrder and time") fun observeNew(time: Long): DataSource.Factory From 8fb54037b767fb6770cb3bd000a0a4b99573955d Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 4 Aug 2019 19:49:23 +0800 Subject: [PATCH 0562/1997] up --- app/src/main/java/io/legado/app/data/entities/SearchBook.kt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt index 4404631a8..674671b64 100644 --- a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt +++ b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt @@ -29,11 +29,9 @@ data class SearchBook( var variable: String? = null, var bookInfoHtml: String? = null, var originOrder: Int = 0, - var searchOrder: Int = 0 -) : Parcelable, BaseBook { - - @Ignore + var searchOrder: Int = 0, var originCount: Int = 0 +) : Parcelable, BaseBook { @IgnoredOnParcel @Ignore From 7f070f2a603cc52bdc186571ede06b153ca34509 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 4 Aug 2019 19:59:59 +0800 Subject: [PATCH 0563/1997] up --- app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt b/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt index 68cd99981..668adda13 100644 --- a/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt @@ -13,7 +13,8 @@ interface SearchBookDao { @Query("SELECT * FROM searchBooks") fun observeAll(): DataSource.Factory - @Query("SELECT name, author, '' bookUrl, '' origin, '' originName, count(origin) originCount, min(time) time, max(intro) intro, max(kind) kind, max(coverUrl) coverUrl, max(latestChapterTitle) latestChapterTitle FROM searchBooks where time >= :time group by name and author order by searchOrder and originOrder and time") + // @Query("SELECT name, author, '' bookUrl, '' origin, '' originName, count(origin) originCount, min(time) time, max(intro) intro, max(kind) kind, max(coverUrl) coverUrl, max(latestChapterTitle) latestChapterTitle FROM searchBooks where time >= :time group by name and author order by searchOrder and originOrder and time") + @Query("SELECT * FROM searchBooks") fun observeNew(time: Long): DataSource.Factory From c12a4e03ab8d6bfed1fb1dabc000370fc4d8ece7 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 4 Aug 2019 20:01:05 +0800 Subject: [PATCH 0564/1997] up --- app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt b/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt index 668adda13..e7cf630d0 100644 --- a/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt @@ -14,7 +14,7 @@ interface SearchBookDao { fun observeAll(): DataSource.Factory // @Query("SELECT name, author, '' bookUrl, '' origin, '' originName, count(origin) originCount, min(time) time, max(intro) intro, max(kind) kind, max(coverUrl) coverUrl, max(latestChapterTitle) latestChapterTitle FROM searchBooks where time >= :time group by name and author order by searchOrder and originOrder and time") - @Query("SELECT * FROM searchBooks") + @Query("SELECT * FROM searchBooks where time >= :time") fun observeNew(time: Long): DataSource.Factory From 2bdaee2699aa2d414a118ba6c7ff9b48c69c7184 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 4 Aug 2019 21:22:26 +0800 Subject: [PATCH 0565/1997] up --- app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt | 3 +++ app/src/main/java/io/legado/app/data/entities/SearchBook.kt | 4 ++-- app/src/main/java/io/legado/app/ui/search/SearchActivity.kt | 3 ++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt b/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt index e7cf630d0..0bde5a81c 100644 --- a/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt @@ -20,4 +20,7 @@ interface SearchBookDao { @Insert(onConflict = OnConflictStrategy.REPLACE) fun insert(vararg searchBook: SearchBook) + + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun insert(searchBook: SearchBook) } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt index 674671b64..71db1dc8b 100644 --- a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt +++ b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt @@ -42,11 +42,11 @@ data class SearchBook( } private fun initVariableMap() { - if (variableMap == null) { + variableMap?.let { variableMap = if (TextUtils.isEmpty(variable)) { HashMap() } else { - GSON.fromJsonObject>(variable!!) + GSON.fromJsonObject(variable) } } } diff --git a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt index 20ba266ef..1e3db77c5 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt @@ -28,6 +28,7 @@ class SearchActivity : VMBaseActivity(R.layout.activity_search) override fun onActivityCreated(savedInstanceState: Bundle?) { initRecyclerView() initSearchView() + initData(0L) } private fun initSearchView() { @@ -68,7 +69,7 @@ class SearchActivity : VMBaseActivity(R.layout.activity_search) private fun initData(startTime: Long) { searchBookData?.removeObservers(this) - searchBookData = LivePagedListBuilder(App.db.searchBookDao().observeNew(startTime), 30).build() + searchBookData = LivePagedListBuilder(App.db.searchBookDao().observeAll(), 30).build() searchBookData?.observe(this, Observer { adapter.submitList(it) }) } From f6acc94ea3d68976f800a54a785594deece4c817 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 4 Aug 2019 21:23:36 +0800 Subject: [PATCH 0566/1997] up --- app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt b/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt index 179d4abb9..cfe671ce5 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt @@ -26,8 +26,8 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { searchBook.author -> searchBook.searchOrder = 1 else -> searchBook.searchOrder = 1000 } + App.db.searchBookDao().insert(searchBook) } - App.db.searchBookDao().insert(*it.toTypedArray()) } } tasks.add(search) From 8a4a1b1b14f7ed01db7cb3c976b671de73823319 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 5 Aug 2019 09:15:04 +0800 Subject: [PATCH 0567/1997] up --- .../java/io/legado/app/data/dao/SearchBookDao.kt | 4 ++-- .../io/legado/app/ui/search/SearchViewModel.kt | 16 ++++++++++------ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt b/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt index 0bde5a81c..157a4f1e4 100644 --- a/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt @@ -19,8 +19,8 @@ interface SearchBookDao { @Insert(onConflict = OnConflictStrategy.REPLACE) - fun insert(vararg searchBook: SearchBook) + fun insert(vararg searchBook: SearchBook): List @Insert(onConflict = OnConflictStrategy.REPLACE) - fun insert(searchBook: SearchBook) + fun insert(searchBook: SearchBook): Long } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt b/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt index cfe671ce5..865b1b3b7 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt @@ -20,19 +20,23 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { val search = WebBook(item).searchBook(key, searchPage) .onSuccess { searchBookS -> searchBookS?.let { - for (searchBook in searchBookS) { - when (key) { - searchBook.name -> searchBook.searchOrder = 0 - searchBook.author -> searchBook.searchOrder = 1 - else -> searchBook.searchOrder = 1000 + execute { + for (searchBook in searchBookS) { + when (key) { + searchBook.name -> searchBook.searchOrder = 0 + searchBook.author -> searchBook.searchOrder = 1 + else -> searchBook.searchOrder = 1000 + } + App.db.searchBookDao().insert(searchBook) } - App.db.searchBookDao().insert(searchBook) } } } tasks.add(search) } + }.onError { + it.printStackTrace() } } From d01b16627a5d3b4b2f02187ee98f0432a4ddcd83 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 5 Aug 2019 09:34:42 +0800 Subject: [PATCH 0568/1997] up --- .../ui/main/bookshelf/BookshelfFragment.kt | 19 +++++---- app/src/main/res/menu/main_bookshelf.xml | 40 +++++++++++++++++++ 2 files changed, 51 insertions(+), 8 deletions(-) create mode 100644 app/src/main/res/menu/main_bookshelf.xml diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index 24b67a9f2..0b014304a 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -1,8 +1,8 @@ package io.legado.app.ui.main.bookshelf import android.os.Bundle -import android.util.Log import android.view.Menu +import android.view.MenuItem import android.view.View import android.widget.EditText import androidx.appcompat.widget.SearchView @@ -22,14 +22,10 @@ import io.legado.app.lib.dialogs.customView import io.legado.app.lib.dialogs.noButton import io.legado.app.lib.dialogs.yesButton import io.legado.app.lib.theme.ATH -import io.legado.app.lib.theme.ThemeStore import io.legado.app.lib.theme.accentColor import io.legado.app.ui.bookshelf.BookshelfActivity import io.legado.app.ui.search.SearchActivity -import io.legado.app.utils.applyTint -import io.legado.app.utils.getViewModel -import io.legado.app.utils.requestInputMethod -import io.legado.app.utils.visible +import io.legado.app.utils.* import kotlinx.android.synthetic.main.dialog_edittext.view.* import kotlinx.android.synthetic.main.fragment_bookshelf.* import kotlinx.android.synthetic.main.view_title_bar.* @@ -50,14 +46,21 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b override fun onViewCreated(view: View, savedInstanceState: Bundle?) { setSupportToolbar(toolbar) - initSearchView() +// initSearchView() initRecyclerView() initBookGroupData() initBookshelfData() } override fun onCompatCreateOptionsMenu(menu: Menu) { - menuInflater.inflate(R.menu.bookshelf, menu) + menuInflater.inflate(R.menu.main_bookshelf, menu) + } + + override fun onCompatOptionsItemSelected(item: MenuItem) { + super.onCompatOptionsItemSelected(item) + when (item.itemId) { + R.id.action_search -> startActivity() + } } private fun initSearchView() { diff --git a/app/src/main/res/menu/main_bookshelf.xml b/app/src/main/res/menu/main_bookshelf.xml new file mode 100644 index 000000000..6c69069c1 --- /dev/null +++ b/app/src/main/res/menu/main_bookshelf.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + \ No newline at end of file From 726f584d88376236d46c71fed23776f0affbfc45 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 5 Aug 2019 09:49:12 +0800 Subject: [PATCH 0569/1997] up --- app/src/main/java/io/legado/app/help/BookHelp.kt | 5 +++++ app/src/main/java/io/legado/app/model/webbook/BookList.kt | 5 +++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/BookHelp.kt b/app/src/main/java/io/legado/app/help/BookHelp.kt index 1e975631f..8d93877bc 100644 --- a/app/src/main/java/io/legado/app/help/BookHelp.kt +++ b/app/src/main/java/io/legado/app/help/BookHelp.kt @@ -20,4 +20,9 @@ object BookHelp { } + fun formatAuthor(author: String?): String { + return author?.replace("作\\s*者[\\s::]*".toRegex(), "")?.replace("\\s+".toRegex(), " ")?.trim { it <= ' ' } + ?: "" + } + } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/model/webbook/BookList.kt b/app/src/main/java/io/legado/app/model/webbook/BookList.kt index 295bfa3eb..635f8e249 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookList.kt @@ -4,6 +4,7 @@ import io.legado.app.App import io.legado.app.R import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.SearchBook +import io.legado.app.help.BookHelp import io.legado.app.model.analyzeRule.AnalyzeRule import io.legado.app.model.analyzeRule.AnalyzeUrl import io.legado.app.utils.NetworkUtils @@ -114,7 +115,7 @@ object BookList { SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.name ?: "") if (!searchBook.name.isNullOrEmpty()) { SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取作者") - searchBook.author = analyzeRule.getString(author ?: "") + searchBook.author = BookHelp.formatAuthor(analyzeRule.getString(author ?: "")) SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.author ?: "") SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取分类") searchBook.kind = analyzeRule.getString(kind ?: "") @@ -167,7 +168,7 @@ object BookList { searchBook.bookUrl = analyzeRule.getString(ruleBookUrl, true) SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.bookUrl, printLog) SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取作者", printLog) - searchBook.author = analyzeRule.getString(ruleAuthor) + searchBook.author = BookHelp.formatAuthor(analyzeRule.getString(ruleAuthor)) SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.author ?: "", printLog) SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取分类", printLog) searchBook.kind = analyzeRule.getString(ruleKind) From 510afe272b4fe006c6e32203dda3c5f929eda49b Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 5 Aug 2019 09:51:22 +0800 Subject: [PATCH 0570/1997] up --- app/src/main/java/io/legado/app/ui/search/SearchActivity.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt index 1e3db77c5..d504f8724 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt @@ -14,6 +14,7 @@ import io.legado.app.base.VMBaseActivity import io.legado.app.data.entities.SearchBook import io.legado.app.lib.theme.ATH import io.legado.app.utils.getViewModel +import io.legado.app.utils.hideSoftInput import kotlinx.android.synthetic.main.activity_search.* import kotlinx.android.synthetic.main.view_title_bar.* @@ -39,6 +40,7 @@ class SearchActivity : VMBaseActivity(R.layout.activity_search) search_view.clearFocus() search_view.setOnQueryTextListener(object : SearchView.OnQueryTextListener { override fun onQueryTextSubmit(query: String?): Boolean { + search_view.hideSoftInput() query?.let { viewModel.search(it, { startTime -> content_view.showContentView() From 31167538259cfd8497405be2c874b22b936956af Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 5 Aug 2019 10:13:19 +0800 Subject: [PATCH 0571/1997] up --- app/src/main/java/io/legado/app/ui/search/SearchActivity.kt | 3 +-- .../java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt | 3 +-- app/src/main/res/layout/item_search.xml | 4 ++++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt index d504f8724..ac24f5ab8 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt @@ -14,7 +14,6 @@ import io.legado.app.base.VMBaseActivity import io.legado.app.data.entities.SearchBook import io.legado.app.lib.theme.ATH import io.legado.app.utils.getViewModel -import io.legado.app.utils.hideSoftInput import kotlinx.android.synthetic.main.activity_search.* import kotlinx.android.synthetic.main.view_title_bar.* @@ -40,7 +39,7 @@ class SearchActivity : VMBaseActivity(R.layout.activity_search) search_view.clearFocus() search_view.setOnQueryTextListener(object : SearchView.OnQueryTextListener { override fun onQueryTextSubmit(query: String?): Boolean { - search_view.hideSoftInput() + search_view.clearFocus() query?.let { viewModel.search(it, { startTime -> content_view.showContentView() diff --git a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt index 9049bbc75..80f7df36d 100644 --- a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt +++ b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt @@ -13,7 +13,6 @@ import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.accentColor import io.legado.app.ui.qrcode.QrCodeActivity import io.legado.app.utils.getViewModel -import io.legado.app.utils.hideSoftInput import kotlinx.android.synthetic.main.activity_source_debug.* import kotlinx.android.synthetic.main.view_title_bar.* import kotlinx.coroutines.launch @@ -58,7 +57,7 @@ class SourceDebugActivity : VMBaseActivity(R.layout.activity_s search_view.clearFocus() search_view.setOnQueryTextListener(object : SearchView.OnQueryTextListener { override fun onQueryTextSubmit(query: String?): Boolean { - search_view.hideSoftInput() + search_view.clearFocus() startSearch(query ?: "我的") return true } diff --git a/app/src/main/res/layout/item_search.xml b/app/src/main/res/layout/item_search.xml index ff3b1149b..57d9b033f 100644 --- a/app/src/main/res/layout/item_search.xml +++ b/app/src/main/res/layout/item_search.xml @@ -24,6 +24,7 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_margin="8dp" + android:singleLine="true" android:text="@string/app_name" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@+id/iv_cover" @@ -48,6 +49,7 @@ android:id="@+id/tv_kind" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:layout_marginEnd="6dp" android:singleLine="true" android:text="@string/app_name" /> @@ -55,6 +57,7 @@ android:id="@+id/tv_kind_1" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:layout_marginEnd="6dp" android:singleLine="true" android:text="@string/app_name" /> @@ -62,6 +65,7 @@ android:id="@+id/tv_kind_2" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:layout_marginEnd="6dp" android:singleLine="true" android:text="@string/app_name" /> From 879d41f255f116bc5b8b97345a7e06026bb14c1d Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 5 Aug 2019 10:56:03 +0800 Subject: [PATCH 0572/1997] up --- .../io/legado/app/data/entities/SearchBook.kt | 13 ++++++++ .../io/legado/app/ui/search/SearchAdapter.kt | 32 +++++++++++++++++++ .../io/legado/app/utils/StringExtensions.kt | 4 +-- app/src/main/res/layout/item_search.xml | 14 +++++--- 4 files changed, 56 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt index 71db1dc8b..66965ea8c 100644 --- a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt +++ b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt @@ -8,6 +8,7 @@ import androidx.room.Index import androidx.room.PrimaryKey import io.legado.app.utils.GSON import io.legado.app.utils.fromJsonObject +import io.legado.app.utils.splitNotBlank import kotlinx.android.parcel.IgnoredOnParcel import kotlinx.android.parcel.Parcelize @@ -56,4 +57,16 @@ data class SearchBook( variableMap?.put(key, value) variable = GSON.toJson(variableMap) } + + fun getKindList(): List { + val kindList = arrayListOf() + wordCount?.let { + if (it.isNotBlank()) kindList.add(it) + } + kind?.let { + val kinds = it.splitNotBlank(",", "\n") + kindList.addAll(kinds) + } + return kindList + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt b/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt index 196b6edd0..d9df3bb43 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt @@ -9,6 +9,8 @@ import androidx.recyclerview.widget.RecyclerView import io.legado.app.R import io.legado.app.data.entities.SearchBook import io.legado.app.help.ImageLoader +import io.legado.app.utils.gone +import io.legado.app.utils.visible import kotlinx.android.synthetic.main.item_bookshelf_list.view.iv_cover import kotlinx.android.synthetic.main.item_bookshelf_list.view.tv_name import kotlinx.android.synthetic.main.item_search.view.* @@ -50,6 +52,36 @@ class SearchAdapter : PagedListAdapter(D tv_name.text = String.format("%s(%s)", searchBook.name, searchBook.author) tv_lasted.text = context.getString(R.string.book_search_last, searchBook.latestChapterTitle) tv_introduce.text = searchBook.intro + val kinds = searchBook.getKindList() + if (kinds.isEmpty()) { + ll_kind.gone() + } else { + ll_kind.visible() + for (index in 0..2) { + if (kinds.size > index) { + when (index) { + 0 -> { + tv_kind.text = kinds[index] + tv_kind.visible() + } + 1 -> { + tv_kind_1.text = kinds[index] + tv_kind_1.visible() + } + 2 -> { + tv_kind_2.text = kinds[index] + tv_kind_2.visible() + } + } + } else { + when (index) { + 0 -> tv_kind.gone() + 1 -> tv_kind_1.gone() + 2 -> tv_kind_2.gone() + } + } + } + } searchBook.coverUrl.let { ImageLoader.load(context, it)//Glide自动识别http://和file:// .placeholder(R.drawable.img_cover_default) diff --git a/app/src/main/java/io/legado/app/utils/StringExtensions.kt b/app/src/main/java/io/legado/app/utils/StringExtensions.kt index 580d8a10f..0100b5f9f 100644 --- a/app/src/main/java/io/legado/app/utils/StringExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/StringExtensions.kt @@ -23,8 +23,8 @@ fun String?.htmlFormat(): String = if (this.isNullOrBlank()) "" else .replace("^[\\n\\s]+".toRegex(), "  ")//移除开头空行,并增加段前缩进2个汉字 .replace("[\\n\\s]+$".toRegex(), "") //移除尾部空行 -fun String.splitNotBlank(delimiter: String): Array = run { - this.split(delimiter).map { it.trim() }.filterNot { it.isBlank() }.toTypedArray() +fun String.splitNotBlank(vararg delimiter: String): Array = run { + this.split(*delimiter).map { it.trim() }.filterNot { it.isBlank() }.toTypedArray() } fun String.splitNotBlank(regex: Regex, limit: Int = 0): Array = run { diff --git a/app/src/main/res/layout/item_search.xml b/app/src/main/res/layout/item_search.xml index 57d9b033f..a106d8601 100644 --- a/app/src/main/res/layout/item_search.xml +++ b/app/src/main/res/layout/item_search.xml @@ -7,8 +7,8 @@ @@ -58,6 +60,8 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="6dp" + android:paddingLeft="3dp" + android:paddingRight="3dp" android:singleLine="true" android:text="@string/app_name" /> @@ -66,6 +70,8 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="6dp" + android:paddingLeft="3dp" + android:paddingRight="3dp" android:singleLine="true" android:text="@string/app_name" /> @@ -85,10 +91,8 @@ From 359d11bf606220c216b0d7167e6f3d74c914e36a Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 5 Aug 2019 11:04:03 +0800 Subject: [PATCH 0573/1997] up --- app/src/main/java/io/legado/app/ui/search/SearchActivity.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt index ac24f5ab8..80cd4a219 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt @@ -28,7 +28,6 @@ class SearchActivity : VMBaseActivity(R.layout.activity_search) override fun onActivityCreated(savedInstanceState: Bundle?) { initRecyclerView() initSearchView() - initData(0L) } private fun initSearchView() { @@ -70,7 +69,7 @@ class SearchActivity : VMBaseActivity(R.layout.activity_search) private fun initData(startTime: Long) { searchBookData?.removeObservers(this) - searchBookData = LivePagedListBuilder(App.db.searchBookDao().observeAll(), 30).build() + searchBookData = LivePagedListBuilder(App.db.searchBookDao().observeNew(startTime), 30).build() searchBookData?.observe(this, Observer { adapter.submitList(it) }) } From 4ebe82ca0354966358921a12271a059af18de60c Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 5 Aug 2019 11:20:18 +0800 Subject: [PATCH 0574/1997] up --- .../io/legado/app/ui/search/SearchAdapter.kt | 3 ++- app/src/main/res/layout/item_search.xml | 26 ++++++++++++++----- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt b/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt index d9df3bb43..9b22a190d 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt @@ -49,7 +49,8 @@ class SearchAdapter : PagedListAdapter(D class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { fun bind(searchBook: SearchBook, callBack: CallBack?) = with(itemView) { - tv_name.text = String.format("%s(%s)", searchBook.name, searchBook.author) + tv_name.text = searchBook.name + tv_author.text = searchBook.author tv_lasted.text = context.getString(R.string.book_search_last, searchBook.latestChapterTitle) tv_introduce.text = searchBook.intro val kinds = searchBook.getKindList() diff --git a/app/src/main/res/layout/item_search.xml b/app/src/main/res/layout/item_search.xml index a106d8601..40e04dd09 100644 --- a/app/src/main/res/layout/item_search.xml +++ b/app/src/main/res/layout/item_search.xml @@ -39,6 +39,16 @@ app:layout_constraintRight_toRightOf="@id/tv_name" app:layout_constraintTop_toBottomOf="@+id/tv_name"> + + + android:text="@string/app_name" + android:textSize="12sp" /> + android:text="@string/app_name" + android:textSize="12sp" /> + android:text="@string/app_name" + android:textSize="12sp" /> @@ -93,7 +105,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:ellipsize="end" - android:text="简介" + android:text="@string/book_intro" android:textColor="@color/tv_text_default" android:textSize="12sp" /> From 82be88ae53372e8d648c1de7a044b6ebbb1ddaf5 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 5 Aug 2019 12:30:29 +0800 Subject: [PATCH 0575/1997] up --- app/src/main/res/drawable/ic_author.xml | 4 ++-- app/src/main/res/layout/item_search.xml | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/drawable/ic_author.xml b/app/src/main/res/drawable/ic_author.xml index 3e3cf2d19..00d53f351 100644 --- a/app/src/main/res/drawable/ic_author.xml +++ b/app/src/main/res/drawable/ic_author.xml @@ -1,6 +1,6 @@ @@ -45,6 +46,7 @@ android:layout_height="wrap_content" android:ellipsize="end" android:lines="1" + android:drawableLeft="@drawable/ic_author" android:text="@string/author" android:textColor="@color/tv_text_default" android:textSize="12sp" /> From 6122fcc4d4984618235545a86ee29883e5a25429 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 5 Aug 2019 12:34:51 +0800 Subject: [PATCH 0576/1997] up --- app/src/main/java/io/legado/app/data/entities/Book.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/Book.kt b/app/src/main/java/io/legado/app/data/entities/Book.kt index dae0621d8..d86bd415f 100644 --- a/app/src/main/java/io/legado/app/data/entities/Book.kt +++ b/app/src/main/java/io/legado/app/data/entities/Book.kt @@ -55,9 +55,9 @@ data class Book( fun getUnreadChapterNum() = max(totalChapterNum - durChapterIndex - 1, 0) - fun getDisplayCover() = customCoverUrl ?: coverUrl + fun getDisplayCover() = if (customCoverUrl.isNullOrEmpty()) coverUrl else customCoverUrl - fun getDisplayIntro() = customIntro ?: intro + fun getDisplayIntro() = if (customIntro.isNullOrEmpty()) intro else customIntro private fun initVariableMap() { if (variableMap == null) { From 9f9a1291b83cc2506d4c2e8085e6cc5ee7e68419 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 5 Aug 2019 13:59:04 +0800 Subject: [PATCH 0577/1997] up --- app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt | 1 - app/src/main/java/io/legado/app/data/entities/SearchBook.kt | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt b/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt index 157a4f1e4..fb58efd8a 100644 --- a/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt @@ -13,7 +13,6 @@ interface SearchBookDao { @Query("SELECT * FROM searchBooks") fun observeAll(): DataSource.Factory - // @Query("SELECT name, author, '' bookUrl, '' origin, '' originName, count(origin) originCount, min(time) time, max(intro) intro, max(kind) kind, max(coverUrl) coverUrl, max(latestChapterTitle) latestChapterTitle FROM searchBooks where time >= :time group by name and author order by searchOrder and originOrder and time") @Query("SELECT * FROM searchBooks where time >= :time") fun observeNew(time: Long): DataSource.Factory diff --git a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt index 66965ea8c..9ac3e181c 100644 --- a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt +++ b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt @@ -29,9 +29,7 @@ data class SearchBook( var time: Long = 0L, var variable: String? = null, var bookInfoHtml: String? = null, - var originOrder: Int = 0, - var searchOrder: Int = 0, - var originCount: Int = 0 + var originOrder: Int = 0 ) : Parcelable, BaseBook { @IgnoredOnParcel From 2c9f5144c825e29af1f7aacdedf2bd374582633e Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 5 Aug 2019 14:00:06 +0800 Subject: [PATCH 0578/1997] up --- .../main/java/io/legado/app/ui/search/SearchViewModel.kt | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt b/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt index 865b1b3b7..e81d5c1b0 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt @@ -21,14 +21,7 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { .onSuccess { searchBookS -> searchBookS?.let { execute { - for (searchBook in searchBookS) { - when (key) { - searchBook.name -> searchBook.searchOrder = 0 - searchBook.author -> searchBook.searchOrder = 1 - else -> searchBook.searchOrder = 1000 - } - App.db.searchBookDao().insert(searchBook) - } + App.db.searchBookDao().insert(*it.toTypedArray()) } } } From 640ba3062a3c8ce35deae50dff3401bd8c48c707 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 5 Aug 2019 14:00:27 +0800 Subject: [PATCH 0579/1997] up --- app/src/main/java/io/legado/app/ui/search/SearchActivity.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt index 80cd4a219..eb26a882c 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt @@ -28,6 +28,7 @@ class SearchActivity : VMBaseActivity(R.layout.activity_search) override fun onActivityCreated(savedInstanceState: Bundle?) { initRecyclerView() initSearchView() + initData(0L) } private fun initSearchView() { From 6d98e6748cf78a554816912a8d995c37a955a062 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 5 Aug 2019 14:06:48 +0800 Subject: [PATCH 0580/1997] up --- app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt b/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt index 9b22a190d..4488d9f8c 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt @@ -29,7 +29,6 @@ class SearchAdapter : PagedListAdapter(D override fun areContentsTheSame(oldItem: SearchBook, newItem: SearchBook): Boolean = oldItem.name == newItem.name && oldItem.author == newItem.author - && oldItem.originCount == newItem.originCount } } From ac74a490546c97b41c5760ee41adc0645077cf83 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 5 Aug 2019 16:40:31 +0800 Subject: [PATCH 0581/1997] up --- .../res/layout/activity_book_info_edit.xml | 130 ++++++++++++++++++ 1 file changed, 130 insertions(+) diff --git a/app/src/main/res/layout/activity_book_info_edit.xml b/app/src/main/res/layout/activity_book_info_edit.xml index d829e291c..e8f969bcb 100644 --- a/app/src/main/res/layout/activity_book_info_edit.xml +++ b/app/src/main/res/layout/activity_book_info_edit.xml @@ -1,7 +1,137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 878f512c5140fc9ebf1cbf0c91852126c632d44c Mon Sep 17 00:00:00 2001 From: Administrator <1760316362@qq.com> Date: Mon, 5 Aug 2019 17:28:15 +0800 Subject: [PATCH 0582/1997] update --- .../java/io/legado/app/base/BaseViewModel.kt | 8 +- .../io/legado/app/help/coroutine/Coroutine.kt | 26 ++++- .../io/legado/app/help/storage/Restore.kt | 107 +++++++++--------- .../main/java/io/legado/app/model/WebBook.kt | 5 +- .../legado/app/model/webbook/SourceDebug.kt | 1 + .../io/legado/app/ui/main/MainActivity.kt | 7 +- .../legado/app/ui/search/SearchViewModel.kt | 23 ++-- .../app/ui/sourcedebug/SourceDebugModel.kt | 1 + .../java/io/legado/app/ui/widget/PageView.kt | 77 ------------- .../legado/app/ui/widget/page/DataSource.kt | 12 ++ .../app/ui/widget/page/PageAnimDelegate.kt | 39 +++++++ .../legado/app/ui/widget/page/PageFactory.kt | 11 ++ .../io/legado/app/ui/widget/page/PageView.kt | 55 +++++++++ .../legado/app/ui/widget/page/TextChapter.kt | 3 + .../io/legado/app/ui/widget/page/TextPage.kt | 3 + .../app/ui/widget/page/TextPageFactory.kt | 26 +++++ app/src/main/res/layout/activity_read.xml | 2 +- app/src/main/res/layout/page_view.xml | 42 +++++++ 18 files changed, 289 insertions(+), 159 deletions(-) delete mode 100644 app/src/main/java/io/legado/app/ui/widget/PageView.kt create mode 100644 app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt create mode 100644 app/src/main/java/io/legado/app/ui/widget/page/PageAnimDelegate.kt create mode 100644 app/src/main/java/io/legado/app/ui/widget/page/PageFactory.kt create mode 100644 app/src/main/java/io/legado/app/ui/widget/page/PageView.kt create mode 100644 app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt create mode 100644 app/src/main/java/io/legado/app/ui/widget/page/TextPage.kt create mode 100644 app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt create mode 100644 app/src/main/res/layout/page_view.xml diff --git a/app/src/main/java/io/legado/app/base/BaseViewModel.kt b/app/src/main/java/io/legado/app/base/BaseViewModel.kt index f21cbdf06..f24e5876c 100644 --- a/app/src/main/java/io/legado/app/base/BaseViewModel.kt +++ b/app/src/main/java/io/legado/app/base/BaseViewModel.kt @@ -12,12 +12,12 @@ import org.jetbrains.anko.AnkoLogger open class BaseViewModel(application: Application) : AndroidViewModel(application), CoroutineScope by MainScope(), AnkoLogger { - fun execute(block: suspend CoroutineScope.() -> T): Coroutine { - return Coroutine.async(this) { block() } + fun execute(scope: CoroutineScope = this, block: suspend CoroutineScope.() -> T): Coroutine { + return Coroutine.async(scope) { block() } } - fun submit(block: suspend CoroutineScope.() -> Deferred): Coroutine { - return Coroutine.async(this) { block().await() } + fun submit(scope: CoroutineScope = this, block: suspend CoroutineScope.() -> Deferred): Coroutine { + return Coroutine.async(scope) { block().await() } } fun plus(coroutine: Coroutine): Coroutine { diff --git a/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt b/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt index 030295275..087107d4a 100644 --- a/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt +++ b/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt @@ -7,7 +7,7 @@ class Coroutine() { companion object { - private val DEFAULT = MainScope() + val DEFAULT = MainScope() fun async(scope: CoroutineScope = DEFAULT, block: suspend CoroutineScope.() -> T): Coroutine { return Coroutine(scope, block) @@ -22,6 +22,7 @@ class Coroutine() { private var job: Job? = null private var start: (suspend CoroutineScope.() -> Unit)? = null + private var execute: (suspend CoroutineScope.(T?) -> Unit)? = null private var success: (suspend CoroutineScope.(T?) -> Unit)? = null private var error: (suspend CoroutineScope.(Throwable) -> Unit)? = null private var finally: (suspend CoroutineScope.() -> Unit)? = null @@ -80,6 +81,15 @@ class Coroutine() { return this@Coroutine } + fun onExecute(execute: suspend CoroutineScope.(T?) -> Unit): Coroutine { + if (this.interceptor != null) { + this.interceptor!!.execute = execute + } else { + this.execute = execute + } + return this@Coroutine + } + fun onSuccess(success: suspend CoroutineScope.(T?) -> Unit): Coroutine { if (this.interceptor != null) { this.interceptor!!.success = success @@ -117,7 +127,7 @@ class Coroutine() { { start?.invoke(this) - val result = executeBlock(block, timeMillis ?: 0L) + val result = executeBlockIO(block, timeMillis ?: 0L) success?.invoke(this, result) }, @@ -136,11 +146,15 @@ class Coroutine() { }) } - private suspend fun executeBlock(block: suspend CoroutineScope.() -> T, timeMillis: Long): T? { - val asyncBlock = withContext(Dispatchers.IO) { - block() + private suspend fun executeBlockIO(block: suspend CoroutineScope.() -> T, timeMillis: Long): T? { + val result: T = withContext(Dispatchers.IO) { + val b = block() + + execute?.invoke(this, b) + + b } - return if (timeMillis > 0L) withTimeout(timeMillis) { asyncBlock } else asyncBlock + return if (timeMillis > 0L) withTimeout(timeMillis) { result } else result } private suspend fun tryCatch( diff --git a/app/src/main/java/io/legado/app/help/storage/Restore.kt b/app/src/main/java/io/legado/app/help/storage/Restore.kt index 62342bb9c..28cfec374 100644 --- a/app/src/main/java/io/legado/app/help/storage/Restore.kt +++ b/app/src/main/java/io/legado/app/help/storage/Restore.kt @@ -102,58 +102,61 @@ object Restore { source.bookSourceUrl = jsonItem.readString("bookSourceUrl") ?: "" if (source.bookSourceUrl.isBlank()) continue if (source.bookSourceUrl in existingSources) continue - source.bookSourceName = jsonItem.readString("bookSourceName") ?: "" - source.bookSourceGroup = jsonItem.readString("bookSourceGroup") ?: "" - source.loginUrl = jsonItem.readString("loginUrl") - source.bookUrlPattern = jsonItem.readString("ruleBookUrlPattern") - source.customOrder = jsonItem.readInt("serialNumber") ?: 0 - val searchRule = SearchRule( - searchUrl = OldRule.toNewUrl(jsonItem.readString("ruleSearchUrl")), - bookList = jsonItem.readString("ruleSearchList"), - name = jsonItem.readString("ruleSearchName"), - author = jsonItem.readString("ruleSearchAuthor"), - intro = jsonItem.readString("ruleSearchIntroduce"), - kind = jsonItem.readString("ruleSearchKind"), - bookUrl = jsonItem.readString("ruleSearchNoteUrl"), - coverUrl = jsonItem.readString("ruleSearchCoverUrl"), - lastChapter = jsonItem.readString("ruleSearchLastChapter") - ) - source.ruleSearch = GSON.toJson(searchRule) - val exploreRule = ExploreRule( - exploreUrl = OldRule.toNewUrl(jsonItem.readString("ruleFindUrl")), - bookList = jsonItem.readString("ruleFindList"), - name = jsonItem.readString("ruleFindName"), - author = jsonItem.readString("ruleFindAuthor"), - intro = jsonItem.readString("ruleFindIntroduce"), - kind = jsonItem.readString("ruleFindKind"), - bookUrl = jsonItem.readString("ruleFindNoteUrl"), - coverUrl = jsonItem.readString("ruleFindCoverUrl"), - lastChapter = jsonItem.readString("ruleFindLastChapter") - ) - source.ruleExplore = GSON.toJson(exploreRule) - val bookInfoRule = BookInfoRule( - init = jsonItem.readString("ruleBookInfoInit"), - name = jsonItem.readString("ruleBookName"), - author = jsonItem.readString("ruleBookAuthor"), - intro = jsonItem.readString("ruleIntroduce"), - kind = jsonItem.readString("ruleBookKind"), - coverUrl = jsonItem.readString("ruleCoverUrl"), - lastChapter = jsonItem.readString("ruleBookLastChapter"), - tocUrl = jsonItem.readString("ruleChapterUrl") - ) - source.ruleBookInfo = GSON.toJson(bookInfoRule) - val chapterRule = TocRule( - chapterList = jsonItem.readString("ruleChapterList"), - chapterName = jsonItem.readString("ruleChapterName"), - chapterUrl = jsonItem.readString("ruleContentUrl"), - nextTocUrl = jsonItem.readString("ruleChapterUrlNext") - ) - source.ruleToc = GSON.toJson(chapterRule) - val contentRule = ContentRule( - content = jsonItem.readString("ruleBookContent"), - nextContentUrl = jsonItem.readString("ruleContentUrlNext") - ) - source.ruleContent = GSON.toJson(contentRule) + runCatching { + source.bookSourceName = jsonItem.readString("bookSourceName") ?: "" + source.bookSourceGroup = jsonItem.readString("bookSourceGroup") ?: "" + source.loginUrl = jsonItem.readString("loginUrl") + source.bookUrlPattern = jsonItem.readString("ruleBookUrlPattern") + source.customOrder = jsonItem.readInt("serialNumber") ?: 0 + val searchRule = SearchRule( + searchUrl = OldRule.toNewUrl(jsonItem.readString("ruleSearchUrl")), + bookList = jsonItem.readString("ruleSearchList"), + name = jsonItem.readString("ruleSearchName"), + author = jsonItem.readString("ruleSearchAuthor"), + intro = jsonItem.readString("ruleSearchIntroduce"), + kind = jsonItem.readString("ruleSearchKind"), + bookUrl = jsonItem.readString("ruleSearchNoteUrl"), + coverUrl = jsonItem.readString("ruleSearchCoverUrl"), + lastChapter = jsonItem.readString("ruleSearchLastChapter") + ) + source.ruleSearch = GSON.toJson(searchRule) + val exploreRule = ExploreRule( + exploreUrl = OldRule.toNewUrl(jsonItem.readString("ruleFindUrl")), + bookList = jsonItem.readString("ruleFindList"), + name = jsonItem.readString("ruleFindName"), + author = jsonItem.readString("ruleFindAuthor"), + intro = jsonItem.readString("ruleFindIntroduce"), + kind = jsonItem.readString("ruleFindKind"), + bookUrl = jsonItem.readString("ruleFindNoteUrl"), + coverUrl = jsonItem.readString("ruleFindCoverUrl"), + lastChapter = jsonItem.readString("ruleFindLastChapter") + ) + source.ruleExplore = GSON.toJson(exploreRule) + val bookInfoRule = BookInfoRule( + init = jsonItem.readString("ruleBookInfoInit"), + name = jsonItem.readString("ruleBookName"), + author = jsonItem.readString("ruleBookAuthor"), + intro = jsonItem.readString("ruleIntroduce"), + kind = jsonItem.readString("ruleBookKind"), + coverUrl = jsonItem.readString("ruleCoverUrl"), + lastChapter = jsonItem.readString("ruleBookLastChapter"), + tocUrl = jsonItem.readString("ruleChapterUrl") + ) + source.ruleBookInfo = GSON.toJson(bookInfoRule) + val chapterRule = TocRule( + chapterList = jsonItem.readString("ruleChapterList"), + chapterName = jsonItem.readString("ruleChapterName"), + chapterUrl = jsonItem.readString("ruleContentUrl"), + nextTocUrl = jsonItem.readString("ruleChapterUrlNext") + ) + source.ruleToc = GSON.toJson(chapterRule) + val contentRule = ContentRule( + content = jsonItem.readString("ruleBookContent"), + nextContentUrl = jsonItem.readString("ruleContentUrlNext") + ) + source.ruleContent = GSON.toJson(contentRule) + } + bookSources.add(source) } App.db.bookSourceDao().insert(*bookSources.toTypedArray()) diff --git a/app/src/main/java/io/legado/app/model/WebBook.kt b/app/src/main/java/io/legado/app/model/WebBook.kt index b8bafd83a..0b764b898 100644 --- a/app/src/main/java/io/legado/app/model/WebBook.kt +++ b/app/src/main/java/io/legado/app/model/WebBook.kt @@ -10,14 +10,15 @@ import io.legado.app.model.webbook.BookChapterList import io.legado.app.model.webbook.BookContent import io.legado.app.model.webbook.BookInfo import io.legado.app.model.webbook.BookList +import kotlinx.coroutines.CoroutineScope class WebBook(private val bookSource: BookSource) { val sourceUrl: String get() = bookSource.bookSourceUrl - fun searchBook(key: String, page: Int?, isSearch: Boolean = true): Coroutine> { - return Coroutine.async { + fun searchBook(key: String, page: Int?, isSearch: Boolean = true, scope: CoroutineScope = Coroutine.DEFAULT): Coroutine> { + return Coroutine.async(scope) { bookSource.getSearchRule().searchUrl?.let { searchUrl -> val analyzeUrl = AnalyzeUrl(searchUrl, key, page, baseUrl = sourceUrl) val response = analyzeUrl.getResponseAsync().await() diff --git a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt index a7cd9c5e7..a51922f7b 100644 --- a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt +++ b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt @@ -5,6 +5,7 @@ import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter import io.legado.app.help.BookHelp import io.legado.app.help.coroutine.CompositeCoroutine +import io.legado.app.help.coroutine.Coroutine import io.legado.app.model.WebBook import io.legado.app.utils.htmlFormat import io.legado.app.utils.isAbsUrl diff --git a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt index 774c6f329..41dd8574a 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt @@ -14,13 +14,14 @@ import io.legado.app.constant.Bus import io.legado.app.help.permission.Permissions import io.legado.app.help.permission.PermissionsCompat import io.legado.app.lib.theme.ATH -import io.legado.app.lib.theme.Selector -import io.legado.app.lib.theme.ThemeStore import io.legado.app.ui.main.bookshelf.BookshelfFragment import io.legado.app.ui.main.findbook.FindBookFragment import io.legado.app.ui.main.my.MyFragment import io.legado.app.ui.main.rss.RssFragment -import io.legado.app.utils.* +import io.legado.app.utils.getPrefInt +import io.legado.app.utils.getViewModel +import io.legado.app.utils.observeEvent +import io.legado.app.utils.putPrefInt import kotlinx.android.synthetic.main.activity_main.* import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.launch diff --git a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt b/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt index e81d5c1b0..ca48a9312 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt @@ -4,37 +4,32 @@ import android.app.Application import io.legado.app.App import io.legado.app.base.BaseViewModel import io.legado.app.help.coroutine.CompositeCoroutine +import io.legado.app.help.coroutine.Coroutine import io.legado.app.model.WebBook class SearchViewModel(application: Application) : BaseViewModel(application) { - private val tasks: CompositeCoroutine = CompositeCoroutine() + private var task: Coroutine<*>? = null + var searchPage = 0 fun search(key: String, start: ((startTime: Long) -> Unit)? = null, finally: (() -> Unit)? = null) { if (key.isEmpty()) return - tasks.clear() + task?.cancel() start?.invoke(System.currentTimeMillis()) - execute { + task = execute {//onCleared时自动取消 val bookSourceList = App.db.bookSourceDao().allEnabled for (item in bookSourceList) { - val search = WebBook(item).searchBook(key, searchPage) - .onSuccess { searchBookS -> + //task取消时自动取消 by (scope = this@execute) + WebBook(item).searchBook(key, searchPage, scope = this) + .onExecute { searchBookS -> searchBookS?.let { - execute { - App.db.searchBookDao().insert(*it.toTypedArray()) - } + App.db.searchBookDao().insert(*it.toTypedArray()) } } - tasks.add(search) } }.onError { it.printStackTrace() } } - - override fun onCleared() { - super.onCleared() - tasks.clear() - } } diff --git a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt index e5c800b20..6d5689ad4 100644 --- a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt +++ b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt @@ -44,4 +44,5 @@ class SourceDebugModel(application: Application) : BaseViewModel(application), S super.onCleared() SourceDebug.cancelDebug(true) } + } diff --git a/app/src/main/java/io/legado/app/ui/widget/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/PageView.kt deleted file mode 100644 index 7844f7e3f..000000000 --- a/app/src/main/java/io/legado/app/ui/widget/PageView.kt +++ /dev/null @@ -1,77 +0,0 @@ -package io.legado.app.ui.widget - -import android.content.Context -import android.graphics.Bitmap -import android.graphics.Canvas -import android.graphics.Rect -import android.graphics.drawable.GradientDrawable -import android.util.AttributeSet -import android.util.Log -import android.view.MotionEvent -import androidx.appcompat.widget.AppCompatTextView -import io.legado.app.utils.screenshot -import kotlin.math.abs - -class PageView(context: Context, attrs: AttributeSet) : AppCompatTextView(context, attrs) { - - private var bitmap: Bitmap? = null - - private var downX: Float = 0.toFloat() - private var offset: Float = 0.toFloat() - - private val srcRect: Rect = Rect() - private val destRect: Rect = Rect() - private val shadowDrawable: GradientDrawable - - init { - val shadowColors = intArrayOf(0x66111111, 0x00000000) - shadowDrawable = GradientDrawable( - GradientDrawable.Orientation.LEFT_RIGHT, shadowColors - ) - shadowDrawable.gradientType = GradientDrawable.LINEAR_GRADIENT - } - - override fun onDraw(canvas: Canvas?) { - canvas?.save() - super.onDraw(canvas) - canvas?.restore() - - - bitmap?.let { - srcRect.set(0, 0, width, height) - destRect.set(-width + offset.toInt(), 0, offset.toInt(), height) - canvas?.drawBitmap(it, srcRect, destRect, null) - addShadow(offset.toInt(), canvas) - } - } - - //添加阴影 - private fun addShadow(left: Int, canvas: Canvas?) { - canvas?.let { - shadowDrawable.setBounds(left, 0, left + 30, height) - shadowDrawable.draw(it) - } - } - - override fun onTouchEvent(event: MotionEvent?): Boolean { - when (event?.action) { - MotionEvent.ACTION_DOWN -> { - bitmap = screenshot() - Log.e("TAG", "bitmap == null: " + (bitmap == null)) - downX = event.x - offset = 0.toFloat() - invalidate() - } - MotionEvent.ACTION_MOVE -> { - offset = abs(event.x - downX) - invalidate() - } - MotionEvent.ACTION_UP -> { - bitmap = null - invalidate() - } - } - - return true - } -} diff --git a/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt b/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt new file mode 100644 index 000000000..f4cb075ed --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt @@ -0,0 +1,12 @@ +package io.legado.app.ui.widget.page + +interface DataSource { + + fun getChapterPosition() + + fun getChapter(position: Int): TextChapter + + fun getNextChapter(): TextChapter + + fun getPreviousChapter(): TextChapter +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageAnimDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageAnimDelegate.kt new file mode 100644 index 000000000..eb4301588 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageAnimDelegate.kt @@ -0,0 +1,39 @@ +package io.legado.app.ui.widget.page + +import android.widget.Scroller +import androidx.interpolator.view.animation.FastOutLinearInInterpolator + +abstract class PageAnimDelegate(protected val pageView: PageView) { + + protected val scroller: Scroller = Scroller(pageView.context, FastOutLinearInInterpolator()) + + //起始点 + protected var startX: Float = 0.toFloat() + protected var startY: Float = 0.toFloat() + //触碰点 + protected var touchX: Float = 0.toFloat() + protected var touchY: Float = 0.toFloat() + //上一个触碰点 + protected var lastX: Float = 0.toFloat() + protected var lastY: Float = 0.toFloat() + + protected var isRunning = false + protected var isStarted = false + + + fun setStartPoint(x: Float, y: Float) { + startX = x + startY = y + + lastX = startX + lastY = startY + } + + fun setTouchPoint(x: Float, y: Float) { + lastX = touchX + lastY = touchY + + touchX = x + touchY = y + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageFactory.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageFactory.kt new file mode 100644 index 000000000..f2bebfbf5 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageFactory.kt @@ -0,0 +1,11 @@ +package io.legado.app.ui.widget.page + +abstract class PageFactory(protected val dataSource: DataSource) { + + abstract fun pageAt(index: Int): DATA + + abstract fun nextPage(): DATA + + abstract fun previousPage(): DATA + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt new file mode 100644 index 000000000..2ff709124 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -0,0 +1,55 @@ +package io.legado.app.ui.widget.page + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.Canvas +import android.graphics.Rect +import android.graphics.drawable.GradientDrawable +import android.util.AttributeSet +import android.util.Log +import android.view.MotionEvent +import android.view.View +import android.widget.FrameLayout +import androidx.appcompat.widget.AppCompatTextView +import io.legado.app.R +import io.legado.app.utils.screenshot +import kotlin.math.abs + +class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, attrs) { + + private var bitmap: Bitmap? = null + + private var downX: Float = 0.toFloat() + private var offset: Float = 0.toFloat() + + private val srcRect: Rect = Rect() + private val destRect: Rect = Rect() + private val shadowDrawable: GradientDrawable + + init { + val shadowColors = intArrayOf(0x66111111, 0x00000000) + shadowDrawable = GradientDrawable( + GradientDrawable.Orientation.LEFT_RIGHT, shadowColors + ) + shadowDrawable.gradientType = GradientDrawable.LINEAR_GRADIENT + + inflate(context, R.layout.page_view, this) + } + + override fun onDraw(canvas: Canvas?) { + canvas?.save() + super.onDraw(canvas) + canvas?.restore() + + + } + + override fun onTouchEvent(event: MotionEvent?): Boolean { + + return true + } + + fun setPageFactory(factory: PageFactory<*>){ + + } +} diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt new file mode 100644 index 000000000..b4414c19b --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt @@ -0,0 +1,3 @@ +package io.legado.app.ui.widget.page + +data class TextChapter(val position: Int, val pages: List) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextPage.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextPage.kt new file mode 100644 index 000000000..186eb757e --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextPage.kt @@ -0,0 +1,3 @@ +package io.legado.app.ui.widget.page + +data class TextPage(val index: Int, val text: String) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt new file mode 100644 index 000000000..2fd3d951c --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt @@ -0,0 +1,26 @@ +package io.legado.app.ui.widget.page + +class TextPageFactory private constructor(dataSource: DataSource) : PageFactory(dataSource) { + + companion object{ + fun create(dataSource: DataSource): TextPageFactory{ + return TextPageFactory(dataSource) + } + } + + private var index: Int = 0 + + override fun pageAt(index: Int): TextPage { + TODO("todo...") + } + + override fun nextPage(): TextPage { + return TextPage(index.plus(1), "index:$index") + } + + override fun previousPage(): TextPage { + return TextPage(index.minus(1), "index:$index") + } + + +} diff --git a/app/src/main/res/layout/activity_read.xml b/app/src/main/res/layout/activity_read.xml index fc9704d8b..72ce083ea 100644 --- a/app/src/main/res/layout/activity_read.xml +++ b/app/src/main/res/layout/activity_read.xml @@ -4,7 +4,7 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - + + + + + + + + + + + + + + + + \ No newline at end of file From cc7816949fba0dd8992a0ced7ad4d738c66dfe69 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 5 Aug 2019 23:07:13 +0800 Subject: [PATCH 0583/1997] up --- .../io/legado/app/data/dao/SearchBookDao.kt | 3 +++ .../io/legado/app/data/entities/SearchShow.kt | 27 +++++++++++++++++++ .../io/legado/app/ui/search/SearchActivity.kt | 6 ++--- .../io/legado/app/ui/search/SearchAdapter.kt | 16 +++++------ 4 files changed, 41 insertions(+), 11 deletions(-) create mode 100644 app/src/main/java/io/legado/app/data/entities/SearchShow.kt diff --git a/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt b/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt index fb58efd8a..0336d7ef7 100644 --- a/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt @@ -6,6 +6,7 @@ import androidx.room.Insert import androidx.room.OnConflictStrategy import androidx.room.Query import io.legado.app.data.entities.SearchBook +import io.legado.app.data.entities.SearchShow @Dao interface SearchBookDao { @@ -16,6 +17,8 @@ interface SearchBookDao { @Query("SELECT * FROM searchBooks where time >= :time") fun observeNew(time: Long): DataSource.Factory + @Query("SELECT name, author, min(time) time, max(kind) kind, max(coverUrl) coverUrl, max(intro) intro, max(wordCount) wordCount, max(latestChapterTitle) latestChapterTitle, count(origin) originCount FROM searchBooks where time >= :time group by name, author") + fun observeShow(time: Long): DataSource.Factory @Insert(onConflict = OnConflictStrategy.REPLACE) fun insert(vararg searchBook: SearchBook): List diff --git a/app/src/main/java/io/legado/app/data/entities/SearchShow.kt b/app/src/main/java/io/legado/app/data/entities/SearchShow.kt new file mode 100644 index 000000000..31268aefb --- /dev/null +++ b/app/src/main/java/io/legado/app/data/entities/SearchShow.kt @@ -0,0 +1,27 @@ +package io.legado.app.data.entities + +import io.legado.app.utils.splitNotBlank + +data class SearchShow( + var name: String? = null, + var author: String? = null, + var kind: String? = null, + var coverUrl: String? = null, + var intro: String? = null, + var wordCount: String? = null, + var latestChapterTitle: String? = null, + var time: Long = 0L, + var originCount: Int = 0 +) { + fun getKindList(): List { + val kindList = arrayListOf() + wordCount?.let { + if (it.isNotBlank()) kindList.add(it) + } + kind?.let { + val kinds = it.splitNotBlank(",", "\n") + kindList.addAll(kinds) + } + return kindList + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt index eb26a882c..25a47169b 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt @@ -11,7 +11,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.App import io.legado.app.R import io.legado.app.base.VMBaseActivity -import io.legado.app.data.entities.SearchBook +import io.legado.app.data.entities.SearchShow import io.legado.app.lib.theme.ATH import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_search.* @@ -23,7 +23,7 @@ class SearchActivity : VMBaseActivity(R.layout.activity_search) get() = getViewModel(SearchViewModel::class.java) private lateinit var adapter: SearchAdapter - private var searchBookData: LiveData>? = null + private var searchBookData: LiveData>? = null override fun onActivityCreated(savedInstanceState: Bundle?) { initRecyclerView() @@ -70,7 +70,7 @@ class SearchActivity : VMBaseActivity(R.layout.activity_search) private fun initData(startTime: Long) { searchBookData?.removeObservers(this) - searchBookData = LivePagedListBuilder(App.db.searchBookDao().observeNew(startTime), 30).build() + searchBookData = LivePagedListBuilder(App.db.searchBookDao().observeShow(startTime), 30).build() searchBookData?.observe(this, Observer { adapter.submitList(it) }) } diff --git a/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt b/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt index 4488d9f8c..2c46fd479 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt @@ -7,7 +7,7 @@ import androidx.paging.PagedListAdapter import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import io.legado.app.R -import io.legado.app.data.entities.SearchBook +import io.legado.app.data.entities.SearchShow import io.legado.app.help.ImageLoader import io.legado.app.utils.gone import io.legado.app.utils.visible @@ -16,17 +16,17 @@ import kotlinx.android.synthetic.main.item_bookshelf_list.view.tv_name import kotlinx.android.synthetic.main.item_search.view.* import org.jetbrains.anko.sdk27.listeners.onClick -class SearchAdapter : PagedListAdapter(DIFF_CALLBACK) { +class SearchAdapter : PagedListAdapter(DIFF_CALLBACK) { companion object { @JvmField - val DIFF_CALLBACK = object : DiffUtil.ItemCallback() { - override fun areItemsTheSame(oldItem: SearchBook, newItem: SearchBook): Boolean = + val DIFF_CALLBACK = object : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: SearchShow, newItem: SearchShow): Boolean = oldItem.name == newItem.name && oldItem.author == newItem.author - override fun areContentsTheSame(oldItem: SearchBook, newItem: SearchBook): Boolean = + override fun areContentsTheSame(oldItem: SearchShow, newItem: SearchShow): Boolean = oldItem.name == newItem.name && oldItem.author == newItem.author } @@ -47,7 +47,7 @@ class SearchAdapter : PagedListAdapter(D class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { - fun bind(searchBook: SearchBook, callBack: CallBack?) = with(itemView) { + fun bind(searchBook: SearchShow, callBack: CallBack?) = with(itemView) { tv_name.text = searchBook.name tv_author.text = searchBook.author tv_lasted.text = context.getString(R.string.book_search_last, searchBook.latestChapterTitle) @@ -90,12 +90,12 @@ class SearchAdapter : PagedListAdapter(D .setAsDrawable(iv_cover) } onClick { - callBack?.showBookInfo(searchBook) + callBack?.showBookInfo(searchBook.name, searchBook.author) } } } interface CallBack { - fun showBookInfo(searchBook: SearchBook) + fun showBookInfo(name: String?, author: String?) } } \ No newline at end of file From 190eb6eff59bc58661b9fad3f5e34eeb23c14fd4 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 6 Aug 2019 14:15:04 +0800 Subject: [PATCH 0584/1997] up --- .../io/legado/app/model/analyzeRule/AnalyzeByJSonPath.kt | 8 ++++---- .../io/legado/app/model/analyzeRule/AnalyzeByJSoup.kt | 4 ++-- .../io/legado/app/model/analyzeRule/AnalyzeByXPath.kt | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSonPath.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSonPath.kt index 298c1d2fa..60a3510c2 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSonPath.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSonPath.kt @@ -62,17 +62,17 @@ class AnalyzeByJSonPath { return result } } else { - val sb = StringBuilder() + val textList = arrayListOf() for (rl in rules) { val temp = getString(rl) - if (!TextUtils.isEmpty(temp)) { - sb.append(temp) + if (!temp.isNullOrEmpty()) { + textList.add(temp) if (elementsType == "|") { break } } } - return sb.toString() + return TextUtils.join(",", textList) } } diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSoup.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSoup.kt index 879d18b05..7be879bbe 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSoup.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSoup.kt @@ -75,7 +75,7 @@ class AnalyzeByJSoup { //拆分规则 val sourceRule = SourceRule(ruleStr) if (isEmpty(sourceRule.elementsRule)) { - textS.add(element!!.data()) + textS.add(element?.data() ?: "") } else { val elementsType: String val ruleStrS: Array @@ -105,7 +105,7 @@ class AnalyzeByJSoup { } else { getResultList(ruleStrX) } - if (temp != null && temp.isNotEmpty()) { + if (!temp.isNullOrEmpty()) { results.add(temp) if (results.isNotEmpty() && elementsType == "|") { break diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByXPath.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByXPath.kt index 23030393c..0989f88d5 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByXPath.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByXPath.kt @@ -154,17 +154,17 @@ class AnalyzeByXPath { } return null } else { - val sb = StringBuilder() + val textList = arrayListOf() for (rl in rules) { val temp = getString(rl) - if (!TextUtils.isEmpty(temp)) { - sb.append(temp) + if (!temp.isNullOrEmpty()) { + textList.add(temp) if (elementsType == "|") { break } } } - return sb.toString() + return TextUtils.join(",", textList) } } } From 5d0462c2f7b8cf25d509f10d769b77e77b5e2275 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 6 Aug 2019 14:39:55 +0800 Subject: [PATCH 0585/1997] up --- .../io/legado/app/model/analyzeRule/AnalyzeByJSoup.kt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSoup.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSoup.kt index 7be879bbe..32e7d2a16 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSoup.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSoup.kt @@ -51,7 +51,7 @@ class AnalyzeByJSoup { val textS = getStringList(ruleStr) return if (textS.isEmpty()) { null - } else join("\n", textS).trim { it <= ' ' } + } else join(",", textS).trim { it <= ' ' } } /** @@ -360,13 +360,15 @@ class AnalyzeByJSoup { textS.add(text) } "textNodes" -> for (element in elements) { + val tn = arrayListOf() val contentEs = element.textNodes() - for (i in contentEs.indices) { - val temp = contentEs[i].text().trim { it <= ' ' } + for (item in contentEs) { + val temp = item.text().trim { it <= ' ' } if (!isEmpty(temp)) { - textS.add(temp) + tn.add(temp) } } + textS.add(join("\n", tn)) } "ownText", "html" -> { elements.select("script").remove() From 189ed326dc58d6511a7fa5a137bafe1f37e0ede7 Mon Sep 17 00:00:00 2001 From: Administrator <1760316362@qq.com> Date: Tue, 6 Aug 2019 14:46:13 +0800 Subject: [PATCH 0586/1997] update --- .../app/help/coroutine/CompositeCoroutine.kt | 11 +++-- .../io/legado/app/help/coroutine/Coroutine.kt | 44 +++++++++---------- .../app/help/coroutine/CoroutineContainer.kt | 2 +- .../io/legado/app/ui/search/SearchActivity.kt | 4 +- .../legado/app/ui/search/SearchViewModel.kt | 28 +++++++++--- app/src/main/res/layout/activity_search.xml | 1 + 6 files changed, 52 insertions(+), 38 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/coroutine/CompositeCoroutine.kt b/app/src/main/java/io/legado/app/help/coroutine/CompositeCoroutine.kt index 99c2df223..c832b475d 100644 --- a/app/src/main/java/io/legado/app/help/coroutine/CompositeCoroutine.kt +++ b/app/src/main/java/io/legado/app/help/coroutine/CompositeCoroutine.kt @@ -1,5 +1,7 @@ package io.legado.app.help.coroutine +import android.util.Log + class CompositeCoroutine : CoroutineContainer { private var resources: HashSet>? = null @@ -76,10 +78,11 @@ class CompositeCoroutine : CoroutineContainer { resources = null } - set?.forEach { - runCatching { - it.cancel() - } + Log.e("TAG", "size: ${set?.size}") + + set?.forEachIndexed { index, coroutine -> + Log.e("TAG", "index: $index") + coroutine.cancel() } } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt b/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt index 087107d4a..f74d880b3 100644 --- a/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt +++ b/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt @@ -44,8 +44,8 @@ class Coroutine() { scope: CoroutineScope, block: suspend CoroutineScope.() -> T ) : this() { - this.job = scope.launch { - executeInternal(block) + this.job = scope.plus(Dispatchers.Main).launch { + executeInternal(this@launch, block) } } @@ -119,55 +119,51 @@ class Coroutine() { //取消当前任务 fun cancel(cause: CancellationException? = null) { + job?.cancelChildren(cause) job?.cancel(cause) } - private suspend fun executeInternal(block: suspend CoroutineScope.() -> T) { + private suspend fun executeInternal(scope: CoroutineScope, block: suspend CoroutineScope.() -> T) { tryCatch( { - start?.invoke(this) - + start?.invoke(scope) val result = executeBlockIO(block, timeMillis ?: 0L) - - success?.invoke(this, result) + success?.invoke(scope, result) }, { e -> val consume: Boolean = errorReturn?.value?.let { value -> - success?.invoke(this, value) + success?.invoke(scope, value) true } ?: false - if (!consume) { - error?.invoke(this, e) + error?.invoke(scope, e) } }, { - finally?.invoke(this) + finally?.invoke(scope) }) } private suspend fun executeBlockIO(block: suspend CoroutineScope.() -> T, timeMillis: Long): T? { - val result: T = withContext(Dispatchers.IO) { - val b = block() - - execute?.invoke(this, b) - - b + val execution = withContext(Dispatchers.IO) { + val result = block() + execute?.invoke(this, result) + result } - return if (timeMillis > 0L) withTimeout(timeMillis) { result } else result + return if (timeMillis > 0L) withTimeout(timeMillis) { execution } else execution } private suspend fun tryCatch( - tryBlock: suspend CoroutineScope.() -> Unit, - errorBlock: (suspend CoroutineScope.(Throwable) -> Unit)? = null, - finallyBlock: (suspend CoroutineScope.() -> Unit)? = null + tryBlock: suspend () -> Unit, + errorBlock: (suspend (Throwable) -> Unit)? = null, + finallyBlock: (suspend () -> Unit)? = null ) { try { - coroutineScope { tryBlock() } + tryBlock() } catch (e: Throwable) { - coroutineScope { errorBlock?.invoke(this, e) } + errorBlock?.invoke(e) } finally { - coroutineScope { finallyBlock?.invoke(this) } + finallyBlock?.invoke() } } diff --git a/app/src/main/java/io/legado/app/help/coroutine/CoroutineContainer.kt b/app/src/main/java/io/legado/app/help/coroutine/CoroutineContainer.kt index d98a2b8da..8ef02af1f 100644 --- a/app/src/main/java/io/legado/app/help/coroutine/CoroutineContainer.kt +++ b/app/src/main/java/io/legado/app/help/coroutine/CoroutineContainer.kt @@ -1,6 +1,6 @@ package io.legado.app.help.coroutine -interface CoroutineContainer { +internal interface CoroutineContainer { fun add(coroutine: Coroutine<*>): Boolean diff --git a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt index 25a47169b..52222d541 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt @@ -11,6 +11,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.App import io.legado.app.R import io.legado.app.base.VMBaseActivity +import io.legado.app.data.entities.SearchBook import io.legado.app.data.entities.SearchShow import io.legado.app.lib.theme.ATH import io.legado.app.utils.getViewModel @@ -44,14 +45,13 @@ class SearchActivity : VMBaseActivity(R.layout.activity_search) viewModel.search(it, { startTime -> content_view.showContentView() initData(startTime) - }, { - }) } return true } override fun onQueryTextChange(newText: String?): Boolean { + if(newText.isNullOrBlank()) viewModel.stop() return false } diff --git a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt b/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt index ca48a9312..12f331fc4 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt @@ -3,7 +3,6 @@ package io.legado.app.ui.search import android.app.Application import io.legado.app.App import io.legado.app.base.BaseViewModel -import io.legado.app.help.coroutine.CompositeCoroutine import io.legado.app.help.coroutine.Coroutine import io.legado.app.model.WebBook @@ -12,18 +11,24 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { var searchPage = 0 - fun search(key: String, start: ((startTime: Long) -> Unit)? = null, finally: (() -> Unit)? = null) { + fun search( + key: String, + start: ((startTime: Long) -> Unit)? = null, + finally: (() -> Unit)? = null + ) { if (key.isEmpty()) return task?.cancel() start?.invoke(System.currentTimeMillis()) - task = execute {//onCleared时自动取消 + task = execute { + //onCleared时自动取消 val bookSourceList = App.db.bookSourceDao().allEnabled for (item in bookSourceList) { //task取消时自动取消 by (scope = this@execute) - WebBook(item).searchBook(key, searchPage, scope = this) - .onExecute { searchBookS -> - searchBookS?.let { - App.db.searchBookDao().insert(*it.toTypedArray()) + WebBook(item).searchBook(key, searchPage, scope = this@execute) + .timeout { 30000L } + .onExecute { + it?.let { list -> + App.db.searchBookDao().insert(*list.toTypedArray()) } } } @@ -32,4 +37,13 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { it.printStackTrace() } } + + fun stop() { + task?.cancel() + } + + override fun onCleared() { + super.onCleared() + task?.cancel() + } } diff --git a/app/src/main/res/layout/activity_search.xml b/app/src/main/res/layout/activity_search.xml index 3837883c7..e330e1565 100644 --- a/app/src/main/res/layout/activity_search.xml +++ b/app/src/main/res/layout/activity_search.xml @@ -11,6 +11,7 @@ android:id="@+id/title_bar" android:layout_width="match_parent" android:layout_height="wrap_content" + app:contentInsetStartWithNavigation="0dp" app:layout_constraintTop_toTopOf="parent" app:title="搜索"/> From a4d60b4abe50da635266a77ab2522742ac0e1847 Mon Sep 17 00:00:00 2001 From: Administrator <1760316362@qq.com> Date: Tue, 6 Aug 2019 16:06:39 +0800 Subject: [PATCH 0587/1997] update --- .../main/java/io/legado/app/help/coroutine/Coroutine.kt | 3 +-- app/src/main/res/layout/activity_read.xml | 8 +------- app/src/main/res/layout/page_view.xml | 1 + 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt b/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt index f74d880b3..9013fc266 100644 --- a/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt +++ b/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt @@ -35,7 +35,7 @@ class Coroutine() { get() = job?.isCancelled ?: false val isActive: Boolean - get() = job?.isActive ?: false + get() = job?.isActive ?: true val isCompleted: Boolean get() = job?.isCompleted ?: false @@ -119,7 +119,6 @@ class Coroutine() { //取消当前任务 fun cancel(cause: CancellationException? = null) { - job?.cancelChildren(cause) job?.cancel(cause) } diff --git a/app/src/main/res/layout/activity_read.xml b/app/src/main/res/layout/activity_read.xml index 72ce083ea..1a16d9005 100644 --- a/app/src/main/res/layout/activity_read.xml +++ b/app/src/main/res/layout/activity_read.xml @@ -6,12 +6,6 @@ + android:layout_height="match_parent"/> \ No newline at end of file diff --git a/app/src/main/res/layout/page_view.xml b/app/src/main/res/layout/page_view.xml index d0c97cfce..fa67d4f81 100644 --- a/app/src/main/res/layout/page_view.xml +++ b/app/src/main/res/layout/page_view.xml @@ -16,6 +16,7 @@ From 65e926d4c1e80c7f1c4d38fe1f79accae70bc33c Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 6 Aug 2019 16:51:20 +0800 Subject: [PATCH 0588/1997] up --- .../java/io/legado/app/data/dao/BookChapterDao.kt | 4 ++++ app/src/main/java/io/legado/app/model/WebBook.kt | 4 ++-- .../java/io/legado/app/model/webbook/BookContent.kt | 13 ++++++++++++- .../java/io/legado/app/model/webbook/SourceDebug.kt | 8 ++++---- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/BookChapterDao.kt b/app/src/main/java/io/legado/app/data/dao/BookChapterDao.kt index 9cfe22e8d..a0b2b002f 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookChapterDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookChapterDao.kt @@ -3,11 +3,15 @@ package io.legado.app.data.dao import androidx.room.Dao import androidx.room.Insert import androidx.room.OnConflictStrategy +import androidx.room.Query import io.legado.app.data.entities.BookChapter @Dao interface BookChapterDao { + @Query("select * from chapters where bookUrl = :bookUrl and `index` = :index") + fun getChapter(bookUrl: String, index: Int): BookChapter? + @Insert(onConflict = OnConflictStrategy.REPLACE) fun insert(vararg bookChapter: BookChapter) diff --git a/app/src/main/java/io/legado/app/model/WebBook.kt b/app/src/main/java/io/legado/app/model/WebBook.kt index 0b764b898..f8b7148c9 100644 --- a/app/src/main/java/io/legado/app/model/WebBook.kt +++ b/app/src/main/java/io/legado/app/model/WebBook.kt @@ -44,11 +44,11 @@ class WebBook(private val bookSource: BookSource) { } } - fun getContent(book: Book, bookChapter: BookChapter): Coroutine { + fun getContent(book: Book, bookChapter: BookChapter, nextChapterUrl: String? = null): Coroutine { return Coroutine.async { val analyzeUrl = AnalyzeUrl(book = book, ruleUrl = bookChapter.url, baseUrl = book.tocUrl) val response = analyzeUrl.getResponseAsync().await() - BookContent.analyzeContent(this, response, book, bookSource) + BookContent.analyzeContent(this, response, book, bookChapter, bookSource, nextChapterUrl) } } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/model/webbook/BookContent.kt b/app/src/main/java/io/legado/app/model/webbook/BookContent.kt index a85ccb28c..a8e92444b 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookContent.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookContent.kt @@ -3,6 +3,7 @@ package io.legado.app.model.webbook import io.legado.app.App import io.legado.app.R import io.legado.app.data.entities.Book +import io.legado.app.data.entities.BookChapter import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.rule.ContentRule import io.legado.app.model.analyzeRule.AnalyzeRule @@ -20,7 +21,9 @@ object BookContent { coroutineScope: CoroutineScope, response: Response, book: Book, - bookSource: BookSource + bookChapter: BookChapter, + bookSource: BookSource, + nextChapterUrlF: String? = null ): String { val baseUrl: String = NetworkUtils.getUrl(response) val body: String? = response.body() @@ -38,7 +41,15 @@ object BookContent { content.append(contentData.content) if (contentData.nextUrl.size == 1) { var nextUrl = contentData.nextUrl[0] + val nextChapterUrl = if (!nextChapterUrlF.isNullOrEmpty()) + nextChapterUrlF + else + App.db.bookChapterDao().getChapter(book.bookUrl, bookChapter.index + 1)?.url while (nextUrl.isNotEmpty() && !nextUrlList.contains(nextUrl)) { + if (!nextChapterUrl.isNullOrEmpty() + && NetworkUtils.getAbsoluteURL(baseUrl, nextUrl) + == NetworkUtils.getAbsoluteURL(baseUrl, nextChapterUrl) + ) break nextUrlList.add(nextUrl) AnalyzeUrl(ruleUrl = nextUrl, book = book).getResponse().execute() .body()?.let { nextBody -> diff --git a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt index a51922f7b..c79b078f9 100644 --- a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt +++ b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt @@ -5,7 +5,6 @@ import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter import io.legado.app.help.BookHelp import io.legado.app.help.coroutine.CompositeCoroutine -import io.legado.app.help.coroutine.Coroutine import io.legado.app.model.WebBook import io.legado.app.utils.htmlFormat import io.legado.app.utils.isAbsUrl @@ -117,7 +116,8 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { if (it.isNotEmpty()) { printLog(debugSource, 1, "目录完成") printLog(debugSource, 1, "", showTime = false) - contentDebug(book, it[0]) + val nextChapterUrl = if (it.size > 1) it[1].url else null + contentDebug(book, it[0], nextChapterUrl) } else { printLog(debugSource, -1, "目录列表为空") } @@ -129,9 +129,9 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { tasks.add(chapterList) } - private fun contentDebug(book: Book, bookChapter: BookChapter) { + private fun contentDebug(book: Book, bookChapter: BookChapter, nextChapterUrl: String?) { printLog(debugSource, 1, "开始获取内容") - val content = webBook.getContent(book, bookChapter) + val content = webBook.getContent(book, bookChapter, nextChapterUrl) .onSuccess { content -> content?.let { printLog(debugSource, 1000, it) From 1f5de3bd2ce8d8976bd39f6401dafa3b571fc696 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 6 Aug 2019 17:09:27 +0800 Subject: [PATCH 0589/1997] up --- app/src/main/java/io/legado/app/data/dao/BookChapterDao.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/java/io/legado/app/data/dao/BookChapterDao.kt b/app/src/main/java/io/legado/app/data/dao/BookChapterDao.kt index a0b2b002f..7f42d74d8 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookChapterDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookChapterDao.kt @@ -1,5 +1,6 @@ package io.legado.app.data.dao +import androidx.paging.DataSource import androidx.room.Dao import androidx.room.Insert import androidx.room.OnConflictStrategy @@ -9,6 +10,9 @@ import io.legado.app.data.entities.BookChapter @Dao interface BookChapterDao { + @Query("select * from chapters where bookUrl = :bookUrl") + fun observeByBook(bookUrl: String): DataSource.Factory + @Query("select * from chapters where bookUrl = :bookUrl and `index` = :index") fun getChapter(bookUrl: String, index: Int): BookChapter? From b2267bf6e6ef0886d18aa49c98103ba2fbca7b5f Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 6 Aug 2019 17:45:44 +0800 Subject: [PATCH 0590/1997] up --- .../scroller/FastScrollRecyclerView.kt | 195 +++++++ .../scroller/FastScrollStateChangeListener.kt | 14 + .../widget/recycler/scroller/FastScroller.kt | 518 ++++++++++++++++++ .../java/io/legado/app/utils/ColorUtil.kt | 80 +++ app/src/main/res/layout/view_fastscroller.xml | 49 ++ app/src/main/res/values/ids.xml | 1 + 6 files changed, 857 insertions(+) create mode 100644 app/src/main/java/io/legado/app/ui/widget/recycler/scroller/FastScrollRecyclerView.kt create mode 100644 app/src/main/java/io/legado/app/ui/widget/recycler/scroller/FastScrollStateChangeListener.kt create mode 100644 app/src/main/java/io/legado/app/ui/widget/recycler/scroller/FastScroller.kt create mode 100644 app/src/main/java/io/legado/app/utils/ColorUtil.kt create mode 100644 app/src/main/res/layout/view_fastscroller.xml diff --git a/app/src/main/java/io/legado/app/ui/widget/recycler/scroller/FastScrollRecyclerView.kt b/app/src/main/java/io/legado/app/ui/widget/recycler/scroller/FastScrollRecyclerView.kt new file mode 100644 index 000000000..0a2ebf741 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/recycler/scroller/FastScrollRecyclerView.kt @@ -0,0 +1,195 @@ +package io.legado.app.ui.widget.recycler.scroller + +import android.content.Context +import android.util.AttributeSet +import android.view.ViewGroup +import androidx.annotation.ColorInt +import androidx.recyclerview.widget.RecyclerView +import io.legado.app.R + +class FastScrollRecyclerView : RecyclerView { + + private var mFastScroller: FastScroller? = null + + constructor(context: Context) : super(context) { + + layout(context, null) + + layoutParams = + LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT) + + } + + + @JvmOverloads + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int = 0) : super(context, attrs, defStyleAttr) { + + layout(context, attrs) + + } + + + override fun setAdapter(adapter: Adapter<*>?) { + + super.setAdapter(adapter) + + if (adapter is FastScroller.SectionIndexer) { + setSectionIndexer(adapter as FastScroller.SectionIndexer?) + } else if (adapter == null) { + setSectionIndexer(null) + } + + } + + + override fun setVisibility(visibility: Int) { + + super.setVisibility(visibility) + mFastScroller?.visibility = visibility + + } + + + /** + * Set the [FastScroller.SectionIndexer] for the [FastScroller]. + * + * @param sectionIndexer The SectionIndexer that provides section text for the FastScroller + */ + fun setSectionIndexer(sectionIndexer: FastScroller.SectionIndexer?) { + + mFastScroller?.setSectionIndexer(sectionIndexer) + + } + + + /** + * Set the enabled state of fast scrolling. + * + * @param enabled True to enable fast scrolling, false otherwise + */ + fun setFastScrollEnabled(enabled: Boolean) { + + mFastScroller!!.isEnabled = enabled + + } + + + /** + * Hide the scrollbar when not scrolling. + * + * @param hideScrollbar True to hide the scrollbar, false to show + */ + fun setHideScrollbar(hideScrollbar: Boolean) { + + mFastScroller?.setFadeScrollbar(hideScrollbar) + + } + + /** + * Display a scroll track while scrolling. + * + * @param visible True to show scroll track, false to hide + */ + fun setTrackVisible(visible: Boolean) { + + mFastScroller?.setTrackVisible(visible) + + } + + /** + * Set the color of the scroll track. + * + * @param color The color for the scroll track + */ + fun setTrackColor(@ColorInt color: Int) { + + mFastScroller?.setTrackColor(color) + + } + + + /** + * Set the color for the scroll handle. + * + * @param color The color for the scroll handle + */ + fun setHandleColor(@ColorInt color: Int) { + + mFastScroller?.setHandleColor(color) + + } + + + /** + * Show the section bubble while scrolling. + * + * @param visible True to show the bubble, false to hide + */ + fun setBubbleVisible(visible: Boolean) { + + mFastScroller?.setBubbleVisible(visible) + + } + + + /** + * Set the background color of the index bubble. + * + * @param color The background color for the index bubble + */ + fun setBubbleColor(@ColorInt color: Int) { + + mFastScroller?.setBubbleColor(color) + + } + + + /** + * Set the text color of the index bubble. + * + * @param color The text color for the index bubble + */ + fun setBubbleTextColor(@ColorInt color: Int) { + mFastScroller?.setBubbleTextColor(color) + } + + + /** + * Set the fast scroll state change listener. + * + * @param fastScrollStateChangeListener The interface that will listen to fastscroll state change events + */ + fun setFastScrollStateChangeListener(fastScrollStateChangeListener: FastScrollStateChangeListener) { + + mFastScroller?.setFastScrollStateChangeListener(fastScrollStateChangeListener) + + } + + + override fun onAttachedToWindow() { + + super.onAttachedToWindow() + + mFastScroller?.attachRecyclerView(this) + + val parent = parent + if (parent is ViewGroup) { + parent.addView(mFastScroller) + mFastScroller?.setLayoutParams(parent) + } + } + + + override fun onDetachedFromWindow() { + mFastScroller?.detachRecyclerView() + super.onDetachedFromWindow() + } + + + private fun layout(context: Context, attrs: AttributeSet?) { + mFastScroller = FastScroller(context, attrs) + mFastScroller?.id = R.id.fast_scroller + + } + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/recycler/scroller/FastScrollStateChangeListener.kt b/app/src/main/java/io/legado/app/ui/widget/recycler/scroller/FastScrollStateChangeListener.kt new file mode 100644 index 000000000..55afa8370 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/recycler/scroller/FastScrollStateChangeListener.kt @@ -0,0 +1,14 @@ +package io.legado.app.ui.widget.recycler.scroller + +interface FastScrollStateChangeListener { + + /** + * Called when fast scrolling begins + */ + fun onFastScrollStart(fastScroller: FastScroller) + + /** + * Called when fast scrolling ends + */ + fun onFastScrollStop(fastScroller: FastScroller) +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/recycler/scroller/FastScroller.kt b/app/src/main/java/io/legado/app/ui/widget/recycler/scroller/FastScroller.kt new file mode 100644 index 000000000..3b5acac27 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/recycler/scroller/FastScroller.kt @@ -0,0 +1,518 @@ +package io.legado.app.ui.widget.recycler.scroller + +import android.animation.Animator +import android.animation.AnimatorListenerAdapter +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.Color +import android.graphics.drawable.Drawable +import android.util.AttributeSet +import android.view.MotionEvent +import android.view.View +import android.view.ViewGroup +import android.view.ViewPropertyAnimator +import android.widget.* +import androidx.annotation.ColorInt +import androidx.annotation.IdRes +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.constraintlayout.widget.ConstraintSet +import androidx.coordinatorlayout.widget.CoordinatorLayout +import androidx.core.content.ContextCompat +import androidx.core.graphics.drawable.DrawableCompat +import androidx.core.view.GravityCompat +import androidx.core.view.ViewCompat +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import androidx.recyclerview.widget.StaggeredGridLayoutManager +import io.legado.app.R +import io.legado.app.lib.theme.accentColor +import io.legado.app.utils.ColorUtil +import io.legado.app.utils.getCompatColor +import kotlin.math.max +import kotlin.math.min +import kotlin.math.roundToInt + + +class FastScroller : LinearLayout { + @ColorInt + private var mBubbleColor: Int = 0 + @ColorInt + private var mHandleColor: Int = 0 + private var mBubbleHeight: Int = 0 + private var mHandleHeight: Int = 0 + private var mViewHeight: Int = 0 + private var mFadeScrollbar: Boolean = false + private var mShowBubble: Boolean = false + private var mSectionIndexer: SectionIndexer? = null + private var mScrollbarAnimator: ViewPropertyAnimator? = null + private var mBubbleAnimator: ViewPropertyAnimator? = null + private var mRecyclerView: RecyclerView? = null + private var mBubbleView: TextView? = null + private var mHandleView: ImageView? = null + private var mTrackView: ImageView? = null + private var mScrollbar: View? = null + private var mBubbleImage: Drawable? = null + private var mHandleImage: Drawable? = null + private var mTrackImage: Drawable? = null + private var mFastScrollStateChangeListener: FastScrollStateChangeListener? = null + private val mScrollbarHider = Runnable { this.hideScrollbar() } + + private val mScrollListener = object : RecyclerView.OnScrollListener() { + override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { + if (!mHandleView!!.isSelected && isEnabled) { + setViewPositions(getScrollProportion(recyclerView)) + } + } + + override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { + super.onScrollStateChanged(recyclerView, newState) + if (isEnabled) { + when (newState) { + RecyclerView.SCROLL_STATE_DRAGGING -> { + handler.removeCallbacks(mScrollbarHider) + cancelAnimation(mScrollbarAnimator) + if (!isViewVisible(mScrollbar)) { + showScrollbar() + } + } + RecyclerView.SCROLL_STATE_IDLE -> if (mFadeScrollbar && !mHandleView!!.isSelected) { + handler.postDelayed(mScrollbarHider, sScrollbarHideDelay.toLong()) + } + } + } + } + } + + constructor(context: Context) : super(context) { + layout(context, null) + layoutParams = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT) + } + + @JvmOverloads + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int = 0) : super(context, attrs, defStyleAttr) { + layout(context, attrs) + layoutParams = generateLayoutParams(attrs) + } + + override fun setLayoutParams(params: ViewGroup.LayoutParams) { + params.width = LayoutParams.WRAP_CONTENT + super.setLayoutParams(params) + } + + fun setLayoutParams(viewGroup: ViewGroup) { + @IdRes val recyclerViewId = if (mRecyclerView != null) mRecyclerView!!.id else View.NO_ID + val marginTop = resources.getDimensionPixelSize(R.dimen.fastscroll_scrollbar_margin_top) + val marginBottom = resources.getDimensionPixelSize(R.dimen.fastscroll_scrollbar_margin_bottom) + if (recyclerViewId == View.NO_ID) { + throw IllegalArgumentException("RecyclerView must have a view ID") + } + when (viewGroup) { + is ConstraintLayout -> { + val constraintSet = ConstraintSet() + @IdRes val layoutId = id + constraintSet.clone(viewGroup) + constraintSet.connect(layoutId, ConstraintSet.TOP, recyclerViewId, ConstraintSet.TOP) + constraintSet.connect(layoutId, ConstraintSet.BOTTOM, recyclerViewId, ConstraintSet.BOTTOM) + constraintSet.connect(layoutId, ConstraintSet.END, recyclerViewId, ConstraintSet.END) + constraintSet.applyTo(viewGroup) + val layoutParams = layoutParams as ConstraintLayout.LayoutParams + layoutParams.setMargins(0, marginTop, 0, marginBottom) + setLayoutParams(layoutParams) + } + is CoordinatorLayout -> { + val layoutParams = layoutParams as CoordinatorLayout.LayoutParams + layoutParams.anchorId = recyclerViewId + layoutParams.anchorGravity = GravityCompat.END + layoutParams.setMargins(0, marginTop, 0, marginBottom) + setLayoutParams(layoutParams) + } + is FrameLayout -> { + val layoutParams = layoutParams as FrameLayout.LayoutParams + layoutParams.gravity = GravityCompat.END + layoutParams.setMargins(0, marginTop, 0, marginBottom) + setLayoutParams(layoutParams) + } + is RelativeLayout -> { + val layoutParams = layoutParams as RelativeLayout.LayoutParams + val endRule = RelativeLayout.ALIGN_END + layoutParams.addRule(RelativeLayout.ALIGN_TOP, recyclerViewId) + layoutParams.addRule(RelativeLayout.ALIGN_BOTTOM, recyclerViewId) + layoutParams.addRule(endRule, recyclerViewId) + layoutParams.setMargins(0, marginTop, 0, marginBottom) + setLayoutParams(layoutParams) + } + else -> throw IllegalArgumentException("Parent ViewGroup must be a ConstraintLayout, CoordinatorLayout, FrameLayout, or RelativeLayout") + } + updateViewHeights() + } + + fun setSectionIndexer(sectionIndexer: SectionIndexer?) { + mSectionIndexer = sectionIndexer + } + + fun attachRecyclerView(recyclerView: RecyclerView) { + mRecyclerView = recyclerView + if (mRecyclerView != null) { + mRecyclerView!!.addOnScrollListener(mScrollListener) + post { + // set initial positions for bubble and handle + setViewPositions(getScrollProportion(mRecyclerView)) + } + } + } + + fun detachRecyclerView() { + if (mRecyclerView != null) { + mRecyclerView!!.removeOnScrollListener(mScrollListener) + mRecyclerView = null + } + } + + /** + * Hide the scrollbar when not scrolling. + * + * @param fadeScrollbar True to hide the scrollbar, false to show + */ + fun setFadeScrollbar(fadeScrollbar: Boolean) { + mFadeScrollbar = fadeScrollbar + mScrollbar!!.visibility = if (fadeScrollbar) View.GONE else View.VISIBLE + } + + /** + * Show the section bubble while scrolling. + * + * @param visible True to show the bubble, false to hide + */ + fun setBubbleVisible(visible: Boolean) { + mShowBubble = visible + } + + /** + * Display a scroll track while scrolling. + * + * @param visible True to show scroll track, false to hide + */ + fun setTrackVisible(visible: Boolean) { + mTrackView!!.visibility = if (visible) View.VISIBLE else View.GONE + } + + /** + * Set the color of the scroll track. + * + * @param color The color for the scroll track + */ + fun setTrackColor(@ColorInt color: Int) { + if (mTrackImage == null) { + val drawable = ContextCompat.getDrawable(context, R.drawable.fastscroll_track) + if (drawable != null) { + mTrackImage = DrawableCompat.wrap(drawable) + } + } + DrawableCompat.setTint(mTrackImage!!, color) + mTrackView!!.setImageDrawable(mTrackImage) + } + + /** + * Set the color for the scroll handle. + * + * @param color The color for the scroll handle + */ + fun setHandleColor(@ColorInt color: Int) { + mHandleColor = color + if (mHandleImage == null) { + val drawable = ContextCompat.getDrawable(context, R.drawable.fastscroll_handle) + if (drawable != null) { + mHandleImage = DrawableCompat.wrap(drawable) + } + } + DrawableCompat.setTint(mHandleImage!!, mHandleColor) + mHandleView!!.setImageDrawable(mHandleImage) + } + + /** + * Set the background color of the index bubble. + * + * @param color The background color for the index bubble + */ + fun setBubbleColor(@ColorInt color: Int) { + mBubbleColor = color + if (mBubbleImage == null) { + val drawable = ContextCompat.getDrawable(context, R.drawable.fastscroll_bubble) + if (drawable != null) { + mBubbleImage = DrawableCompat.wrap(drawable) + } + } + DrawableCompat.setTint(mBubbleImage!!, mBubbleColor) + mBubbleView!!.background = mBubbleImage + } + + /** + * Set the text color of the index bubble. + * + * @param color The text color for the index bubble + */ + fun setBubbleTextColor(@ColorInt color: Int) { + mBubbleView!!.setTextColor(color) + } + + /** + * Set the fast scroll state change listener. + * + * @param fastScrollStateChangeListener The interface that will listen to fastscroll state change events + */ + fun setFastScrollStateChangeListener(fastScrollStateChangeListener: FastScrollStateChangeListener) { + mFastScrollStateChangeListener = fastScrollStateChangeListener + } + + override fun setEnabled(enabled: Boolean) { + super.setEnabled(enabled) + visibility = if (enabled) View.VISIBLE else View.GONE + } + + @SuppressLint("ClickableViewAccessibility") + override fun onTouchEvent(event: MotionEvent): Boolean { + when (event.action) { + MotionEvent.ACTION_DOWN -> { + if (event.x < mHandleView!!.x - ViewCompat.getPaddingStart(mHandleView!!)) { + return false + } + requestDisallowInterceptTouchEvent(true) + setHandleSelected(true) + handler.removeCallbacks(mScrollbarHider) + cancelAnimation(mScrollbarAnimator) + cancelAnimation(mBubbleAnimator) + if (!isViewVisible(mScrollbar)) { + showScrollbar() + } + if (mShowBubble && mSectionIndexer != null) { + showBubble() + } + if (mFastScrollStateChangeListener != null) { + mFastScrollStateChangeListener!!.onFastScrollStart(this) + } + val y = event.y + setViewPositions(y) + setRecyclerViewPosition(y) + return true + } + MotionEvent.ACTION_MOVE -> { + val y = event.y + setViewPositions(y) + setRecyclerViewPosition(y) + return true + } + MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { + requestDisallowInterceptTouchEvent(false) + setHandleSelected(false) + if (mFadeScrollbar) { + handler.postDelayed(mScrollbarHider, sScrollbarHideDelay.toLong()) + } + hideBubble() + if (mFastScrollStateChangeListener != null) { + mFastScrollStateChangeListener!!.onFastScrollStop(this) + } + return true + } + } + return super.onTouchEvent(event) + } + + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + super.onSizeChanged(w, h, oldw, oldh) + mViewHeight = h + } + + private fun setRecyclerViewPosition(y: Float) { + if (mRecyclerView != null && mRecyclerView!!.adapter != null) { + val itemCount = mRecyclerView!!.adapter!!.itemCount + val proportion: Float = when { + mHandleView!!.y == 0f -> 0f + mHandleView!!.y + mHandleHeight >= mViewHeight - sTrackSnapRange -> 1f + else -> y / mViewHeight.toFloat() + } + var scrolledItemCount = (proportion * itemCount).roundToInt() + if (isLayoutReversed(mRecyclerView!!.layoutManager!!)) { + scrolledItemCount = itemCount - scrolledItemCount + } + val targetPos = getValueInRange(0, itemCount - 1, scrolledItemCount) + mRecyclerView!!.layoutManager!!.scrollToPosition(targetPos) + if (mShowBubble && mSectionIndexer != null) { + mBubbleView!!.text = mSectionIndexer!!.getSectionText(targetPos) + } + } + } + + private fun getScrollProportion(recyclerView: RecyclerView?): Float { + if (recyclerView == null) { + return 0f + } + val verticalScrollOffset = recyclerView.computeVerticalScrollOffset() + val verticalScrollRange = recyclerView.computeVerticalScrollRange() + val rangeDiff = (verticalScrollRange - mViewHeight).toFloat() + val proportion = verticalScrollOffset.toFloat() / if (rangeDiff > 0) rangeDiff else 1f + return mViewHeight * proportion + } + + private fun getValueInRange(min: Int, max: Int, value: Int): Int { + val minimum = max(min, value) + return min(minimum, max) + } + + private fun setViewPositions(y: Float) { + mBubbleHeight = mBubbleView!!.height + mHandleHeight = mHandleView!!.height + val bubbleY = getValueInRange(0, mViewHeight - mBubbleHeight - mHandleHeight / 2, (y - mBubbleHeight).toInt()) + val handleY = getValueInRange(0, mViewHeight - mHandleHeight, (y - mHandleHeight / 2).toInt()) + if (mShowBubble) { + mBubbleView!!.y = bubbleY.toFloat() + } + mHandleView!!.y = handleY.toFloat() + } + + private fun updateViewHeights() { + val measureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED) + mBubbleView!!.measure(measureSpec, measureSpec) + mBubbleHeight = mBubbleView!!.measuredHeight + mHandleView!!.measure(measureSpec, measureSpec) + mHandleHeight = mHandleView!!.measuredHeight + } + + private fun isLayoutReversed(layoutManager: RecyclerView.LayoutManager): Boolean { + if (layoutManager is LinearLayoutManager) { + return layoutManager.reverseLayout + } else if (layoutManager is StaggeredGridLayoutManager) { + return layoutManager.reverseLayout + } + return false + } + + private fun isViewVisible(view: View?): Boolean { + return view != null && view.visibility == View.VISIBLE + } + + private fun cancelAnimation(animator: ViewPropertyAnimator?) { + animator?.cancel() + } + + private fun showBubble() { + if (!isViewVisible(mBubbleView)) { + mBubbleView!!.visibility = View.VISIBLE + mBubbleAnimator = mBubbleView!!.animate().alpha(1f) + .setDuration(sBubbleAnimDuration.toLong()) + .setListener(object : AnimatorListenerAdapter() { + + // adapter required for new alpha value to stick + }) + } + } + + private fun hideBubble() { + if (isViewVisible(mBubbleView)) { + mBubbleAnimator = mBubbleView!!.animate().alpha(0f) + .setDuration(sBubbleAnimDuration.toLong()) + .setListener(object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator) { + super.onAnimationEnd(animation) + mBubbleView!!.visibility = View.GONE + mBubbleAnimator = null + } + + override fun onAnimationCancel(animation: Animator) { + super.onAnimationCancel(animation) + mBubbleView!!.visibility = View.GONE + mBubbleAnimator = null + } + }) + } + } + + private fun showScrollbar() { + if (mRecyclerView!!.computeVerticalScrollRange() - mViewHeight > 0) { + val transX = resources.getDimensionPixelSize(R.dimen.fastscroll_scrollbar_padding_end).toFloat() + mScrollbar!!.translationX = transX + mScrollbar!!.visibility = View.VISIBLE + mScrollbarAnimator = mScrollbar!!.animate().translationX(0f).alpha(1f) + .setDuration(sScrollbarAnimDuration.toLong()) + .setListener(object : AnimatorListenerAdapter() { + + // adapter required for new alpha value to stick + }) + } + } + + private fun hideScrollbar() { + val transX = resources.getDimensionPixelSize(R.dimen.fastscroll_scrollbar_padding_end).toFloat() + mScrollbarAnimator = mScrollbar!!.animate().translationX(transX).alpha(0f) + .setDuration(sScrollbarAnimDuration.toLong()) + .setListener(object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator) { + super.onAnimationEnd(animation) + mScrollbar!!.visibility = View.GONE + mScrollbarAnimator = null + } + + override fun onAnimationCancel(animation: Animator) { + super.onAnimationCancel(animation) + mScrollbar!!.visibility = View.GONE + mScrollbarAnimator = null + } + }) + } + + private fun setHandleSelected(selected: Boolean) { + mHandleView!!.isSelected = selected + DrawableCompat.setTint(mHandleImage!!, if (selected) mBubbleColor else mHandleColor) + } + + private fun layout(context: Context, attrs: AttributeSet?) { + View.inflate(context, R.layout.view_fastscroller, this) + clipChildren = false + orientation = HORIZONTAL + mBubbleView = findViewById(R.id.fastscroll_bubble) + mHandleView = findViewById(R.id.fastscroll_handle) + mTrackView = findViewById(R.id.fastscroll_track) + mScrollbar = findViewById(R.id.fastscroll_scrollbar) + @ColorInt var bubbleColor = ColorUtil.adjustAlpha(context.accentColor, 0.8f) + @ColorInt var handleColor = context.accentColor + @ColorInt var trackColor = context.getCompatColor(R.color.transparent30) + @ColorInt var textColor = if (ColorUtil.isColorLight(bubbleColor)) Color.BLACK else Color.WHITE + var fadeScrollbar = true + var showBubble = false + var showTrack = true + if (attrs != null) { + val typedArray = context.obtainStyledAttributes(attrs, R.styleable.FastScroller, 0, 0) + if (typedArray != null) { + try { + bubbleColor = typedArray.getColor(R.styleable.FastScroller_bubbleColor, bubbleColor) + handleColor = typedArray.getColor(R.styleable.FastScroller_handleColor, handleColor) + trackColor = typedArray.getColor(R.styleable.FastScroller_trackColor, trackColor) + textColor = typedArray.getColor(R.styleable.FastScroller_bubbleTextColor, textColor) + fadeScrollbar = typedArray.getBoolean(R.styleable.FastScroller_fadeScrollbar, fadeScrollbar) + showBubble = typedArray.getBoolean(R.styleable.FastScroller_showBubble, showBubble) + showTrack = typedArray.getBoolean(R.styleable.FastScroller_showTrack, showTrack) + } finally { + typedArray.recycle() + } + } + } + setTrackColor(trackColor) + setHandleColor(handleColor) + setBubbleColor(bubbleColor) + setBubbleTextColor(textColor) + setFadeScrollbar(fadeScrollbar) + setBubbleVisible(showBubble) + setTrackVisible(showTrack) + } + + interface SectionIndexer { + fun getSectionText(position: Int): String + } + + companion object { + private const val sBubbleAnimDuration = 100 + private const val sScrollbarAnimDuration = 300 + private const val sScrollbarHideDelay = 1000 + private const val sTrackSnapRange = 5 + } + +} diff --git a/app/src/main/java/io/legado/app/utils/ColorUtil.kt b/app/src/main/java/io/legado/app/utils/ColorUtil.kt new file mode 100644 index 000000000..bce3ea27c --- /dev/null +++ b/app/src/main/java/io/legado/app/utils/ColorUtil.kt @@ -0,0 +1,80 @@ +package io.legado.app.utils + +import android.graphics.Color + +import androidx.annotation.ColorInt +import androidx.annotation.FloatRange + +object ColorUtil { + + fun intToString(intColor: Int): String { + return String.format("#%06X", 0xFFFFFF and intColor) + } + + + fun stripAlpha(@ColorInt color: Int): Int { + return -0x1000000 or color + } + + @ColorInt + fun shiftColor(@ColorInt color: Int, @FloatRange(from = 0.0, to = 2.0) by: Float): Int { + if (by == 1f) return color + val alpha = Color.alpha(color) + val hsv = FloatArray(3) + Color.colorToHSV(color, hsv) + hsv[2] *= by // value component + return (alpha shl 24) + (0x00ffffff and Color.HSVToColor(hsv)) + } + + @ColorInt + fun darkenColor(@ColorInt color: Int): Int { + return shiftColor(color, 0.9f) + } + + @ColorInt + fun lightenColor(@ColorInt color: Int): Int { + return shiftColor(color, 1.1f) + } + + fun isColorLight(@ColorInt color: Int): Boolean { + val darkness = 1 - (0.299 * Color.red(color) + 0.587 * Color.green(color) + 0.114 * Color.blue(color)) / 255 + return darkness < 0.4 + } + + @ColorInt + fun invertColor(@ColorInt color: Int): Int { + val r = 255 - Color.red(color) + val g = 255 - Color.green(color) + val b = 255 - Color.blue(color) + return Color.argb(Color.alpha(color), r, g, b) + } + + @ColorInt + fun adjustAlpha(@ColorInt color: Int, @FloatRange(from = 0.0, to = 1.0) factor: Float): Int { + val alpha = Math.round(Color.alpha(color) * factor) + val red = Color.red(color) + val green = Color.green(color) + val blue = Color.blue(color) + return Color.argb(alpha, red, green, blue) + } + + @ColorInt + fun withAlpha(@ColorInt baseColor: Int, @FloatRange(from = 0.0, to = 1.0) alpha: Float): Int { + val a = Math.min(255, Math.max(0, (alpha * 255).toInt())) shl 24 + val rgb = 0x00ffffff and baseColor + return a + rgb + } + + /** + * Taken from CollapsingToolbarLayout's CollapsingTextHelper class. + */ + fun blendColors(color1: Int, color2: Int, @FloatRange(from = 0.0, to = 1.0) ratio: Float): Int { + val inverseRatio = 1f - ratio + val a = Color.alpha(color1) * inverseRatio + Color.alpha(color2) * ratio + val r = Color.red(color1) * inverseRatio + Color.red(color2) * ratio + val g = Color.green(color1) * inverseRatio + Color.green(color2) * ratio + val b = Color.blue(color1) * inverseRatio + Color.blue(color2) * ratio + return Color.argb(a.toInt(), r.toInt(), g.toInt(), b.toInt()) + } + +} diff --git a/app/src/main/res/layout/view_fastscroller.xml b/app/src/main/res/layout/view_fastscroller.xml new file mode 100644 index 000000000..7256c640f --- /dev/null +++ b/app/src/main/res/layout/view_fastscroller.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/ids.xml b/app/src/main/res/values/ids.xml index bb25a8ab0..016946f36 100644 --- a/app/src/main/res/values/ids.xml +++ b/app/src/main/res/values/ids.xml @@ -7,4 +7,5 @@ + \ No newline at end of file From 42fe4ffee51831c3d8fa18d4e608242f54878d7c Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 6 Aug 2019 17:48:47 +0800 Subject: [PATCH 0591/1997] up --- app/src/main/res/layout/activity_book_source.xml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/layout/activity_book_source.xml b/app/src/main/res/layout/activity_book_source.xml index 4069bd48a..8297c7268 100644 --- a/app/src/main/res/layout/activity_book_source.xml +++ b/app/src/main/res/layout/activity_book_source.xml @@ -13,9 +13,15 @@ app:displayHomeAsUp="true" app:title="@string/book_source"/> - + + + + \ No newline at end of file From 190437b3e0d02f50298ed2019ce774a2b2c59eea Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 6 Aug 2019 17:58:19 +0800 Subject: [PATCH 0592/1997] up --- .../widget/recycler/scroller/FastScroller.kt | 88 ++++++++++--------- 1 file changed, 45 insertions(+), 43 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/recycler/scroller/FastScroller.kt b/app/src/main/java/io/legado/app/ui/widget/recycler/scroller/FastScroller.kt index 3b5acac27..85a04b8b3 100644 --- a/app/src/main/java/io/legado/app/ui/widget/recycler/scroller/FastScroller.kt +++ b/app/src/main/java/io/legado/app/ui/widget/recycler/scroller/FastScroller.kt @@ -47,10 +47,10 @@ class FastScroller : LinearLayout { private var mScrollbarAnimator: ViewPropertyAnimator? = null private var mBubbleAnimator: ViewPropertyAnimator? = null private var mRecyclerView: RecyclerView? = null - private var mBubbleView: TextView? = null - private var mHandleView: ImageView? = null - private var mTrackView: ImageView? = null - private var mScrollbar: View? = null + private lateinit var mBubbleView: TextView + private lateinit var mHandleView: ImageView + private lateinit var mTrackView: ImageView + private lateinit var mScrollbar: View private var mBubbleImage: Drawable? = null private var mHandleImage: Drawable? = null private var mTrackImage: Drawable? = null @@ -59,7 +59,7 @@ class FastScroller : LinearLayout { private val mScrollListener = object : RecyclerView.OnScrollListener() { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { - if (!mHandleView!!.isSelected && isEnabled) { + if (!mHandleView.isSelected && isEnabled) { setViewPositions(getScrollProportion(recyclerView)) } } @@ -75,7 +75,7 @@ class FastScroller : LinearLayout { showScrollbar() } } - RecyclerView.SCROLL_STATE_IDLE -> if (mFadeScrollbar && !mHandleView!!.isSelected) { + RecyclerView.SCROLL_STATE_IDLE -> if (mFadeScrollbar && !mHandleView.isSelected) { handler.postDelayed(mScrollbarHider, sScrollbarHideDelay.toLong()) } } @@ -175,7 +175,7 @@ class FastScroller : LinearLayout { */ fun setFadeScrollbar(fadeScrollbar: Boolean) { mFadeScrollbar = fadeScrollbar - mScrollbar!!.visibility = if (fadeScrollbar) View.GONE else View.VISIBLE + mScrollbar.visibility = if (fadeScrollbar) View.GONE else View.VISIBLE } /** @@ -193,7 +193,7 @@ class FastScroller : LinearLayout { * @param visible True to show scroll track, false to hide */ fun setTrackVisible(visible: Boolean) { - mTrackView!!.visibility = if (visible) View.VISIBLE else View.GONE + mTrackView.visibility = if (visible) View.VISIBLE else View.GONE } /** @@ -209,7 +209,7 @@ class FastScroller : LinearLayout { } } DrawableCompat.setTint(mTrackImage!!, color) - mTrackView!!.setImageDrawable(mTrackImage) + mTrackView.setImageDrawable(mTrackImage) } /** @@ -226,7 +226,7 @@ class FastScroller : LinearLayout { } } DrawableCompat.setTint(mHandleImage!!, mHandleColor) - mHandleView!!.setImageDrawable(mHandleImage) + mHandleView.setImageDrawable(mHandleImage) } /** @@ -243,7 +243,7 @@ class FastScroller : LinearLayout { } } DrawableCompat.setTint(mBubbleImage!!, mBubbleColor) - mBubbleView!!.background = mBubbleImage + mBubbleView.background = mBubbleImage } /** @@ -252,7 +252,7 @@ class FastScroller : LinearLayout { * @param color The text color for the index bubble */ fun setBubbleTextColor(@ColorInt color: Int) { - mBubbleView!!.setTextColor(color) + mBubbleView.setTextColor(color) } /** @@ -273,7 +273,7 @@ class FastScroller : LinearLayout { override fun onTouchEvent(event: MotionEvent): Boolean { when (event.action) { MotionEvent.ACTION_DOWN -> { - if (event.x < mHandleView!!.x - ViewCompat.getPaddingStart(mHandleView!!)) { + if (event.x < mHandleView.x - ViewCompat.getPaddingStart(mHandleView)) { return false } requestDisallowInterceptTouchEvent(true) @@ -326,8 +326,8 @@ class FastScroller : LinearLayout { if (mRecyclerView != null && mRecyclerView!!.adapter != null) { val itemCount = mRecyclerView!!.adapter!!.itemCount val proportion: Float = when { - mHandleView!!.y == 0f -> 0f - mHandleView!!.y + mHandleHeight >= mViewHeight - sTrackSnapRange -> 1f + mHandleView.y == 0f -> 0f + mHandleView.y + mHandleHeight >= mViewHeight - sTrackSnapRange -> 1f else -> y / mViewHeight.toFloat() } var scrolledItemCount = (proportion * itemCount).roundToInt() @@ -337,7 +337,7 @@ class FastScroller : LinearLayout { val targetPos = getValueInRange(0, itemCount - 1, scrolledItemCount) mRecyclerView!!.layoutManager!!.scrollToPosition(targetPos) if (mShowBubble && mSectionIndexer != null) { - mBubbleView!!.text = mSectionIndexer!!.getSectionText(targetPos) + mBubbleView.text = mSectionIndexer!!.getSectionText(targetPos) } } } @@ -359,22 +359,22 @@ class FastScroller : LinearLayout { } private fun setViewPositions(y: Float) { - mBubbleHeight = mBubbleView!!.height - mHandleHeight = mHandleView!!.height + mBubbleHeight = mBubbleView.height + mHandleHeight = mHandleView.height val bubbleY = getValueInRange(0, mViewHeight - mBubbleHeight - mHandleHeight / 2, (y - mBubbleHeight).toInt()) val handleY = getValueInRange(0, mViewHeight - mHandleHeight, (y - mHandleHeight / 2).toInt()) if (mShowBubble) { - mBubbleView!!.y = bubbleY.toFloat() + mBubbleView.y = bubbleY.toFloat() } - mHandleView!!.y = handleY.toFloat() + mHandleView.y = handleY.toFloat() } private fun updateViewHeights() { val measureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED) - mBubbleView!!.measure(measureSpec, measureSpec) - mBubbleHeight = mBubbleView!!.measuredHeight - mHandleView!!.measure(measureSpec, measureSpec) - mHandleHeight = mHandleView!!.measuredHeight + mBubbleView.measure(measureSpec, measureSpec) + mBubbleHeight = mBubbleView.measuredHeight + mHandleView.measure(measureSpec, measureSpec) + mHandleHeight = mHandleView.measuredHeight } private fun isLayoutReversed(layoutManager: RecyclerView.LayoutManager): Boolean { @@ -396,8 +396,8 @@ class FastScroller : LinearLayout { private fun showBubble() { if (!isViewVisible(mBubbleView)) { - mBubbleView!!.visibility = View.VISIBLE - mBubbleAnimator = mBubbleView!!.animate().alpha(1f) + mBubbleView.visibility = View.VISIBLE + mBubbleAnimator = mBubbleView.animate().alpha(1f) .setDuration(sBubbleAnimDuration.toLong()) .setListener(object : AnimatorListenerAdapter() { @@ -408,18 +408,18 @@ class FastScroller : LinearLayout { private fun hideBubble() { if (isViewVisible(mBubbleView)) { - mBubbleAnimator = mBubbleView!!.animate().alpha(0f) + mBubbleAnimator = mBubbleView.animate().alpha(0f) .setDuration(sBubbleAnimDuration.toLong()) .setListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator) { super.onAnimationEnd(animation) - mBubbleView!!.visibility = View.GONE + mBubbleView.visibility = View.GONE mBubbleAnimator = null } override fun onAnimationCancel(animation: Animator) { super.onAnimationCancel(animation) - mBubbleView!!.visibility = View.GONE + mBubbleView.visibility = View.GONE mBubbleAnimator = null } }) @@ -427,40 +427,42 @@ class FastScroller : LinearLayout { } private fun showScrollbar() { - if (mRecyclerView!!.computeVerticalScrollRange() - mViewHeight > 0) { - val transX = resources.getDimensionPixelSize(R.dimen.fastscroll_scrollbar_padding_end).toFloat() - mScrollbar!!.translationX = transX - mScrollbar!!.visibility = View.VISIBLE - mScrollbarAnimator = mScrollbar!!.animate().translationX(0f).alpha(1f) - .setDuration(sScrollbarAnimDuration.toLong()) - .setListener(object : AnimatorListenerAdapter() { - - // adapter required for new alpha value to stick - }) + mRecyclerView?.let { mRecyclerView -> + if (mRecyclerView.computeVerticalScrollRange() - mViewHeight > 0) { + val transX = resources.getDimensionPixelSize(R.dimen.fastscroll_scrollbar_padding_end).toFloat() + mScrollbar.translationX = transX + mScrollbar.visibility = View.VISIBLE + mScrollbarAnimator = mScrollbar.animate().translationX(0f).alpha(1f) + .setDuration(sScrollbarAnimDuration.toLong()) + .setListener(object : AnimatorListenerAdapter() { + + // adapter required for new alpha value to stick + }) + } } } private fun hideScrollbar() { val transX = resources.getDimensionPixelSize(R.dimen.fastscroll_scrollbar_padding_end).toFloat() - mScrollbarAnimator = mScrollbar!!.animate().translationX(transX).alpha(0f) + mScrollbarAnimator = mScrollbar.animate().translationX(transX).alpha(0f) .setDuration(sScrollbarAnimDuration.toLong()) .setListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator) { super.onAnimationEnd(animation) - mScrollbar!!.visibility = View.GONE + mScrollbar.visibility = View.GONE mScrollbarAnimator = null } override fun onAnimationCancel(animation: Animator) { super.onAnimationCancel(animation) - mScrollbar!!.visibility = View.GONE + mScrollbar.visibility = View.GONE mScrollbarAnimator = null } }) } private fun setHandleSelected(selected: Boolean) { - mHandleView!!.isSelected = selected + mHandleView.isSelected = selected DrawableCompat.setTint(mHandleImage!!, if (selected) mBubbleColor else mHandleColor) } From df422bcb1165ef38716adc00ea6e0a7b333bb0de Mon Sep 17 00:00:00 2001 From: Administrator <1760316362@qq.com> Date: Tue, 6 Aug 2019 18:47:26 +0800 Subject: [PATCH 0593/1997] update --- .../io/legado/app/help/coroutine/Coroutine.kt | 15 ++++++++++----- .../io/legado/app/ui/search/SearchActivity.kt | 5 +++-- .../io/legado/app/ui/search/SearchViewModel.kt | 5 +++++ 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt b/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt index 9013fc266..af62ac20e 100644 --- a/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt +++ b/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt @@ -19,7 +19,7 @@ class Coroutine() { } private var interceptor: Coroutine? = null - private var job: Job? = null + private lateinit var job: Job private var start: (suspend CoroutineScope.() -> Unit)? = null private var execute: (suspend CoroutineScope.(T?) -> Unit)? = null @@ -32,13 +32,13 @@ class Coroutine() { private var errorReturn: Result? = null val isCancelled: Boolean - get() = job?.isCancelled ?: false + get() = job.isCancelled val isActive: Boolean - get() = job?.isActive ?: true + get() = job.isActive val isCompleted: Boolean - get() = job?.isCompleted ?: false + get() = job.isCompleted private constructor( scope: CoroutineScope, @@ -119,7 +119,11 @@ class Coroutine() { //取消当前任务 fun cancel(cause: CancellationException? = null) { - job?.cancel(cause) + job.cancel(cause) + } + + fun invokeOnCompletion(handler: CompletionHandler): DisposableHandle{ + return job.invokeOnCompletion(handler) } private suspend fun executeInternal(scope: CoroutineScope, block: suspend CoroutineScope.() -> T) { @@ -134,6 +138,7 @@ class Coroutine() { success?.invoke(scope, value) true } ?: false + if (!consume) { error?.invoke(scope, e) } diff --git a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt index 52222d541..74a51d172 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt @@ -11,7 +11,6 @@ import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.App import io.legado.app.R import io.legado.app.base.VMBaseActivity -import io.legado.app.data.entities.SearchBook import io.legado.app.data.entities.SearchShow import io.legado.app.lib.theme.ATH import io.legado.app.utils.getViewModel @@ -45,13 +44,15 @@ class SearchActivity : VMBaseActivity(R.layout.activity_search) viewModel.search(it, { startTime -> content_view.showContentView() initData(startTime) + }, { + }) } return true } override fun onQueryTextChange(newText: String?): Boolean { - if(newText.isNullOrBlank()) viewModel.stop() + if (newText.isNullOrBlank()) viewModel.stop() return false } diff --git a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt b/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt index 12f331fc4..096d8643e 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt @@ -1,6 +1,7 @@ package io.legado.app.ui.search import android.app.Application +import android.util.Log import io.legado.app.App import io.legado.app.base.BaseViewModel import io.legado.app.help.coroutine.Coroutine @@ -36,6 +37,10 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { }.onError { it.printStackTrace() } + + task?.invokeOnCompletion { + Log.e("TAG", "complete") + } } fun stop() { From 86fb6260a1070d22db57335044715bf37dcc5794 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 6 Aug 2019 19:09:51 +0800 Subject: [PATCH 0594/1997] up --- app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt b/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt index 096d8643e..8fdf5e22d 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt @@ -40,6 +40,7 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { task?.invokeOnCompletion { Log.e("TAG", "complete") + finally?.invoke() } } From 63b74cbc2bc9c1a50e04572b9c27c7507aa324b6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 6 Aug 2019 20:28:07 +0800 Subject: [PATCH 0595/1997] up --- .../io/legado/app/ui/widget/recycler/scroller/FastScroller.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/recycler/scroller/FastScroller.kt b/app/src/main/java/io/legado/app/ui/widget/recycler/scroller/FastScroller.kt index 85a04b8b3..eee187a85 100644 --- a/app/src/main/java/io/legado/app/ui/widget/recycler/scroller/FastScroller.kt +++ b/app/src/main/java/io/legado/app/ui/widget/recycler/scroller/FastScroller.kt @@ -100,7 +100,7 @@ class FastScroller : LinearLayout { } fun setLayoutParams(viewGroup: ViewGroup) { - @IdRes val recyclerViewId = if (mRecyclerView != null) mRecyclerView!!.id else View.NO_ID + @IdRes val recyclerViewId = mRecyclerView?.id ?: View.NO_ID val marginTop = resources.getDimensionPixelSize(R.dimen.fastscroll_scrollbar_margin_top) val marginBottom = resources.getDimensionPixelSize(R.dimen.fastscroll_scrollbar_margin_bottom) if (recyclerViewId == View.NO_ID) { From 2e7f6834c4eade541f3525f2111b8e6314cb1687 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 6 Aug 2019 20:39:37 +0800 Subject: [PATCH 0596/1997] up --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 90f626586..ec7a99bee 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -106,7 +106,7 @@ dependencies { implementation "org.jetbrains.anko:anko-sdk27-listeners:$anko_version" //liveEventBus - implementation 'com.jeremyliao:live-event-bus-x:1.4.4' + implementation 'com.jeremyliao:live-event-bus-x:1.4.5' //协程 def coroutines_version = '1.2.2' From d9392769216e6391c40c00c07d13714896579ed9 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 6 Aug 2019 22:26:46 +0800 Subject: [PATCH 0597/1997] up --- app/src/main/AndroidManifest.xml | 1 + .../app/ui/chapterlist/ChapterListActivity.kt | 13 +++++++++++++ app/src/main/res/layout/activity_chapter_list.xml | 7 +++++++ 3 files changed, 21 insertions(+) create mode 100644 app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt create mode 100644 app/src/main/res/layout/activity_chapter_list.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 9f73953a6..865feb29f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -55,6 +55,7 @@ + diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt new file mode 100644 index 000000000..89aa188c5 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt @@ -0,0 +1,13 @@ +package io.legado.app.ui.chapterlist + +import android.os.Bundle +import io.legado.app.R +import io.legado.app.base.BaseActivity + +class ChapterListActivity : BaseActivity(R.layout.activity_chapter_list) { + + override fun onActivityCreated(savedInstanceState: Bundle?) { + + } + +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_chapter_list.xml b/app/src/main/res/layout/activity_chapter_list.xml new file mode 100644 index 000000000..d829e291c --- /dev/null +++ b/app/src/main/res/layout/activity_chapter_list.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file From 0ecdef542edf664f45069fbe3e19b53ad404e9d8 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 7 Aug 2019 09:11:53 +0800 Subject: [PATCH 0598/1997] up --- .../io/legado/app/ui/search/SearchAdapter.kt | 8 +++++++- .../java/io/legado/app/ui/widget/BadgeView.kt | 18 +++++++++--------- app/src/main/res/layout/item_search.xml | 12 ++++++++++-- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt b/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt index 2c46fd479..66b55595d 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt @@ -49,8 +49,14 @@ class SearchAdapter : PagedListAdapter(D fun bind(searchBook: SearchShow, callBack: CallBack?) = with(itemView) { tv_name.text = searchBook.name + bv_originCount.setBadgeCount(searchBook.originCount) tv_author.text = searchBook.author - tv_lasted.text = context.getString(R.string.book_search_last, searchBook.latestChapterTitle) + if (searchBook.latestChapterTitle.isNullOrEmpty()) { + tv_lasted.gone() + } else { + tv_lasted.text = context.getString(R.string.book_search_last, searchBook.latestChapterTitle) + tv_lasted.visible() + } tv_introduce.text = searchBook.intro val kinds = searchBook.getKindList() if (kinds.isEmpty()) { diff --git a/app/src/main/java/io/legado/app/ui/widget/BadgeView.kt b/app/src/main/java/io/legado/app/ui/widget/BadgeView.kt index 5f09a8744..aad98f5dd 100644 --- a/app/src/main/java/io/legado/app/ui/widget/BadgeView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/BadgeView.kt @@ -15,6 +15,9 @@ import android.widget.FrameLayout.LayoutParams import android.widget.TabWidget import androidx.appcompat.widget.AppCompatTextView import io.legado.app.R +import io.legado.app.lib.theme.accentColor +import io.legado.app.utils.gone +import io.legado.app.utils.visible /** @@ -71,11 +74,6 @@ class BadgeView @JvmOverloads constructor( } init { - - init() - } - - private fun init() { if (layoutParams !is LayoutParams) { val layoutParams = LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, @@ -93,7 +91,7 @@ class BadgeView @JvmOverloads constructor( radius = 8f // set default background - setBackground(radius, Color.parseColor("#d3321b")) + setBackground(radius, context.accentColor) gravity = Gravity.CENTER @@ -132,9 +130,9 @@ class BadgeView @JvmOverloads constructor( */ override fun setText(text: CharSequence, type: BufferType) { if (isHideOnNull && TextUtils.isEmpty(text)) { - visibility = View.GONE + gone() } else { - visibility = View.VISIBLE + visible() } super.setText(text, type) } @@ -142,7 +140,9 @@ class BadgeView @JvmOverloads constructor( fun setBadgeCount(count: Int) { text = count.toString() if (count == 0) { - visibility = View.GONE + gone() + } else { + visible() } } diff --git a/app/src/main/res/layout/item_search.xml b/app/src/main/res/layout/item_search.xml index ec2466f7f..4a71b3049 100644 --- a/app/src/main/res/layout/item_search.xml +++ b/app/src/main/res/layout/item_search.xml @@ -19,6 +19,14 @@ app:layout_constraintTop_toTopOf="parent" tools:ignore="UnusedAttribute" /> + + @@ -46,7 +54,7 @@ android:layout_height="wrap_content" android:ellipsize="end" android:lines="1" - android:drawableLeft="@drawable/ic_author" + android:drawableStart="@drawable/ic_author" android:text="@string/author" android:textColor="@color/tv_text_default" android:textSize="12sp" /> From 0eff3e98d49de19def2cb500f8829904363f7517 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 7 Aug 2019 15:45:54 +0800 Subject: [PATCH 0599/1997] up --- .../recycler/refresh/RefreshProgressBar.kt | 195 ++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 app/src/main/java/io/legado/app/ui/widget/recycler/refresh/RefreshProgressBar.kt diff --git a/app/src/main/java/io/legado/app/ui/widget/recycler/refresh/RefreshProgressBar.kt b/app/src/main/java/io/legado/app/ui/widget/recycler/refresh/RefreshProgressBar.kt new file mode 100644 index 000000000..090a43ce7 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/recycler/refresh/RefreshProgressBar.kt @@ -0,0 +1,195 @@ +package io.legado.app.ui.widget.recycler.refresh + +import android.content.Context +import android.graphics.Canvas +import android.graphics.Paint +import android.graphics.Rect +import android.graphics.RectF +import android.os.Looper +import android.util.AttributeSet +import android.view.View +import io.legado.app.R + +class RefreshProgressBar @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : View(context, attrs, defStyleAttr) { + internal var a = 1 + var maxProgress = 100 + private var durProgress = 0 + var secondMaxProgress = 100 + private var secondDurProgress = 0 + var bgColor = 0x00000000 + var secondColor = -0x3e3e3f + var fontColor = -0xc9c9ca + var speed = 1 + var secondFinalProgress = 0 + private set + private var paint: Paint = Paint() + private var rect = Rect() + private var rectF = RectF() + var isAutoLoading: Boolean = false + set(loading) { + if (loading && visibility != VISIBLE) { + visibility = VISIBLE + } + field = loading + if ((!this.isAutoLoading)) { + secondDurProgress = 0 + secondFinalProgress = 0 + } + maxProgress = 0 + + invalidate() + } + + init { + paint.style = Paint.Style.FILL + + val a = context.obtainStyledAttributes(attrs, R.styleable.RefreshProgressBar) + speed = a.getDimensionPixelSize(R.styleable.RefreshProgressBar_speed, speed) + maxProgress = a.getInt(R.styleable.RefreshProgressBar_max_progress, maxProgress) + durProgress = a.getInt(R.styleable.RefreshProgressBar_dur_progress, durProgress) + secondDurProgress = + a.getDimensionPixelSize(R.styleable.RefreshProgressBar_second_dur_progress, secondDurProgress) + secondFinalProgress = secondDurProgress + secondMaxProgress = + a.getDimensionPixelSize(R.styleable.RefreshProgressBar_second_max_progress, secondMaxProgress) + bgColor = a.getColor(R.styleable.RefreshProgressBar_bg_color, bgColor) + secondColor = a.getColor(R.styleable.RefreshProgressBar_second_color, secondColor) + fontColor = a.getColor(R.styleable.RefreshProgressBar_font_color, fontColor) + a.recycle() + } + + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + super.onSizeChanged(w, h, oldw, oldh) + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + + paint.color = bgColor + rect.set(0, 0, measuredWidth, measuredHeight) + canvas.drawRect(rect, paint) + + if (secondDurProgress > 0 && secondMaxProgress > 0) { + var secondDur = secondDurProgress + if (secondDur < 0) { + secondDur = 0 + } + if (secondDur > secondMaxProgress) { + secondDur = secondMaxProgress + } + paint.color = secondColor + val tempW = (measuredWidth.toFloat() * 1.0f * (secondDur * 1.0f / secondMaxProgress)).toInt() + rect.set(measuredWidth / 2 - tempW / 2, 0, measuredWidth / 2 + tempW / 2, measuredHeight) + canvas.drawRect(rect, paint) + } + + if (durProgress > 0 && maxProgress > 0) { + paint.color = fontColor + rectF.set( + 0f, + 0f, + measuredWidth.toFloat() * 1.0f * (durProgress * 1.0f / maxProgress), + measuredHeight.toFloat() + ) + canvas.drawRect(rectF, paint) + } + + if (this.isAutoLoading) { + if (secondDurProgress >= secondMaxProgress) { + a = -1 + } else if (secondDurProgress <= 0) { + a = 1 + } + secondDurProgress += a * speed + if (secondDurProgress < 0) + secondDurProgress = 0 + else if (secondDurProgress > secondMaxProgress) + secondDurProgress = secondMaxProgress + secondFinalProgress = secondDurProgress + invalidate() + } else { + if (secondDurProgress != secondFinalProgress) { + if (secondDurProgress > secondFinalProgress) { + secondDurProgress -= speed + if (secondDurProgress < secondFinalProgress) { + secondDurProgress = secondFinalProgress + } + } else { + secondDurProgress += speed + if (secondDurProgress > secondFinalProgress) { + secondDurProgress = secondFinalProgress + } + } + this.invalidate() + } + if (secondDurProgress == 0 && durProgress == 0 && secondFinalProgress == 0 && visibility == VISIBLE) { + visibility = View.INVISIBLE + } + } + } + + fun getDurProgress(): Int { + return durProgress + } + + fun setDurProgress(durProgress: Int) { + var durProgress = durProgress + if (durProgress < 0) { + durProgress = 0 + } + if (durProgress > maxProgress) { + durProgress = maxProgress + } + this.durProgress = durProgress + if (Looper.myLooper() == Looper.getMainLooper()) { + this.invalidate() + } else { + this.postInvalidate() + } + } + + fun getSecondDurProgress(): Int { + return secondDurProgress + } + + fun setSecondDurProgress(secondDur: Int) { + this.secondDurProgress = secondDur + this.secondFinalProgress = secondDurProgress + if (Looper.myLooper() == Looper.getMainLooper()) { + this.invalidate() + } else { + this.postInvalidate() + } + } + + fun setSecondDurProgressWithAnim(secondDur: Int) { + var secondDur = secondDur + if (secondDur < 0) { + secondDur = 0 + } + if (secondDur > secondMaxProgress) { + secondDur = secondMaxProgress + } + this.secondFinalProgress = secondDur + if (Looper.myLooper() == Looper.getMainLooper()) { + this.invalidate() + } else { + this.postInvalidate() + } + } + + fun clean() { + durProgress = 0 + secondDurProgress = 0 + secondFinalProgress = 0 + if (Looper.myLooper() == Looper.getMainLooper()) { + this.invalidate() + } else { + this.postInvalidate() + } + } +} From 4894d51863fc84a62a6f7fcca8c8b18762541355 Mon Sep 17 00:00:00 2001 From: Administrator <1760316362@qq.com> Date: Wed, 7 Aug 2019 16:00:00 +0800 Subject: [PATCH 0600/1997] update --- .../java/io/legado/app/base/BaseViewModel.kt | 4 -- .../io/legado/app/help/coroutine/Coroutine.kt | 70 ++++++------------- .../legado/app/ui/search/SearchViewModel.kt | 7 +- 3 files changed, 24 insertions(+), 57 deletions(-) diff --git a/app/src/main/java/io/legado/app/base/BaseViewModel.kt b/app/src/main/java/io/legado/app/base/BaseViewModel.kt index f24e5876c..655cd7097 100644 --- a/app/src/main/java/io/legado/app/base/BaseViewModel.kt +++ b/app/src/main/java/io/legado/app/base/BaseViewModel.kt @@ -20,10 +20,6 @@ open class BaseViewModel(application: Application) : AndroidViewModel(applicatio return Coroutine.async(scope) { block().await() } } - fun plus(coroutine: Coroutine): Coroutine { - return Coroutine.plus(coroutine) - } - override fun onCleared() { super.onCleared() cancel() diff --git a/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt b/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt index af62ac20e..14dd69f14 100644 --- a/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt +++ b/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt @@ -3,7 +3,7 @@ package io.legado.app.help.coroutine import kotlinx.coroutines.* -class Coroutine() { +class Coroutine(scope: CoroutineScope, block: suspend CoroutineScope.() -> T) { companion object { @@ -13,13 +13,9 @@ class Coroutine() { return Coroutine(scope, block) } - fun plus(coroutine: Coroutine): Coroutine { - return Coroutine(coroutine) - } } - private var interceptor: Coroutine? = null - private lateinit var job: Job + private val job: Job private var start: (suspend CoroutineScope.() -> Unit)? = null private var execute: (suspend CoroutineScope.(T?) -> Unit)? = null @@ -40,80 +36,54 @@ class Coroutine() { val isCompleted: Boolean get() = job.isCompleted - private constructor( - scope: CoroutineScope, - block: suspend CoroutineScope.() -> T - ) : this() { + init { this.job = scope.plus(Dispatchers.Main).launch { executeInternal(this@launch, block) } } - private constructor(coroutine: Coroutine) : this() { - this.interceptor = coroutine - this.job = coroutine.job + fun timeout(timeMillis: () -> Long): Coroutine { + this.timeMillis = timeMillis() + return this@Coroutine } - fun timeout(timeMillis: () -> Long): Coroutine { - if (this.interceptor != null) { - this.interceptor!!.timeMillis = timeMillis() - } else { - this.timeMillis = timeMillis() - } + fun timeout(timeMillis: Long): Coroutine { + this.timeMillis = timeMillis return this@Coroutine } fun onErrorReturn(value: () -> T?): Coroutine { - if (this.interceptor != null) { - this.interceptor!!.errorReturn = Result(value()) - } else { - errorReturn = Result(value()) - } + this.errorReturn = Result(value()) + return this@Coroutine + } + + fun onErrorReturn(value: T?): Coroutine { + this.errorReturn = Result(value) return this@Coroutine } fun onStart(start: (suspend CoroutineScope.() -> Unit)): Coroutine { - if (this.interceptor != null) { - this.interceptor!!.start = start - } else { - this.start = start - } + this.start = start return this@Coroutine } fun onExecute(execute: suspend CoroutineScope.(T?) -> Unit): Coroutine { - if (this.interceptor != null) { - this.interceptor!!.execute = execute - } else { - this.execute = execute - } + this.execute = execute return this@Coroutine } fun onSuccess(success: suspend CoroutineScope.(T?) -> Unit): Coroutine { - if (this.interceptor != null) { - this.interceptor!!.success = success - } else { - this.success = success - } + this.success = success return this@Coroutine } fun onError(error: suspend CoroutineScope.(Throwable) -> Unit): Coroutine { - if (this.interceptor != null) { - this.interceptor!!.error = error - } else { - this.error = error - } + this.error = error return this@Coroutine } fun onFinally(finally: suspend CoroutineScope.() -> Unit): Coroutine { - if (this.interceptor != null) { - this.interceptor!!.finally = finally - } else { - this.finally = finally - } + this.finally = finally return this@Coroutine } @@ -122,7 +92,7 @@ class Coroutine() { job.cancel(cause) } - fun invokeOnCompletion(handler: CompletionHandler): DisposableHandle{ + fun invokeOnCompletion(handler: CompletionHandler): DisposableHandle { return job.invokeOnCompletion(handler) } diff --git a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt b/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt index 8fdf5e22d..f4faf69f7 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt @@ -4,8 +4,10 @@ import android.app.Application import android.util.Log import io.legado.app.App import io.legado.app.base.BaseViewModel +import io.legado.app.data.entities.SearchBook import io.legado.app.help.coroutine.Coroutine import io.legado.app.model.WebBook +import kotlinx.coroutines.CoroutineScope class SearchViewModel(application: Application) : BaseViewModel(application) { private var task: Coroutine<*>? = null @@ -26,8 +28,8 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { for (item in bookSourceList) { //task取消时自动取消 by (scope = this@execute) WebBook(item).searchBook(key, searchPage, scope = this@execute) - .timeout { 30000L } - .onExecute { + .timeout(30000L) + .onExecute{ it?.let { list -> App.db.searchBookDao().insert(*list.toTypedArray()) } @@ -39,7 +41,6 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { } task?.invokeOnCompletion { - Log.e("TAG", "complete") finally?.invoke() } } From 95f9f0376acbe4cdef2c82ad546c474a6b4f149d Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 8 Aug 2019 08:26:36 +0800 Subject: [PATCH 0601/1997] up --- .../app/ui/chapterlist/BookmarkFragment.kt | 8 +++++ .../app/ui/chapterlist/ChapterListActivity.kt | 33 ++++++++++++++++++- .../app/ui/chapterlist/ChapterListFragment.kt | 8 +++++ .../ui/main/bookshelf/BookshelfFragment.kt | 13 +++++++- .../io/legado/app/ui/main/my/MyFragment.kt | 4 +-- .../main/res/layout/activity_chapter_list.xml | 10 ++++++ app/src/main/res/layout/fragment_bookmark.xml | 7 ++++ .../main/res/layout/fragment_chapter_list.xml | 7 ++++ app/src/main/res/layout/view_title_bar.xml | 6 ++++ 9 files changed, 92 insertions(+), 4 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/chapterlist/BookmarkFragment.kt create mode 100644 app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt create mode 100644 app/src/main/res/layout/fragment_bookmark.xml create mode 100644 app/src/main/res/layout/fragment_chapter_list.xml diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/BookmarkFragment.kt b/app/src/main/java/io/legado/app/ui/chapterlist/BookmarkFragment.kt new file mode 100644 index 000000000..867872e8d --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/chapterlist/BookmarkFragment.kt @@ -0,0 +1,8 @@ +package io.legado.app.ui.chapterlist + +import io.legado.app.R +import io.legado.app.base.BaseFragment + +class BookmarkFragment : BaseFragment(R.layout.fragment_bookmark) { + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt index 89aa188c5..b4ff2583b 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt +++ b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt @@ -1,13 +1,44 @@ package io.legado.app.ui.chapterlist import android.os.Bundle +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.FragmentPagerAdapter import io.legado.app.R import io.legado.app.base.BaseActivity +import io.legado.app.utils.visible +import kotlinx.android.synthetic.main.activity_chapter_list.* +import kotlinx.android.synthetic.main.view_title_bar.* class ChapterListActivity : BaseActivity(R.layout.activity_chapter_list) { override fun onActivityCreated(savedInstanceState: Bundle?) { - + setSupportActionBar(toolbar) + tab_layout.visible() + view_pager.adapter = TabFragmentPageAdapter(supportFragmentManager) + tab_layout.setupWithViewPager(view_pager) } + + private inner class TabFragmentPageAdapter internal constructor(fm: FragmentManager) : + FragmentPagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { + override fun getItem(position: Int): Fragment { + return when (position) { + 1 -> BookmarkFragment() + else -> ChapterListFragment() + } + } + + override fun getCount(): Int { + return 2 + } + + override fun getPageTitle(position: Int): CharSequence? { + return when (position) { + 1 -> getString(R.string.bookmark) + else -> getString(R.string.chapter_list) + } + } + + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt new file mode 100644 index 000000000..1e6dd3870 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt @@ -0,0 +1,8 @@ +package io.legado.app.ui.chapterlist + +import io.legado.app.R +import io.legado.app.base.BaseFragment + +class ChapterListFragment : BaseFragment(R.layout.fragment_chapter_list) { + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index 0b014304a..814947fe2 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -24,6 +24,7 @@ import io.legado.app.lib.dialogs.yesButton import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.accentColor import io.legado.app.ui.bookshelf.BookshelfActivity +import io.legado.app.ui.read.ReadActivity import io.legado.app.ui.search.SearchActivity import io.legado.app.utils.* import kotlinx.android.synthetic.main.dialog_edittext.view.* @@ -34,7 +35,8 @@ import org.jetbrains.anko.textColor class BookshelfFragment : VMBaseFragment(R.layout.fragment_bookshelf), SearchView.OnQueryTextListener, - BookGroupAdapter.CallBack { + BookGroupAdapter.CallBack, + BookshelfAdapter.CallBack { override val viewModel: BookshelfViewModel get() = getViewModel(BookshelfViewModel::class.java) @@ -87,6 +89,7 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b rv_bookshelf.addItemDecoration(DividerItemDecoration(rv_bookshelf.context, LinearLayoutManager.VERTICAL)) bookshelfAdapter = BookshelfAdapter() rv_bookshelf.adapter = bookshelfAdapter + bookshelfAdapter.callBack = this } private fun initBookGroupData() { @@ -108,6 +111,14 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b } } + override fun open(book: Book) { + context?.startActivity() + } + + override fun search() { + + } + override fun onQueryTextSubmit(query: String?): Boolean { context?.startActivity(Pair("key", query)) return false diff --git a/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt b/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt index 5c23674e2..d64f3c6f0 100644 --- a/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt @@ -6,7 +6,7 @@ import android.view.MenuItem import android.view.View import io.legado.app.R import io.legado.app.base.BaseFragment -import io.legado.app.ui.read.ReadActivity +import io.legado.app.ui.chapterlist.ChapterListActivity import io.legado.app.utils.startActivity import kotlinx.android.synthetic.main.view_title_bar.* @@ -26,7 +26,7 @@ class MyFragment : BaseFragment(R.layout.fragment_my_config) { override fun onCompatOptionsItemSelected(item: MenuItem) { when (item.itemId) { - R.id.action_settings -> startActivity() + R.id.action_settings -> startActivity() } } } \ No newline at end of file diff --git a/app/src/main/res/layout/activity_chapter_list.xml b/app/src/main/res/layout/activity_chapter_list.xml index d829e291c..94bb27054 100644 --- a/app/src/main/res/layout/activity_chapter_list.xml +++ b/app/src/main/res/layout/activity_chapter_list.xml @@ -4,4 +4,14 @@ android:layout_width="match_parent" android:layout_height="match_parent"> + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_bookmark.xml b/app/src/main/res/layout/fragment_bookmark.xml new file mode 100644 index 000000000..d829e291c --- /dev/null +++ b/app/src/main/res/layout/fragment_bookmark.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_chapter_list.xml b/app/src/main/res/layout/fragment_chapter_list.xml new file mode 100644 index 000000000..d829e291c --- /dev/null +++ b/app/src/main/res/layout/fragment_chapter_list.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_title_bar.xml b/app/src/main/res/layout/view_title_bar.xml index 051bbc03d..5200ed5e8 100644 --- a/app/src/main/res/layout/view_title_bar.xml +++ b/app/src/main/res/layout/view_title_bar.xml @@ -15,4 +15,10 @@ android:imeOptions="actionSearch" app:defaultQueryHint="搜索" /> + + From e344fe9fb6192088b9d8d2bd17f82cde7faafd42 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 8 Aug 2019 09:03:52 +0800 Subject: [PATCH 0602/1997] up --- .../app/ui/chapterlist/ChapterListActivity.kt | 37 +++++++++++++++++++ app/src/main/res/menu/search_view.xml | 11 ++++++ 2 files changed, 48 insertions(+) create mode 100644 app/src/main/res/menu/search_view.xml diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt index b4ff2583b..3d379ac41 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt +++ b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt @@ -1,17 +1,23 @@ package io.legado.app.ui.chapterlist import android.os.Bundle +import android.view.Menu +import androidx.appcompat.widget.SearchView +import androidx.core.view.isGone import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentPagerAdapter import io.legado.app.R import io.legado.app.base.BaseActivity +import io.legado.app.utils.gone import io.legado.app.utils.visible import kotlinx.android.synthetic.main.activity_chapter_list.* import kotlinx.android.synthetic.main.view_title_bar.* class ChapterListActivity : BaseActivity(R.layout.activity_chapter_list) { + private var searchView: SearchView? = null + override fun onActivityCreated(savedInstanceState: Bundle?) { setSupportActionBar(toolbar) tab_layout.visible() @@ -19,6 +25,28 @@ class ChapterListActivity : BaseActivity(R.layout.activity_chapter_list) { tab_layout.setupWithViewPager(view_pager) } + override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { + menuInflater.inflate(R.menu.search_view, menu) + val search = menu.findItem(R.id.action_search) + searchView = search.actionView as SearchView + searchView?.maxWidth = resources.displayMetrics.widthPixels + searchView?.onActionViewCollapsed() + searchView?.setOnCloseListener { + tab_layout.visible() + false + } + searchView?.setOnSearchClickListener { tab_layout.gone() } + searchView?.setOnQueryTextListener(object : SearchView.OnQueryTextListener { + override fun onQueryTextSubmit(query: String): Boolean { + return false + } + + override fun onQueryTextChange(newText: String): Boolean { + return false + } + }) + return super.onCompatCreateOptionsMenu(menu) + } private inner class TabFragmentPageAdapter internal constructor(fm: FragmentManager) : FragmentPagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { @@ -41,4 +69,13 @@ class ChapterListActivity : BaseActivity(R.layout.activity_chapter_list) { } } + + override fun onBackPressed() { + if (tab_layout.isGone) { + searchView?.onActionViewCollapsed() + tab_layout.visible() + } else { + super.onBackPressed() + } + } } \ No newline at end of file diff --git a/app/src/main/res/menu/search_view.xml b/app/src/main/res/menu/search_view.xml new file mode 100644 index 000000000..ee23fae6b --- /dev/null +++ b/app/src/main/res/menu/search_view.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file From 5fc1808f292102dc444444f5a6b81dd4683a077b Mon Sep 17 00:00:00 2001 From: Administrator <1760316362@qq.com> Date: Thu, 8 Aug 2019 14:15:04 +0800 Subject: [PATCH 0603/1997] update --- .../app/ui/booksource/BookSourceActivity.kt | 2 +- .../app/ui/chapterlist/ChapterListActivity.kt | 1 + .../ui/main/bookshelf/BookshelfFragment.kt | 12 +-- .../io/legado/app/ui/search/SearchActivity.kt | 3 +- .../app/ui/sourcedebug/SourceDebugActivity.kt | 2 +- .../java/io/legado/app/ui/widget/TitleBar.kt | 8 +- .../io/legado/app/ui/widget/page/PageView.kt | 99 +++++++++++++++---- .../io/legado/app/utils/ViewExtensions.kt | 2 +- .../main/res/layout/activity_book_source.xml | 13 +-- .../main/res/layout/activity_chapter_list.xml | 20 ++-- app/src/main/res/layout/activity_search.xml | 1 + .../main/res/layout/activity_source_debug.xml | 1 + .../{page_view.xml => view_book_page.xml} | 3 +- app/src/main/res/layout/view_search.xml | 10 ++ app/src/main/res/layout/view_tab_layout.xml | 7 ++ app/src/main/res/layout/view_title_bar.xml | 18 +--- app/src/main/res/values/attrs.xml | 1 + 17 files changed, 138 insertions(+), 65 deletions(-) rename app/src/main/res/layout/{page_view.xml => view_book_page.xml} (63%) create mode 100644 app/src/main/res/layout/view_search.xml create mode 100644 app/src/main/res/layout/view_tab_layout.xml diff --git a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt index fd849ad63..36305d870 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt @@ -23,6 +23,7 @@ import io.legado.app.ui.qrcode.QrCodeActivity import io.legado.app.ui.sourceedit.SourceEditActivity import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_book_source.* +import kotlinx.android.synthetic.main.view_search.* import kotlinx.android.synthetic.main.view_title_bar.* import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.launch @@ -93,7 +94,6 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity } private fun initSearchView() { - search_view.visibility = View.VISIBLE search_view.onActionViewExpanded() search_view.queryHint = getString(R.string.search_book_source) search_view.clearFocus() diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt index 3d379ac41..b253d5c72 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt +++ b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt @@ -12,6 +12,7 @@ import io.legado.app.base.BaseActivity import io.legado.app.utils.gone import io.legado.app.utils.visible import kotlinx.android.synthetic.main.activity_chapter_list.* +import kotlinx.android.synthetic.main.view_tab_layout.* import kotlinx.android.synthetic.main.view_title_bar.* class ChapterListActivity : BaseActivity(R.layout.activity_chapter_list) { diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index 814947fe2..5ff3135a8 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -29,6 +29,7 @@ import io.legado.app.ui.search.SearchActivity import io.legado.app.utils.* import kotlinx.android.synthetic.main.dialog_edittext.view.* import kotlinx.android.synthetic.main.fragment_bookshelf.* +import kotlinx.android.synthetic.main.view_search.* import kotlinx.android.synthetic.main.view_title_bar.* import org.jetbrains.anko.startActivity import org.jetbrains.anko.textColor @@ -66,12 +67,11 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b } private fun initSearchView() { - search_view.visible() - search_view.onActionViewExpanded() - search_view.isSubmitButtonEnabled = true - search_view.queryHint = getString(R.string.search_book_key) - search_view.clearFocus() - search_view.setOnQueryTextListener(this) +// search_view.onActionViewExpanded() +// search_view.isSubmitButtonEnabled = true +// search_view.queryHint = getString(R.string.search_book_key) +// search_view.clearFocus() +// search_view.setOnQueryTextListener(this) } private fun initRecyclerView() { diff --git a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt index 74a51d172..1730b9d34 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt @@ -15,7 +15,7 @@ import io.legado.app.data.entities.SearchShow import io.legado.app.lib.theme.ATH import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_search.* -import kotlinx.android.synthetic.main.view_title_bar.* +import kotlinx.android.synthetic.main.view_search.* class SearchActivity : VMBaseActivity(R.layout.activity_search) { @@ -32,7 +32,6 @@ class SearchActivity : VMBaseActivity(R.layout.activity_search) } private fun initSearchView() { - search_view.visibility = View.VISIBLE search_view.onActionViewExpanded() search_view.isSubmitButtonEnabled = true search_view.queryHint = getString(R.string.search_book_key) diff --git a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt index 80f7df36d..2290654e4 100644 --- a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt +++ b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt @@ -14,6 +14,7 @@ import io.legado.app.lib.theme.accentColor import io.legado.app.ui.qrcode.QrCodeActivity import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_source_debug.* +import kotlinx.android.synthetic.main.view_search.* import kotlinx.android.synthetic.main.view_title_bar.* import kotlinx.coroutines.launch import org.jetbrains.anko.startActivityForResult @@ -50,7 +51,6 @@ class SourceDebugActivity : VMBaseActivity(R.layout.activity_s } private fun initSearchView() { - search_view.visibility = View.VISIBLE search_view.onActionViewExpanded() search_view.isSubmitButtonEnabled = true search_view.queryHint = getString(R.string.search_book_key) diff --git a/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt b/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt index 631356af0..7e57837b4 100644 --- a/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt +++ b/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt @@ -10,7 +10,6 @@ import android.view.Menu import android.view.View import androidx.annotation.ColorInt import androidx.annotation.StyleRes -import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.Toolbar import androidx.core.graphics.drawable.DrawableCompat import com.google.android.material.appbar.AppBarLayout @@ -126,6 +125,9 @@ class TitleBar(context: Context, attrs: AttributeSet?) : AppBarLayout(context, a this.subtitle = subtitleText } + if (a.hasValue(R.styleable.TitleBar_contentLayout)) { + inflate(context, a.getResourceId(R.styleable.TitleBar_contentLayout, 0), this) + } } if (a.getBoolean(R.styleable.TitleBar_fitStatusBar, true)) { @@ -146,7 +148,7 @@ class TitleBar(context: Context, attrs: AttributeSet?) : AppBarLayout(context, a if (attachToActivity) { attachToActivity() } - wrapAppTheme() + wrapTheme() } fun setNavigationOnClickListener(clickListener: ((View) -> Unit)) { @@ -177,7 +179,7 @@ class TitleBar(context: Context, attrs: AttributeSet?) : AppBarLayout(context, a toolbar.setSubtitleTextAppearance(context, resId) } - private fun wrapAppTheme() { + private fun wrapTheme() { val primaryTextColor = if (isInEditMode) Color.BLACK else context.primaryTextColor DrawableUtils.setTint(toolbar.overflowIcon, primaryTextColor) toolbar.setTitleTextColor(primaryTextColor) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 2ff709124..353087726 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -1,19 +1,17 @@ package io.legado.app.ui.widget.page import android.content.Context -import android.graphics.Bitmap -import android.graphics.Canvas -import android.graphics.Rect +import android.graphics.* import android.graphics.drawable.GradientDrawable import android.util.AttributeSet -import android.util.Log import android.view.MotionEvent -import android.view.View import android.widget.FrameLayout -import androidx.appcompat.widget.AppCompatTextView import io.legado.app.R +import io.legado.app.utils.dp import io.legado.app.utils.screenshot -import kotlin.math.abs +import kotlinx.android.synthetic.main.view_book_page.view.* +import org.jetbrains.anko.backgroundColor +import org.jetbrains.anko.horizontalPadding class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, attrs) { @@ -22,34 +20,99 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att private var downX: Float = 0.toFloat() private var offset: Float = 0.toFloat() - private val srcRect: Rect = Rect() - private val destRect: Rect = Rect() - private val shadowDrawable: GradientDrawable + private val shadowDrawableR: GradientDrawable + private val shadowDrawableL: GradientDrawable + + private val bitmapMatrix = Matrix() + + private var cover: Boolean = true init { val shadowColors = intArrayOf(0x66111111, 0x00000000) - shadowDrawable = GradientDrawable( + shadowDrawableR = GradientDrawable( GradientDrawable.Orientation.LEFT_RIGHT, shadowColors ) - shadowDrawable.gradientType = GradientDrawable.LINEAR_GRADIENT + shadowDrawableR.gradientType = GradientDrawable.LINEAR_GRADIENT + + shadowDrawableL = GradientDrawable( + GradientDrawable.Orientation.RIGHT_LEFT, shadowColors + ) + shadowDrawableL.gradientType = GradientDrawable.LINEAR_GRADIENT + + inflate(context, R.layout.view_book_page, this) + + setWillNotDraw(false) + + page_panel.backgroundColor = Color.WHITE + + page_panel.horizontalPadding = 16.dp - inflate(context, R.layout.page_view, this) } - override fun onDraw(canvas: Canvas?) { - canvas?.save() - super.onDraw(canvas) - canvas?.restore() + override fun dispatchDraw(canvas: Canvas?) { + super.dispatchDraw(canvas) + + bitmap?.let { + val dx = if (offset > 0) offset - width else offset + width + bitmapMatrix.setTranslate(dx, 0.toFloat()) + canvas?.drawBitmap(it, bitmapMatrix, null) + + if (cover) { + addShadow(dx.toInt(), canvas) + } + } + } + private fun addShadow(left: Int, canvas: Canvas?) { + canvas?.let { + if (left < 0) { + shadowDrawableR.setBounds(left + width, 0, left+ width + 30, height) + shadowDrawableR.draw(it) + } else { + shadowDrawableL.setBounds(left - 30, 0, left, height) + shadowDrawableL.draw(it) + } + } } override fun onTouchEvent(event: MotionEvent?): Boolean { + when (event?.action) { + MotionEvent.ACTION_DOWN -> { + bitmap = page_panel.screenshot() + downX = event.x + offset = 0.toFloat() + if (!cover) { + page_panel.translationX = 0.toFloat() + } + invalidate() + } + MotionEvent.ACTION_MOVE -> { + offset = event.x - downX + if (!cover) { + page_panel.translationX = offset + } + invalidate() + } + + MotionEvent.ACTION_UP -> { + bitmap = null + if (!cover) { + page_panel.translationX = 0.toFloat() + } + invalidate() + } + } return true } - fun setPageFactory(factory: PageFactory<*>){ + fun setTranslate(translationX: Float, translationY: Float) { + page_panel.translationX = translationX + page_panel.translationY = translationY + } + + fun setPageFactory(factory: PageFactory<*>) { } } diff --git a/app/src/main/java/io/legado/app/utils/ViewExtensions.kt b/app/src/main/java/io/legado/app/utils/ViewExtensions.kt index cbde9e3f1..1c7fb29c3 100644 --- a/app/src/main/java/io/legado/app/utils/ViewExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/ViewExtensions.kt @@ -28,7 +28,7 @@ private tailrec fun getCompatActivity(context: Context?): AppCompatActivity? { val View.activity: AppCompatActivity? get() = getCompatActivity(context) -fun View.hideSoftInput() = run { +inline fun View.hideSoftInput() = run { val imm = App.INSTANCE.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager imm?.let { imm.hideSoftInputFromWindow(this.windowToken, 0) diff --git a/app/src/main/res/layout/activity_book_source.xml b/app/src/main/res/layout/activity_book_source.xml index 8297c7268..e884787c0 100644 --- a/app/src/main/res/layout/activity_book_source.xml +++ b/app/src/main/res/layout/activity_book_source.xml @@ -11,16 +11,17 @@ android:layout_height="wrap_content" app:contentInsetStartWithNavigation="0dp" app:displayHomeAsUp="true" - app:title="@string/book_source"/> + app:title="@string/book_source" + app:contentLayout="@layout/view_search"/> + android:layout_width="match_parent" + android:layout_height="match_parent"> + android:id="@+id/recycler_view" + android:layout_width="match_parent" + android:layout_height="match_parent"/> diff --git a/app/src/main/res/layout/activity_chapter_list.xml b/app/src/main/res/layout/activity_chapter_list.xml index 94bb27054..159f77324 100644 --- a/app/src/main/res/layout/activity_chapter_list.xml +++ b/app/src/main/res/layout/activity_chapter_list.xml @@ -1,17 +1,19 @@ + xmlns:app="http://schemas.android.com/apk/res-auto" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"> + android:id="@+id/title_bar" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:contentLayout="@layout/view_tab_layout"/> + android:id="@+id/view_pager" + android:layout_width="match_parent" + android:layout_height="match_parent"/> \ No newline at end of file diff --git a/app/src/main/res/layout/activity_search.xml b/app/src/main/res/layout/activity_search.xml index e330e1565..6f4f88662 100644 --- a/app/src/main/res/layout/activity_search.xml +++ b/app/src/main/res/layout/activity_search.xml @@ -11,6 +11,7 @@ android:id="@+id/title_bar" android:layout_width="match_parent" android:layout_height="wrap_content" + app:contentLayout="@layout/view_search" app:contentInsetStartWithNavigation="0dp" app:layout_constraintTop_toTopOf="parent" app:title="搜索"/> diff --git a/app/src/main/res/layout/activity_source_debug.xml b/app/src/main/res/layout/activity_source_debug.xml index 4a98208bd..1b79a6058 100644 --- a/app/src/main/res/layout/activity_source_debug.xml +++ b/app/src/main/res/layout/activity_source_debug.xml @@ -10,6 +10,7 @@ android:id="@+id/title_bar" android:layout_width="match_parent" android:layout_height="wrap_content" + app:contentLayout="@layout/view_search" app:layout_constraintTop_toTopOf="parent" app:title="@string/debug_source" /> diff --git a/app/src/main/res/layout/page_view.xml b/app/src/main/res/layout/view_book_page.xml similarity index 63% rename from app/src/main/res/layout/page_view.xml rename to app/src/main/res/layout/view_book_page.xml index fa67d4f81..ec9423495 100644 --- a/app/src/main/res/layout/page_view.xml +++ b/app/src/main/res/layout/view_book_page.xml @@ -24,7 +24,8 @@ + android:layout_height="match_parent" + android:text="233333333333333333333333333333333333333333333333333233333333333333333333333333333333333333333333333333233333333333333333333333333333333333333333333333333233333333333333333333333333333333333333333333333333233333333333333333333333333333333333333333333333333233333333333333333333333333333333333333333333333333233333333333333333333333333333333333333333333333333233333333333333333333333333333333333333333333333333233333333333333333333333333333333333333333333333333233333333333333333333333333333333333333333333333333233333333333333333333333333333333333333333333333333233333333333333333333333333333333333333333333333333233333333333333333333333333333333333333333333333333233333333333333333333333333333333333333333333333333"/> + \ No newline at end of file diff --git a/app/src/main/res/layout/view_tab_layout.xml b/app/src/main/res/layout/view_tab_layout.xml new file mode 100644 index 000000000..80cfe13e4 --- /dev/null +++ b/app/src/main/res/layout/view_tab_layout.xml @@ -0,0 +1,7 @@ + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_title_bar.xml b/app/src/main/res/layout/view_title_bar.xml index 5200ed5e8..3b7641388 100644 --- a/app/src/main/res/layout/view_title_bar.xml +++ b/app/src/main/res/layout/view_title_bar.xml @@ -5,20 +5,4 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="?attr/actionBarStyle" - app:popupTheme="@style/AppTheme.PopupOverlay"> - - - - - - + app:popupTheme="@style/AppTheme.PopupOverlay"/> diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index c782a6e9a..67c52d7c9 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -14,6 +14,7 @@ + From 9768c0eed3a0e5cc9a6d360442a271abb77955b0 Mon Sep 17 00:00:00 2001 From: Administrator <1760316362@qq.com> Date: Thu, 8 Aug 2019 14:38:29 +0800 Subject: [PATCH 0604/1997] update --- .../java/io/legado/app/base/BaseActivity.kt | 2 +- .../java/io/legado/app/base/BaseFragment.kt | 4 ++-- .../main/java/io/legado/app/lib/theme/ATH.kt | 2 +- .../io/legado/app/lib/theme/TintHelper.kt | 8 ++++++- .../app/ui/booksource/BookSourceActivity.kt | 2 ++ .../app/ui/chapterlist/ChapterListActivity.kt | 3 +++ .../ui/main/bookshelf/BookshelfFragment.kt | 3 +-- .../io/legado/app/ui/search/SearchActivity.kt | 2 ++ .../java/io/legado/app/ui/widget/TitleBar.kt | 21 ++++++++----------- .../io/legado/app/utils/MenuExtensions.kt | 2 +- 10 files changed, 29 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/io/legado/app/base/BaseActivity.kt b/app/src/main/java/io/legado/app/base/BaseActivity.kt index 881323bc6..96d3d21d5 100644 --- a/app/src/main/java/io/legado/app/base/BaseActivity.kt +++ b/app/src/main/java/io/legado/app/base/BaseActivity.kt @@ -41,7 +41,7 @@ abstract class BaseActivity(private val layoutID: Int, private val fullScreen: B final override fun onCreateOptionsMenu(menu: Menu?): Boolean { return menu?.let { val bool = onCompatCreateOptionsMenu(it) - it.setIconColor(this) + it.applyTint(this) bool } ?: super.onCreateOptionsMenu(menu) } diff --git a/app/src/main/java/io/legado/app/base/BaseFragment.kt b/app/src/main/java/io/legado/app/base/BaseFragment.kt index f8314c44c..1f3ff2dcb 100644 --- a/app/src/main/java/io/legado/app/base/BaseFragment.kt +++ b/app/src/main/java/io/legado/app/base/BaseFragment.kt @@ -6,7 +6,7 @@ import android.view.MenuItem import androidx.appcompat.view.SupportMenuInflater import androidx.appcompat.widget.Toolbar import androidx.fragment.app.Fragment -import io.legado.app.utils.setIconColor +import io.legado.app.utils.applyTint import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.MainScope import kotlinx.coroutines.cancel @@ -31,7 +31,7 @@ abstract class BaseFragment(layoutID: Int) : Fragment(layoutID), supportToolbar?.let { it.menu.apply { onCompatCreateOptionsMenu(this) - setIconColor(requireContext()) + applyTint(requireContext()) } it.setOnMenuItemClickListener { item -> diff --git a/app/src/main/java/io/legado/app/lib/theme/ATH.kt b/app/src/main/java/io/legado/app/lib/theme/ATH.kt index e59d87149..512b2ffa7 100644 --- a/app/src/main/java/io/legado/app/lib/theme/ATH.kt +++ b/app/src/main/java/io/legado/app/lib/theme/ATH.kt @@ -178,7 +178,7 @@ object ATH { } } - fun applyTint(view: View?) { + fun applyAccentTint(view: View?) { view?.apply { setTint(this, context.accentColor) } diff --git a/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt b/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt index dd727063a..0ab6fcfc4 100644 --- a/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt +++ b/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt @@ -147,7 +147,13 @@ object TintHelper { is SwitchCompat -> setTint(view, color, isDark) is SearchView -> { val iconIdS = - intArrayOf(androidx.appcompat.R.id.search_button, androidx.appcompat.R.id.search_close_btn) + intArrayOf( + androidx.appcompat.R.id.search_button, + androidx.appcompat.R.id.search_close_btn, + androidx.appcompat.R.id.search_go_btn, + androidx.appcompat.R.id.search_voice_btn, + androidx.appcompat.R.id.search_mag_icon + ) for (iconId in iconIdS) { val icon = view.findViewById(iconId) if (icon != null) { diff --git a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt index 36305d870..3486589a8 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt @@ -19,6 +19,7 @@ import io.legado.app.base.VMBaseActivity import io.legado.app.data.entities.BookSource import io.legado.app.help.ItemTouchCallback import io.legado.app.lib.theme.ATH +import io.legado.app.lib.theme.primaryTextColor import io.legado.app.ui.qrcode.QrCodeActivity import io.legado.app.ui.sourceedit.SourceEditActivity import io.legado.app.utils.getViewModel @@ -94,6 +95,7 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity } private fun initSearchView() { + ATH.setTint(search_view, primaryTextColor) search_view.onActionViewExpanded() search_view.queryHint = getString(R.string.search_book_source) search_view.clearFocus() diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt index b253d5c72..e77642729 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt +++ b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt @@ -9,6 +9,8 @@ import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentPagerAdapter import io.legado.app.R import io.legado.app.base.BaseActivity +import io.legado.app.lib.theme.ATH +import io.legado.app.lib.theme.primaryTextColor import io.legado.app.utils.gone import io.legado.app.utils.visible import kotlinx.android.synthetic.main.activity_chapter_list.* @@ -30,6 +32,7 @@ class ChapterListActivity : BaseActivity(R.layout.activity_chapter_list) { menuInflater.inflate(R.menu.search_view, menu) val search = menu.findItem(R.id.action_search) searchView = search.actionView as SearchView + ATH.setTint(searchView!!, primaryTextColor) searchView?.maxWidth = resources.displayMetrics.widthPixels searchView?.onActionViewCollapsed() searchView?.setOnCloseListener { diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index 5ff3135a8..06ebcdc77 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -29,7 +29,6 @@ import io.legado.app.ui.search.SearchActivity import io.legado.app.utils.* import kotlinx.android.synthetic.main.dialog_edittext.view.* import kotlinx.android.synthetic.main.fragment_bookshelf.* -import kotlinx.android.synthetic.main.view_search.* import kotlinx.android.synthetic.main.view_title_bar.* import org.jetbrains.anko.startActivity import org.jetbrains.anko.textColor @@ -135,7 +134,7 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b customView { layoutInflater.inflate(R.layout.dialog_edittext, null).apply { editText = edit_view.apply { - ATH.applyTint(this) + ATH.applyAccentTint(this) hint = "分组名称" } } diff --git a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt index 1730b9d34..1b19f5b1d 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt @@ -13,6 +13,7 @@ import io.legado.app.R import io.legado.app.base.VMBaseActivity import io.legado.app.data.entities.SearchShow import io.legado.app.lib.theme.ATH +import io.legado.app.lib.theme.primaryTextColor import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_search.* import kotlinx.android.synthetic.main.view_search.* @@ -32,6 +33,7 @@ class SearchActivity : VMBaseActivity(R.layout.activity_search) } private fun initSearchView() { + ATH.setTint(search_view, primaryTextColor) search_view.onActionViewExpanded() search_view.isSubmitButtonEnabled = true search_view.queryHint = getString(R.string.search_book_key) diff --git a/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt b/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt index 7e57837b4..796e6fcb3 100644 --- a/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt +++ b/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt @@ -145,10 +145,7 @@ class TitleBar(context: Context, attrs: AttributeSet?) : AppBarLayout(context, a override fun onAttachedToWindow() { super.onAttachedToWindow() - if (attachToActivity) { - attachToActivity() - } - wrapTheme() + attachToActivity() } fun setNavigationOnClickListener(clickListener: ((View) -> Unit)) { @@ -179,7 +176,14 @@ class TitleBar(context: Context, attrs: AttributeSet?) : AppBarLayout(context, a toolbar.setSubtitleTextAppearance(context, resId) } - private fun wrapTheme() { + private fun attachToActivity() { + if(attachToActivity) { + activity?.let { + it.setSupportActionBar(toolbar) + it.supportActionBar?.setDisplayHomeAsUpEnabled(displayHomeAsUp) + } + } + val primaryTextColor = if (isInEditMode) Color.BLACK else context.primaryTextColor DrawableUtils.setTint(toolbar.overflowIcon, primaryTextColor) toolbar.setTitleTextColor(primaryTextColor) @@ -191,13 +195,6 @@ class TitleBar(context: Context, attrs: AttributeSet?) : AppBarLayout(context, a } } - private fun attachToActivity() { - activity?.let { - it.setSupportActionBar(toolbar) - it.supportActionBar?.setDisplayHomeAsUpEnabled(displayHomeAsUp) - } - } - private fun wrapDrawableTint(drawable: Drawable?, tintList: ColorStateList?, tintMode: Int) { if (drawable == null || tintList == null) return val wrappedDrawable = DrawableCompat.wrap(drawable.mutate()) diff --git a/app/src/main/java/io/legado/app/utils/MenuExtensions.kt b/app/src/main/java/io/legado/app/utils/MenuExtensions.kt index 8d97321af..21eeae968 100644 --- a/app/src/main/java/io/legado/app/utils/MenuExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/MenuExtensions.kt @@ -10,7 +10,7 @@ import io.legado.app.lib.theme.DrawableUtils import io.legado.app.lib.theme.getPrimaryTextColor import io.legado.app.lib.theme.primaryTextColor -fun Menu.setIconColor(context: Context): Menu = this.let { menu -> +fun Menu.applyTint(context: Context): Menu = this.let { menu -> if (menu is MenuBuilder) { menu.setOptionalIconsVisible(true) } From af5d7553fe3a2a82893824d56a2c21d7c78a17ad Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 8 Aug 2019 16:04:47 +0800 Subject: [PATCH 0605/1997] up --- app/src/main/res/layout/fragment_bookmark.xml | 14 +++-- .../main/res/layout/fragment_chapter_list.xml | 61 +++++++++++++++++-- 2 files changed, 67 insertions(+), 8 deletions(-) diff --git a/app/src/main/res/layout/fragment_bookmark.xml b/app/src/main/res/layout/fragment_bookmark.xml index d829e291c..e9b393f1e 100644 --- a/app/src/main/res/layout/fragment_bookmark.xml +++ b/app/src/main/res/layout/fragment_bookmark.xml @@ -1,7 +1,13 @@ - + android:layout_height="match_parent" + android:descendantFocusability="blocksDescendants"> - \ No newline at end of file + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_chapter_list.xml b/app/src/main/res/layout/fragment_chapter_list.xml index d829e291c..5fa516994 100644 --- a/app/src/main/res/layout/fragment_chapter_list.xml +++ b/app/src/main/res/layout/fragment_chapter_list.xml @@ -1,7 +1,60 @@ - + android:layout_height="match_parent" + android:descendantFocusability="blocksDescendants"> - \ No newline at end of file + + + + + + + + + + + + \ No newline at end of file From 6811c20259be4db73a334d30ed3a47e57f932812 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 8 Aug 2019 16:49:00 +0800 Subject: [PATCH 0606/1997] up --- .../io/legado/app/ui/chapterlist/BookmarkFragment.kt | 8 ++++++-- .../io/legado/app/ui/chapterlist/ChapterListActivity.kt | 7 +++++-- .../io/legado/app/ui/chapterlist/ChapterListFragment.kt | 9 +++++++-- .../io/legado/app/ui/chapterlist/ChapterListViewModel.kt | 8 ++++++++ 4 files changed, 26 insertions(+), 6 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/chapterlist/ChapterListViewModel.kt diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/BookmarkFragment.kt b/app/src/main/java/io/legado/app/ui/chapterlist/BookmarkFragment.kt index 867872e8d..b62fa6f49 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/BookmarkFragment.kt +++ b/app/src/main/java/io/legado/app/ui/chapterlist/BookmarkFragment.kt @@ -1,8 +1,12 @@ package io.legado.app.ui.chapterlist import io.legado.app.R -import io.legado.app.base.BaseFragment +import io.legado.app.base.VMBaseFragment +import io.legado.app.utils.getViewModelOfActivity + +class BookmarkFragment : VMBaseFragment(R.layout.fragment_bookmark) { + override val viewModel: ChapterListViewModel + get() = getViewModelOfActivity(ChapterListViewModel::class.java) -class BookmarkFragment : BaseFragment(R.layout.fragment_bookmark) { } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt index e77642729..dc3553754 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt +++ b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt @@ -8,16 +8,19 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentPagerAdapter import io.legado.app.R -import io.legado.app.base.BaseActivity +import io.legado.app.base.VMBaseActivity import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.primaryTextColor +import io.legado.app.utils.getViewModel import io.legado.app.utils.gone import io.legado.app.utils.visible import kotlinx.android.synthetic.main.activity_chapter_list.* import kotlinx.android.synthetic.main.view_tab_layout.* import kotlinx.android.synthetic.main.view_title_bar.* -class ChapterListActivity : BaseActivity(R.layout.activity_chapter_list) { +class ChapterListActivity : VMBaseActivity(R.layout.activity_chapter_list) { + override val viewModel: ChapterListViewModel + get() = getViewModel(ChapterListViewModel::class.java) private var searchView: SearchView? = null diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt index 1e6dd3870..f88f0dbb6 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt +++ b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt @@ -1,8 +1,13 @@ package io.legado.app.ui.chapterlist import io.legado.app.R -import io.legado.app.base.BaseFragment +import io.legado.app.base.VMBaseFragment +import io.legado.app.utils.getViewModelOfActivity + +class ChapterListFragment : VMBaseFragment(R.layout.fragment_chapter_list) { + override val viewModel: ChapterListViewModel + get() = getViewModelOfActivity(ChapterListViewModel::class.java) + -class ChapterListFragment : BaseFragment(R.layout.fragment_chapter_list) { } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListViewModel.kt b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListViewModel.kt new file mode 100644 index 000000000..3b41d0a73 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListViewModel.kt @@ -0,0 +1,8 @@ +package io.legado.app.ui.chapterlist + +import io.legado.app.App +import io.legado.app.base.BaseViewModel + +class ChapterListViewModel : BaseViewModel(App.INSTANCE) { + +} \ No newline at end of file From 3d0b3e107acd4a51553aca54816dc8d5a21152d3 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 8 Aug 2019 17:01:08 +0800 Subject: [PATCH 0607/1997] up --- app/src/main/res/layout/activity_book_info.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/res/layout/activity_book_info.xml b/app/src/main/res/layout/activity_book_info.xml index d829e291c..3e997899a 100644 --- a/app/src/main/res/layout/activity_book_info.xml +++ b/app/src/main/res/layout/activity_book_info.xml @@ -4,4 +4,10 @@ android:layout_width="match_parent" android:layout_height="match_parent"> + + + \ No newline at end of file From 67cd13b185445b75e87910d0d022cdb573d3304b Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 8 Aug 2019 18:09:57 +0800 Subject: [PATCH 0608/1997] up --- .../java/io/legado/app/ui/chapterlist/ChapterListActivity.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt index dc3553754..62996558e 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt +++ b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt @@ -26,7 +26,6 @@ class ChapterListActivity : VMBaseActivity(R.layout.activi override fun onActivityCreated(savedInstanceState: Bundle?) { setSupportActionBar(toolbar) - tab_layout.visible() view_pager.adapter = TabFragmentPageAdapter(supportFragmentManager) tab_layout.setupWithViewPager(view_pager) } From 9a6d5e06efabc1eb678eeaddc67faff53028a05f Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 8 Aug 2019 21:46:50 +0800 Subject: [PATCH 0609/1997] up --- .../java/io/legado/app/data/AppDatabase.kt | 2 +- .../io/legado/app/data/entities/Bookmark.kt | 21 +++++++++++++++++++ .../app/ui/chapterlist/BookmarkAdapter.kt | 2 ++ .../app/ui/chapterlist/ChapterListAdapter.kt | 2 ++ app/src/main/res/layout/item_bookmark.xml | 7 +++++++ app/src/main/res/layout/item_chapter_list.xml | 7 +++++++ 6 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/io/legado/app/data/entities/Bookmark.kt create mode 100644 app/src/main/java/io/legado/app/ui/chapterlist/BookmarkAdapter.kt create mode 100644 app/src/main/java/io/legado/app/ui/chapterlist/ChapterListAdapter.kt create mode 100644 app/src/main/res/layout/item_bookmark.xml create mode 100644 app/src/main/res/layout/item_chapter_list.xml diff --git a/app/src/main/java/io/legado/app/data/AppDatabase.kt b/app/src/main/java/io/legado/app/data/AppDatabase.kt index 630763064..5fdff03e0 100644 --- a/app/src/main/java/io/legado/app/data/AppDatabase.kt +++ b/app/src/main/java/io/legado/app/data/AppDatabase.kt @@ -12,7 +12,7 @@ import io.legado.app.data.entities.* @Database( entities = [Book::class, BookGroup::class, BookSource::class, BookChapter::class, ReplaceRule::class, SearchBook::class, - SearchKeyword::class, SourceCookie::class, RssSource::class], + SearchKeyword::class, SourceCookie::class, RssSource::class, Bookmark::class], version = 1, exportSchema = true ) diff --git a/app/src/main/java/io/legado/app/data/entities/Bookmark.kt b/app/src/main/java/io/legado/app/data/entities/Bookmark.kt new file mode 100644 index 000000000..c1f638137 --- /dev/null +++ b/app/src/main/java/io/legado/app/data/entities/Bookmark.kt @@ -0,0 +1,21 @@ +package io.legado.app.data.entities + +import android.os.Parcelable +import androidx.room.Entity +import androidx.room.Index +import androidx.room.PrimaryKey +import kotlinx.android.parcel.Parcelize + +@Parcelize +@Entity(tableName = "bookmarks", indices = [(Index(value = ["bookUrl"], unique = true))]) +data class Bookmark( + @PrimaryKey + var time: Long = System.currentTimeMillis(), + var bookUrl: String = "", + var bookName: String = "", + var chapterName: String = "", + var chapterIndex: Int = 0, + var pageIndex: Int = 0, + var content: String = "" + +) : Parcelable \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/BookmarkAdapter.kt b/app/src/main/java/io/legado/app/ui/chapterlist/BookmarkAdapter.kt new file mode 100644 index 000000000..8fe0ecbe6 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/chapterlist/BookmarkAdapter.kt @@ -0,0 +1,2 @@ +package io.legado.app.ui.chapterlist + diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListAdapter.kt b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListAdapter.kt new file mode 100644 index 000000000..8fe0ecbe6 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListAdapter.kt @@ -0,0 +1,2 @@ +package io.legado.app.ui.chapterlist + diff --git a/app/src/main/res/layout/item_bookmark.xml b/app/src/main/res/layout/item_bookmark.xml new file mode 100644 index 000000000..d829e291c --- /dev/null +++ b/app/src/main/res/layout/item_bookmark.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_chapter_list.xml b/app/src/main/res/layout/item_chapter_list.xml new file mode 100644 index 000000000..d829e291c --- /dev/null +++ b/app/src/main/res/layout/item_chapter_list.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file From 0934ee4b4a08a12b4885d1e0d0c94dcebb900736 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 8 Aug 2019 22:04:23 +0800 Subject: [PATCH 0610/1997] up --- .../java/io/legado/app/data/AppDatabase.kt | 1 + .../java/io/legado/app/data/dao/BookmarkDao.kt | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 app/src/main/java/io/legado/app/data/dao/BookmarkDao.kt diff --git a/app/src/main/java/io/legado/app/data/AppDatabase.kt b/app/src/main/java/io/legado/app/data/AppDatabase.kt index 5fdff03e0..d58a5ccb7 100644 --- a/app/src/main/java/io/legado/app/data/AppDatabase.kt +++ b/app/src/main/java/io/legado/app/data/AppDatabase.kt @@ -57,4 +57,5 @@ abstract class AppDatabase : RoomDatabase() { abstract fun searchKeywordDao(): SearchKeywordDao abstract fun sourceCookieDao(): SourceCookieDao abstract fun rssSourceDao(): RssSourceDao + abstract fun bookmarkDao(): BookmarkDao } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/data/dao/BookmarkDao.kt b/app/src/main/java/io/legado/app/data/dao/BookmarkDao.kt new file mode 100644 index 000000000..eb757c547 --- /dev/null +++ b/app/src/main/java/io/legado/app/data/dao/BookmarkDao.kt @@ -0,0 +1,18 @@ +package io.legado.app.data.dao + +import androidx.paging.DataSource +import androidx.room.Dao +import androidx.room.Query +import io.legado.app.data.entities.Bookmark + + +@Dao +interface BookmarkDao { + + @Query("select * from bookmarks") + fun all(): List + + @Query("select * from bookmarks where bookUrl = :bookUrl") + fun observeByBook(bookUrl: String): DataSource.Factory + +} \ No newline at end of file From 8ccd7895e44c3f249609e6e84564fbc0d7b65776 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 8 Aug 2019 22:44:48 +0800 Subject: [PATCH 0611/1997] up --- .../app/ui/chapterlist/BookmarkAdapter.kt | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/BookmarkAdapter.kt b/app/src/main/java/io/legado/app/ui/chapterlist/BookmarkAdapter.kt index 8fe0ecbe6..ef07eb323 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/BookmarkAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/chapterlist/BookmarkAdapter.kt @@ -1,2 +1,46 @@ package io.legado.app.ui.chapterlist +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.paging.PagedListAdapter +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.RecyclerView +import io.legado.app.R +import io.legado.app.data.entities.Bookmark + + +class BookmarkAdapter : PagedListAdapter(DIFF_CALLBACK) { + + companion object { + + @JvmField + val DIFF_CALLBACK = object : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: Bookmark, newItem: Bookmark): Boolean = + oldItem.time == newItem.time + + override fun areContentsTheSame(oldItem: Bookmark, newItem: Bookmark): Boolean = + oldItem.time == newItem.time + && oldItem.bookUrl == newItem.bookUrl + && oldItem.chapterName == newItem.chapterName + && oldItem.content == newItem.content + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { + return MyViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_bookmark, parent, false)) + } + + override fun onBindViewHolder(holder: MyViewHolder, position: Int) { + getItem(position)?.let { + holder.bind(it) + } + } + + class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { + + fun bind(bookmark: Bookmark) { + + } + } +} \ No newline at end of file From c86a6714479ac13605e674983c491a3fe0ad7c70 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 9 Aug 2019 08:24:58 +0800 Subject: [PATCH 0612/1997] up --- app/src/main/res/layout/item_bookmark.xml | 13 +++++++++++++ app/src/main/res/layout/item_chapter_list.xml | 7 +++++++ 2 files changed, 20 insertions(+) diff --git a/app/src/main/res/layout/item_bookmark.xml b/app/src/main/res/layout/item_bookmark.xml index d829e291c..7afd9dfa2 100644 --- a/app/src/main/res/layout/item_bookmark.xml +++ b/app/src/main/res/layout/item_bookmark.xml @@ -4,4 +4,17 @@ android:layout_width="match_parent" android:layout_height="match_parent"> + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_chapter_list.xml b/app/src/main/res/layout/item_chapter_list.xml index d829e291c..51e40bd8d 100644 --- a/app/src/main/res/layout/item_chapter_list.xml +++ b/app/src/main/res/layout/item_chapter_list.xml @@ -4,4 +4,11 @@ android:layout_width="match_parent" android:layout_height="match_parent"> + + + \ No newline at end of file From 22be80f7f67d8839061c784d4120a9b0d7d4c4cc Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 9 Aug 2019 09:36:02 +0800 Subject: [PATCH 0613/1997] up --- .../app/ui/chapterlist/BookmarkAdapter.kt | 18 +++++++++-- .../app/ui/chapterlist/BookmarkFragment.kt | 30 +++++++++++++++++++ .../ui/chapterlist/ChapterListViewModel.kt | 2 ++ .../ui/main/bookshelf/BookshelfFragment.kt | 14 +++------ 4 files changed, 51 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/BookmarkAdapter.kt b/app/src/main/java/io/legado/app/ui/chapterlist/BookmarkAdapter.kt index ef07eb323..6eff6e223 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/BookmarkAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/chapterlist/BookmarkAdapter.kt @@ -8,6 +8,8 @@ import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import io.legado.app.R import io.legado.app.data.entities.Bookmark +import kotlinx.android.synthetic.main.item_bookmark.view.* +import org.jetbrains.anko.sdk27.listeners.onClick class BookmarkAdapter : PagedListAdapter(DIFF_CALLBACK) { @@ -27,20 +29,30 @@ class BookmarkAdapter : PagedListAdapter } } + var callback: Callback? = null + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { return MyViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_bookmark, parent, false)) } override fun onBindViewHolder(holder: MyViewHolder, position: Int) { getItem(position)?.let { - holder.bind(it) + holder.bind(it, callback) } } class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { - fun bind(bookmark: Bookmark) { - + fun bind(bookmark: Bookmark, callback: Callback?) = with(itemView) { + tv_chapter_name.text = bookmark.chapterName + tv_content.text = bookmark.content + itemView.onClick { + callback?.open(bookmark) + } } } + + interface Callback { + fun open(bookmark: Bookmark) + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/BookmarkFragment.kt b/app/src/main/java/io/legado/app/ui/chapterlist/BookmarkFragment.kt index b62fa6f49..5133474bf 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/BookmarkFragment.kt +++ b/app/src/main/java/io/legado/app/ui/chapterlist/BookmarkFragment.kt @@ -1,12 +1,42 @@ package io.legado.app.ui.chapterlist +import android.os.Bundle +import android.view.View +import androidx.lifecycle.LiveData +import androidx.lifecycle.Observer +import androidx.paging.LivePagedListBuilder +import androidx.paging.PagedList +import androidx.recyclerview.widget.LinearLayoutManager +import io.legado.app.App import io.legado.app.R import io.legado.app.base.VMBaseFragment +import io.legado.app.data.entities.Bookmark +import io.legado.app.lib.theme.ATH import io.legado.app.utils.getViewModelOfActivity +import kotlinx.android.synthetic.main.fragment_bookmark.* class BookmarkFragment : VMBaseFragment(R.layout.fragment_bookmark) { override val viewModel: ChapterListViewModel get() = getViewModelOfActivity(ChapterListViewModel::class.java) + private lateinit var adapter: BookmarkAdapter + private var bookmarkLiveData: LiveData>? = null + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + initRecyclerView() + } + + private fun initRecyclerView() { + ATH.applyEdgeEffectColor(rv_list) + adapter = BookmarkAdapter() + rv_list.layoutManager = LinearLayoutManager(requireContext()) + rv_list.adapter = adapter + } + + private fun initData() { + bookmarkLiveData?.removeObservers(viewLifecycleOwner) + bookmarkLiveData = LivePagedListBuilder(App.db.bookmarkDao().observeByBook(""), 20).build() + bookmarkLiveData?.observe(viewLifecycleOwner, Observer { adapter.submitList(it) }) + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListViewModel.kt b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListViewModel.kt index 3b41d0a73..a76b6386d 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListViewModel.kt @@ -5,4 +5,6 @@ import io.legado.app.base.BaseViewModel class ChapterListViewModel : BaseViewModel(App.INSTANCE) { + var bookUrl: String? = null + } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index 06ebcdc77..5efb1801a 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -26,7 +26,10 @@ import io.legado.app.lib.theme.accentColor import io.legado.app.ui.bookshelf.BookshelfActivity import io.legado.app.ui.read.ReadActivity import io.legado.app.ui.search.SearchActivity -import io.legado.app.utils.* +import io.legado.app.utils.applyTint +import io.legado.app.utils.getViewModel +import io.legado.app.utils.requestInputMethod +import io.legado.app.utils.startActivity import kotlinx.android.synthetic.main.dialog_edittext.view.* import kotlinx.android.synthetic.main.fragment_bookshelf.* import kotlinx.android.synthetic.main.view_title_bar.* @@ -48,7 +51,6 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b override fun onViewCreated(view: View, savedInstanceState: Bundle?) { setSupportToolbar(toolbar) -// initSearchView() initRecyclerView() initBookGroupData() initBookshelfData() @@ -65,14 +67,6 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b } } - private fun initSearchView() { -// search_view.onActionViewExpanded() -// search_view.isSubmitButtonEnabled = true -// search_view.queryHint = getString(R.string.search_book_key) -// search_view.clearFocus() -// search_view.setOnQueryTextListener(this) - } - private fun initRecyclerView() { ATH.applyEdgeEffectColor(rv_bookshelf) refresh_layout.setColorSchemeColors(accentColor) From d11e58315b90696ac0f14bb2c1c8ee0e45808012 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 9 Aug 2019 11:30:49 +0800 Subject: [PATCH 0614/1997] up --- .../app/ui/chapterlist/ChapterListAdapter.kt | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListAdapter.kt b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListAdapter.kt index 8fe0ecbe6..5dc8d27f2 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListAdapter.kt @@ -1,2 +1,55 @@ package io.legado.app.ui.chapterlist +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.paging.PagedListAdapter +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.RecyclerView +import io.legado.app.R +import io.legado.app.data.entities.BookChapter +import kotlinx.android.synthetic.main.item_bookmark.view.* +import org.jetbrains.anko.sdk27.listeners.onClick + +class ChapterListAdapter : PagedListAdapter(DIFF_CALLBACK) { + + companion object { + + @JvmField + val DIFF_CALLBACK = object : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: BookChapter, newItem: BookChapter): Boolean = + oldItem.bookUrl == newItem.bookUrl + && oldItem.url == newItem.url + + override fun areContentsTheSame(oldItem: BookChapter, newItem: BookChapter): Boolean = + oldItem.title == newItem.title + } + } + + var callback: Callback? = null + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { + return MyViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_chapter_list, parent, false)) + } + + override fun onBindViewHolder(holder: MyViewHolder, position: Int) { + getItem(position)?.let { + holder.bind(it, callback) + } + } + + class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { + + fun bind(bookChapter: BookChapter, callback: Callback?) = with(itemView) { + tv_chapter_name.text = bookChapter.title + + itemView.onClick { + callback?.openChapter() + } + } + } + + interface Callback { + fun openChapter() + } +} \ No newline at end of file From 83cfc65455ae2c396f37e6e4372491cdda68414b Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 9 Aug 2019 12:16:12 +0800 Subject: [PATCH 0615/1997] up --- .../app/ui/chapterlist/BookmarkFragment.kt | 6 ++-- .../app/ui/chapterlist/ChapterListFragment.kt | 28 +++++++++++++++++++ app/src/main/res/layout/fragment_bookmark.xml | 2 +- .../main/res/layout/fragment_chapter_list.xml | 2 +- 4 files changed, 33 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/BookmarkFragment.kt b/app/src/main/java/io/legado/app/ui/chapterlist/BookmarkFragment.kt index 5133474bf..ecb17d9cb 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/BookmarkFragment.kt +++ b/app/src/main/java/io/legado/app/ui/chapterlist/BookmarkFragment.kt @@ -28,10 +28,10 @@ class BookmarkFragment : VMBaseFragment(R.layout.fragment_ } private fun initRecyclerView() { - ATH.applyEdgeEffectColor(rv_list) + ATH.applyEdgeEffectColor(recycler_view) adapter = BookmarkAdapter() - rv_list.layoutManager = LinearLayoutManager(requireContext()) - rv_list.adapter = adapter + recycler_view.layoutManager = LinearLayoutManager(requireContext()) + recycler_view.adapter = adapter } private fun initData() { diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt index f88f0dbb6..ec6418a73 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt +++ b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt @@ -1,13 +1,41 @@ package io.legado.app.ui.chapterlist +import android.os.Bundle +import android.view.View +import androidx.lifecycle.LiveData +import androidx.lifecycle.Observer +import androidx.paging.LivePagedListBuilder +import androidx.paging.PagedList +import androidx.recyclerview.widget.LinearLayoutManager +import io.legado.app.App import io.legado.app.R import io.legado.app.base.VMBaseFragment +import io.legado.app.data.entities.BookChapter import io.legado.app.utils.getViewModelOfActivity +import kotlinx.android.synthetic.main.fragment_chapter_list.* class ChapterListFragment : VMBaseFragment(R.layout.fragment_chapter_list) { override val viewModel: ChapterListViewModel get() = getViewModelOfActivity(ChapterListViewModel::class.java) + lateinit var adapter: ChapterListAdapter + var liveData: LiveData>? = null + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + initRecyclerView() + initData() + } + private fun initRecyclerView() { + adapter = ChapterListAdapter() + recycler_view.layoutManager = LinearLayoutManager(requireContext()) + recycler_view.adapter = adapter + } + + private fun initData() { + liveData?.removeObservers(viewLifecycleOwner) + liveData = LivePagedListBuilder(App.db.bookChapterDao().observeByBook(""), 30).build() + liveData?.observe(viewLifecycleOwner, Observer { adapter.submitList(it) }) + } } \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_bookmark.xml b/app/src/main/res/layout/fragment_bookmark.xml index e9b393f1e..fab36a60b 100644 --- a/app/src/main/res/layout/fragment_bookmark.xml +++ b/app/src/main/res/layout/fragment_bookmark.xml @@ -5,7 +5,7 @@ android:descendantFocusability="blocksDescendants"> diff --git a/app/src/main/res/layout/fragment_chapter_list.xml b/app/src/main/res/layout/fragment_chapter_list.xml index 5fa516994..40633c3d8 100644 --- a/app/src/main/res/layout/fragment_chapter_list.xml +++ b/app/src/main/res/layout/fragment_chapter_list.xml @@ -6,7 +6,7 @@ android:descendantFocusability="blocksDescendants"> Date: Fri, 9 Aug 2019 12:30:46 +0800 Subject: [PATCH 0616/1997] up --- app/src/main/res/layout/activity_read.xml | 33 +++++++++++++++++++---- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/app/src/main/res/layout/activity_read.xml b/app/src/main/res/layout/activity_read.xml index 1a16d9005..ec5acad1b 100644 --- a/app/src/main/res/layout/activity_read.xml +++ b/app/src/main/res/layout/activity_read.xml @@ -1,11 +1,34 @@ - + - \ No newline at end of file + + + + + + + + + + \ No newline at end of file From 4cf51ac940ded4d8a937da2462f1d7fc60aa0593 Mon Sep 17 00:00:00 2001 From: Administrator <1760316362@qq.com> Date: Fri, 9 Aug 2019 13:20:24 +0800 Subject: [PATCH 0617/1997] update --- .../io/legado/app/data/api/CommonHttpApi.kt | 18 --- .../io/legado/app/data/api/IHttpGetApi.kt | 13 -- .../io/legado/app/data/api/IHttpPostApi.kt | 14 -- .../io/legado/app/help/coroutine/Coroutine.kt | 131 +++++++++++------- .../app/model/analyzeRule/AnalyzeUrl.kt | 17 --- .../app/model/webbook/BookChapterList.kt | 2 +- .../legado/app/model/webbook/BookContent.kt | 2 +- .../legado/app/ui/search/SearchViewModel.kt | 16 ++- 8 files changed, 90 insertions(+), 123 deletions(-) delete mode 100644 app/src/main/java/io/legado/app/data/api/CommonHttpApi.kt diff --git a/app/src/main/java/io/legado/app/data/api/CommonHttpApi.kt b/app/src/main/java/io/legado/app/data/api/CommonHttpApi.kt deleted file mode 100644 index 0819b3281..000000000 --- a/app/src/main/java/io/legado/app/data/api/CommonHttpApi.kt +++ /dev/null @@ -1,18 +0,0 @@ -package io.legado.app.data.api - -import kotlinx.coroutines.Deferred -import retrofit2.http.* - -interface CommonHttpApi { - - @GET - fun get(@Url url: String, @QueryMap map: Map): Deferred - - @FormUrlEncoded - @POST - fun post(@Url url: String, @FieldMap map: Map): Deferred - - - @GET - fun get(@Url url: String) : Deferred -} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/data/api/IHttpGetApi.kt b/app/src/main/java/io/legado/app/data/api/IHttpGetApi.kt index e4180fa59..774cf6c89 100644 --- a/app/src/main/java/io/legado/app/data/api/IHttpGetApi.kt +++ b/app/src/main/java/io/legado/app/data/api/IHttpGetApi.kt @@ -1,7 +1,6 @@ package io.legado.app.data.api import kotlinx.coroutines.Deferred -import retrofit2.Call import retrofit2.Response import retrofit2.http.GET import retrofit2.http.HeaderMap @@ -27,16 +26,4 @@ interface IHttpGetApi { @HeaderMap headers: Map ): Deferred> - @GET - fun get( - @Url url: String, - @HeaderMap headers: Map - ): Call - - @GET - fun getMap( - @Url url: String, - @QueryMap(encoded = true) queryMap: Map, - @HeaderMap headers: Map - ): Call } diff --git a/app/src/main/java/io/legado/app/data/api/IHttpPostApi.kt b/app/src/main/java/io/legado/app/data/api/IHttpPostApi.kt index 0aa3ef3db..21fb2622c 100644 --- a/app/src/main/java/io/legado/app/data/api/IHttpPostApi.kt +++ b/app/src/main/java/io/legado/app/data/api/IHttpPostApi.kt @@ -28,18 +28,4 @@ interface IHttpPostApi { @HeaderMap headers: Map ): Deferred> - @FormUrlEncoded - @POST - fun postMap( - @Url url: String, - @FieldMap(encoded = true) fieldMap: Map, - @HeaderMap headers: Map - ): Call - - @POST - fun postBody( - @Url url: String, - @Body body: RequestBody, - @HeaderMap headers: Map - ): Call } diff --git a/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt b/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt index 14dd69f14..5b8c3d2c0 100644 --- a/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt +++ b/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt @@ -1,6 +1,8 @@ package io.legado.app.help.coroutine +import android.util.Log import kotlinx.coroutines.* +import kotlin.coroutines.CoroutineContext class Coroutine(scope: CoroutineScope, block: suspend CoroutineScope.() -> T) { @@ -17,14 +19,12 @@ class Coroutine(scope: CoroutineScope, block: suspend CoroutineScope.() -> T) private val job: Job - private var start: (suspend CoroutineScope.() -> Unit)? = null - private var execute: (suspend CoroutineScope.(T?) -> Unit)? = null - private var success: (suspend CoroutineScope.(T?) -> Unit)? = null - private var error: (suspend CoroutineScope.(Throwable) -> Unit)? = null - private var finally: (suspend CoroutineScope.() -> Unit)? = null + private var start: VoidCallback? = null + private var success: Callback? = null + private var error: Callback? = null + private var finally: VoidCallback? = null private var timeMillis: Long? = null - private var errorReturn: Result? = null val isCancelled: Boolean @@ -37,9 +37,7 @@ class Coroutine(scope: CoroutineScope, block: suspend CoroutineScope.() -> T) get() = job.isCompleted init { - this.job = scope.plus(Dispatchers.Main).launch { - executeInternal(this@launch, block) - } + this.job = executeInternal(scope, block) } fun timeout(timeMillis: () -> Long): Coroutine { @@ -62,28 +60,35 @@ class Coroutine(scope: CoroutineScope, block: suspend CoroutineScope.() -> T) return this@Coroutine } - fun onStart(start: (suspend CoroutineScope.() -> Unit)): Coroutine { - this.start = start - return this@Coroutine - } - - fun onExecute(execute: suspend CoroutineScope.(T?) -> Unit): Coroutine { - this.execute = execute + fun onStart( + context: CoroutineContext? = null, + block: (suspend CoroutineScope.() -> Unit) + ): Coroutine { + this.start = VoidCallback(context, block) return this@Coroutine } - fun onSuccess(success: suspend CoroutineScope.(T?) -> Unit): Coroutine { - this.success = success + fun onSuccess( + context: CoroutineContext? = null, + block: suspend CoroutineScope.(T?) -> Unit + ): Coroutine { + this.success = Callback(context, block) return this@Coroutine } - fun onError(error: suspend CoroutineScope.(Throwable) -> Unit): Coroutine { - this.error = error + fun onError( + context: CoroutineContext? = null, + block: suspend CoroutineScope.(Throwable) -> Unit + ): Coroutine { + this.error = Callback(context, block) return this@Coroutine } - fun onFinally(finally: suspend CoroutineScope.() -> Unit): Coroutine { - this.finally = finally + fun onFinally( + context: CoroutineContext? = null, + block: suspend CoroutineScope.() -> Unit + ): Coroutine { + this.finally = VoidCallback(context, block) return this@Coroutine } @@ -96,50 +101,72 @@ class Coroutine(scope: CoroutineScope, block: suspend CoroutineScope.() -> T) return job.invokeOnCompletion(handler) } - private suspend fun executeInternal(scope: CoroutineScope, block: suspend CoroutineScope.() -> T) { - tryCatch( - { - start?.invoke(scope) - val result = executeBlockIO(block, timeMillis ?: 0L) - success?.invoke(scope, result) - }, - { e -> + private fun executeInternal(scope: CoroutineScope, block: suspend CoroutineScope.() -> T): Job { + return scope.plus(Dispatchers.Main).launch { + try { + start?.let { dispatchVoidCallback(this, it) } + val value = executeBlock(scope, timeMillis ?: 0L, block) + success?.let { dispatchCallback(this, value, it) } + } catch (e: Throwable) { val consume: Boolean = errorReturn?.value?.let { value -> - success?.invoke(scope, value) + success?.let { dispatchCallback(this, value, it) } true } ?: false if (!consume) { - error?.invoke(scope, e) + error?.let { dispatchCallback(this, e, it) } } - }, - { - finally?.invoke(scope) - }) + } finally { + finally?.let { dispatchVoidCallback(this, it) } + } + } } - private suspend fun executeBlockIO(block: suspend CoroutineScope.() -> T, timeMillis: Long): T? { - val execution = withContext(Dispatchers.IO) { - val result = block() - execute?.invoke(this, result) - result + private suspend inline fun dispatchVoidCallback(scope: CoroutineScope, callback: VoidCallback) { + if (null == callback.context) { + callback.block.invoke(scope) + } else { + withContext(scope.coroutineContext.plus(callback.context)) { + callback.block.invoke(this) + } } - return if (timeMillis > 0L) withTimeout(timeMillis) { execution } else execution } - private suspend fun tryCatch( - tryBlock: suspend () -> Unit, - errorBlock: (suspend (Throwable) -> Unit)? = null, - finallyBlock: (suspend () -> Unit)? = null + private suspend inline fun dispatchCallback( + scope: CoroutineScope, + value: R, + callback: Callback ) { - try { - tryBlock() - } catch (e: Throwable) { - errorBlock?.invoke(e) - } finally { - finallyBlock?.invoke() + if (null == callback.context) { + callback.block.invoke(scope, value) + } else { + withContext(scope.coroutineContext.plus(callback.context)) { + callback.block.invoke(this, value) + } + } + } + + private suspend inline fun executeBlock( + scope: CoroutineScope, + timeMillis: Long, + noinline block: suspend CoroutineScope.() -> T + ): T? { + return withContext(scope.coroutineContext.plus(Dispatchers.IO)) { + if (timeMillis > 0L) withTimeout(timeMillis) { + block() + } else block() } } private data class Result(val value: T?) + + private inner class VoidCallback( + val context: CoroutineContext?, + val block: suspend CoroutineScope.() -> Unit + ) + + private inner class Callback( + val context: CoroutineContext?, + val block: suspend CoroutineScope.(VALUE) -> Unit + ) } diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt index bb32ec0fa..c2950aae0 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt @@ -223,21 +223,4 @@ class AnalyzeUrl( .getMapAsync(url, fieldMap, headerMap) } } - - fun getResponse(): Call { - return when { - method == Method.POST -> HttpHelper.getApiService( - baseUrl - ).postBody( - url, - body, - headerMap - ) - fieldMap.isEmpty() -> HttpHelper.getApiService( - baseUrl - ).get(url, headerMap) - else -> HttpHelper.getApiService(baseUrl) - .getMap(url, fieldMap, headerMap) - } - } } diff --git a/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt b/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt index 2bf02391e..8d8b4c22d 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt @@ -52,7 +52,7 @@ object BookChapterList { var nextUrl = chapterData.nextUrl[0] while (nextUrl.isNotEmpty() && !nextUrlList.contains(nextUrl)) { nextUrlList.add(nextUrl) - AnalyzeUrl(ruleUrl = nextUrl, book = book).getResponse().execute() + AnalyzeUrl(ruleUrl = nextUrl, book = book).getResponseAsync().await() .body()?.let { nextBody -> chapterData = analyzeChapterList(nextBody, nextUrl, tocRule, listRule, book, bookSource) nextUrl = if (chapterData.nextUrl.isNotEmpty()) chapterData.nextUrl[0] else "" diff --git a/app/src/main/java/io/legado/app/model/webbook/BookContent.kt b/app/src/main/java/io/legado/app/model/webbook/BookContent.kt index a8e92444b..0b77b10a4 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookContent.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookContent.kt @@ -51,7 +51,7 @@ object BookContent { == NetworkUtils.getAbsoluteURL(baseUrl, nextChapterUrl) ) break nextUrlList.add(nextUrl) - AnalyzeUrl(ruleUrl = nextUrl, book = book).getResponse().execute() + AnalyzeUrl(ruleUrl = nextUrl, book = book).getResponseAsync().await() .body()?.let { nextBody -> contentData = analyzeContent(nextBody, contentRule, book, baseUrl) nextUrl = if (contentData.nextUrl.isNotEmpty()) contentData.nextUrl[0] else "" diff --git a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt b/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt index f4faf69f7..1defc8695 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt @@ -4,10 +4,14 @@ import android.app.Application import android.util.Log import io.legado.app.App import io.legado.app.base.BaseViewModel -import io.legado.app.data.entities.SearchBook import io.legado.app.help.coroutine.Coroutine import io.legado.app.model.WebBook -import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.cancel +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import java.lang.Exception +import java.util.concurrent.CancellationException class SearchViewModel(application: Application) : BaseViewModel(application) { private var task: Coroutine<*>? = null @@ -29,7 +33,7 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { //task取消时自动取消 by (scope = this@execute) WebBook(item).searchBook(key, searchPage, scope = this@execute) .timeout(30000L) - .onExecute{ + .onSuccess(Dispatchers.IO) { it?.let { list -> App.db.searchBookDao().insert(*list.toTypedArray()) } @@ -43,14 +47,12 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { task?.invokeOnCompletion { finally?.invoke() } + + } fun stop() { task?.cancel() } - override fun onCleared() { - super.onCleared() - task?.cancel() - } } From 929f915c905936a3957170e92a55a69f28fe8ebc Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 9 Aug 2019 15:36:35 +0800 Subject: [PATCH 0618/1997] up --- app/src/main/res/layout/activity_read.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/src/main/res/layout/activity_read.xml b/app/src/main/res/layout/activity_read.xml index ec5acad1b..9c7911686 100644 --- a/app/src/main/res/layout/activity_read.xml +++ b/app/src/main/res/layout/activity_read.xml @@ -20,12 +20,20 @@ android:id="@+id/tv_chapter_name" android:layout_width="match_parent" android:layout_height="wrap_content" + android:background="@color/background" + android:paddingLeft="10dp" + android:paddingRight="10dp" + android:text="@string/chapter" android:textSize="12sp" /> From 08fea53d0f55a1050e1e7c6be87e417c6179c79e Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 9 Aug 2019 15:57:38 +0800 Subject: [PATCH 0619/1997] up --- app/src/main/res/layout/activity_read.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/res/layout/activity_read.xml b/app/src/main/res/layout/activity_read.xml index 9c7911686..250aeb815 100644 --- a/app/src/main/res/layout/activity_read.xml +++ b/app/src/main/res/layout/activity_read.xml @@ -14,13 +14,13 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:visibility="gone" + android:theme="?attr/actionBarStyle" app:layout_constraintTop_toTopOf="parent"> Date: Fri, 9 Aug 2019 22:41:48 +0800 Subject: [PATCH 0620/1997] up --- .../java/io/legado/app/ui/chapterlist/BookmarkFragment.kt | 3 ++- .../java/io/legado/app/ui/chapterlist/ChapterListActivity.kt | 1 + .../java/io/legado/app/ui/chapterlist/ChapterListFragment.kt | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/BookmarkFragment.kt b/app/src/main/java/io/legado/app/ui/chapterlist/BookmarkFragment.kt index ecb17d9cb..43c583e7f 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/BookmarkFragment.kt +++ b/app/src/main/java/io/legado/app/ui/chapterlist/BookmarkFragment.kt @@ -25,6 +25,7 @@ class BookmarkFragment : VMBaseFragment(R.layout.fragment_ override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) initRecyclerView() + initData() } private fun initRecyclerView() { @@ -36,7 +37,7 @@ class BookmarkFragment : VMBaseFragment(R.layout.fragment_ private fun initData() { bookmarkLiveData?.removeObservers(viewLifecycleOwner) - bookmarkLiveData = LivePagedListBuilder(App.db.bookmarkDao().observeByBook(""), 20).build() + bookmarkLiveData = LivePagedListBuilder(App.db.bookmarkDao().observeByBook(viewModel.bookUrl ?: ""), 20).build() bookmarkLiveData?.observe(viewLifecycleOwner, Observer { adapter.submitList(it) }) } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt index 62996558e..24576fe41 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt +++ b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt @@ -26,6 +26,7 @@ class ChapterListActivity : VMBaseActivity(R.layout.activi override fun onActivityCreated(savedInstanceState: Bundle?) { setSupportActionBar(toolbar) + viewModel.bookUrl = intent.getStringExtra("bookUrl") view_pager.adapter = TabFragmentPageAdapter(supportFragmentManager) tab_layout.setupWithViewPager(view_pager) } diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt index ec6418a73..2435bb07a 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt +++ b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt @@ -19,7 +19,7 @@ class ChapterListFragment : VMBaseFragment(R.layout.fragme get() = getViewModelOfActivity(ChapterListViewModel::class.java) lateinit var adapter: ChapterListAdapter - var liveData: LiveData>? = null + private var liveData: LiveData>? = null override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -35,7 +35,7 @@ class ChapterListFragment : VMBaseFragment(R.layout.fragme private fun initData() { liveData?.removeObservers(viewLifecycleOwner) - liveData = LivePagedListBuilder(App.db.bookChapterDao().observeByBook(""), 30).build() + liveData = LivePagedListBuilder(App.db.bookChapterDao().observeByBook(viewModel.bookUrl ?: ""), 30).build() liveData?.observe(viewLifecycleOwner, Observer { adapter.submitList(it) }) } } \ No newline at end of file From 46d7914ca3d01dc075184ac55122625662c21997 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 9 Aug 2019 22:51:40 +0800 Subject: [PATCH 0621/1997] up --- .../io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt | 9 ++++++++- .../io/legado/app/ui/main/bookshelf/BookshelfFragment.kt | 5 +++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt index 64e9ab388..9f533e2c8 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt @@ -12,6 +12,8 @@ import io.legado.app.help.ImageLoader import io.legado.app.lib.theme.ThemeStore import kotlinx.android.synthetic.main.item_bookshelf_list.view.* import kotlinx.android.synthetic.main.item_relace_rule.view.tv_name +import org.jetbrains.anko.sdk27.listeners.onClick +import org.jetbrains.anko.sdk27.listeners.onLongClick class BookshelfAdapter : PagedListAdapter(DIFF_CALLBACK) { @@ -58,12 +60,17 @@ class BookshelfAdapter : PagedListAdapter(D .centerCrop() .setAsDrawable(iv_cover) } - itemView.setOnClickListener { callBack?.open(book) } + itemView.onClick { callBack?.open(book) } + itemView.onLongClick { + callBack?.openBookInfo(book) + true + } } } interface CallBack { fun open(book: Book) + fun openBookInfo(book: Book) fun search() } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index 5efb1801a..30cb4e293 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -24,6 +24,7 @@ import io.legado.app.lib.dialogs.yesButton import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.accentColor import io.legado.app.ui.bookshelf.BookshelfActivity +import io.legado.app.ui.chapterlist.ChapterListActivity import io.legado.app.ui.read.ReadActivity import io.legado.app.ui.search.SearchActivity import io.legado.app.utils.applyTint @@ -108,6 +109,10 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b context?.startActivity() } + override fun openBookInfo(book: Book) { + context?.startActivity(Pair("bookUrl", book.bookUrl)) + } + override fun search() { } From d134c7e7c30e05c5b722773daeb9031b8ec32290 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 9 Aug 2019 23:13:46 +0800 Subject: [PATCH 0622/1997] up --- .../io/legado/app/ui/chapterlist/ChapterListViewModel.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListViewModel.kt b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListViewModel.kt index a76b6386d..c17237185 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListViewModel.kt @@ -1,9 +1,10 @@ package io.legado.app.ui.chapterlist -import io.legado.app.App + +import android.app.Application import io.legado.app.base.BaseViewModel -class ChapterListViewModel : BaseViewModel(App.INSTANCE) { +class ChapterListViewModel(application: Application) : BaseViewModel(application) { var bookUrl: String? = null From 68aeaa5ecb40acbd400e03a4362f9f0b97e3ce1f Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 10 Aug 2019 10:35:04 +0800 Subject: [PATCH 0623/1997] up --- app/src/main/java/io/legado/app/help/BookHelp.kt | 5 ++++- .../main/java/io/legado/app/ui/read/ReadViewModel.kt | 12 ++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/help/BookHelp.kt b/app/src/main/java/io/legado/app/help/BookHelp.kt index 8d93877bc..1cdb6e570 100644 --- a/app/src/main/java/io/legado/app/help/BookHelp.kt +++ b/app/src/main/java/io/legado/app/help/BookHelp.kt @@ -21,7 +21,10 @@ object BookHelp { fun formatAuthor(author: String?): String { - return author?.replace("作\\s*者[\\s::]*".toRegex(), "")?.replace("\\s+".toRegex(), " ")?.trim { it <= ' ' } + return author + ?.replace("作\\s*者[\\s::]*".toRegex(), "") + ?.replace("\\s+".toRegex(), " ") + ?.trim { it <= ' ' } ?: "" } diff --git a/app/src/main/java/io/legado/app/ui/read/ReadViewModel.kt b/app/src/main/java/io/legado/app/ui/read/ReadViewModel.kt index 098ad52d7..4528e2d1a 100644 --- a/app/src/main/java/io/legado/app/ui/read/ReadViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/read/ReadViewModel.kt @@ -1,8 +1,20 @@ package io.legado.app.ui.read import android.app.Application +import android.content.Intent +import androidx.lifecycle.MutableLiveData import io.legado.app.base.BaseViewModel +import io.legado.app.data.entities.Book class ReadViewModel(application: Application) : BaseViewModel(application) { + val bookData = MutableLiveData() + + fun initData(intent: Intent) { + val bookUrl = intent.getStringExtra("bookUrl") + if (!bookUrl.isNullOrEmpty()) { + + } + } + } \ No newline at end of file From 1989e36902329236d08ec44f18085b331dac5e82 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 10 Aug 2019 11:08:11 +0800 Subject: [PATCH 0624/1997] up --- .../io/legado/app/data/dao/BookChapterDao.kt | 2 ++ .../main/java/io/legado/app/data/dao/BookDao.kt | 3 +++ .../java/io/legado/app/ui/read/ReadViewModel.kt | 17 +++++++++++++++-- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/BookChapterDao.kt b/app/src/main/java/io/legado/app/data/dao/BookChapterDao.kt index 7f42d74d8..20d233149 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookChapterDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookChapterDao.kt @@ -16,6 +16,8 @@ interface BookChapterDao { @Query("select * from chapters where bookUrl = :bookUrl and `index` = :index") fun getChapter(bookUrl: String, index: Int): BookChapter? + @Query("select count(url) from chapters where bookUrl = :bookUrl") + fun getChapterCount(bookUrl: String): Int @Insert(onConflict = OnConflictStrategy.REPLACE) fun insert(vararg bookChapter: BookChapter) diff --git a/app/src/main/java/io/legado/app/data/dao/BookDao.kt b/app/src/main/java/io/legado/app/data/dao/BookDao.kt index 670ed6b6c..58bd7a36c 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookDao.kt @@ -30,6 +30,9 @@ interface BookDao { @Query("SELECT * FROM books WHERE `name` in (:names)") fun findByName(vararg names: String): List + @Query("select * from books where bookUrl = :bookUrl") + fun getBook(bookUrl: String): Book? + @get:Query("SELECT bookUrl FROM books") val allBookUrls: List diff --git a/app/src/main/java/io/legado/app/ui/read/ReadViewModel.kt b/app/src/main/java/io/legado/app/ui/read/ReadViewModel.kt index 4528e2d1a..d27ba5dc9 100644 --- a/app/src/main/java/io/legado/app/ui/read/ReadViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/read/ReadViewModel.kt @@ -2,18 +2,31 @@ package io.legado.app.ui.read import android.app.Application import android.content.Intent -import androidx.lifecycle.MutableLiveData +import io.legado.app.App import io.legado.app.base.BaseViewModel import io.legado.app.data.entities.Book +import io.legado.app.data.entities.BookSource class ReadViewModel(application: Application) : BaseViewModel(application) { - val bookData = MutableLiveData() + var book: Book? = null + var bookSource: BookSource? = null fun initData(intent: Intent) { val bookUrl = intent.getStringExtra("bookUrl") if (!bookUrl.isNullOrEmpty()) { + execute { + book = App.db.bookDao().getBook(bookUrl) + book?.let { book -> + if (App.db.bookChapterDao().getChapterCount(bookUrl) == 0) { + bookSource = App.db.bookSourceDao().findByKey(book.origin) + if (bookSource == null) { + } + } + } + + } } } From dc0842f516632030729b31b445528edfd31fc923 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 10 Aug 2019 18:25:28 +0800 Subject: [PATCH 0625/1997] up --- .../main/java/io/legado/app/ui/read/ReadActivity.kt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/read/ReadActivity.kt b/app/src/main/java/io/legado/app/ui/read/ReadActivity.kt index ede69761d..f7a5ae999 100644 --- a/app/src/main/java/io/legado/app/ui/read/ReadActivity.kt +++ b/app/src/main/java/io/legado/app/ui/read/ReadActivity.kt @@ -4,14 +4,24 @@ import android.os.Bundle import io.legado.app.R import io.legado.app.base.VMBaseActivity import io.legado.app.utils.getViewModel +import kotlinx.android.synthetic.main.activity_read.* +import org.jetbrains.anko.sdk27.listeners.onClick class ReadActivity : VMBaseActivity(R.layout.activity_read) { override val viewModel: ReadViewModel get() = getViewModel(ReadViewModel::class.java) override fun onActivityCreated(savedInstanceState: Bundle?) { - + initView() + viewModel.initData(intent) } + private fun initView() { + tv_chapter_name.onClick { + + } + tv_chapter_url.onClick { + } + } } \ No newline at end of file From 3c78f855f61d6918fb472507ed32273623e2aea1 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 10 Aug 2019 23:36:28 +0800 Subject: [PATCH 0626/1997] up --- .../legado/app/ui/bookinfo/BookInfoEditActivity.kt | 14 ++++++++++++++ .../main/res/layout/activity_book_info_edit.xml | 2 +- app/src/main/res/menu/book_info_edit.xml | 11 +++++++++++ app/src/main/res/values/strings.xml | 1 + 4 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 app/src/main/res/menu/book_info_edit.xml diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoEditActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoEditActivity.kt index 689398fdc..33fd29e83 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoEditActivity.kt @@ -1,6 +1,8 @@ package io.legado.app.ui.bookinfo import android.os.Bundle +import android.view.Menu +import android.view.MenuItem import io.legado.app.R import io.legado.app.base.VMBaseActivity import io.legado.app.utils.getViewModel @@ -13,4 +15,16 @@ class BookInfoEditActivity : VMBaseActivity(R.layout.activity } + override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { + menuInflater.inflate(R.menu.book_info_edit, menu) + return super.onCompatCreateOptionsMenu(menu) + } + + override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.action_save -> { + } + } + return super.onCompatOptionsItemSelected(item) + } } \ No newline at end of file diff --git a/app/src/main/res/layout/activity_book_info_edit.xml b/app/src/main/res/layout/activity_book_info_edit.xml index e8f969bcb..b56e9d55a 100644 --- a/app/src/main/res/layout/activity_book_info_edit.xml +++ b/app/src/main/res/layout/activity_book_info_edit.xml @@ -10,7 +10,7 @@ android:id="@+id/title_bar" android:layout_width="match_parent" android:layout_height="wrap_content" - app:title="@string/book_info" /> + app:title="@string/book_info_edit" /> + + + + + \ 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 5736d0bf8..976375c91 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -286,6 +286,7 @@ 停止自动翻页 自动翻页间隔 书籍信息 + 书籍信息编辑 默认打开书架 自动跳转最近阅读 替换范围,选填书名或者源名 From 3f018fc2ed1db8ee07784e9b39d84e49ccc0006a Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 11 Aug 2019 00:12:32 +0800 Subject: [PATCH 0627/1997] up --- .../app/ui/bookinfo/BookInfoEditActivity.kt | 14 +++++++- .../app/ui/bookinfo/BookInfoViewModel.kt | 4 +++ .../res/layout/activity_book_info_edit.xml | 34 +++++++++---------- 3 files changed, 34 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoEditActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoEditActivity.kt index 33fd29e83..5e632cd6c 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoEditActivity.kt @@ -3,16 +3,19 @@ package io.legado.app.ui.bookinfo import android.os.Bundle import android.view.Menu import android.view.MenuItem +import androidx.lifecycle.Observer import io.legado.app.R import io.legado.app.base.VMBaseActivity +import io.legado.app.data.entities.Book import io.legado.app.utils.getViewModel +import kotlinx.android.synthetic.main.activity_book_info_edit.* class BookInfoEditActivity : VMBaseActivity(R.layout.activity_book_info_edit) { override val viewModel: BookInfoViewModel get() = getViewModel(BookInfoViewModel::class.java) override fun onActivityCreated(savedInstanceState: Bundle?) { - + viewModel.bookData.observe(this, Observer { upView(it) }) } override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { @@ -27,4 +30,13 @@ class BookInfoEditActivity : VMBaseActivity(R.layout.activity } return super.onCompatOptionsItemSelected(item) } + + private fun upView(book: Book) { + tie_book_name.setText(book.name) + tie_book_author.setText(book.author) + tie_cover_url.setText(book.getDisplayCover()) + tie_book_intro.setText(book.getDisplayIntro()) + } + + } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt index cf943895d..d47df4b70 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt @@ -1,8 +1,12 @@ package io.legado.app.ui.bookinfo import android.app.Application +import androidx.lifecycle.MutableLiveData import io.legado.app.base.BaseViewModel +import io.legado.app.data.entities.Book class BookInfoViewModel(application: Application) : BaseViewModel(application) { + val bookData = MutableLiveData() + } \ No newline at end of file diff --git a/app/src/main/res/layout/activity_book_info_edit.xml b/app/src/main/res/layout/activity_book_info_edit.xml index b56e9d55a..4244c2b89 100644 --- a/app/src/main/res/layout/activity_book_info_edit.xml +++ b/app/src/main/res/layout/activity_book_info_edit.xml @@ -28,7 +28,7 @@ android:orientation="horizontal" android:padding="5dp"> - - - - + - - - + - - - + - - - - - - + From cc51eaf12359d850e99d81ad7765300bdf04fb6e Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 11 Aug 2019 17:07:42 +0800 Subject: [PATCH 0628/1997] up --- .../app/ui/bookinfo/BookInfoEditActivity.kt | 18 +++++++++++++++--- .../app/ui/bookinfo/BookInfoViewModel.kt | 19 +++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoEditActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoEditActivity.kt index 5e632cd6c..61387502d 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoEditActivity.kt @@ -8,6 +8,7 @@ import io.legado.app.R import io.legado.app.base.VMBaseActivity import io.legado.app.data.entities.Book import io.legado.app.utils.getViewModel +import io.legado.app.utils.toast import kotlinx.android.synthetic.main.activity_book_info_edit.* class BookInfoEditActivity : VMBaseActivity(R.layout.activity_book_info_edit) { @@ -16,6 +17,9 @@ class BookInfoEditActivity : VMBaseActivity(R.layout.activity override fun onActivityCreated(savedInstanceState: Bundle?) { viewModel.bookData.observe(this, Observer { upView(it) }) + intent.getStringExtra("bookUrl")?.let { + viewModel.loadBook(it) + } } override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { @@ -25,8 +29,7 @@ class BookInfoEditActivity : VMBaseActivity(R.layout.activity override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { - R.id.action_save -> { - } + R.id.action_save -> saveData() } return super.onCompatOptionsItemSelected(item) } @@ -38,5 +41,14 @@ class BookInfoEditActivity : VMBaseActivity(R.layout.activity tie_book_intro.setText(book.getDisplayIntro()) } - + private fun saveData() { + viewModel.bookData.value?.let { book -> + book.name = tie_book_name.text?.toString() + book.author = tie_book_author.text?.toString() + val customCoverUrl = tie_cover_url.text?.toString() + book.customCoverUrl = if (customCoverUrl == book.coverUrl) null else customCoverUrl + book.customIntro = tie_book_intro.text?.toString() + viewModel.saveBook(book, success = { finish() }, error = { toast(it) }) + } + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt index d47df4b70..8b4c0cb71 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt @@ -2,6 +2,7 @@ package io.legado.app.ui.bookinfo import android.app.Application import androidx.lifecycle.MutableLiveData +import io.legado.app.App import io.legado.app.base.BaseViewModel import io.legado.app.data.entities.Book @@ -9,4 +10,22 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { val bookData = MutableLiveData() + + fun loadBook(bookUrl: String) { + execute { + App.db.bookDao().getBook(bookUrl)?.let { + bookData.postValue(it) + } + } + } + + fun saveBook(book: Book, success: (() -> Unit)?, error: ((msg: String) -> Unit)?) { + execute { + App.db.bookDao().insert(book) + }.onSuccess { + success?.invoke() + }.onError { + error?.invoke(it.localizedMessage) + } + } } \ No newline at end of file From d0381ed78666e28995320ecabb3bf4b694c747d3 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 11 Aug 2019 17:12:42 +0800 Subject: [PATCH 0629/1997] up --- .../legado/app/ui/bookinfo/BookInfoEditActivity.kt | 12 +++++++----- ...BookInfoViewModel.kt => BookInfoEditViewModel.kt} | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) rename app/src/main/java/io/legado/app/ui/bookinfo/{BookInfoViewModel.kt => BookInfoEditViewModel.kt} (89%) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoEditActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoEditActivity.kt index 61387502d..fc15bd18b 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoEditActivity.kt @@ -11,14 +11,16 @@ import io.legado.app.utils.getViewModel import io.legado.app.utils.toast import kotlinx.android.synthetic.main.activity_book_info_edit.* -class BookInfoEditActivity : VMBaseActivity(R.layout.activity_book_info_edit) { - override val viewModel: BookInfoViewModel - get() = getViewModel(BookInfoViewModel::class.java) +class BookInfoEditActivity : VMBaseActivity(R.layout.activity_book_info_edit) { + override val viewModel: BookInfoEditViewModel + get() = getViewModel(BookInfoEditViewModel::class.java) override fun onActivityCreated(savedInstanceState: Bundle?) { viewModel.bookData.observe(this, Observer { upView(it) }) - intent.getStringExtra("bookUrl")?.let { - viewModel.loadBook(it) + if (viewModel.bookData.value == null) { + intent.getStringExtra("bookUrl")?.let { + viewModel.loadBook(it) + } } } diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoEditViewModel.kt similarity index 89% rename from app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt rename to app/src/main/java/io/legado/app/ui/bookinfo/BookInfoEditViewModel.kt index 8b4c0cb71..b331b8a78 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoEditViewModel.kt @@ -6,7 +6,7 @@ import io.legado.app.App import io.legado.app.base.BaseViewModel import io.legado.app.data.entities.Book -class BookInfoViewModel(application: Application) : BaseViewModel(application) { +class BookInfoEditViewModel(application: Application) : BaseViewModel(application) { val bookData = MutableLiveData() From 433440609ea86527a5c26f02ec0e778ebbd7b6b6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 11 Aug 2019 17:21:29 +0800 Subject: [PATCH 0630/1997] up --- .../java/io/legado/app/ui/bookinfo/BookInfoActivity.kt | 7 +++++-- .../java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt | 9 +++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index 314a76cf4..b7c553c85 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -2,9 +2,12 @@ package io.legado.app.ui.bookinfo import android.os.Bundle import io.legado.app.R -import io.legado.app.base.BaseActivity +import io.legado.app.base.VMBaseActivity +import io.legado.app.utils.getViewModel -class BookInfoActivity : BaseActivity(R.layout.activity_book_info) { +class BookInfoActivity : VMBaseActivity(R.layout.activity_book_info) { + override val viewModel: BookInfoViewModel + get() = getViewModel(BookInfoViewModel::class.java) override fun onActivityCreated(savedInstanceState: Bundle?) { diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt new file mode 100644 index 000000000..687c04350 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt @@ -0,0 +1,9 @@ +package io.legado.app.ui.bookinfo + +import android.app.Application +import io.legado.app.base.BaseViewModel + +class BookInfoViewModel(application: Application) : BaseViewModel(application) { + + +} \ No newline at end of file From 5800bb9e679049b5f32f0098ab913337f9b6dc67 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 11 Aug 2019 19:45:52 +0800 Subject: [PATCH 0631/1997] up --- .../main/res/layout/activity_book_info.xml | 177 +++++++++++++++++- 1 file changed, 174 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/layout/activity_book_info.xml b/app/src/main/res/layout/activity_book_info.xml index 3e997899a..0f2f12be1 100644 --- a/app/src/main/res/layout/activity_book_info.xml +++ b/app/src/main/res/layout/activity_book_info.xml @@ -1,5 +1,6 @@ - @@ -7,7 +8,177 @@ + android:layout_height="wrap_content" + app:title="@string/book_info" + app:layout_constraintTop_toTopOf="parent" /> + - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 2fd8c5f278649ff2e5d7a5d5bce83c8a415a69a2 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 11 Aug 2019 20:35:44 +0800 Subject: [PATCH 0632/1997] up --- .../java/io/legado/app/data/entities/Book.kt | 3 ++- .../io/legado/app/help/storage/Restore.kt | 1 + .../app/ui/bookinfo/BookInfoActivity.kt | 20 +++++++++++++++++++ .../app/ui/bookinfo/BookInfoViewModel.kt | 15 ++++++++++++++ .../ui/main/bookshelf/BookshelfFragment.kt | 6 +++--- .../main/res/layout/activity_book_info.xml | 1 + 6 files changed, 42 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/Book.kt b/app/src/main/java/io/legado/app/data/entities/Book.kt index d86bd415f..4d08f9dcb 100644 --- a/app/src/main/java/io/legado/app/data/entities/Book.kt +++ b/app/src/main/java/io/legado/app/data/entities/Book.kt @@ -6,6 +6,7 @@ import androidx.room.Entity import androidx.room.Ignore import androidx.room.Index import androidx.room.PrimaryKey +import io.legado.app.constant.BookType import io.legado.app.utils.GSON import io.legado.app.utils.fromJsonObject import kotlinx.android.parcel.IgnoredOnParcel @@ -18,7 +19,7 @@ data class Book( @PrimaryKey var bookUrl: String = "", // 详情页Url(本地书源存储完整文件路径) var tocUrl: String = "", // 目录页Url (toc=table of Contents) - var origin: String = "", // 书源URL(默认BookType.local) + var origin: String = BookType.local, // 书源URL(默认BookType.local) var name: String? = null, // 书籍名称(书源获取) var author: String? = null, // 作者名称(书源获取) var kind: String? = null, // 分类信息(书源获取) diff --git a/app/src/main/java/io/legado/app/help/storage/Restore.kt b/app/src/main/java/io/legado/app/help/storage/Restore.kt index 28cfec374..7eb6c1411 100644 --- a/app/src/main/java/io/legado/app/help/storage/Restore.kt +++ b/app/src/main/java/io/legado/app/help/storage/Restore.kt @@ -52,6 +52,7 @@ object Restore { Log.d(AppConst.APP_TAG, "Found existing book: ${book.name}") continue } + book.origin = jsonItem.readString("$.bookInfoBean.tag") ?: "" book.author = jsonItem.readString("$.bookInfoBean.author") book.type = if (jsonItem.readString("$.bookInfoBean.bookSourceType") == "AUDIO") 1 else 0 book.tocUrl = jsonItem.readString("$.bookInfoBean.chapterUrl") ?: book.bookUrl diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index b7c553c85..91e2d73a4 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -1,16 +1,36 @@ package io.legado.app.ui.bookinfo import android.os.Bundle +import androidx.lifecycle.Observer import io.legado.app.R import io.legado.app.base.VMBaseActivity +import io.legado.app.data.entities.Book +import io.legado.app.help.ImageLoader import io.legado.app.utils.getViewModel +import kotlinx.android.synthetic.main.activity_book_info.* class BookInfoActivity : VMBaseActivity(R.layout.activity_book_info) { override val viewModel: BookInfoViewModel get() = getViewModel(BookInfoViewModel::class.java) override fun onActivityCreated(savedInstanceState: Bundle?) { + viewModel.bookData.observe(this, Observer { showBook(it) }) + viewModel.loadData(intent) + } + private fun showBook(book: Book) { + tv_name.text = book.name + tv_author.text = book.author + tv_origin.text = book.origin + tv_lasted.text = book.latestChapterTitle + tv_intro.text = book.getDisplayIntro() + book.getDisplayCover()?.let { + ImageLoader.load(this, it) + .placeholder(R.drawable.img_cover_default) + .error(R.drawable.img_cover_default) + .centerCrop() + .setAsDrawable(iv_cover) + } } diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt index 687c04350..296565424 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt @@ -1,9 +1,24 @@ package io.legado.app.ui.bookinfo import android.app.Application +import android.content.Intent +import androidx.lifecycle.MutableLiveData +import io.legado.app.App import io.legado.app.base.BaseViewModel +import io.legado.app.data.entities.Book class BookInfoViewModel(application: Application) : BaseViewModel(application) { + val bookData = MutableLiveData() + + fun loadData(intent: Intent) { + execute { + intent.getStringExtra("bookUrl")?.let { + App.db.bookDao().getBook(it)?.let { book -> + bookData.postValue(book) + } + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index 30cb4e293..2cba38d6d 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -23,8 +23,8 @@ import io.legado.app.lib.dialogs.noButton import io.legado.app.lib.dialogs.yesButton import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.accentColor +import io.legado.app.ui.bookinfo.BookInfoActivity import io.legado.app.ui.bookshelf.BookshelfActivity -import io.legado.app.ui.chapterlist.ChapterListActivity import io.legado.app.ui.read.ReadActivity import io.legado.app.ui.search.SearchActivity import io.legado.app.utils.applyTint @@ -106,11 +106,11 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b } override fun open(book: Book) { - context?.startActivity() + context?.startActivity(Pair("bookUrl", book.bookUrl)) } override fun openBookInfo(book: Book) { - context?.startActivity(Pair("bookUrl", book.bookUrl)) + context?.startActivity(Pair("bookUrl", book.bookUrl)) } override fun search() { diff --git a/app/src/main/res/layout/activity_book_info.xml b/app/src/main/res/layout/activity_book_info.xml index 0f2f12be1..80d451fe6 100644 --- a/app/src/main/res/layout/activity_book_info.xml +++ b/app/src/main/res/layout/activity_book_info.xml @@ -17,6 +17,7 @@ android:layout_width="76dp" android:layout_height="110dp" android:layout_margin="10dp" + android:src="@drawable/img_cover_default" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toBottomOf="@+id/title_bar" /> From 99ba9a265d2b8fdbb9ae442e5ad5009c9dd2c7ff Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 12 Aug 2019 10:07:54 +0800 Subject: [PATCH 0633/1997] up --- .../java/io/legado/app/data/entities/Book.kt | 1 + .../java/io/legado/app/help/storage/Restore.kt | 6 +++--- .../legado/app/ui/bookinfo/BookInfoActivity.kt | 2 +- app/src/main/res/layout/activity_book_info.xml | 16 +++++++++++++++- 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/Book.kt b/app/src/main/java/io/legado/app/data/entities/Book.kt index 4d08f9dcb..02c751114 100644 --- a/app/src/main/java/io/legado/app/data/entities/Book.kt +++ b/app/src/main/java/io/legado/app/data/entities/Book.kt @@ -20,6 +20,7 @@ data class Book( var bookUrl: String = "", // 详情页Url(本地书源存储完整文件路径) var tocUrl: String = "", // 目录页Url (toc=table of Contents) var origin: String = BookType.local, // 书源URL(默认BookType.local) + var originName: String = "", //书源名称 var name: String? = null, // 书籍名称(书源获取) var author: String? = null, // 作者名称(书源获取) var kind: String? = null, // 分类信息(书源获取) diff --git a/app/src/main/java/io/legado/app/help/storage/Restore.kt b/app/src/main/java/io/legado/app/help/storage/Restore.kt index 7eb6c1411..c10908dcd 100644 --- a/app/src/main/java/io/legado/app/help/storage/Restore.kt +++ b/app/src/main/java/io/legado/app/help/storage/Restore.kt @@ -52,7 +52,8 @@ object Restore { Log.d(AppConst.APP_TAG, "Found existing book: ${book.name}") continue } - book.origin = jsonItem.readString("$.bookInfoBean.tag") ?: "" + book.origin = jsonItem.readString("$.tag") ?: "" + book.originName = jsonItem.readString("$.bookInfoBean.origin") ?: "" book.author = jsonItem.readString("$.bookInfoBean.author") book.type = if (jsonItem.readString("$.bookInfoBean.bookSourceType") == "AUDIO") 1 else 0 book.tocUrl = jsonItem.readString("$.bookInfoBean.chapterUrl") ?: book.bookUrl @@ -66,8 +67,7 @@ object Restore { book.durChapterPos = jsonItem.readInt("$.durChapterPage") ?: 0 book.durChapterTime = jsonItem.readLong("$.finalDate") ?: 0 book.group = jsonItem.readInt("$.group") ?: 0 - // book. = jsonItem.readString("$.hasUpdate") - // book. = jsonItem.readString("$.isLoading") + book.intro = jsonItem.readString("$.bookInfoBean.introduce") book.latestChapterTitle = jsonItem.readString("$.lastChapterName") book.lastCheckCount = jsonItem.readInt("$.newChapters") ?: 0 book.order = jsonItem.readInt("$.serialNumber") ?: 0 diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index 91e2d73a4..6b27b6562 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -21,7 +21,7 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo private fun showBook(book: Book) { tv_name.text = book.name tv_author.text = book.author - tv_origin.text = book.origin + tv_origin.text = book.originName tv_lasted.text = book.latestChapterTitle tv_intro.text = book.getDisplayIntro() book.getDisplayCover()?.let { diff --git a/app/src/main/res/layout/activity_book_info.xml b/app/src/main/res/layout/activity_book_info.xml index 80d451fe6..760019f21 100644 --- a/app/src/main/res/layout/activity_book_info.xml +++ b/app/src/main/res/layout/activity_book_info.xml @@ -66,13 +66,22 @@ android:layout_width="match_parent" android:layout_height="80dp" android:layout_margin="10dp" + android:scrollbars="vertical" + android:textIsSelectable="true" + app:layout_constraintTop_toBottomOf="@+id/iv_cover" /> + + + + Date: Mon, 12 Aug 2019 11:47:57 +0800 Subject: [PATCH 0634/1997] up --- .../java/io/legado/app/data/entities/Book.kt | 13 +++ .../app/ui/bookinfo/BookInfoActivity.kt | 32 ++++++ .../main/res/layout/activity_book_info.xml | 107 +++++++++++++----- 3 files changed, 121 insertions(+), 31 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/Book.kt b/app/src/main/java/io/legado/app/data/entities/Book.kt index 02c751114..2274a973c 100644 --- a/app/src/main/java/io/legado/app/data/entities/Book.kt +++ b/app/src/main/java/io/legado/app/data/entities/Book.kt @@ -9,6 +9,7 @@ import androidx.room.PrimaryKey import io.legado.app.constant.BookType import io.legado.app.utils.GSON import io.legado.app.utils.fromJsonObject +import io.legado.app.utils.splitNotBlank import kotlinx.android.parcel.IgnoredOnParcel import kotlinx.android.parcel.Parcelize import kotlin.math.max @@ -76,4 +77,16 @@ data class Book( variableMap?.put(key, value) variable = GSON.toJson(variableMap) } + + fun getKindList(): List { + val kindList = arrayListOf() + wordCount?.let { + if (it.isNotBlank()) kindList.add(it) + } + kind?.let { + val kinds = it.splitNotBlank(",", "\n") + kindList.addAll(kinds) + } + return kindList + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index 6b27b6562..104a52dda 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -7,6 +7,8 @@ import io.legado.app.base.VMBaseActivity import io.legado.app.data.entities.Book import io.legado.app.help.ImageLoader import io.legado.app.utils.getViewModel +import io.legado.app.utils.gone +import io.legado.app.utils.visible import kotlinx.android.synthetic.main.activity_book_info.* class BookInfoActivity : VMBaseActivity(R.layout.activity_book_info) { @@ -31,6 +33,36 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo .centerCrop() .setAsDrawable(iv_cover) } + val kinds = book.getKindList() + if (kinds.isEmpty()) { + ll_kind.gone() + } else { + ll_kind.visible() + for (index in 0..2) { + if (kinds.size > index) { + when (index) { + 0 -> { + tv_kind.text = kinds[index] + tv_kind.visible() + } + 1 -> { + tv_kind_1.text = kinds[index] + tv_kind_1.visible() + } + 2 -> { + tv_kind_2.text = kinds[index] + tv_kind_2.visible() + } + } + } else { + when (index) { + 0 -> tv_kind.gone() + 1 -> tv_kind_1.gone() + 2 -> tv_kind_2.gone() + } + } + } + } } diff --git a/app/src/main/res/layout/activity_book_info.xml b/app/src/main/res/layout/activity_book_info.xml index 760019f21..02ceb64a8 100644 --- a/app/src/main/res/layout/activity_book_info.xml +++ b/app/src/main/res/layout/activity_book_info.xml @@ -21,45 +21,90 @@ app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toBottomOf="@+id/title_bar" /> - + app:layout_constraintRight_toRightOf="parent" + app:layout_constraintBottom_toBottomOf="@+id/iv_cover"> - + - + - + + + + + + + + + + + + + + + Date: Mon, 12 Aug 2019 16:32:18 +0800 Subject: [PATCH 0635/1997] up --- .../io/legado/app/data/dao/SearchBookDao.kt | 6 ++++++ .../io/legado/app/data/entities/SearchBook.kt | 16 ++++++++++++++++ .../main/java/io/legado/app/help/BookHelp.kt | 18 ------------------ .../io/legado/app/model/webbook/SourceDebug.kt | 3 +-- .../app/ui/bookinfo/BookInfoViewModel.kt | 4 ++++ .../io/legado/app/ui/search/SearchActivity.kt | 13 +++++++++++-- .../io/legado/app/ui/search/SearchAdapter.kt | 6 +++--- .../io/legado/app/ui/search/SearchViewModel.kt | 15 +++++++-------- app/src/main/res/layout/item_search.xml | 1 - app/src/main/res/values/strings.xml | 1 + 10 files changed, 49 insertions(+), 34 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt b/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt index 0336d7ef7..f6f3d8f07 100644 --- a/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt @@ -20,6 +20,12 @@ interface SearchBookDao { @Query("SELECT name, author, min(time) time, max(kind) kind, max(coverUrl) coverUrl, max(intro) intro, max(wordCount) wordCount, max(latestChapterTitle) latestChapterTitle, count(origin) originCount FROM searchBooks where time >= :time group by name, author") fun observeShow(time: Long): DataSource.Factory + @Query("select * from searchBooks where bookUrl = :bookUrl") + fun getSearchBook(bookUrl: String): SearchBook? + + @Query("select * from searchBooks where name = :name and author = :author order by originOrder limit 1") + fun getByNameAuthor(name: String, author: String?): SearchBook? + @Insert(onConflict = OnConflictStrategy.REPLACE) fun insert(vararg searchBook: SearchBook): List diff --git a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt index 9ac3e181c..ea8e1aa84 100644 --- a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt +++ b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt @@ -67,4 +67,20 @@ data class SearchBook( } return kindList } + + fun toBook(): Book { + val book = Book() + book.name = name + book.author = author + book.kind = kind + book.bookUrl = bookUrl + book.origin = origin + book.originName = originName + book.wordCount = wordCount + book.latestChapterTitle = latestChapterTitle + book.coverUrl = coverUrl + book.intro = intro + + return book + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/help/BookHelp.kt b/app/src/main/java/io/legado/app/help/BookHelp.kt index 1cdb6e570..db0b27222 100644 --- a/app/src/main/java/io/legado/app/help/BookHelp.kt +++ b/app/src/main/java/io/legado/app/help/BookHelp.kt @@ -1,25 +1,7 @@ package io.legado.app.help -import io.legado.app.data.entities.Book -import io.legado.app.data.entities.SearchBook - object BookHelp { - fun toBook(searchBook: SearchBook): Book { - val book = Book() - book.name = searchBook.name - book.author = searchBook.author - book.kind = searchBook.kind - book.bookUrl = searchBook.bookUrl - book.origin = searchBook.origin - book.wordCount = searchBook.wordCount - book.latestChapterTitle = searchBook.latestChapterTitle - book.coverUrl = searchBook.coverUrl - - return book - } - - fun formatAuthor(author: String?): String { return author ?.replace("作\\s*者[\\s::]*".toRegex(), "") diff --git a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt index c79b078f9..cd599f54b 100644 --- a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt +++ b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt @@ -3,7 +3,6 @@ package io.legado.app.model.webbook import android.annotation.SuppressLint import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter -import io.legado.app.help.BookHelp import io.legado.app.help.coroutine.CompositeCoroutine import io.legado.app.model.WebBook import io.legado.app.utils.htmlFormat @@ -82,7 +81,7 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { if (searchBooks.isNotEmpty()) { printLog(debugSource, 1, "搜索完成") printLog(debugSource, 1, "", showTime = false) - infoDebug(BookHelp.toBook(searchBooks[0])) + infoDebug(searchBooks[0].toBook()) } else { printLog(debugSource, -1, "未获取到书籍") } diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt index 296565424..ea88b145c 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt @@ -17,6 +17,10 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { App.db.bookDao().getBook(it)?.let { book -> bookData.postValue(book) } + } ?: intent.getStringExtra("searchBookUrl")?.let { + App.db.searchBookDao().getSearchBook(it)?.let { searchBook -> + bookData.postValue(searchBook.toBook()) + } } } } diff --git a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt index 1b19f5b1d..2493916b3 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt @@ -1,7 +1,6 @@ package io.legado.app.ui.search import android.os.Bundle -import android.view.View import androidx.appcompat.widget.SearchView import androidx.lifecycle.LiveData import androidx.lifecycle.Observer @@ -14,11 +13,13 @@ import io.legado.app.base.VMBaseActivity import io.legado.app.data.entities.SearchShow import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.primaryTextColor +import io.legado.app.ui.bookinfo.BookInfoActivity import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_search.* import kotlinx.android.synthetic.main.view_search.* +import org.jetbrains.anko.startActivity -class SearchActivity : VMBaseActivity(R.layout.activity_search) { +class SearchActivity : VMBaseActivity(R.layout.activity_search), SearchAdapter.CallBack { override val viewModel: SearchViewModel get() = getViewModel(SearchViewModel::class.java) @@ -66,6 +67,7 @@ class SearchActivity : VMBaseActivity(R.layout.activity_search) private fun initRecyclerView() { ATH.applyEdgeEffectColor(rv_search_list) adapter = SearchAdapter() + adapter.callBack = this rv_search_list.layoutManager = LinearLayoutManager(this) rv_search_list.adapter = adapter } @@ -76,4 +78,11 @@ class SearchActivity : VMBaseActivity(R.layout.activity_search) searchBookData?.observe(this, Observer { adapter.submitList(it) }) } + override fun showBookInfo(name: String, author: String?) { + viewModel.getSearchBook(name, author) { searchBook -> + searchBook?.let { + startActivity(Pair("searchBookUrl", it.bookUrl)) + } + } + } } diff --git a/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt b/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt index 66b55595d..c25e3f323 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt @@ -50,7 +50,7 @@ class SearchAdapter : PagedListAdapter(D fun bind(searchBook: SearchShow, callBack: CallBack?) = with(itemView) { tv_name.text = searchBook.name bv_originCount.setBadgeCount(searchBook.originCount) - tv_author.text = searchBook.author + tv_author.text = context.getString(R.string.author_show, searchBook.author) if (searchBook.latestChapterTitle.isNullOrEmpty()) { tv_lasted.gone() } else { @@ -96,12 +96,12 @@ class SearchAdapter : PagedListAdapter(D .setAsDrawable(iv_cover) } onClick { - callBack?.showBookInfo(searchBook.name, searchBook.author) + callBack?.showBookInfo(searchBook.name!!, searchBook.author) } } } interface CallBack { - fun showBookInfo(name: String?, author: String?) + fun showBookInfo(name: String, author: String?) } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt b/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt index 1defc8695..870e64d05 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt @@ -1,17 +1,12 @@ package io.legado.app.ui.search import android.app.Application -import android.util.Log import io.legado.app.App import io.legado.app.base.BaseViewModel +import io.legado.app.data.entities.SearchBook import io.legado.app.help.coroutine.Coroutine import io.legado.app.model.WebBook import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.cancel -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch -import java.lang.Exception -import java.util.concurrent.CancellationException class SearchViewModel(application: Application) : BaseViewModel(application) { private var task: Coroutine<*>? = null @@ -47,12 +42,16 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { task?.invokeOnCompletion { finally?.invoke() } - - } fun stop() { task?.cancel() } + fun getSearchBook(name: String, author: String?, success: ((searchBook: SearchBook?) -> Unit)?) { + execute { + val searchBook = App.db.searchBookDao().getByNameAuthor(name, author) + success?.invoke(searchBook) + } + } } diff --git a/app/src/main/res/layout/item_search.xml b/app/src/main/res/layout/item_search.xml index 4a71b3049..6b849210a 100644 --- a/app/src/main/res/layout/item_search.xml +++ b/app/src/main/res/layout/item_search.xml @@ -54,7 +54,6 @@ android:layout_height="wrap_content" android:ellipsize="end" android:lines="1" - android:drawableStart="@drawable/ic_author" android:text="@string/author" android:textColor="@color/tv_text_default" android:textSize="12sp" /> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 976375c91..d1b9122c2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -141,6 +141,7 @@ 添加书籍网址 背景 作者 + 作者:%s 站点暂时不支持解析,请反馈 朗读停止 清除缓存 From 093beaae8606c4e4f89d396461428f746cb01541 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 12 Aug 2019 17:00:22 +0800 Subject: [PATCH 0636/1997] up --- .../app/ui/bookinfo/BookInfoActivity.kt | 8 +++---- .../app/ui/bookinfo/BookInfoViewModel.kt | 2 ++ .../io/legado/app/ui/search/SearchAdapter.kt | 2 +- .../main/res/layout/activity_book_info.xml | 22 ++++++++++--------- .../main/res/layout/item_bookshelf_list.xml | 4 ++-- app/src/main/res/values/strings.xml | 5 +++-- 6 files changed, 24 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index 104a52dda..0172fea6e 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -22,10 +22,10 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo private fun showBook(book: Book) { tv_name.text = book.name - tv_author.text = book.author - tv_origin.text = book.originName - tv_lasted.text = book.latestChapterTitle - tv_intro.text = book.getDisplayIntro() + tv_author.text = getString(R.string.author_show, book.author) + tv_origin.text = getString(R.string.origin_show, book.originName) + tv_lasted.text = getString(R.string.lasted_show, book.latestChapterTitle) + tv_intro.text = getString(R.string.intro_show, book.getDisplayIntro()) book.getDisplayCover()?.let { ImageLoader.load(this, it) .placeholder(R.drawable.img_cover_default) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt index ea88b145c..eafdc8b70 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt @@ -10,11 +10,13 @@ import io.legado.app.data.entities.Book class BookInfoViewModel(application: Application) : BaseViewModel(application) { val bookData = MutableLiveData() + var inBookshelf = false fun loadData(intent: Intent) { execute { intent.getStringExtra("bookUrl")?.let { App.db.bookDao().getBook(it)?.let { book -> + inBookshelf = true bookData.postValue(book) } } ?: intent.getStringExtra("searchBookUrl")?.let { diff --git a/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt b/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt index c25e3f323..61ebcc5f1 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt @@ -54,7 +54,7 @@ class SearchAdapter : PagedListAdapter(D if (searchBook.latestChapterTitle.isNullOrEmpty()) { tv_lasted.gone() } else { - tv_lasted.text = context.getString(R.string.book_search_last, searchBook.latestChapterTitle) + tv_lasted.text = context.getString(R.string.lasted_show, searchBook.latestChapterTitle) tv_lasted.visible() } tv_introduce.text = searchBook.intro diff --git a/app/src/main/res/layout/activity_book_info.xml b/app/src/main/res/layout/activity_book_info.xml index 02ceb64a8..c93413b91 100644 --- a/app/src/main/res/layout/activity_book_info.xml +++ b/app/src/main/res/layout/activity_book_info.xml @@ -36,29 +36,29 @@ + android:layout_height="0dp" + android:layout_weight="1" + android:singleLine="true" /> diff --git a/app/src/main/res/layout/item_bookshelf_list.xml b/app/src/main/res/layout/item_bookshelf_list.xml index aaed990db..29b58d03f 100644 --- a/app/src/main/res/layout/item_bookshelf_list.xml +++ b/app/src/main/res/layout/item_bookshelf_list.xml @@ -134,7 +134,7 @@ android:layout_width="@dimen/desc_icon_size" android:layout_height="@dimen/desc_icon_size" android:layout_marginLeft="8dp" - android:contentDescription="@string/book_search_last" + android:contentDescription="@string/lasted_show" android:paddingStart="2dp" android:paddingEnd="2dp" android:src="@drawable/ic_book_last" @@ -150,7 +150,7 @@ android:layout_height="wrap_content" android:layout_marginBottom="8dp" android:singleLine="true" - android:text="@string/book_search_last" + android:text="@string/lasted_show" android:textColor="@color/tv_text_secondary" android:textSize="13sp" app:layout_constraintBottom_toBottomOf="parent" diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d1b9122c2..10b7bec83 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -65,7 +65,7 @@ 来源: %s 最近: %s 书名 - 最新: %s + 最新: %s 是否将《%s》放入书架? 共%s个Text文件 加载中… @@ -197,8 +197,9 @@ 加载数据中… 加载失败,点击重试 内容简介 + 简介:%s 打开外部书籍 - 来源 + 来源:%s 本地导入 网络导入 书架排序 From a0e875209bceb41dc31be7a56bf8563cf6d9c4e0 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 12 Aug 2019 17:03:18 +0800 Subject: [PATCH 0637/1997] up --- app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt b/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt index 61ebcc5f1..e6653287f 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt @@ -57,7 +57,7 @@ class SearchAdapter : PagedListAdapter(D tv_lasted.text = context.getString(R.string.lasted_show, searchBook.latestChapterTitle) tv_lasted.visible() } - tv_introduce.text = searchBook.intro + tv_introduce.text = context.getString(R.string.intro_show, searchBook.intro) val kinds = searchBook.getKindList() if (kinds.isEmpty()) { ll_kind.gone() From 7cb8b70cdb5f097a9b03ebdb7e1a00a20b242bff Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 12 Aug 2019 20:05:05 +0800 Subject: [PATCH 0638/1997] up --- .../io/legado/app/help/BlurTransformation.kt | 57 +++++++++++++++++++ .../app/ui/bookinfo/BookInfoActivity.kt | 2 +- .../app/ui/bookinfo/BookInfoViewModel.kt | 2 +- .../main/res/layout/activity_book_info.xml | 5 +- 4 files changed, 62 insertions(+), 4 deletions(-) create mode 100644 app/src/main/java/io/legado/app/help/BlurTransformation.kt diff --git a/app/src/main/java/io/legado/app/help/BlurTransformation.kt b/app/src/main/java/io/legado/app/help/BlurTransformation.kt new file mode 100644 index 000000000..7cf8de88b --- /dev/null +++ b/app/src/main/java/io/legado/app/help/BlurTransformation.kt @@ -0,0 +1,57 @@ +package io.legado.app.help + +import android.annotation.TargetApi +import android.content.Context +import android.graphics.Bitmap +import android.os.Build +import android.renderscript.Allocation +import android.renderscript.Element +import android.renderscript.RenderScript +import android.renderscript.ScriptIntrinsicBlur + +import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool +import com.bumptech.glide.load.resource.bitmap.BitmapTransformation + +import java.security.MessageDigest + +class BlurTransformation(context: Context, private val radius: Int) : BitmapTransformation() { + private val rs: RenderScript = RenderScript.create(context) + + @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) + override fun transform(pool: BitmapPool, toTransform: Bitmap, outWidth: Int, outHeight: Int): Bitmap { + val blurredBitmap = toTransform.copy(Bitmap.Config.ARGB_8888, true) + + // Allocate memory for Renderscript to work with + //分配用于渲染脚本的内存 + val input = Allocation.createFromBitmap( + rs, + blurredBitmap, + Allocation.MipmapControl.MIPMAP_FULL, + Allocation.USAGE_SHARED + ) + val output = Allocation.createTyped(rs, input.type) + + // Load up an instance of the specific script that we want to use. + //加载我们想要使用的特定脚本的实例。 + val script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)) + script.setInput(input) + + // Set the blur radius + //设置模糊半径 + script.setRadius(radius.toFloat()) + + // Start the ScriptIntrinsicBlur + //启动 ScriptIntrinsicBlur, + script.forEach(output) + + // Copy the output to the blurred bitmap + //将输出复制到模糊的位图 + output.copyTo(blurredBitmap) + + return blurredBitmap + } + + override fun updateDiskCacheKey(messageDigest: MessageDigest) { + messageDigest.update("blur transformation".toByteArray()) + } +} diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index 0172fea6e..40c9cf32b 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -17,7 +17,7 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo override fun onActivityCreated(savedInstanceState: Bundle?) { viewModel.bookData.observe(this, Observer { showBook(it) }) - viewModel.loadData(intent) + viewModel.loadBook(intent) } private fun showBook(book: Book) { diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt index eafdc8b70..199f5f1a4 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt @@ -12,7 +12,7 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { val bookData = MutableLiveData() var inBookshelf = false - fun loadData(intent: Intent) { + fun loadBook(intent: Intent) { execute { intent.getStringExtra("bookUrl")?.let { App.db.bookDao().getBook(it)?.let { book -> diff --git a/app/src/main/res/layout/activity_book_info.xml b/app/src/main/res/layout/activity_book_info.xml index c93413b91..cf1e0fd1f 100644 --- a/app/src/main/res/layout/activity_book_info.xml +++ b/app/src/main/res/layout/activity_book_info.xml @@ -38,7 +38,8 @@ android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" - android:singleLine="true" /> + android:singleLine="true" + android:textSize="16sp" /> Date: Mon, 12 Aug 2019 21:30:04 +0800 Subject: [PATCH 0639/1997] up --- app/src/main/java/io/legado/app/data/entities/Book.kt | 2 +- app/src/main/java/io/legado/app/data/entities/SearchBook.kt | 3 ++- .../main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt | 4 ++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/Book.kt b/app/src/main/java/io/legado/app/data/entities/Book.kt index 2274a973c..e02d8ff06 100644 --- a/app/src/main/java/io/legado/app/data/entities/Book.kt +++ b/app/src/main/java/io/legado/app/data/entities/Book.kt @@ -19,7 +19,7 @@ import kotlin.math.max data class Book( @PrimaryKey var bookUrl: String = "", // 详情页Url(本地书源存储完整文件路径) - var tocUrl: String = "", // 目录页Url (toc=table of Contents) + var tocUrl: String? = null, // 目录页Url (toc=table of Contents) var origin: String = BookType.local, // 书源URL(默认BookType.local) var originName: String = "", //书源名称 var name: String? = null, // 书籍名称(书源获取) diff --git a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt index ea8e1aa84..fea706639 100644 --- a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt +++ b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt @@ -26,6 +26,7 @@ data class SearchBook( var intro: String? = null, var wordCount: String? = null, var latestChapterTitle: String? = null, + var tocUrl: String? = null, // 目录页Url (toc=table of Contents) var time: Long = 0L, var variable: String? = null, var bookInfoHtml: String? = null, @@ -80,7 +81,7 @@ data class SearchBook( book.latestChapterTitle = latestChapterTitle book.coverUrl = coverUrl book.intro = intro - + book.tocUrl = tocUrl return book } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt index 199f5f1a4..c44140716 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt @@ -27,4 +27,8 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { } } + fun loadBookInfo() { + + } + } \ No newline at end of file From 220f924d660bab45ab7c72cd02b25b8a89c5e35f Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 12 Aug 2019 22:30:44 +0800 Subject: [PATCH 0640/1997] up --- .../io/legado/app/ui/bookinfo/BookInfoActivity.kt | 7 +++++++ .../io/legado/app/ui/bookinfo/BookInfoViewModel.kt | 14 ++++++++++++-- app/src/main/res/layout/activity_book_info.xml | 3 +-- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index 40c9cf32b..a06f8f2d7 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -17,6 +17,13 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo override fun onActivityCreated(savedInstanceState: Bundle?) { viewModel.bookData.observe(this, Observer { showBook(it) }) + viewModel.isLoadingData.observe(this, Observer { + if (it) { + tv_loading.visible() + } else { + tv_loading.gone() + } + }) viewModel.loadBook(intent) } diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt index c44140716..235e57483 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt @@ -10,6 +10,7 @@ import io.legado.app.data.entities.Book class BookInfoViewModel(application: Application) : BaseViewModel(application) { val bookData = MutableLiveData() + val isLoadingData = MutableLiveData() var inBookshelf = false fun loadBook(intent: Intent) { @@ -20,8 +21,13 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { bookData.postValue(book) } } ?: intent.getStringExtra("searchBookUrl")?.let { - App.db.searchBookDao().getSearchBook(it)?.let { searchBook -> - bookData.postValue(searchBook.toBook()) + App.db.searchBookDao().getSearchBook(it)?.toBook()?.let { book -> + bookData.postValue(book) + if (book.tocUrl.isNullOrEmpty()) { + loadBookInfo() + } else { + loadChapter() + } } } } @@ -31,4 +37,8 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { } + fun loadChapter() { + + } + } \ No newline at end of file diff --git a/app/src/main/res/layout/activity_book_info.xml b/app/src/main/res/layout/activity_book_info.xml index cf1e0fd1f..a905af79f 100644 --- a/app/src/main/res/layout/activity_book_info.xml +++ b/app/src/main/res/layout/activity_book_info.xml @@ -240,8 +240,7 @@ android:gravity="center" android:text="@string/data_loading" android:textColor="#767676" - android:textSize="16sp" - android:visibility="gone" /> + android:textSize="16sp" /> \ No newline at end of file From bf27e2107322a788677028308f45b7654373b91a Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 12 Aug 2019 22:54:02 +0800 Subject: [PATCH 0641/1997] up --- app/src/main/java/io/legado/app/data/entities/Book.kt | 2 +- app/src/main/java/io/legado/app/data/entities/SearchBook.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/Book.kt b/app/src/main/java/io/legado/app/data/entities/Book.kt index e02d8ff06..2274a973c 100644 --- a/app/src/main/java/io/legado/app/data/entities/Book.kt +++ b/app/src/main/java/io/legado/app/data/entities/Book.kt @@ -19,7 +19,7 @@ import kotlin.math.max data class Book( @PrimaryKey var bookUrl: String = "", // 详情页Url(本地书源存储完整文件路径) - var tocUrl: String? = null, // 目录页Url (toc=table of Contents) + var tocUrl: String = "", // 目录页Url (toc=table of Contents) var origin: String = BookType.local, // 书源URL(默认BookType.local) var originName: String = "", //书源名称 var name: String? = null, // 书籍名称(书源获取) diff --git a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt index fea706639..819d45758 100644 --- a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt +++ b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt @@ -26,7 +26,7 @@ data class SearchBook( var intro: String? = null, var wordCount: String? = null, var latestChapterTitle: String? = null, - var tocUrl: String? = null, // 目录页Url (toc=table of Contents) + var tocUrl: String = "", // 目录页Url (toc=table of Contents) var time: Long = 0L, var variable: String? = null, var bookInfoHtml: String? = null, From 2ce78ae4b26de48e0066e78cfe8bb5172d157e22 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 13 Aug 2019 09:20:23 +0800 Subject: [PATCH 0642/1997] up --- .../java/io/legado/app/data/entities/SearchBook.kt | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt index 819d45758..770fb4117 100644 --- a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt +++ b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt @@ -8,7 +8,6 @@ import androidx.room.Index import androidx.room.PrimaryKey import io.legado.app.utils.GSON import io.legado.app.utils.fromJsonObject -import io.legado.app.utils.splitNotBlank import kotlinx.android.parcel.IgnoredOnParcel import kotlinx.android.parcel.Parcelize @@ -57,18 +56,6 @@ data class SearchBook( variable = GSON.toJson(variableMap) } - fun getKindList(): List { - val kindList = arrayListOf() - wordCount?.let { - if (it.isNotBlank()) kindList.add(it) - } - kind?.let { - val kinds = it.splitNotBlank(",", "\n") - kindList.addAll(kinds) - } - return kindList - } - fun toBook(): Book { val book = Book() book.name = name From 66ea00b41e8ca0ae410f140ae05ab176072be7ff Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 13 Aug 2019 09:48:03 +0800 Subject: [PATCH 0643/1997] up --- .../app/ui/bookinfo/BookInfoActivity.kt | 33 +++++++++++++++---- .../app/ui/bookinfo/BookInfoViewModel.kt | 20 +++++++++-- .../main/res/layout/activity_book_info.xml | 2 +- app/src/main/res/values/strings.xml | 1 + 4 files changed, 45 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index a06f8f2d7..89333ef25 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -10,6 +10,7 @@ import io.legado.app.utils.getViewModel import io.legado.app.utils.gone import io.legado.app.utils.visible import kotlinx.android.synthetic.main.activity_book_info.* +import org.jetbrains.anko.sdk27.listeners.onClick class BookInfoActivity : VMBaseActivity(R.layout.activity_book_info) { override val viewModel: BookInfoViewModel @@ -17,14 +18,9 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo override fun onActivityCreated(savedInstanceState: Bundle?) { viewModel.bookData.observe(this, Observer { showBook(it) }) - viewModel.isLoadingData.observe(this, Observer { - if (it) { - tv_loading.visible() - } else { - tv_loading.gone() - } - }) + viewModel.isLoadingData.observe(this, Observer { upLoading(it) }) viewModel.loadBook(intent) + initView() } private fun showBook(book: Book) { @@ -72,5 +68,28 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo } } + private fun upLoading(isLoading: Boolean) { + if (isLoading) { + tv_loading.visible() + } else { + if (viewModel.inBookshelf) { + tv_shelf.text = getString(R.string.remove_from_bookshelf) + } else { + tv_shelf.text = getString(R.string.add_to_shelf) + } + tv_loading.gone() + } + } + + private fun initView() { + tv_read.onClick { + } + tv_shelf.onClick { + viewModel.saveBook { + tv_shelf.text = getString(R.string.remove_from_bookshelf) + } + } + tv_loading.onClick { } + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt index 235e57483..af4291452 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt @@ -6,10 +6,12 @@ import androidx.lifecycle.MutableLiveData import io.legado.app.App import io.legado.app.base.BaseViewModel import io.legado.app.data.entities.Book +import io.legado.app.data.entities.BookChapter class BookInfoViewModel(application: Application) : BaseViewModel(application) { val bookData = MutableLiveData() + val chapterListData = MutableLiveData>() val isLoadingData = MutableLiveData() var inBookshelf = false @@ -23,7 +25,7 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { } ?: intent.getStringExtra("searchBookUrl")?.let { App.db.searchBookDao().getSearchBook(it)?.toBook()?.let { book -> bookData.postValue(book) - if (book.tocUrl.isNullOrEmpty()) { + if (book.tocUrl.isEmpty()) { loadBookInfo() } else { loadChapter() @@ -34,11 +36,23 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { } fun loadBookInfo() { - + isLoadingData.postValue(false) } fun loadChapter() { - + isLoadingData.postValue(false) } + fun saveBook(success: (() -> Unit)?) { + execute { + bookData.value?.let { book -> + App.db.bookDao().insert(book) + } + chapterListData.value?.let { + App.db.bookChapterDao().insert(*it.toTypedArray()) + } + }.onSuccess { + success?.invoke() + } + } } \ No newline at end of file diff --git a/app/src/main/res/layout/activity_book_info.xml b/app/src/main/res/layout/activity_book_info.xml index a905af79f..d12e9980e 100644 --- a/app/src/main/res/layout/activity_book_info.xml +++ b/app/src/main/res/layout/activity_book_info.xml @@ -224,7 +224,7 @@ android:focusable="true" android:gravity="center" android:includeFontPadding="false" - android:text="@string/start_read" + android:text="@string/reading" android:textColor="@color/tv_text_default" android:textSize="15sp" /> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 10b7bec83..6caf136b6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -473,4 +473,5 @@ 我的 ]]> + 阅读 From 17a9e0d41778548dc0372efef310f7714a0509e5 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 13 Aug 2019 16:09:24 +0800 Subject: [PATCH 0644/1997] up --- .../io/legado/app/ui/read/ReadActivity.kt | 109 ++++++ .../io/legado/app/ui/read/ReadBottomMenu.kt | 193 ++++++++++ app/src/main/res/anim/anim_none.xml | 4 + .../main/res/anim/anim_readbook_bottom_in.xml | 7 + .../res/anim/anim_readbook_bottom_out.xml | 7 + .../main/res/anim/anim_readbook_top_in.xml | 7 + .../main/res/anim/anim_readbook_top_out.xml | 7 + .../main/res/anim/moprogress_bottom_in.xml | 8 + .../main/res/anim/moprogress_bottom_out.xml | 9 + app/src/main/res/anim/moprogress_in.xml | 17 + .../res/anim/moprogress_in_bottom_right.xml | 17 + .../main/res/anim/moprogress_in_top_right.xml | 17 + app/src/main/res/anim/moprogress_out.xml | 17 + .../res/anim/moprogress_out_bottom_right.xml | 17 + .../res/anim/moprogress_out_top_right.xml | 17 + app/src/main/res/layout/activity_read.xml | 58 ++- .../main/res/layout/view_read_bottom_menu.xml | 358 ++++++++++++++++++ app/src/main/res/menu/read_book.xml | 93 +++++ 18 files changed, 941 insertions(+), 21 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/read/ReadBottomMenu.kt create mode 100644 app/src/main/res/anim/anim_none.xml create mode 100644 app/src/main/res/anim/anim_readbook_bottom_in.xml create mode 100644 app/src/main/res/anim/anim_readbook_bottom_out.xml create mode 100644 app/src/main/res/anim/anim_readbook_top_in.xml create mode 100644 app/src/main/res/anim/anim_readbook_top_out.xml create mode 100644 app/src/main/res/anim/moprogress_bottom_in.xml create mode 100644 app/src/main/res/anim/moprogress_bottom_out.xml create mode 100644 app/src/main/res/anim/moprogress_in.xml create mode 100644 app/src/main/res/anim/moprogress_in_bottom_right.xml create mode 100644 app/src/main/res/anim/moprogress_in_top_right.xml create mode 100644 app/src/main/res/anim/moprogress_out.xml create mode 100644 app/src/main/res/anim/moprogress_out_bottom_right.xml create mode 100644 app/src/main/res/anim/moprogress_out_top_right.xml create mode 100644 app/src/main/res/layout/view_read_bottom_menu.xml create mode 100644 app/src/main/res/menu/read_book.xml diff --git a/app/src/main/java/io/legado/app/ui/read/ReadActivity.kt b/app/src/main/java/io/legado/app/ui/read/ReadActivity.kt index f7a5ae999..7a0ce4ece 100644 --- a/app/src/main/java/io/legado/app/ui/read/ReadActivity.kt +++ b/app/src/main/java/io/legado/app/ui/read/ReadActivity.kt @@ -1,21 +1,76 @@ package io.legado.app.ui.read import android.os.Bundle +import android.view.KeyEvent +import android.view.Menu +import android.view.MenuItem +import android.view.animation.Animation +import android.view.animation.AnimationUtils +import androidx.core.view.isVisible import io.legado.app.R import io.legado.app.base.VMBaseActivity import io.legado.app.utils.getViewModel +import io.legado.app.utils.invisible +import io.legado.app.utils.visible import kotlinx.android.synthetic.main.activity_read.* +import kotlinx.android.synthetic.main.view_title_bar.* import org.jetbrains.anko.sdk27.listeners.onClick class ReadActivity : VMBaseActivity(R.layout.activity_read) { override val viewModel: ReadViewModel get() = getViewModel(ReadViewModel::class.java) + private var menuBarShow: Boolean = false + private lateinit var menuTopIn: Animation + private lateinit var menuTopOut: Animation + private lateinit var menuBottomIn: Animation + private lateinit var menuBottomOut: Animation + override fun onActivityCreated(savedInstanceState: Bundle?) { + setSupportActionBar(toolbar) + initAnimation() initView() viewModel.initData(intent) } + private fun initAnimation() { + menuTopIn = AnimationUtils.loadAnimation(this, R.anim.anim_readbook_top_in) + menuBottomIn = AnimationUtils.loadAnimation(this, R.anim.anim_readbook_bottom_in) + menuBottomIn.setAnimationListener(object : Animation.AnimationListener { + override fun onAnimationStart(animation: Animation) { + + } + + override fun onAnimationEnd(animation: Animation) { + vw_menu_bg.onClick { runMenuOut() } + } + + override fun onAnimationRepeat(animation: Animation) { + + } + }) + + //隐藏菜单 + menuTopOut = AnimationUtils.loadAnimation(this, R.anim.anim_readbook_top_out) + menuBottomOut = AnimationUtils.loadAnimation(this, R.anim.anim_readbook_bottom_out) + menuBottomOut.setAnimationListener(object : Animation.AnimationListener { + override fun onAnimationStart(animation: Animation) { + vw_menu_bg.setOnClickListener(null) + } + + override fun onAnimationEnd(animation: Animation) { + fl_menu.invisible() + title_bar.invisible() + bottom_menu.invisible() + menuBarShow = false + } + + override fun onAnimationRepeat(animation: Animation) { + + } + }) + } + private fun initView() { tv_chapter_name.onClick { @@ -24,4 +79,58 @@ class ReadActivity : VMBaseActivity(R.layout.activity_read) { } } + + override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { + menuInflater.inflate(R.menu.read_book, menu) + return super.onCompatCreateOptionsMenu(menu) + } + + override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + + } + return super.onCompatOptionsItemSelected(item) + } + + override fun dispatchKeyEvent(event: KeyEvent?): Boolean { + val keyCode = event?.keyCode + val action = event?.action + val isDown = action == 0 + + if (keyCode == KeyEvent.KEYCODE_MENU) { + if (isDown && !menuBarShow) { + runMenuIn() + return true + } + if (!isDown && !menuBarShow) { + menuBarShow = true + return true + } + } + return super.dispatchKeyEvent(event) + } + + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { + when (keyCode) { + + } + return super.onKeyDown(keyCode, event) + } + + private fun runMenuIn() { + fl_menu.visible() + title_bar.visible() + bottom_menu.visible() + title_bar.startAnimation(menuTopIn) + bottom_menu.startAnimation(menuBottomIn) + } + + private fun runMenuOut() { + if (fl_menu.isVisible) { + if (bottom_menu.isVisible) { + title_bar.startAnimation(menuTopOut) + bottom_menu.startAnimation(menuBottomOut) + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/read/ReadBottomMenu.kt b/app/src/main/java/io/legado/app/ui/read/ReadBottomMenu.kt new file mode 100644 index 000000000..45ea48921 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/read/ReadBottomMenu.kt @@ -0,0 +1,193 @@ +package io.legado.app.ui.read + +import android.content.Context +import android.util.AttributeSet +import android.widget.FrameLayout +import android.widget.SeekBar +import io.legado.app.R +import io.legado.app.utils.gone +import io.legado.app.utils.visible +import kotlinx.android.synthetic.main.view_read_bottom_menu.view.* +import org.jetbrains.anko.sdk27.listeners.onClick +import org.jetbrains.anko.sdk27.listeners.onLongClick + +class ReadBottomMenu : FrameLayout { + + private var callback: Callback? = null + + val readProgress: SeekBar + get() = hpb_read_progress + + constructor(context: Context) : super(context) { + init(context) + } + + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { + init(context) + } + + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { + init(context) + } + + private fun init(context: Context) { + inflate(context, R.layout.view_read_bottom_menu, this) + vw_bg.onClick { } + vwNavigationBar.onClick { } + } + + fun setNavigationBarHeight(height: Int) { + vwNavigationBar.layoutParams.height = height + } + + fun setListener(callback: Callback) { + this.callback = callback + bindEvent() + } + + private fun bindEvent() { + ll_read_aloud_timer.onClick { callback?.dismiss() } + ll_floating_button.onClick { callback?.dismiss() } + + //阅读进度 + hpb_read_progress.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { + override fun onProgressChanged(seekBar: SeekBar, i: Int, b: Boolean) { + + } + + override fun onStartTrackingTouch(seekBar: SeekBar) { + + } + + override fun onStopTrackingTouch(seekBar: SeekBar) { + callback!!.skipToPage(seekBar.progress) + } + }) + + //朗读定时 + fab_read_aloud_timer.onClick { } + + //朗读 + fab_read_aloud.onClick { callback?.onMediaButton() } + //长按停止朗读 + fab_read_aloud.onClick { + true + } + + //自动翻页 + fabAutoPage.onClick { callback?.autoPage() } + fabAutoPage.onLongClick { + callback?.toast(R.string.auto_next_page) + true + } + + //替换 + fabReplaceRule.onClick { callback?.openReplaceRule() } + fabReplaceRule.onLongClick { + callback!!.toast(R.string.replace_rule_title) + true + } + + //夜间模式 + fabNightTheme.onClick { callback?.setNightTheme() } + fabNightTheme.onLongClick { + callback?.toast(R.string.night_theme) + true + } + + //上一章 + tv_pre.onClick { callback?.skipPreChapter() } + + //下一章 + tv_next.onClick { callback?.skipNextChapter() } + + //目录 + ll_catalog.onClick { callback?.openChapterList() } + + //调节 + ll_adjust.onClick { callback?.openAdjust() } + + //界面 + ll_font.onClick { callback?.openReadInterface() } + + //设置 + ll_setting.onClick { callback?.openMoreSetting() } + + tv_read_aloud_timer.onClick { } + } + + fun setFabReadAloudImage(id: Int) { + fab_read_aloud.setImageResource(id) + } + + fun setReadAloudTimer(visibility: Boolean) { + if (visibility) { + ll_read_aloud_timer.visible() + } else { + ll_read_aloud_timer.gone() + } + } + + fun setReadAloudTimer(text: String) { + tv_read_aloud_timer.text = text + } + + fun setFabReadAloudText(text: String) { + fab_read_aloud.contentDescription = text + } + + fun setTvPre(enable: Boolean) { + tv_pre.isEnabled = enable + } + + fun setTvNext(enable: Boolean) { + tv_next.isEnabled = enable + } + + fun setAutoPage(autoPage: Boolean) { + if (autoPage) { + fabAutoPage.setImageResource(R.drawable.ic_auto_page_stop) + fabAutoPage.contentDescription = context.getString(R.string.auto_next_page_stop) + } else { + fabAutoPage.setImageResource(R.drawable.ic_auto_page) + fabAutoPage.contentDescription = context.getString(R.string.auto_next_page) + } + } + + fun setFabNightTheme(isNightTheme: Boolean) { + if (isNightTheme) { + fabNightTheme.setImageResource(R.drawable.ic_daytime) + } else { + fabNightTheme.setImageResource(R.drawable.ic_brightness) + } + } + + interface Callback { + fun skipToPage(page: Int) + + fun onMediaButton() + + fun autoPage() + + fun setNightTheme() + + fun skipPreChapter() + + fun skipNextChapter() + + fun openReplaceRule() + + fun openChapterList() + + fun openAdjust() + + fun openReadInterface() + + fun openMoreSetting() + + fun toast(id: Int) + + fun dismiss() + } + +} diff --git a/app/src/main/res/anim/anim_none.xml b/app/src/main/res/anim/anim_none.xml new file mode 100644 index 000000000..fe9ddac3b --- /dev/null +++ b/app/src/main/res/anim/anim_none.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/anim_readbook_bottom_in.xml b/app/src/main/res/anim/anim_readbook_bottom_in.xml new file mode 100644 index 000000000..48fe0c0aa --- /dev/null +++ b/app/src/main/res/anim/anim_readbook_bottom_in.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/anim_readbook_bottom_out.xml b/app/src/main/res/anim/anim_readbook_bottom_out.xml new file mode 100644 index 000000000..2e91beb95 --- /dev/null +++ b/app/src/main/res/anim/anim_readbook_bottom_out.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/anim_readbook_top_in.xml b/app/src/main/res/anim/anim_readbook_top_in.xml new file mode 100644 index 000000000..e36360bc0 --- /dev/null +++ b/app/src/main/res/anim/anim_readbook_top_in.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/anim_readbook_top_out.xml b/app/src/main/res/anim/anim_readbook_top_out.xml new file mode 100644 index 000000000..0b8acbceb --- /dev/null +++ b/app/src/main/res/anim/anim_readbook_top_out.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/moprogress_bottom_in.xml b/app/src/main/res/anim/moprogress_bottom_in.xml new file mode 100644 index 000000000..59904f594 --- /dev/null +++ b/app/src/main/res/anim/moprogress_bottom_in.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/moprogress_bottom_out.xml b/app/src/main/res/anim/moprogress_bottom_out.xml new file mode 100644 index 000000000..2348594fc --- /dev/null +++ b/app/src/main/res/anim/moprogress_bottom_out.xml @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/moprogress_in.xml b/app/src/main/res/anim/moprogress_in.xml new file mode 100644 index 000000000..8e922153b --- /dev/null +++ b/app/src/main/res/anim/moprogress_in.xml @@ -0,0 +1,17 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/moprogress_in_bottom_right.xml b/app/src/main/res/anim/moprogress_in_bottom_right.xml new file mode 100644 index 000000000..93348f5a8 --- /dev/null +++ b/app/src/main/res/anim/moprogress_in_bottom_right.xml @@ -0,0 +1,17 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/moprogress_in_top_right.xml b/app/src/main/res/anim/moprogress_in_top_right.xml new file mode 100644 index 000000000..81bb2e919 --- /dev/null +++ b/app/src/main/res/anim/moprogress_in_top_right.xml @@ -0,0 +1,17 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/moprogress_out.xml b/app/src/main/res/anim/moprogress_out.xml new file mode 100644 index 000000000..546619cc2 --- /dev/null +++ b/app/src/main/res/anim/moprogress_out.xml @@ -0,0 +1,17 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/moprogress_out_bottom_right.xml b/app/src/main/res/anim/moprogress_out_bottom_right.xml new file mode 100644 index 000000000..d0d1eaffa --- /dev/null +++ b/app/src/main/res/anim/moprogress_out_bottom_right.xml @@ -0,0 +1,17 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/moprogress_out_top_right.xml b/app/src/main/res/anim/moprogress_out_top_right.xml new file mode 100644 index 000000000..310b29d7e --- /dev/null +++ b/app/src/main/res/anim/moprogress_out_top_right.xml @@ -0,0 +1,17 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_read.xml b/app/src/main/res/layout/activity_read.xml index 250aeb815..a7396af3d 100644 --- a/app/src/main/res/layout/activity_read.xml +++ b/app/src/main/res/layout/activity_read.xml @@ -1,6 +1,5 @@ @@ -9,33 +8,50 @@ android:layout_width="match_parent" android:layout_height="match_parent"/> - + android:layout_height="match_parent" + android:visibility="gone"> - + android:layout_height="match_parent" /> - + android:visibility="gone" + android:theme="?attr/actionBarStyle"> + + + + - + + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_read_bottom_menu.xml b/app/src/main/res/layout/view_read_bottom_menu.xml new file mode 100644 index 000000000..41abf95f3 --- /dev/null +++ b/app/src/main/res/layout/view_read_bottom_menu.xml @@ -0,0 +1,358 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/read_book.xml b/app/src/main/res/menu/read_book.xml new file mode 100644 index 000000000..b141dc68d --- /dev/null +++ b/app/src/main/res/menu/read_book.xml @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 407fdf9dcf418d8bd4a171d21cff180ae232cfd0 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 13 Aug 2019 18:16:34 +0800 Subject: [PATCH 0645/1997] up --- .../io/legado/app/ui/read/ReadActivity.kt | 72 ++++++++++++++++--- 1 file changed, 62 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/read/ReadActivity.kt b/app/src/main/java/io/legado/app/ui/read/ReadActivity.kt index 7a0ce4ece..1d2b6dd4b 100644 --- a/app/src/main/java/io/legado/app/ui/read/ReadActivity.kt +++ b/app/src/main/java/io/legado/app/ui/read/ReadActivity.kt @@ -7,14 +7,16 @@ import android.view.MenuItem import android.view.animation.Animation import android.view.animation.AnimationUtils import androidx.core.view.isVisible +import io.legado.app.App import io.legado.app.R import io.legado.app.base.VMBaseActivity -import io.legado.app.utils.getViewModel -import io.legado.app.utils.invisible -import io.legado.app.utils.visible +import io.legado.app.ui.chapterlist.ChapterListActivity +import io.legado.app.ui.replacerule.ReplaceRuleActivity +import io.legado.app.utils.* import kotlinx.android.synthetic.main.activity_read.* import kotlinx.android.synthetic.main.view_title_bar.* import org.jetbrains.anko.sdk27.listeners.onClick +import org.jetbrains.anko.startActivity class ReadActivity : VMBaseActivity(R.layout.activity_read) { override val viewModel: ReadViewModel @@ -78,6 +80,63 @@ class ReadActivity : VMBaseActivity(R.layout.activity_read) { tv_chapter_url.onClick { } + bottom_menu.setListener(object : ReadBottomMenu.Callback { + override fun skipToPage(page: Int) { + + } + + override fun onMediaButton() { + + } + + override fun autoPage() { + + } + + override fun setNightTheme() { + putPrefBoolean("isNightTheme", !isNightTheme) + App.INSTANCE.applyDayNight() + } + + override fun skipPreChapter() { + + } + + override fun skipNextChapter() { + + } + + override fun openReplaceRule() { + startActivity() + } + + override fun openChapterList() { + viewModel.book?.let { + startActivity(Pair("bookUrl", it.bookUrl)) + } + } + + override fun openAdjust() { + + } + + override fun openReadInterface() { + + } + + override fun openMoreSetting() { + + } + + override fun toast(id: Int) { + toast(id) + } + + override fun dismiss() { + runMenuOut() + } + + }) } override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { @@ -110,13 +169,6 @@ class ReadActivity : VMBaseActivity(R.layout.activity_read) { return super.dispatchKeyEvent(event) } - override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { - when (keyCode) { - - } - return super.onKeyDown(keyCode, event) - } - private fun runMenuIn() { fl_menu.visible() title_bar.visible() From c33f72b15cbfef199185ed644bcd7aeb5732a988 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 13 Aug 2019 19:50:47 +0800 Subject: [PATCH 0646/1997] up --- app/src/main/res/drawable-v21/bg_ib_pre.xml | 7 ------- .../main/res/drawable-v21/bg_ib_pre_round.xml | 3 --- app/src/main/res/drawable/bg_ib_pre.xml | 5 ----- app/src/main/res/drawable/bg_ib_pre_round.xml | 4 ---- app/src/main/res/layout/activity_book_info.xml | 4 ++-- .../main/res/layout/fragment_chapter_list.xml | 4 ++-- app/src/main/res/layout/item_book_group.xml | 2 +- app/src/main/res/layout/item_book_source.xml | 6 +++--- .../main/res/layout/item_bookshelf_list_add.xml | 2 +- app/src/main/res/layout/item_relace_rule.xml | 4 ++-- .../main/res/layout/view_read_bottom_menu.xml | 16 ++++++++-------- 11 files changed, 19 insertions(+), 38 deletions(-) delete mode 100644 app/src/main/res/drawable-v21/bg_ib_pre.xml delete mode 100644 app/src/main/res/drawable-v21/bg_ib_pre_round.xml delete mode 100644 app/src/main/res/drawable/bg_ib_pre.xml delete mode 100644 app/src/main/res/drawable/bg_ib_pre_round.xml diff --git a/app/src/main/res/drawable-v21/bg_ib_pre.xml b/app/src/main/res/drawable-v21/bg_ib_pre.xml deleted file mode 100644 index 06af9ee57..000000000 --- a/app/src/main/res/drawable-v21/bg_ib_pre.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable-v21/bg_ib_pre_round.xml b/app/src/main/res/drawable-v21/bg_ib_pre_round.xml deleted file mode 100644 index e996f918f..000000000 --- a/app/src/main/res/drawable-v21/bg_ib_pre_round.xml +++ /dev/null @@ -1,3 +0,0 @@ - - \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_ib_pre.xml b/app/src/main/res/drawable/bg_ib_pre.xml deleted file mode 100644 index 6dd3de7d4..000000000 --- a/app/src/main/res/drawable/bg_ib_pre.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_ib_pre_round.xml b/app/src/main/res/drawable/bg_ib_pre_round.xml deleted file mode 100644 index b0ffc0e7e..000000000 --- a/app/src/main/res/drawable/bg_ib_pre_round.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/activity_book_info.xml b/app/src/main/res/layout/activity_book_info.xml index d12e9980e..24fe0d268 100644 --- a/app/src/main/res/layout/activity_book_info.xml +++ b/app/src/main/res/layout/activity_book_info.xml @@ -160,7 +160,7 @@ android:id="@+id/iv_chapter_top" android:layout_width="36dp" android:layout_height="match_parent" - android:background="@drawable/bg_ib_pre_round" + android:background="?android:attr/selectableItemBackgroundBorderless" android:contentDescription="@string/go_to_top" android:src="@drawable/ic_arrow_drop_up" app:tint="@color/tv_text_default" /> @@ -169,7 +169,7 @@ android:id="@+id/iv_chapter_bottom" android:layout_width="36dp" android:layout_height="match_parent" - android:background="@drawable/bg_ib_pre_round" + android:background="?android:attr/selectableItemBackgroundBorderless" android:contentDescription="@string/go_to_bottom" android:src="@drawable/ic_arrow_drop_down" app:tint="@color/tv_text_default" /> diff --git a/app/src/main/res/layout/fragment_chapter_list.xml b/app/src/main/res/layout/fragment_chapter_list.xml index 40633c3d8..28622e165 100644 --- a/app/src/main/res/layout/fragment_chapter_list.xml +++ b/app/src/main/res/layout/fragment_chapter_list.xml @@ -42,7 +42,7 @@ android:id="@+id/iv_chapter_top" android:layout_width="36dp" android:layout_height="match_parent" - android:background="@drawable/bg_ib_pre_round" + android:background="?android:attr/selectableItemBackgroundBorderless" android:contentDescription="@string/go_to_top" android:src="@drawable/ic_arrow_drop_up" app:tint="@color/tv_text_default" /> @@ -51,7 +51,7 @@ android:id="@+id/iv_chapter_bottom" android:layout_width="36dp" android:layout_height="match_parent" - android:background="@drawable/bg_ib_pre_round" + android:background="?android:attr/selectableItemBackgroundBorderless" android:contentDescription="@string/go_to_bottom" android:src="@drawable/ic_arrow_drop_down" app:tint="@color/tv_text_default" /> diff --git a/app/src/main/res/layout/item_book_group.xml b/app/src/main/res/layout/item_book_group.xml index 1fd1e0d0e..04536bac4 100644 --- a/app/src/main/res/layout/item_book_group.xml +++ b/app/src/main/res/layout/item_book_group.xml @@ -3,6 +3,6 @@ android:id="@+id/tv_group" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:background="@drawable/bg_ib_pre" + android:background="?android:attr/selectableItemBackground" android:layout_margin="5dp" android:padding="5dp" /> \ No newline at end of file diff --git a/app/src/main/res/layout/item_book_source.xml b/app/src/main/res/layout/item_book_source.xml index 9e3c0df00..cc6889cfb 100644 --- a/app/src/main/res/layout/item_book_source.xml +++ b/app/src/main/res/layout/item_book_source.xml @@ -23,7 +23,7 @@ android:layout_width="40dp" android:layout_height="40dp" android:layout_gravity="center" - android:background="@drawable/bg_ib_pre_round" + android:background="?android:attr/selectableItemBackgroundBorderless" android:contentDescription="@string/edit" android:padding="8dp" android:src="@drawable/ic_edit" @@ -34,7 +34,7 @@ android:layout_width="40dp" android:layout_height="40dp" android:layout_gravity="center" - android:background="@drawable/bg_ib_pre_round" + android:background="?android:attr/selectableItemBackgroundBorderless" android:contentDescription="@string/to_top" android:padding="8dp" android:src="@drawable/ic_top_source" @@ -45,7 +45,7 @@ android:layout_width="40dp" android:layout_height="40dp" android:layout_gravity="center" - android:background="@drawable/bg_ib_pre_round" + android:background="?android:attr/selectableItemBackgroundBorderless" android:contentDescription="@string/delete" android:padding="8dp" android:src="@drawable/ic_clear_all" diff --git a/app/src/main/res/layout/item_bookshelf_list_add.xml b/app/src/main/res/layout/item_bookshelf_list_add.xml index 7bfed269a..87c630d65 100644 --- a/app/src/main/res/layout/item_bookshelf_list_add.xml +++ b/app/src/main/res/layout/item_bookshelf_list_add.xml @@ -2,7 +2,7 @@ \ No newline at end of file diff --git a/app/src/main/res/layout/item_relace_rule.xml b/app/src/main/res/layout/item_relace_rule.xml index 6f145f350..87d714997 100644 --- a/app/src/main/res/layout/item_relace_rule.xml +++ b/app/src/main/res/layout/item_relace_rule.xml @@ -9,7 +9,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="8dp" - android:background="@drawable/bg_ib_pre_round" + android:background="?android:attr/selectableItemBackgroundBorderless" android:contentDescription="@string/edit" android:src="@drawable/ic_edit" android:visibility="gone" @@ -23,7 +23,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="8dp" - android:background="@drawable/bg_ib_pre_round" + android:background="?android:attr/selectableItemBackgroundBorderless" android:contentDescription="@string/delete" android:src="@drawable/ic_clear_all" android:visibility="gone" diff --git a/app/src/main/res/layout/view_read_bottom_menu.xml b/app/src/main/res/layout/view_read_bottom_menu.xml index 41abf95f3..c7f3aa4a2 100644 --- a/app/src/main/res/layout/view_read_bottom_menu.xml +++ b/app/src/main/res/layout/view_read_bottom_menu.xml @@ -133,13 +133,13 @@ + android:layout_height="match_parent" /> Date: Tue, 13 Aug 2019 20:46:13 +0800 Subject: [PATCH 0647/1997] up --- app/src/main/java/io/legado/app/data/dao/BookDao.kt | 3 +++ .../io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/app/src/main/java/io/legado/app/data/dao/BookDao.kt b/app/src/main/java/io/legado/app/data/dao/BookDao.kt index 58bd7a36c..f1afa562e 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookDao.kt @@ -42,6 +42,9 @@ interface BookDao { @Query("SELECT * FROM books ORDER BY durChapterTime DESC limit 0,10") fun recentRead(): DataSource.Factory + @Query("SELECT * FROM books ORDER BY durChapterTime DESC limit 0,10") + fun getRecentRead(): DataSource.Factory + @Insert(onConflict = OnConflictStrategy.REPLACE) fun insert(vararg books: Book) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt index 1bb9a3b64..99f495040 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt @@ -20,4 +20,12 @@ class BookshelfViewModel(application: Application) : BaseViewModel(application) } } + + fun upChapterList() { + execute { + App.db.bookDao().getRecentRead().map { + + } + } + } } From b541ed2e2eac8a87d06faee9ad6aa16c2cd2bdff Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 13 Aug 2019 21:26:38 +0800 Subject: [PATCH 0648/1997] up --- app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt | 2 +- .../io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt | 7 +++++-- app/src/main/java/io/legado/app/ui/read/ReadViewModel.kt | 2 +- .../java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt | 5 +---- .../io/legado/app/ui/sourceedit/SourceEditViewModel.kt | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt index ddc2fdc1b..5270d3c5f 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt @@ -29,7 +29,7 @@ interface BookSourceDao { val allEnabled: List @Query("select * from book_sources where bookSourceUrl = :key") - fun findByKey(key: String): BookSource? + fun getBookSource(key: String): BookSource? @Query("select count(*) from book_sources") fun allCount(): Int diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt index 99f495040..a146bf845 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt @@ -3,6 +3,7 @@ package io.legado.app.ui.main.bookshelf import android.app.Application import io.legado.app.App import io.legado.app.base.BaseViewModel +import io.legado.app.constant.BookType import io.legado.app.data.entities.BookGroup class BookshelfViewModel(application: Application) : BaseViewModel(application) { @@ -23,8 +24,10 @@ class BookshelfViewModel(application: Application) : BaseViewModel(application) fun upChapterList() { execute { - App.db.bookDao().getRecentRead().map { - + App.db.bookDao().getRecentRead().map { book -> + if (book.origin != BookType.local) { + val bookSource = App.db.bookSourceDao().getBookSource(book.origin) + } } } } diff --git a/app/src/main/java/io/legado/app/ui/read/ReadViewModel.kt b/app/src/main/java/io/legado/app/ui/read/ReadViewModel.kt index d27ba5dc9..fed906c6b 100644 --- a/app/src/main/java/io/legado/app/ui/read/ReadViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/read/ReadViewModel.kt @@ -19,7 +19,7 @@ class ReadViewModel(application: Application) : BaseViewModel(application) { book = App.db.bookDao().getBook(bookUrl) book?.let { book -> if (App.db.bookChapterDao().getChapterCount(bookUrl) == 0) { - bookSource = App.db.bookSourceDao().findByKey(book.origin) + bookSource = App.db.bookSourceDao().getBookSource(book.origin) if (bookSource == null) { } diff --git a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt index 6d5689ad4..6873a30cb 100644 --- a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt +++ b/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt @@ -3,11 +3,8 @@ package io.legado.app.ui.sourcedebug import android.app.Application import io.legado.app.App import io.legado.app.base.BaseViewModel -import io.legado.app.constant.Bus -import io.legado.app.help.EventMessage import io.legado.app.model.WebBook import io.legado.app.model.webbook.SourceDebug -import io.legado.app.utils.postEvent class SourceDebugModel(application: Application) : BaseViewModel(application), SourceDebug.Callback { @@ -19,7 +16,7 @@ class SourceDebugModel(application: Application) : BaseViewModel(application), S sourceUrl?.let { //优先使用这个,不会抛出异常 execute { - val bookSource = App.db.bookSourceDao().findByKey(sourceUrl) + val bookSource = App.db.bookSourceDao().getBookSource(sourceUrl) bookSource?.let { webBook = WebBook(it) } } } diff --git a/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditViewModel.kt b/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditViewModel.kt index e65cc5c94..90b72305c 100644 --- a/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditViewModel.kt @@ -14,7 +14,7 @@ class SourceEditViewModel(application: Application) : BaseViewModel(application) fun setBookSource(key: String) { launch(IO) { - App.db.bookSourceDao().findByKey(key)?.let { + App.db.bookSourceDao().getBookSource(key)?.let { sourceLiveData.postValue(it) } ?: sourceLiveData.postValue(BookSource()) } From c674d0b9a6246adaa19c662bb30b6267f97957de Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 13 Aug 2019 22:21:47 +0800 Subject: [PATCH 0649/1997] up --- app/src/main/java/io/legado/app/data/dao/BookDao.kt | 9 ++++----- .../app/ui/main/bookshelf/BookshelfViewModel.kt | 11 +++++++++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/BookDao.kt b/app/src/main/java/io/legado/app/data/dao/BookDao.kt index f1afa562e..523aca465 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookDao.kt @@ -2,10 +2,7 @@ package io.legado.app.data.dao import androidx.lifecycle.LiveData import androidx.paging.DataSource -import androidx.room.Dao -import androidx.room.Insert -import androidx.room.OnConflictStrategy -import androidx.room.Query +import androidx.room.* import io.legado.app.constant.BookType import io.legado.app.data.entities.Book @@ -46,6 +43,8 @@ interface BookDao { fun getRecentRead(): DataSource.Factory @Insert(onConflict = OnConflictStrategy.REPLACE) - fun insert(vararg books: Book) + fun insert(vararg book: Book) + @Update + fun update(vararg books: Book) } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt index a146bf845..148c20b6a 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt @@ -5,6 +5,8 @@ import io.legado.app.App import io.legado.app.base.BaseViewModel import io.legado.app.constant.BookType import io.legado.app.data.entities.BookGroup +import io.legado.app.model.WebBook +import kotlinx.coroutines.Dispatchers.IO class BookshelfViewModel(application: Application) : BaseViewModel(application) { @@ -27,6 +29,15 @@ class BookshelfViewModel(application: Application) : BaseViewModel(application) App.db.bookDao().getRecentRead().map { book -> if (book.origin != BookType.local) { val bookSource = App.db.bookSourceDao().getBookSource(book.origin) + bookSource?.let { + WebBook(bookSource).getChapterList(book).onSuccess(IO) { + it?.let { + if (it.size > App.db.bookChapterDao().getChapterCount(book.bookUrl)) { + + } + } + } + } } } } From f6b50650f56ff62f9f836491af98ab9002be8322 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 14 Aug 2019 08:26:31 +0800 Subject: [PATCH 0650/1997] up --- app/src/main/java/io/legado/app/ui/read/ReadBottomMenu.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/read/ReadBottomMenu.kt b/app/src/main/java/io/legado/app/ui/read/ReadBottomMenu.kt index 45ea48921..b46f53098 100644 --- a/app/src/main/java/io/legado/app/ui/read/ReadBottomMenu.kt +++ b/app/src/main/java/io/legado/app/ui/read/ReadBottomMenu.kt @@ -60,7 +60,7 @@ class ReadBottomMenu : FrameLayout { } override fun onStopTrackingTouch(seekBar: SeekBar) { - callback!!.skipToPage(seekBar.progress) + callback?.skipToPage(seekBar.progress) } }) @@ -84,7 +84,7 @@ class ReadBottomMenu : FrameLayout { //替换 fabReplaceRule.onClick { callback?.openReplaceRule() } fabReplaceRule.onLongClick { - callback!!.toast(R.string.replace_rule_title) + callback?.toast(R.string.replace_rule_title) true } From c2b88b50fd79adfdad13d5e55099cf81bec1dd1e Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 14 Aug 2019 09:08:17 +0800 Subject: [PATCH 0651/1997] up --- .../io/legado/app/ui/read/ReadActivity.kt | 2 +- .../io/legado/app/ui/read/ReadBottomMenu.kt | 13 ------------ .../main/res/layout/view_read_bottom_menu.xml | 20 ++++++++++++++----- 3 files changed, 16 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/read/ReadActivity.kt b/app/src/main/java/io/legado/app/ui/read/ReadActivity.kt index 1d2b6dd4b..ed29d2692 100644 --- a/app/src/main/java/io/legado/app/ui/read/ReadActivity.kt +++ b/app/src/main/java/io/legado/app/ui/read/ReadActivity.kt @@ -129,7 +129,7 @@ class ReadActivity : VMBaseActivity(R.layout.activity_read) { } override fun toast(id: Int) { - toast(id) + this@ReadActivity.toast(id) } override fun dismiss() { diff --git a/app/src/main/java/io/legado/app/ui/read/ReadBottomMenu.kt b/app/src/main/java/io/legado/app/ui/read/ReadBottomMenu.kt index b46f53098..196d86e9d 100644 --- a/app/src/main/java/io/legado/app/ui/read/ReadBottomMenu.kt +++ b/app/src/main/java/io/legado/app/ui/read/ReadBottomMenu.kt @@ -9,7 +9,6 @@ import io.legado.app.utils.gone import io.legado.app.utils.visible import kotlinx.android.synthetic.main.view_read_bottom_menu.view.* import org.jetbrains.anko.sdk27.listeners.onClick -import org.jetbrains.anko.sdk27.listeners.onLongClick class ReadBottomMenu : FrameLayout { @@ -76,24 +75,12 @@ class ReadBottomMenu : FrameLayout { //自动翻页 fabAutoPage.onClick { callback?.autoPage() } - fabAutoPage.onLongClick { - callback?.toast(R.string.auto_next_page) - true - } //替换 fabReplaceRule.onClick { callback?.openReplaceRule() } - fabReplaceRule.onLongClick { - callback?.toast(R.string.replace_rule_title) - true - } //夜间模式 fabNightTheme.onClick { callback?.setNightTheme() } - fabNightTheme.onLongClick { - callback?.toast(R.string.night_theme) - true - } //上一章 tv_pre.onClick { callback?.skipPreChapter() } diff --git a/app/src/main/res/layout/view_read_bottom_menu.xml b/app/src/main/res/layout/view_read_bottom_menu.xml index c7f3aa4a2..7dc266d02 100644 --- a/app/src/main/res/layout/view_read_bottom_menu.xml +++ b/app/src/main/res/layout/view_read_bottom_menu.xml @@ -23,10 +23,12 @@ android:contentDescription="@string/set_timer" android:src="@drawable/ic_timer_black_24dp" android:tint="@color/tv_text_default" + android:tooltipText="@string/set_timer" app:backgroundTint="@color/background_menu" app:elevation="2dp" app:fabSize="mini" - app:pressedTranslationZ="2dp" /> + app:pressedTranslationZ="2dp" + tools:ignore="UnusedAttribute" /> + app:pressedTranslationZ="2dp" + tools:ignore="UnusedAttribute" /> + app:pressedTranslationZ="2dp" + tools:ignore="UnusedAttribute" /> + app:pressedTranslationZ="2dp" + tools:ignore="UnusedAttribute" /> + app:pressedTranslationZ="2dp" + tools:ignore="UnusedAttribute" /> From ec5a990dd7170eb30302d6d2cd22c69fc78c320f Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 14 Aug 2019 10:27:24 +0800 Subject: [PATCH 0652/1997] up --- .../io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt | 8 ++++++++ .../io/legado/app/ui/main/bookshelf/BookshelfFragment.kt | 5 +++++ .../io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt | 8 ++++++-- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt index 9f533e2c8..120f4e383 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt @@ -65,6 +65,13 @@ class BookshelfAdapter : PagedListAdapter(D callBack?.openBookInfo(book) true } + callBack?.let { + if (book.bookUrl in it.updateList()) { + rl_loading.show() + } else { + rl_loading.hide() + } + } ?: rl_loading.hide() } } @@ -72,5 +79,6 @@ class BookshelfAdapter : PagedListAdapter(D fun open(book: Book) fun openBookInfo(book: Book) fun search() + fun updateList(): List } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index 2cba38d6d..74576b5ed 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -73,6 +73,7 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b refresh_layout.setColorSchemeColors(accentColor) refresh_layout.setOnRefreshListener { refresh_layout.isRefreshing = false + viewModel.upChapterList() } tv_recent_reading.textColor = accentColor rv_book_group.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) @@ -117,6 +118,10 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b } + override fun updateList(): List { + return viewModel.updateList + } + override fun onQueryTextSubmit(query: String?): Boolean { context?.startActivity(Pair("key", query)) return false diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt index 148c20b6a..639910953 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt @@ -10,6 +10,9 @@ import kotlinx.coroutines.Dispatchers.IO class BookshelfViewModel(application: Application) : BaseViewModel(application) { + val updateList = arrayListOf() + + fun saveBookGroup(group: String?) { if (!group.isNullOrBlank()) { execute { @@ -30,13 +33,14 @@ class BookshelfViewModel(application: Application) : BaseViewModel(application) if (book.origin != BookType.local) { val bookSource = App.db.bookSourceDao().getBookSource(book.origin) bookSource?.let { + updateList.add(book.bookUrl) WebBook(bookSource).getChapterList(book).onSuccess(IO) { it?.let { if (it.size > App.db.bookChapterDao().getChapterCount(book.bookUrl)) { - + App.db.bookChapterDao().insert(*it.toTypedArray()) } } - } + }.onFinally { updateList.remove(book.bookUrl) } } } } From cae1a5c0faf924347bdc885a2f30c9b6604aba2c Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 14 Aug 2019 10:39:24 +0800 Subject: [PATCH 0653/1997] up --- .../java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt | 5 +++-- .../io/legado/app/ui/main/bookshelf/BookshelfFragment.kt | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt index 120f4e383..0f70422e3 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt @@ -7,6 +7,7 @@ import androidx.paging.PagedListAdapter import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import io.legado.app.R +import io.legado.app.constant.BookType import io.legado.app.data.entities.Book import io.legado.app.help.ImageLoader import io.legado.app.lib.theme.ThemeStore @@ -66,7 +67,7 @@ class BookshelfAdapter : PagedListAdapter(D true } callBack?.let { - if (book.bookUrl in it.updateList()) { + if (book.origin != BookType.local && it.isUpdate(book.bookUrl)) { rl_loading.show() } else { rl_loading.hide() @@ -79,6 +80,6 @@ class BookshelfAdapter : PagedListAdapter(D fun open(book: Book) fun openBookInfo(book: Book) fun search() - fun updateList(): List + fun isUpdate(bookUrl: String): Boolean } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index 74576b5ed..86cb82006 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -118,8 +118,8 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b } - override fun updateList(): List { - return viewModel.updateList + override fun isUpdate(bookUrl: String): Boolean { + return bookUrl in viewModel.updateList } override fun onQueryTextSubmit(query: String?): Boolean { From 3a723b11b6ed544b1e501453e4186eb951bb7783 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 14 Aug 2019 11:21:33 +0800 Subject: [PATCH 0654/1997] up --- app/src/main/java/io/legado/app/data/dao/BookDao.kt | 2 +- .../legado/app/ui/main/bookshelf/BookshelfAdapter.kt | 11 +++++++++++ .../legado/app/ui/main/bookshelf/BookshelfFragment.kt | 1 + .../app/ui/main/bookshelf/BookshelfViewModel.kt | 9 +++++++-- 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/BookDao.kt b/app/src/main/java/io/legado/app/data/dao/BookDao.kt index 523aca465..2e30f937d 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookDao.kt @@ -40,7 +40,7 @@ interface BookDao { fun recentRead(): DataSource.Factory @Query("SELECT * FROM books ORDER BY durChapterTime DESC limit 0,10") - fun getRecentRead(): DataSource.Factory + fun getRecentRead(): List @Insert(onConflict = OnConflictStrategy.REPLACE) fun insert(vararg book: Book) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt index 0f70422e3..b67ad32cf 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt @@ -33,6 +33,17 @@ class BookshelfAdapter : PagedListAdapter(D var callBack: CallBack? = null + fun notification(bookUrl: String) { + for (i in 0..itemCount) { + getItem(i)?.let { + if (it.bookUrl == bookUrl) { + notifyItemChanged(i) + return + } + } + } + } + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { return MyViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_bookshelf_list, parent, false)) } diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index 86cb82006..11dec61a1 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -85,6 +85,7 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b bookshelfAdapter = BookshelfAdapter() rv_bookshelf.adapter = bookshelfAdapter bookshelfAdapter.callBack = this + viewModel.adapterNotification.observe(viewLifecycleOwner, Observer { bookshelfAdapter.notification(it) }) } private fun initBookGroupData() { diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt index 639910953..b4b2a6e21 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt @@ -1,6 +1,7 @@ package io.legado.app.ui.main.bookshelf import android.app.Application +import androidx.lifecycle.MediatorLiveData import io.legado.app.App import io.legado.app.base.BaseViewModel import io.legado.app.constant.BookType @@ -11,7 +12,7 @@ import kotlinx.coroutines.Dispatchers.IO class BookshelfViewModel(application: Application) : BaseViewModel(application) { val updateList = arrayListOf() - + val adapterNotification = MediatorLiveData() fun saveBookGroup(group: String?) { if (!group.isNullOrBlank()) { @@ -34,13 +35,17 @@ class BookshelfViewModel(application: Application) : BaseViewModel(application) val bookSource = App.db.bookSourceDao().getBookSource(book.origin) bookSource?.let { updateList.add(book.bookUrl) + adapterNotification.postValue(book.bookUrl) WebBook(bookSource).getChapterList(book).onSuccess(IO) { it?.let { if (it.size > App.db.bookChapterDao().getChapterCount(book.bookUrl)) { App.db.bookChapterDao().insert(*it.toTypedArray()) } } - }.onFinally { updateList.remove(book.bookUrl) } + }.onFinally { + updateList.remove(book.bookUrl) + adapterNotification.postValue(book.bookUrl) + } } } } From 2ef7058191a811058616eb2bb675ba781557ab0f Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 14 Aug 2019 11:42:32 +0800 Subject: [PATCH 0655/1997] up --- app/src/main/java/io/legado/app/constant/Bus.kt | 2 +- .../io/legado/app/ui/main/bookshelf/BookshelfFragment.kt | 8 +++----- .../io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt | 8 ++++---- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/io/legado/app/constant/Bus.kt b/app/src/main/java/io/legado/app/constant/Bus.kt index 98acde903..ab7d44c84 100644 --- a/app/src/main/java/io/legado/app/constant/Bus.kt +++ b/app/src/main/java/io/legado/app/constant/Bus.kt @@ -2,5 +2,5 @@ package io.legado.app.constant object Bus { const val RECREATE = "RECREATE" - const val SOURCE_DEBUG_LOG = "sourceDebugLog" + const val UP_BOOK = "sourceDebugLog" } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index 11dec61a1..aba0b214c 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -15,6 +15,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.App import io.legado.app.R import io.legado.app.base.VMBaseFragment +import io.legado.app.constant.Bus import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookGroup import io.legado.app.lib.dialogs.alert @@ -27,10 +28,7 @@ import io.legado.app.ui.bookinfo.BookInfoActivity import io.legado.app.ui.bookshelf.BookshelfActivity import io.legado.app.ui.read.ReadActivity import io.legado.app.ui.search.SearchActivity -import io.legado.app.utils.applyTint -import io.legado.app.utils.getViewModel -import io.legado.app.utils.requestInputMethod -import io.legado.app.utils.startActivity +import io.legado.app.utils.* import kotlinx.android.synthetic.main.dialog_edittext.view.* import kotlinx.android.synthetic.main.fragment_bookshelf.* import kotlinx.android.synthetic.main.view_title_bar.* @@ -85,7 +83,7 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b bookshelfAdapter = BookshelfAdapter() rv_bookshelf.adapter = bookshelfAdapter bookshelfAdapter.callBack = this - viewModel.adapterNotification.observe(viewLifecycleOwner, Observer { bookshelfAdapter.notification(it) }) + observeEvent(Bus.UP_BOOK) { bookshelfAdapter.notification(it) } } private fun initBookGroupData() { diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt index b4b2a6e21..451b6443f 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt @@ -1,18 +1,18 @@ package io.legado.app.ui.main.bookshelf import android.app.Application -import androidx.lifecycle.MediatorLiveData import io.legado.app.App import io.legado.app.base.BaseViewModel import io.legado.app.constant.BookType +import io.legado.app.constant.Bus import io.legado.app.data.entities.BookGroup import io.legado.app.model.WebBook +import io.legado.app.utils.postEvent import kotlinx.coroutines.Dispatchers.IO class BookshelfViewModel(application: Application) : BaseViewModel(application) { val updateList = arrayListOf() - val adapterNotification = MediatorLiveData() fun saveBookGroup(group: String?) { if (!group.isNullOrBlank()) { @@ -35,7 +35,7 @@ class BookshelfViewModel(application: Application) : BaseViewModel(application) val bookSource = App.db.bookSourceDao().getBookSource(book.origin) bookSource?.let { updateList.add(book.bookUrl) - adapterNotification.postValue(book.bookUrl) + postEvent(Bus.UP_BOOK, book.bookUrl) WebBook(bookSource).getChapterList(book).onSuccess(IO) { it?.let { if (it.size > App.db.bookChapterDao().getChapterCount(book.bookUrl)) { @@ -44,7 +44,7 @@ class BookshelfViewModel(application: Application) : BaseViewModel(application) } }.onFinally { updateList.remove(book.bookUrl) - adapterNotification.postValue(book.bookUrl) + postEvent(Bus.UP_BOOK, book.bookUrl) } } } From 119fd0c79d20be806b9894dcf860a40e12faac10 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 14 Aug 2019 11:55:50 +0800 Subject: [PATCH 0656/1997] up --- app/src/main/java/io/legado/app/data/entities/BookChapter.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/data/entities/BookChapter.kt b/app/src/main/java/io/legado/app/data/entities/BookChapter.kt index 3203313d7..7d405d927 100644 --- a/app/src/main/java/io/legado/app/data/entities/BookChapter.kt +++ b/app/src/main/java/io/legado/app/data/entities/BookChapter.kt @@ -11,7 +11,7 @@ import kotlinx.android.parcel.Parcelize @Entity( tableName = "chapters", primaryKeys = ["url", "bookUrl"], - indices = [(Index(value = ["bookUrl"], unique = true)), (Index(value = ["bookUrl", "index"], unique = true))], + indices = [(Index(value = ["bookUrl"], unique = false)), (Index(value = ["bookUrl", "index"], unique = true))], foreignKeys = [(ForeignKey( entity = Book::class, parentColumns = ["bookUrl"], From 17414beeef95edbd9077b50c3eb71766226b6514 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 14 Aug 2019 11:56:11 +0800 Subject: [PATCH 0657/1997] up --- .../legado/app/data/entities/BookChapter.kt | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/BookChapter.kt b/app/src/main/java/io/legado/app/data/entities/BookChapter.kt index 7d405d927..61006a6ea 100644 --- a/app/src/main/java/io/legado/app/data/entities/BookChapter.kt +++ b/app/src/main/java/io/legado/app/data/entities/BookChapter.kt @@ -9,24 +9,24 @@ import kotlinx.android.parcel.Parcelize @Parcelize @Entity( - tableName = "chapters", - primaryKeys = ["url", "bookUrl"], + tableName = "chapters", + primaryKeys = ["url", "bookUrl"], indices = [(Index(value = ["bookUrl"], unique = false)), (Index(value = ["bookUrl", "index"], unique = true))], - foreignKeys = [(ForeignKey( - entity = Book::class, - parentColumns = ["bookUrl"], - childColumns = ["bookUrl"], - onDelete = ForeignKey.CASCADE - ))] + foreignKeys = [(ForeignKey( + entity = Book::class, + parentColumns = ["bookUrl"], + childColumns = ["bookUrl"], + onDelete = ForeignKey.CASCADE + ))] ) // 删除书籍时自动删除章节 data class BookChapter( - var url: String = "", // 章节地址 - var title: String = "", // 章节标题 - var bookUrl: String = "", // 书籍地址 - var index: Int = 0, // 章节序号 - var resourceUrl: String? = null, // 音频真实URL - var tag: String? = null, // - var start: Long? = null, // 章节起始位置 - var end: Long? = null // 章节终止位置 + var url: String = "", // 章节地址 + var title: String = "", // 章节标题 + var bookUrl: String = "", // 书籍地址 + var index: Int = 0, // 章节序号 + var resourceUrl: String? = null, // 音频真实URL + var tag: String? = null, // + var start: Long? = null, // 章节起始位置 + var end: Long? = null // 章节终止位置 ) : Parcelable From cebd9c0d9aa548f0826854e8145f3274e5d27fec Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 14 Aug 2019 12:21:02 +0800 Subject: [PATCH 0658/1997] up --- .../main/java/io/legado/app/model/webbook/BookChapterList.kt | 3 +++ app/src/main/res/layout/item_bookmark.xml | 2 +- app/src/main/res/layout/item_chapter_list.xml | 4 +++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt b/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt index 8d8b4c22d..c387008a7 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt @@ -95,6 +95,9 @@ object BookChapterList { val lh = LinkedHashSet(chapterList) chapterList = ArrayList(lh) chapterList.reverse() + for ((index, item) in chapterList.withIndex()) { + item.index = index + } return chapterList } diff --git a/app/src/main/res/layout/item_bookmark.xml b/app/src/main/res/layout/item_bookmark.xml index 7afd9dfa2..58be6b0e7 100644 --- a/app/src/main/res/layout/item_bookmark.xml +++ b/app/src/main/res/layout/item_bookmark.xml @@ -2,7 +2,7 @@ + android:layout_height="wrap_content"> + android:layout_height="wrap_content" + android:background="?android:attr/selectableItemBackground" + android:padding="12dp"> Date: Wed, 14 Aug 2019 14:43:55 +0800 Subject: [PATCH 0659/1997] up --- .../app/ui/chapterlist/ChapterListActivity.kt | 1 + .../app/ui/chapterlist/ChapterListFragment.kt | 21 +++++++++++++++++++ .../ui/chapterlist/ChapterListViewModel.kt | 13 ++++++++++++ .../main/res/layout/fragment_chapter_list.xml | 10 +++++++-- 4 files changed, 43 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt index 24576fe41..70367f9f8 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt +++ b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt @@ -27,6 +27,7 @@ class ChapterListActivity : VMBaseActivity(R.layout.activi override fun onActivityCreated(savedInstanceState: Bundle?) { setSupportActionBar(toolbar) viewModel.bookUrl = intent.getStringExtra("bookUrl") + viewModel.loadBook() view_pager.adapter = TabFragmentPageAdapter(supportFragmentManager) tab_layout.setupWithViewPager(view_pager) } diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt index 2435bb07a..b77da5dc9 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt +++ b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt @@ -13,6 +13,7 @@ import io.legado.app.base.VMBaseFragment import io.legado.app.data.entities.BookChapter import io.legado.app.utils.getViewModelOfActivity import kotlinx.android.synthetic.main.fragment_chapter_list.* +import org.jetbrains.anko.sdk27.listeners.onClick class ChapterListFragment : VMBaseFragment(R.layout.fragment_chapter_list) { override val viewModel: ChapterListViewModel @@ -24,6 +25,7 @@ class ChapterListFragment : VMBaseFragment(R.layout.fragme override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) initRecyclerView() + initView() initData() } @@ -38,4 +40,23 @@ class ChapterListFragment : VMBaseFragment(R.layout.fragme liveData = LivePagedListBuilder(App.db.bookChapterDao().observeByBook(viewModel.bookUrl ?: ""), 30).build() liveData?.observe(viewLifecycleOwner, Observer { adapter.submitList(it) }) } + + private fun initView() { + viewModel.bookDate.value?.let { + tv_current_chapter_info.text = it.durChapterTitle + } ?: viewModel.bookDate.observe(viewLifecycleOwner, Observer { + tv_current_chapter_info.text = it.durChapterTitle + }) + iv_chapter_top.onClick { recycler_view.scrollToPosition(0) } + iv_chapter_bottom.onClick { + if (adapter.itemCount > 0) { + recycler_view.scrollToPosition(adapter.itemCount - 1) + } + } + tv_current_chapter_info.onClick { + viewModel.bookDate.value?.let { + recycler_view.scrollToPosition(it.durChapterIndex) + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListViewModel.kt b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListViewModel.kt index c17237185..11d1b38e9 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListViewModel.kt @@ -2,10 +2,23 @@ package io.legado.app.ui.chapterlist import android.app.Application +import androidx.lifecycle.MutableLiveData +import io.legado.app.App import io.legado.app.base.BaseViewModel +import io.legado.app.data.entities.Book class ChapterListViewModel(application: Application) : BaseViewModel(application) { + var bookDate = MutableLiveData() var bookUrl: String? = null + fun loadBook() { + execute { + bookUrl?.let { + App.db.bookDao().getBook(it)?.let { book -> + bookDate.postValue(book) + } + } + } + } } \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_chapter_list.xml b/app/src/main/res/layout/fragment_chapter_list.xml index 28622e165..8964c91c6 100644 --- a/app/src/main/res/layout/fragment_chapter_list.xml +++ b/app/src/main/res/layout/fragment_chapter_list.xml @@ -1,6 +1,7 @@ @@ -30,6 +31,7 @@ android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" + android:background="?android:attr/selectableItemBackgroundBorderless" android:ellipsize="middle" android:paddingLeft="10dp" android:paddingRight="10dp" @@ -45,7 +47,9 @@ android:background="?android:attr/selectableItemBackgroundBorderless" android:contentDescription="@string/go_to_top" android:src="@drawable/ic_arrow_drop_up" - app:tint="@color/tv_text_default" /> + android:tooltipText="@string/go_to_top" + app:tint="@color/tv_text_default" + tools:ignore="UnusedAttribute" /> + android:tooltipText="@string/go_to_bottom" + app:tint="@color/tv_text_default" + tools:ignore="UnusedAttribute" /> \ No newline at end of file From 9c9d5f5883d182e6d8d44f03597ebd1f8f217676 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 14 Aug 2019 15:01:36 +0800 Subject: [PATCH 0660/1997] up --- .../app/ui/bookinfo/BookInfoActivity.kt | 23 +++++++++++++++++++ app/src/main/res/menu/book_info.xml | 18 +++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 app/src/main/res/menu/book_info.xml diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index 89333ef25..ee34a35f0 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -1,6 +1,8 @@ package io.legado.app.ui.bookinfo import android.os.Bundle +import android.view.Menu +import android.view.MenuItem import androidx.lifecycle.Observer import io.legado.app.R import io.legado.app.base.VMBaseActivity @@ -10,19 +12,40 @@ import io.legado.app.utils.getViewModel import io.legado.app.utils.gone import io.legado.app.utils.visible import kotlinx.android.synthetic.main.activity_book_info.* +import kotlinx.android.synthetic.main.view_title_bar.* import org.jetbrains.anko.sdk27.listeners.onClick +import org.jetbrains.anko.startActivity class BookInfoActivity : VMBaseActivity(R.layout.activity_book_info) { override val viewModel: BookInfoViewModel get() = getViewModel(BookInfoViewModel::class.java) override fun onActivityCreated(savedInstanceState: Bundle?) { + setSupportActionBar(toolbar) viewModel.bookData.observe(this, Observer { showBook(it) }) viewModel.isLoadingData.observe(this, Observer { upLoading(it) }) viewModel.loadBook(intent) initView() } + override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { + menuInflater.inflate(R.menu.book_info, menu) + return super.onCompatCreateOptionsMenu(menu) + } + + override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.menu_edit -> { + if (viewModel.inBookshelf) { + viewModel.bookData.value?.let { + startActivity(Pair("bookUrl", it.bookUrl)) + } + } + } + } + return super.onCompatOptionsItemSelected(item) + } + private fun showBook(book: Book) { tv_name.text = book.name tv_author.text = getString(R.string.author_show, book.author) diff --git a/app/src/main/res/menu/book_info.xml b/app/src/main/res/menu/book_info.xml new file mode 100644 index 000000000..5e1832752 --- /dev/null +++ b/app/src/main/res/menu/book_info.xml @@ -0,0 +1,18 @@ + + + + + + + + + \ No newline at end of file From 95b93171d502a9ce0e14d6f2e386d6991109fe82 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 14 Aug 2019 15:08:03 +0800 Subject: [PATCH 0661/1997] up --- app/src/main/res/menu/book_info.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/menu/book_info.xml b/app/src/main/res/menu/book_info.xml index 5e1832752..762942705 100644 --- a/app/src/main/res/menu/book_info.xml +++ b/app/src/main/res/menu/book_info.xml @@ -4,7 +4,7 @@ @@ -12,7 +12,7 @@ android:id="@+id/menu_refresh" android:icon="@drawable/ic_refresh_black_24dp" android:title="@string/refresh" - app:showAsAction="ifRoom" /> + app:showAsAction="never" /> \ No newline at end of file From cc1768038eab0bf71a8697cd425f35dcd4e12d7f Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 14 Aug 2019 15:19:00 +0800 Subject: [PATCH 0662/1997] up --- .../main/java/io/legado/app/ui/read/ReadViewModel.kt | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/read/ReadViewModel.kt b/app/src/main/java/io/legado/app/ui/read/ReadViewModel.kt index fed906c6b..7f45b52c2 100644 --- a/app/src/main/java/io/legado/app/ui/read/ReadViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/read/ReadViewModel.kt @@ -6,6 +6,7 @@ import io.legado.app.App import io.legado.app.base.BaseViewModel import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookSource +import io.legado.app.model.WebBook class ReadViewModel(application: Application) : BaseViewModel(application) { @@ -19,8 +20,14 @@ class ReadViewModel(application: Application) : BaseViewModel(application) { book = App.db.bookDao().getBook(bookUrl) book?.let { book -> if (App.db.bookChapterDao().getChapterCount(bookUrl) == 0) { - bookSource = App.db.bookSourceDao().getBookSource(book.origin) - if (bookSource == null) { + App.db.bookSourceDao().getBookSource(book.origin)?.let { + WebBook(it).getChapterList(book) + .onSuccess { cList -> + cList?.let { + App.db.bookChapterDao().insert(*cList.toTypedArray()) + } + } + } ?: let { } } From 75eec52b854ebf332adfc16102f8e50346b3a731 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 14 Aug 2019 15:36:07 +0800 Subject: [PATCH 0663/1997] up --- app/src/main/java/io/legado/app/ui/read/ReadViewModel.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/read/ReadViewModel.kt b/app/src/main/java/io/legado/app/ui/read/ReadViewModel.kt index 7f45b52c2..3d0cc0b59 100644 --- a/app/src/main/java/io/legado/app/ui/read/ReadViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/read/ReadViewModel.kt @@ -2,6 +2,7 @@ package io.legado.app.ui.read import android.app.Application import android.content.Intent +import androidx.lifecycle.MediatorLiveData import io.legado.app.App import io.legado.app.base.BaseViewModel import io.legado.app.data.entities.Book @@ -12,6 +13,7 @@ class ReadViewModel(application: Application) : BaseViewModel(application) { var book: Book? = null var bookSource: BookSource? = null + var chapterMaxIndex = MediatorLiveData() fun initData(intent: Intent) { val bookUrl = intent.getStringExtra("bookUrl") @@ -19,7 +21,8 @@ class ReadViewModel(application: Application) : BaseViewModel(application) { execute { book = App.db.bookDao().getBook(bookUrl) book?.let { book -> - if (App.db.bookChapterDao().getChapterCount(bookUrl) == 0) { + val count = App.db.bookChapterDao().getChapterCount(bookUrl) + if (count == 0) { App.db.bookSourceDao().getBookSource(book.origin)?.let { WebBook(it).getChapterList(book) .onSuccess { cList -> @@ -30,6 +33,8 @@ class ReadViewModel(application: Application) : BaseViewModel(application) { } ?: let { } + } else { + chapterMaxIndex.postValue(count) } } From 7164dcf5aa4c35607ec806c2eef133136e9e480d Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 14 Aug 2019 16:49:34 +0800 Subject: [PATCH 0664/1997] up --- .../java/io/legado/app/ui/changesource/ChangeSourceAdapter.kt | 2 ++ .../java/io/legado/app/ui/changesource/ChangeSourceDialog.kt | 2 ++ 2 files changed, 4 insertions(+) create mode 100644 app/src/main/java/io/legado/app/ui/changesource/ChangeSourceAdapter.kt create mode 100644 app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceAdapter.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceAdapter.kt new file mode 100644 index 000000000..455615940 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceAdapter.kt @@ -0,0 +1,2 @@ +package io.legado.app.ui.changesource + diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt new file mode 100644 index 000000000..455615940 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt @@ -0,0 +1,2 @@ +package io.legado.app.ui.changesource + From 548c94b775c14e3686dab1ff9d8ef2c07493c482 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 14 Aug 2019 17:41:35 +0800 Subject: [PATCH 0665/1997] up --- .../app/ui/changesource/ChangeSourceDialog.kt | 20 +++++++++++++++++++ .../main/res/layout/dialog_change_source.xml | 7 +++++++ 2 files changed, 27 insertions(+) create mode 100644 app/src/main/res/layout/dialog_change_source.xml diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt index 455615940..54a8deffe 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt @@ -1,2 +1,22 @@ package io.legado.app.ui.changesource +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.DialogFragment +import io.legado.app.R + + +class ChangeSourceDialog : DialogFragment() { + + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + return inflater.inflate(R.layout.dialog_change_source, container) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + } + +} \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_change_source.xml b/app/src/main/res/layout/dialog_change_source.xml new file mode 100644 index 000000000..d829e291c --- /dev/null +++ b/app/src/main/res/layout/dialog_change_source.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file From 0013dd6e762b93ff4b5525fabe91bbfbc8348a66 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 14 Aug 2019 17:49:44 +0800 Subject: [PATCH 0666/1997] up --- .../java/io/legado/app/ui/changesource/ChangeSourceDialog.kt | 1 + app/src/main/res/layout/dialog_change_source.xml | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt index 54a8deffe..6044c448a 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt @@ -19,4 +19,5 @@ class ChangeSourceDialog : DialogFragment() { super.onViewCreated(view, savedInstanceState) } + } \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_change_source.xml b/app/src/main/res/layout/dialog_change_source.xml index d829e291c..0f07a9375 100644 --- a/app/src/main/res/layout/dialog_change_source.xml +++ b/app/src/main/res/layout/dialog_change_source.xml @@ -1,7 +1,8 @@ - - \ No newline at end of file + + \ No newline at end of file From 5ba780f6cb24a8153a1a840e47e76a8af3ea4cda Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 14 Aug 2019 17:59:27 +0800 Subject: [PATCH 0667/1997] up --- .../main/res/layout/activity_book_info.xml | 24 ++++++++++++++++--- .../main/res/layout/dialog_change_source.xml | 8 +++++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/layout/activity_book_info.xml b/app/src/main/res/layout/activity_book_info.xml index 24fe0d268..38a326100 100644 --- a/app/src/main/res/layout/activity_book_info.xml +++ b/app/src/main/res/layout/activity_book_info.xml @@ -1,6 +1,7 @@ @@ -48,12 +49,29 @@ android:layout_weight="1" android:singleLine="true" /> - + android:orientation="horizontal"> + + + + + + + + \ No newline at end of file From 947b01edd0c7e25c1506bd9be36e716a72830770 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 14 Aug 2019 20:00:28 +0800 Subject: [PATCH 0668/1997] up --- app/src/main/res/layout/activity_book_info.xml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/layout/activity_book_info.xml b/app/src/main/res/layout/activity_book_info.xml index 38a326100..5ab89bd2b 100644 --- a/app/src/main/res/layout/activity_book_info.xml +++ b/app/src/main/res/layout/activity_book_info.xml @@ -63,7 +63,7 @@ android:singleLine="true" tools:ignore="NestedWeights" /> - + android:tooltipText="@string/go_to_top" + app:tint="@color/tv_text_default" + tools:ignore="UnusedAttribute" /> + android:tooltipText="@string/go_to_bottom" + app:tint="@color/tv_text_default" + tools:ignore="UnusedAttribute" /> Date: Wed, 14 Aug 2019 20:21:28 +0800 Subject: [PATCH 0669/1997] up --- .../java/io/legado/app/ui/bookinfo/BookInfoActivity.kt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index ee34a35f0..b1275721f 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -8,6 +8,7 @@ import io.legado.app.R import io.legado.app.base.VMBaseActivity import io.legado.app.data.entities.Book import io.legado.app.help.ImageLoader +import io.legado.app.ui.changesource.ChangeSourceDialog import io.legado.app.utils.getViewModel import io.legado.app.utils.gone import io.legado.app.utils.visible @@ -20,6 +21,8 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo override val viewModel: BookInfoViewModel get() = getViewModel(BookInfoViewModel::class.java) + var changeSourceDialog: ChangeSourceDialog? = null + override fun onActivityCreated(savedInstanceState: Bundle?) { setSupportActionBar(toolbar) viewModel.bookData.observe(this, Observer { showBook(it) }) @@ -114,5 +117,11 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo } } tv_loading.onClick { } + tv_change_source.onClick { + if (changeSourceDialog == null) { + changeSourceDialog = ChangeSourceDialog() + } + changeSourceDialog?.show(supportFragmentManager, "changeSource") + } } } \ No newline at end of file From 2bdca6ed64a6f46cd92af54ec90c79a9ef6f8b28 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 14 Aug 2019 20:52:01 +0800 Subject: [PATCH 0670/1997] up --- .../java/io/legado/app/ui/changesource/ChangeSourceDialog.kt | 2 ++ app/src/main/res/layout/dialog_change_source.xml | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt index 6044c448a..197e8df5d 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt @@ -6,6 +6,7 @@ import android.view.View import android.view.ViewGroup import androidx.fragment.app.DialogFragment import io.legado.app.R +import kotlinx.android.synthetic.main.dialog_change_source.* class ChangeSourceDialog : DialogFragment() { @@ -17,6 +18,7 @@ class ChangeSourceDialog : DialogFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + tool_bar.inflateMenu(R.menu.search_view) } diff --git a/app/src/main/res/layout/dialog_change_source.xml b/app/src/main/res/layout/dialog_change_source.xml index 7d20fe160..68db3890e 100644 --- a/app/src/main/res/layout/dialog_change_source.xml +++ b/app/src/main/res/layout/dialog_change_source.xml @@ -5,10 +5,11 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - From d024b60d03983539bfb2835fb70c2e8f01a21dc1 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 14 Aug 2019 21:15:49 +0800 Subject: [PATCH 0671/1997] up --- .../java/io/legado/app/data/entities/Book.kt | 4 ++-- .../io/legado/app/data/entities/SearchBook.kt | 4 ++-- .../io/legado/app/help/storage/Restore.kt | 4 ++-- .../io/legado/app/model/webbook/BookList.kt | 4 ++-- .../app/ui/bookinfo/BookInfoActivity.kt | 4 +++- .../app/ui/bookinfo/BookInfoEditActivity.kt | 4 ++-- .../app/ui/changesource/ChangeSourceDialog.kt | 19 +++++++++++++++++-- .../app/ui/chapterlist/ChapterListActivity.kt | 2 +- .../ui/main/bookshelf/BookshelfFragment.kt | 2 +- app/src/main/res/menu/main_bookshelf.xml | 2 +- app/src/main/res/menu/search_view.xml | 2 +- 11 files changed, 34 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/Book.kt b/app/src/main/java/io/legado/app/data/entities/Book.kt index 2274a973c..fb3027435 100644 --- a/app/src/main/java/io/legado/app/data/entities/Book.kt +++ b/app/src/main/java/io/legado/app/data/entities/Book.kt @@ -22,8 +22,8 @@ data class Book( var tocUrl: String = "", // 目录页Url (toc=table of Contents) var origin: String = BookType.local, // 书源URL(默认BookType.local) var originName: String = "", //书源名称 - var name: String? = null, // 书籍名称(书源获取) - var author: String? = null, // 作者名称(书源获取) + var name: String = "", // 书籍名称(书源获取) + var author: String = "", // 作者名称(书源获取) var kind: String? = null, // 分类信息(书源获取) var customTag: String? = null, // 分类信息(用户修改) var coverUrl: String? = null, // 封面Url(书源获取) diff --git a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt index 770fb4117..45e905847 100644 --- a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt +++ b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt @@ -18,8 +18,8 @@ data class SearchBook( var bookUrl: String = "", var origin: String = "", // 书源规则 var originName: String = "", - var name: String? = null, - var author: String? = null, + var name: String = "", + var author: String = "", var kind: String? = null, var coverUrl: String? = null, var intro: String? = null, diff --git a/app/src/main/java/io/legado/app/help/storage/Restore.kt b/app/src/main/java/io/legado/app/help/storage/Restore.kt index c10908dcd..0e9b73dbf 100644 --- a/app/src/main/java/io/legado/app/help/storage/Restore.kt +++ b/app/src/main/java/io/legado/app/help/storage/Restore.kt @@ -47,14 +47,14 @@ object Restore { val book = Book() book.bookUrl = jsonItem.readString("$.noteUrl") ?: "" if (book.bookUrl.isBlank()) continue - book.name = jsonItem.readString("$.bookInfoBean.name") + book.name = jsonItem.readString("$.bookInfoBean.name") ?: "" if (book.bookUrl in existingBooks) { Log.d(AppConst.APP_TAG, "Found existing book: ${book.name}") continue } book.origin = jsonItem.readString("$.tag") ?: "" book.originName = jsonItem.readString("$.bookInfoBean.origin") ?: "" - book.author = jsonItem.readString("$.bookInfoBean.author") + book.author = jsonItem.readString("$.bookInfoBean.author") ?: "" book.type = if (jsonItem.readString("$.bookInfoBean.bookSourceType") == "AUDIO") 1 else 0 book.tocUrl = jsonItem.readString("$.bookInfoBean.chapterUrl") ?: book.bookUrl book.coverUrl = jsonItem.readString("$.bookInfoBean.coverUrl") diff --git a/app/src/main/java/io/legado/app/model/webbook/BookList.kt b/app/src/main/java/io/legado/app/model/webbook/BookList.kt index 635f8e249..b5af7027f 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookList.kt @@ -111,7 +111,7 @@ object BookList { analyzeRule.setContent(analyzeRule.getElement(it)) } SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取书名") - searchBook.name = analyzeRule.getString(name ?: "") + searchBook.name = analyzeRule.getString(name ?: "") ?: "" SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.name ?: "") if (!searchBook.name.isNullOrEmpty()) { SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取作者") @@ -162,7 +162,7 @@ object BookList { analyzeRule.setContent(item) SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取书名", printLog) searchBook.name = analyzeRule.getString(ruleName) - SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.name ?: "", printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.name, printLog) if (!searchBook.name.isNullOrEmpty()) { SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取书籍Url", printLog) searchBook.bookUrl = analyzeRule.getString(ruleBookUrl, true) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index b1275721f..c72da24b6 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -119,7 +119,9 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo tv_loading.onClick { } tv_change_source.onClick { if (changeSourceDialog == null) { - changeSourceDialog = ChangeSourceDialog() + viewModel.bookData.value?.let { + changeSourceDialog = ChangeSourceDialog(it.name, it.author) + } } changeSourceDialog?.show(supportFragmentManager, "changeSource") } diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoEditActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoEditActivity.kt index fc15bd18b..11cbbe490 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoEditActivity.kt @@ -45,8 +45,8 @@ class BookInfoEditActivity : VMBaseActivity(R.layout.acti private fun saveData() { viewModel.bookData.value?.let { book -> - book.name = tie_book_name.text?.toString() - book.author = tie_book_author.text?.toString() + book.name = tie_book_name.text?.toString() ?: "" + book.author = tie_book_author.text?.toString() ?: "" val customCoverUrl = tie_cover_url.text?.toString() book.customCoverUrl = if (customCoverUrl == book.coverUrl) null else customCoverUrl book.customIntro = tie_book_intro.text?.toString() diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt index 197e8df5d..2649ecb7c 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt @@ -4,13 +4,13 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.appcompat.widget.SearchView import androidx.fragment.app.DialogFragment import io.legado.app.R import kotlinx.android.synthetic.main.dialog_change_source.* -class ChangeSourceDialog : DialogFragment() { - +class ChangeSourceDialog(val name: String, val author: String) : DialogFragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.dialog_change_source, container) @@ -19,7 +19,22 @@ class ChangeSourceDialog : DialogFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) tool_bar.inflateMenu(R.menu.search_view) + tool_bar.title = name + tool_bar.subtitle = author + initSearchView() } + private fun initSearchView() { + val searchView = tool_bar.menu.findItem(R.id.menu_search).actionView as SearchView + searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { + override fun onQueryTextSubmit(query: String?): Boolean { + return false + } + + override fun onQueryTextChange(newText: String?): Boolean { + return false + } + }) + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt index 70367f9f8..ef5be2761 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt +++ b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListActivity.kt @@ -34,7 +34,7 @@ class ChapterListActivity : VMBaseActivity(R.layout.activi override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { menuInflater.inflate(R.menu.search_view, menu) - val search = menu.findItem(R.id.action_search) + val search = menu.findItem(R.id.menu_search) searchView = search.actionView as SearchView ATH.setTint(searchView!!, primaryTextColor) searchView?.maxWidth = resources.displayMetrics.widthPixels diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index aba0b214c..8ed1d310b 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -62,7 +62,7 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b override fun onCompatOptionsItemSelected(item: MenuItem) { super.onCompatOptionsItemSelected(item) when (item.itemId) { - R.id.action_search -> startActivity() + R.id.menu_search -> startActivity() } } diff --git a/app/src/main/res/menu/main_bookshelf.xml b/app/src/main/res/menu/main_bookshelf.xml index 6c69069c1..e4bc08efe 100644 --- a/app/src/main/res/menu/main_bookshelf.xml +++ b/app/src/main/res/menu/main_bookshelf.xml @@ -3,7 +3,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> diff --git a/app/src/main/res/menu/search_view.xml b/app/src/main/res/menu/search_view.xml index ee23fae6b..0b897362d 100644 --- a/app/src/main/res/menu/search_view.xml +++ b/app/src/main/res/menu/search_view.xml @@ -3,7 +3,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> From d643d022ad3154c3491c361b4215b47170e021ed Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 14 Aug 2019 21:21:07 +0800 Subject: [PATCH 0672/1997] up --- .../legado/app/ui/changesource/ChangeSourceDialog.kt | 10 +++++++++- app/src/main/res/layout/dialog_change_source.xml | 6 ++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt index 2649ecb7c..df376b041 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt @@ -6,6 +6,7 @@ import android.view.View import android.view.ViewGroup import androidx.appcompat.widget.SearchView import androidx.fragment.app.DialogFragment +import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.R import kotlinx.android.synthetic.main.dialog_change_source.* @@ -20,10 +21,15 @@ class ChangeSourceDialog(val name: String, val author: String) : DialogFragment( super.onViewCreated(view, savedInstanceState) tool_bar.inflateMenu(R.menu.search_view) tool_bar.title = name - tool_bar.subtitle = author + tool_bar.subtitle = getString(R.string.author_show, author) + initRecyclerView() initSearchView() } + private fun initRecyclerView() { + recycler_view.layoutManager = LinearLayoutManager(context) + } + private fun initSearchView() { val searchView = tool_bar.menu.findItem(R.id.menu_search).actionView as SearchView searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { @@ -37,4 +43,6 @@ class ChangeSourceDialog(val name: String, val author: String) : DialogFragment( }) } + + } \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_change_source.xml b/app/src/main/res/layout/dialog_change_source.xml index 68db3890e..e43f8cdae 100644 --- a/app/src/main/res/layout/dialog_change_source.xml +++ b/app/src/main/res/layout/dialog_change_source.xml @@ -13,5 +13,11 @@ app:fitStatusBar="false" app:layout_constraintTop_toTopOf="parent" /> + \ No newline at end of file From 813784669047a99e7def6ce069ae141753887bc2 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 14 Aug 2019 22:35:11 +0800 Subject: [PATCH 0673/1997] up --- .../java/io/legado/app/ui/changesource/ChangeSourceDialog.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt index df376b041..13007195a 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt @@ -26,6 +26,11 @@ class ChangeSourceDialog(val name: String, val author: String) : DialogFragment( initSearchView() } + override fun onStart() { + super.onStart() + dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) + } + private fun initRecyclerView() { recycler_view.layoutManager = LinearLayoutManager(context) } From 0875f84eb1216a4a7396889a75f0d576986ec5e1 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 14 Aug 2019 23:01:52 +0800 Subject: [PATCH 0674/1997] up --- .../app/ui/changesource/ChangeSourceDialog.kt | 16 ++++++++++++++-- app/src/main/res/layout/dialog_change_source.xml | 2 ++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt index 13007195a..f8bf69c21 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt @@ -20,8 +20,7 @@ class ChangeSourceDialog(val name: String, val author: String) : DialogFragment( override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) tool_bar.inflateMenu(R.menu.search_view) - tool_bar.title = name - tool_bar.subtitle = getString(R.string.author_show, author) + showTitle() initRecyclerView() initSearchView() } @@ -31,12 +30,25 @@ class ChangeSourceDialog(val name: String, val author: String) : DialogFragment( dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) } + private fun showTitle() { + tool_bar.title = name + tool_bar.subtitle = getString(R.string.author_show, author) + } + private fun initRecyclerView() { recycler_view.layoutManager = LinearLayoutManager(context) } private fun initSearchView() { val searchView = tool_bar.menu.findItem(R.id.menu_search).actionView as SearchView + searchView.setOnCloseListener { + showTitle() + false + } + searchView.setOnSearchClickListener { + tool_bar.title = "" + tool_bar.subtitle = "" + } searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { override fun onQueryTextSubmit(query: String?): Boolean { return false diff --git a/app/src/main/res/layout/dialog_change_source.xml b/app/src/main/res/layout/dialog_change_source.xml index e43f8cdae..cd6738e3c 100644 --- a/app/src/main/res/layout/dialog_change_source.xml +++ b/app/src/main/res/layout/dialog_change_source.xml @@ -9,6 +9,8 @@ android:id="@+id/tool_bar" android:layout_width="match_parent" android:layout_height="wrap_content" + android:background="@color/background" + android:elevation="5dp" app:displayHomeAsUp="false" app:fitStatusBar="false" app:layout_constraintTop_toTopOf="parent" /> From 8b81829bd73bce33f291417b4ac6be7dd8081bc0 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 15 Aug 2019 09:09:27 +0800 Subject: [PATCH 0675/1997] up --- .../app/ui/bookinfo/BookInfoActivity.kt | 2 +- .../app/ui/changesource/ChangeSourceDialog.kt | 34 ++++++++++++++++--- .../ui/changesource/ChangeSourceViewModel.kt | 11 ++++++ 3 files changed, 42 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index c72da24b6..b43433de7 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -120,7 +120,7 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo tv_change_source.onClick { if (changeSourceDialog == null) { viewModel.bookData.value?.let { - changeSourceDialog = ChangeSourceDialog(it.name, it.author) + changeSourceDialog = ChangeSourceDialog.newInstance(it.name, it.author) } } changeSourceDialog?.show(supportFragmentManager, "changeSource") diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt index f8bf69c21..b4d2f4589 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt @@ -1,6 +1,7 @@ package io.legado.app.ui.changesource import android.os.Bundle +import android.util.DisplayMetrics import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -8,17 +9,40 @@ import androidx.appcompat.widget.SearchView import androidx.fragment.app.DialogFragment import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.R +import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.dialog_change_source.* -class ChangeSourceDialog(val name: String, val author: String) : DialogFragment() { +class ChangeSourceDialog : DialogFragment() { + + companion object { + fun newInstance(name: String, author: String): ChangeSourceDialog { + val changeSourceDialog = ChangeSourceDialog() + val bundle = Bundle() + bundle.putString("name", name) + bundle.putString("author", author) + changeSourceDialog.arguments = bundle + return changeSourceDialog + } + } + + private lateinit var viewModel: ChangeSourceViewModel override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + viewModel = getViewModel(ChangeSourceViewModel::class.java) return inflater.inflate(R.layout.dialog_change_source, container) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + arguments?.let { bundle -> + bundle.getString("name")?.let { + viewModel.name = it + } + bundle.getString("author")?.let { + viewModel.author = it + } + } tool_bar.inflateMenu(R.menu.search_view) showTitle() initRecyclerView() @@ -27,12 +51,14 @@ class ChangeSourceDialog(val name: String, val author: String) : DialogFragment( override fun onStart() { super.onStart() - dialog?.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) + val dm = DisplayMetrics() + activity?.windowManager?.defaultDisplay?.getMetrics(dm) + dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.9).toInt()) } private fun showTitle() { - tool_bar.title = name - tool_bar.subtitle = getString(R.string.author_show, author) + tool_bar.title = viewModel.name + tool_bar.subtitle = getString(R.string.author_show, viewModel.author) } private fun initRecyclerView() { diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt new file mode 100644 index 000000000..d5e36c5e3 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt @@ -0,0 +1,11 @@ +package io.legado.app.ui.changesource + +import android.app.Application +import io.legado.app.base.BaseViewModel + +class ChangeSourceViewModel(application: Application) : BaseViewModel(application) { + + var name: String = "" + var author: String = "" + +} \ No newline at end of file From 845e8a3b181406cb57ae784aaf431d3066b807fa Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 15 Aug 2019 09:46:50 +0800 Subject: [PATCH 0676/1997] up --- .../java/io/legado/app/ui/bookinfo/BookInfoActivity.kt | 7 ++++++- .../io/legado/app/ui/changesource/ChangeSourceDialog.kt | 5 +++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index b43433de7..eb59a6dce 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -17,7 +17,7 @@ import kotlinx.android.synthetic.main.view_title_bar.* import org.jetbrains.anko.sdk27.listeners.onClick import org.jetbrains.anko.startActivity -class BookInfoActivity : VMBaseActivity(R.layout.activity_book_info) { +class BookInfoActivity : VMBaseActivity(R.layout.activity_book_info), ChangeSourceDialog.CallBack { override val viewModel: BookInfoViewModel get() = getViewModel(BookInfoViewModel::class.java) @@ -29,6 +29,10 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo viewModel.isLoadingData.observe(this, Observer { upLoading(it) }) viewModel.loadBook(intent) initView() + savedInstanceState?.let { + changeSourceDialog = supportFragmentManager.findFragmentByTag("changeSourceDialog") as? ChangeSourceDialog + changeSourceDialog?.callBack = this + } } override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { @@ -121,6 +125,7 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo if (changeSourceDialog == null) { viewModel.bookData.value?.let { changeSourceDialog = ChangeSourceDialog.newInstance(it.name, it.author) + changeSourceDialog?.callBack = this } } changeSourceDialog?.show(supportFragmentManager, "changeSource") diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt index b4d2f4589..e563be35f 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt @@ -27,6 +27,7 @@ class ChangeSourceDialog : DialogFragment() { } private lateinit var viewModel: ChangeSourceViewModel + var callBack: CallBack? = null override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { viewModel = getViewModel(ChangeSourceViewModel::class.java) @@ -88,4 +89,8 @@ class ChangeSourceDialog : DialogFragment() { } + public interface CallBack { + + } + } \ No newline at end of file From 055b6d9e55c2468e6351865f6d6b7a8cf9c1c572 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 15 Aug 2019 09:53:41 +0800 Subject: [PATCH 0677/1997] up --- .../main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt | 4 ++-- .../java/io/legado/app/ui/changesource/ChangeSourceDialog.kt | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index eb59a6dce..93866c856 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -30,7 +30,7 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo viewModel.loadBook(intent) initView() savedInstanceState?.let { - changeSourceDialog = supportFragmentManager.findFragmentByTag("changeSourceDialog") as? ChangeSourceDialog + changeSourceDialog = supportFragmentManager.findFragmentByTag(ChangeSourceDialog.tag) as? ChangeSourceDialog changeSourceDialog?.callBack = this } } @@ -128,7 +128,7 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo changeSourceDialog?.callBack = this } } - changeSourceDialog?.show(supportFragmentManager, "changeSource") + changeSourceDialog?.show(supportFragmentManager, ChangeSourceDialog.tag) } } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt index e563be35f..d81562bf8 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt @@ -16,6 +16,8 @@ import kotlinx.android.synthetic.main.dialog_change_source.* class ChangeSourceDialog : DialogFragment() { companion object { + const val tag = "changeSourceDialog" + fun newInstance(name: String, author: String): ChangeSourceDialog { val changeSourceDialog = ChangeSourceDialog() val bundle = Bundle() From fcdbc98d23b3ef0bebb0712f8c5dac6e2048ee41 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 15 Aug 2019 10:00:55 +0800 Subject: [PATCH 0678/1997] up --- .../main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt | 4 ++++ .../java/io/legado/app/ui/changesource/ChangeSourceDialog.kt | 5 +++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index 93866c856..56d0657ba 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -131,4 +131,8 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo changeSourceDialog?.show(supportFragmentManager, ChangeSourceDialog.tag) } } + + override fun changeTo(book: Book) { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt index d81562bf8..bc57ec135 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt @@ -9,6 +9,7 @@ import androidx.appcompat.widget.SearchView import androidx.fragment.app.DialogFragment import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.R +import io.legado.app.data.entities.Book import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.dialog_change_source.* @@ -91,8 +92,8 @@ class ChangeSourceDialog : DialogFragment() { } - public interface CallBack { - + interface CallBack { + fun changeTo(book: Book) } } \ No newline at end of file From 634b989b3cd9fd311e0336bf9c1a313560e02b32 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 15 Aug 2019 10:22:32 +0800 Subject: [PATCH 0679/1997] up --- .../ui/changesource/ChangeSourceAdapter.kt | 20 +++++++++++++++++++ .../app/ui/changesource/ChangeSourceDialog.kt | 3 +++ .../main/res/layout/item_change_source.xml | 18 +++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 app/src/main/res/layout/item_change_source.xml diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceAdapter.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceAdapter.kt index 455615940..f6e3e62d7 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceAdapter.kt @@ -1,2 +1,22 @@ package io.legado.app.ui.changesource +import android.content.Context +import io.legado.app.R +import io.legado.app.base.adapter.ItemViewHolder +import io.legado.app.base.adapter.SimpleRecyclerAdapter +import io.legado.app.data.entities.SearchBook +import kotlinx.android.synthetic.main.item_change_source.view.* + + +class ChangeSourceAdapter(context: Context) : SimpleRecyclerAdapter(context, R.layout.item_change_source) { + + + override fun convert(holder: ItemViewHolder, item: SearchBook, payloads: MutableList) { + holder.itemView.apply { + tv_origin.text = item.originName + tv_last.text = item.latestChapterTitle + } + } + + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt index bc57ec135..bb9f8ab67 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt @@ -30,6 +30,7 @@ class ChangeSourceDialog : DialogFragment() { } private lateinit var viewModel: ChangeSourceViewModel + private lateinit var changeSourceAdapter: ChangeSourceAdapter var callBack: CallBack? = null override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { @@ -66,7 +67,9 @@ class ChangeSourceDialog : DialogFragment() { } private fun initRecyclerView() { + changeSourceAdapter = ChangeSourceAdapter(requireContext()) recycler_view.layoutManager = LinearLayoutManager(context) + recycler_view.adapter = changeSourceAdapter } private fun initSearchView() { diff --git a/app/src/main/res/layout/item_change_source.xml b/app/src/main/res/layout/item_change_source.xml new file mode 100644 index 000000000..128f2710f --- /dev/null +++ b/app/src/main/res/layout/item_change_source.xml @@ -0,0 +1,18 @@ + + + + + + + \ No newline at end of file From 4ce13fb5927e6e7feb3b48932be4693e6260ca03 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 15 Aug 2019 10:27:41 +0800 Subject: [PATCH 0680/1997] up --- .../java/io/legado/app/ui/changesource/ChangeSourceDialog.kt | 1 + .../io/legado/app/ui/changesource/ChangeSourceViewModel.kt | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt index bb9f8ab67..b34cef9cc 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt @@ -52,6 +52,7 @@ class ChangeSourceDialog : DialogFragment() { showTitle() initRecyclerView() initSearchView() + viewModel.startSearch() } override fun onStart() { diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt index d5e36c5e3..218a4868f 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt @@ -8,4 +8,8 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio var name: String = "" var author: String = "" + + fun startSearch() { + + } } \ No newline at end of file From 1216e4270254477a59ebef15fdce194777e7542d Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 15 Aug 2019 11:46:05 +0800 Subject: [PATCH 0681/1997] up --- app/src/main/AndroidManifest.xml | 2 +- .../app/ui/bookinfo/BookInfoActivity.kt | 2 +- .../ui/main/bookshelf/BookshelfFragment.kt | 4 +-- .../ReadBookActivity.kt} | 31 ++++++++++++++---- .../ReadBookViewModel.kt} | 4 +-- .../ui/{read => readbook}/ReadBottomMenu.kt | 2 +- app/src/main/res/layout/activity_read.xml | 2 +- app/src/main/res/menu/read_book.xml | 32 +++++++++---------- app/src/main/res/menu/source_edit.xml | 2 +- 9 files changed, 50 insertions(+), 31 deletions(-) rename app/src/main/java/io/legado/app/ui/{read/ReadActivity.kt => readbook/ReadBookActivity.kt} (80%) rename app/src/main/java/io/legado/app/ui/{read/ReadViewModel.kt => readbook/ReadBookViewModel.kt} (92%) rename app/src/main/java/io/legado/app/ui/{read => readbook}/ReadBottomMenu.kt (99%) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 865feb29f..0a1261a13 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -54,7 +54,7 @@ - + diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index 56d0657ba..92e5c15c3 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -21,7 +21,7 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo override val viewModel: BookInfoViewModel get() = getViewModel(BookInfoViewModel::class.java) - var changeSourceDialog: ChangeSourceDialog? = null + private var changeSourceDialog: ChangeSourceDialog? = null override fun onActivityCreated(savedInstanceState: Bundle?) { setSupportActionBar(toolbar) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index 8ed1d310b..92a405b4c 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -26,7 +26,7 @@ import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.accentColor import io.legado.app.ui.bookinfo.BookInfoActivity import io.legado.app.ui.bookshelf.BookshelfActivity -import io.legado.app.ui.read.ReadActivity +import io.legado.app.ui.readbook.ReadBookActivity import io.legado.app.ui.search.SearchActivity import io.legado.app.utils.* import kotlinx.android.synthetic.main.dialog_edittext.view.* @@ -106,7 +106,7 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b } override fun open(book: Book) { - context?.startActivity(Pair("bookUrl", book.bookUrl)) + context?.startActivity(Pair("bookUrl", book.bookUrl)) } override fun openBookInfo(book: Book) { diff --git a/app/src/main/java/io/legado/app/ui/read/ReadActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt similarity index 80% rename from app/src/main/java/io/legado/app/ui/read/ReadActivity.kt rename to app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index ed29d2692..96857f8cf 100644 --- a/app/src/main/java/io/legado/app/ui/read/ReadActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.read +package io.legado.app.ui.readbook import android.os.Bundle import android.view.KeyEvent @@ -10,6 +10,8 @@ import androidx.core.view.isVisible import io.legado.app.App import io.legado.app.R import io.legado.app.base.VMBaseActivity +import io.legado.app.data.entities.Book +import io.legado.app.ui.changesource.ChangeSourceDialog import io.legado.app.ui.chapterlist.ChapterListActivity import io.legado.app.ui.replacerule.ReplaceRuleActivity import io.legado.app.utils.* @@ -18,10 +20,11 @@ import kotlinx.android.synthetic.main.view_title_bar.* import org.jetbrains.anko.sdk27.listeners.onClick import org.jetbrains.anko.startActivity -class ReadActivity : VMBaseActivity(R.layout.activity_read) { - override val viewModel: ReadViewModel - get() = getViewModel(ReadViewModel::class.java) +class ReadBookActivity : VMBaseActivity(R.layout.activity_read), ChangeSourceDialog.CallBack { + override val viewModel: ReadBookViewModel + get() = getViewModel(ReadBookViewModel::class.java) + private var changeSourceDialog: ChangeSourceDialog? = null private var menuBarShow: Boolean = false private lateinit var menuTopIn: Animation private lateinit var menuTopOut: Animation @@ -33,6 +36,10 @@ class ReadActivity : VMBaseActivity(R.layout.activity_read) { initAnimation() initView() viewModel.initData(intent) + savedInstanceState?.let { + changeSourceDialog = supportFragmentManager.findFragmentByTag(ChangeSourceDialog.tag) as? ChangeSourceDialog + changeSourceDialog?.callBack = this + } } private fun initAnimation() { @@ -129,7 +136,7 @@ class ReadActivity : VMBaseActivity(R.layout.activity_read) { } override fun toast(id: Int) { - this@ReadActivity.toast(id) + this@ReadBookActivity.toast(id) } override fun dismiss() { @@ -146,7 +153,15 @@ class ReadActivity : VMBaseActivity(R.layout.activity_read) { override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { - + R.id.menu_change_source -> { + if (changeSourceDialog == null) { + viewModel.book?.let { + changeSourceDialog = ChangeSourceDialog.newInstance(it.name, it.author) + changeSourceDialog?.callBack = this + } + } + changeSourceDialog?.show(supportFragmentManager, ChangeSourceDialog.tag) + } } return super.onCompatOptionsItemSelected(item) } @@ -185,4 +200,8 @@ class ReadActivity : VMBaseActivity(R.layout.activity_read) { } } } + + override fun changeTo(book: Book) { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/read/ReadViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt similarity index 92% rename from app/src/main/java/io/legado/app/ui/read/ReadViewModel.kt rename to app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index 3d0cc0b59..d793c0cb0 100644 --- a/app/src/main/java/io/legado/app/ui/read/ReadViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.read +package io.legado.app.ui.readbook import android.app.Application import android.content.Intent @@ -9,7 +9,7 @@ import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookSource import io.legado.app.model.WebBook -class ReadViewModel(application: Application) : BaseViewModel(application) { +class ReadBookViewModel(application: Application) : BaseViewModel(application) { var book: Book? = null var bookSource: BookSource? = null diff --git a/app/src/main/java/io/legado/app/ui/read/ReadBottomMenu.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBottomMenu.kt similarity index 99% rename from app/src/main/java/io/legado/app/ui/read/ReadBottomMenu.kt rename to app/src/main/java/io/legado/app/ui/readbook/ReadBottomMenu.kt index 196d86e9d..ba13a07aa 100644 --- a/app/src/main/java/io/legado/app/ui/read/ReadBottomMenu.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBottomMenu.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.read +package io.legado.app.ui.readbook import android.content.Context import android.util.AttributeSet diff --git a/app/src/main/res/layout/activity_read.xml b/app/src/main/res/layout/activity_read.xml index a7396af3d..e59480522 100644 --- a/app/src/main/res/layout/activity_read.xml +++ b/app/src/main/res/layout/activity_read.xml @@ -46,7 +46,7 @@ - - + - + - + - + diff --git a/app/src/main/res/menu/source_edit.xml b/app/src/main/res/menu/source_edit.xml index f9831f9a4..f1ee15173 100644 --- a/app/src/main/res/menu/source_edit.xml +++ b/app/src/main/res/menu/source_edit.xml @@ -15,7 +15,7 @@ app:showAsAction="ifRoom" /> From 8ed835b8cfd6ed9289d9825cc844f07cf43675b9 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 15 Aug 2019 11:48:00 +0800 Subject: [PATCH 0682/1997] up --- app/src/main/java/io/legado/app/ui/readrss/ReadRssActivity.kt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 app/src/main/java/io/legado/app/ui/readrss/ReadRssActivity.kt diff --git a/app/src/main/java/io/legado/app/ui/readrss/ReadRssActivity.kt b/app/src/main/java/io/legado/app/ui/readrss/ReadRssActivity.kt new file mode 100644 index 000000000..543d7968b --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/readrss/ReadRssActivity.kt @@ -0,0 +1,2 @@ +package io.legado.app.ui.readrss + From 1bd522181e74d6117fd624314ea447eef275bece Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 15 Aug 2019 13:58:35 +0800 Subject: [PATCH 0683/1997] up --- app/src/main/AndroidManifest.xml | 1 + .../io/legado/app/ui/readbook/ReadBookActivity.kt | 4 ++-- .../io/legado/app/ui/readrss/ReadRssActivity.kt | 13 +++++++++++++ .../{activity_read.xml => activity_read_book.xml} | 0 app/src/main/res/layout/activity_read_rss.xml | 7 +++++++ 5 files changed, 23 insertions(+), 2 deletions(-) rename app/src/main/res/layout/{activity_read.xml => activity_read_book.xml} (100%) create mode 100644 app/src/main/res/layout/activity_read_rss.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 0a1261a13..0e4a258e1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -56,6 +56,7 @@ + diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 96857f8cf..16b35573a 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -15,12 +15,12 @@ import io.legado.app.ui.changesource.ChangeSourceDialog import io.legado.app.ui.chapterlist.ChapterListActivity import io.legado.app.ui.replacerule.ReplaceRuleActivity import io.legado.app.utils.* -import kotlinx.android.synthetic.main.activity_read.* +import kotlinx.android.synthetic.main.activity_read_book.* import kotlinx.android.synthetic.main.view_title_bar.* import org.jetbrains.anko.sdk27.listeners.onClick import org.jetbrains.anko.startActivity -class ReadBookActivity : VMBaseActivity(R.layout.activity_read), ChangeSourceDialog.CallBack { +class ReadBookActivity : VMBaseActivity(R.layout.activity_read_book), ChangeSourceDialog.CallBack { override val viewModel: ReadBookViewModel get() = getViewModel(ReadBookViewModel::class.java) diff --git a/app/src/main/java/io/legado/app/ui/readrss/ReadRssActivity.kt b/app/src/main/java/io/legado/app/ui/readrss/ReadRssActivity.kt index 543d7968b..f73e43676 100644 --- a/app/src/main/java/io/legado/app/ui/readrss/ReadRssActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readrss/ReadRssActivity.kt @@ -1,2 +1,15 @@ package io.legado.app.ui.readrss +import android.os.Bundle +import io.legado.app.R +import io.legado.app.base.BaseActivity + + +class ReadRssActivity : BaseActivity(R.layout.activity_read_rss) { + + override fun onActivityCreated(savedInstanceState: Bundle?) { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_read.xml b/app/src/main/res/layout/activity_read_book.xml similarity index 100% rename from app/src/main/res/layout/activity_read.xml rename to app/src/main/res/layout/activity_read_book.xml diff --git a/app/src/main/res/layout/activity_read_rss.xml b/app/src/main/res/layout/activity_read_rss.xml new file mode 100644 index 000000000..d829e291c --- /dev/null +++ b/app/src/main/res/layout/activity_read_rss.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file From ea49ae88b7c18f956349277306d326dd302e5817 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 15 Aug 2019 14:28:44 +0800 Subject: [PATCH 0684/1997] up --- .../main/java/io/legado/app/data/dao/SearchBookDao.kt | 5 ++++- .../java/io/legado/app/data/entities/SearchShow.kt | 4 ++-- .../legado/app/ui/changesource/ChangeSourceDialog.kt | 7 +++++++ .../app/ui/changesource/ChangeSourceViewModel.kt | 11 +++++++++-- .../java/io/legado/app/ui/search/SearchActivity.kt | 2 +- .../java/io/legado/app/ui/search/SearchAdapter.kt | 4 ++-- .../java/io/legado/app/ui/search/SearchViewModel.kt | 4 ++-- app/src/main/res/layout/dialog_change_source.xml | 2 +- app/src/main/res/layout/item_change_source.xml | 2 +- 9 files changed, 29 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt b/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt index f6f3d8f07..a5f76d907 100644 --- a/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt @@ -24,7 +24,10 @@ interface SearchBookDao { fun getSearchBook(bookUrl: String): SearchBook? @Query("select * from searchBooks where name = :name and author = :author order by originOrder limit 1") - fun getByNameAuthor(name: String, author: String?): SearchBook? + fun getFirstByNameAuthor(name: String, author: String): SearchBook? + + @Query("select * from searchBooks where name = :name and author = :author order by originOrder") + fun getByNameAuthor(name: String, author: String): List @Insert(onConflict = OnConflictStrategy.REPLACE) fun insert(vararg searchBook: SearchBook): List diff --git a/app/src/main/java/io/legado/app/data/entities/SearchShow.kt b/app/src/main/java/io/legado/app/data/entities/SearchShow.kt index 31268aefb..1611e04ac 100644 --- a/app/src/main/java/io/legado/app/data/entities/SearchShow.kt +++ b/app/src/main/java/io/legado/app/data/entities/SearchShow.kt @@ -3,8 +3,8 @@ package io.legado.app.data.entities import io.legado.app.utils.splitNotBlank data class SearchShow( - var name: String? = null, - var author: String? = null, + var name: String = "", + var author: String = "", var kind: String? = null, var coverUrl: String? = null, var intro: String? = null, diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt index b34cef9cc..8ae5c0857 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt @@ -5,8 +5,11 @@ import android.util.DisplayMetrics import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.LinearLayout import androidx.appcompat.widget.SearchView import androidx.fragment.app.DialogFragment +import androidx.lifecycle.Observer +import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.R import io.legado.app.data.entities.Book @@ -70,7 +73,11 @@ class ChangeSourceDialog : DialogFragment() { private fun initRecyclerView() { changeSourceAdapter = ChangeSourceAdapter(requireContext()) recycler_view.layoutManager = LinearLayoutManager(context) + recycler_view.addItemDecoration(DividerItemDecoration(requireContext(), LinearLayout.VERTICAL)) recycler_view.adapter = changeSourceAdapter + viewModel.searchBookData.observe(viewLifecycleOwner, Observer { + changeSourceAdapter.addItems(it) + }) } private fun initSearchView() { diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt index 218a4868f..c95189097 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt @@ -1,15 +1,22 @@ package io.legado.app.ui.changesource import android.app.Application +import androidx.lifecycle.MutableLiveData +import io.legado.app.App import io.legado.app.base.BaseViewModel +import io.legado.app.data.entities.SearchBook class ChangeSourceViewModel(application: Application) : BaseViewModel(application) { var name: String = "" var author: String = "" - + val searchBookData = MutableLiveData>() fun startSearch() { - + execute { + App.db.searchBookDao().getByNameAuthor(name, author).let { + searchBookData.postValue(it) + } + } } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt index 2493916b3..61030e62c 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt @@ -78,7 +78,7 @@ class SearchActivity : VMBaseActivity(R.layout.activity_search) searchBookData?.observe(this, Observer { adapter.submitList(it) }) } - override fun showBookInfo(name: String, author: String?) { + override fun showBookInfo(name: String, author: String) { viewModel.getSearchBook(name, author) { searchBook -> searchBook?.let { startActivity(Pair("searchBookUrl", it.bookUrl)) diff --git a/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt b/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt index e6653287f..d3bcf6bed 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt @@ -96,12 +96,12 @@ class SearchAdapter : PagedListAdapter(D .setAsDrawable(iv_cover) } onClick { - callBack?.showBookInfo(searchBook.name!!, searchBook.author) + callBack?.showBookInfo(searchBook.name, searchBook.author) } } } interface CallBack { - fun showBookInfo(name: String, author: String?) + fun showBookInfo(name: String, author: String) } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt b/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt index 870e64d05..7ab0db2d8 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt @@ -48,9 +48,9 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { task?.cancel() } - fun getSearchBook(name: String, author: String?, success: ((searchBook: SearchBook?) -> Unit)?) { + fun getSearchBook(name: String, author: String, success: ((searchBook: SearchBook?) -> Unit)?) { execute { - val searchBook = App.db.searchBookDao().getByNameAuthor(name, author) + val searchBook = App.db.searchBookDao().getFirstByNameAuthor(name, author) success?.invoke(searchBook) } } diff --git a/app/src/main/res/layout/dialog_change_source.xml b/app/src/main/res/layout/dialog_change_source.xml index cd6738e3c..5d96cbdf8 100644 --- a/app/src/main/res/layout/dialog_change_source.xml +++ b/app/src/main/res/layout/dialog_change_source.xml @@ -18,7 +18,7 @@ diff --git a/app/src/main/res/layout/item_change_source.xml b/app/src/main/res/layout/item_change_source.xml index 128f2710f..2cf9b5649 100644 --- a/app/src/main/res/layout/item_change_source.xml +++ b/app/src/main/res/layout/item_change_source.xml @@ -1,7 +1,7 @@ Date: Thu, 15 Aug 2019 15:51:38 +0800 Subject: [PATCH 0685/1997] up --- .../main/res/layout/item_change_source.xml | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/app/src/main/res/layout/item_change_source.xml b/app/src/main/res/layout/item_change_source.xml index 2cf9b5649..cc1364b64 100644 --- a/app/src/main/res/layout/item_change_source.xml +++ b/app/src/main/res/layout/item_change_source.xml @@ -1,18 +1,40 @@ - + xmlns:app="http://schemas.android.com/apk/res-auto" + android:background="?android:attr/selectableItemBackground" + android:padding="10dp"> + android:singleLine="true" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toLeftOf="@+id/iv_checked" /> - \ No newline at end of file + android:singleLine="true" + app:layout_constraintTop_toBottomOf="@+id/tv_origin" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toLeftOf="@+id/iv_checked" /> + + + + \ No newline at end of file From d95f54924c50e58bf095399c8adc48cc49a4f2fb Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 15 Aug 2019 16:11:31 +0800 Subject: [PATCH 0686/1997] up --- .../ui/changesource/ChangeSourceAdapter.kt | 19 ++++++++++++++++++- .../app/ui/changesource/ChangeSourceDialog.kt | 18 +++++++++++++++++- .../ui/changesource/ChangeSourceViewModel.kt | 2 +- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceAdapter.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceAdapter.kt index f6e3e62d7..368527d4f 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceAdapter.kt @@ -5,18 +5,35 @@ import io.legado.app.R import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.data.entities.SearchBook +import io.legado.app.utils.invisible +import io.legado.app.utils.visible import kotlinx.android.synthetic.main.item_change_source.view.* +import org.jetbrains.anko.sdk27.listeners.onClick class ChangeSourceAdapter(context: Context) : SimpleRecyclerAdapter(context, R.layout.item_change_source) { + var callBack: CallBack? = null override fun convert(holder: ItemViewHolder, item: SearchBook, payloads: MutableList) { holder.itemView.apply { + this.onClick { + callBack?.changeTo(item) + } tv_origin.text = item.originName tv_last.text = item.latestChapterTitle + callBack?.let { + if (it.curBookUrl() == item.bookUrl) { + iv_checked.visible() + } else { + iv_checked.invisible() + } + } ?: iv_checked.invisible() } } - + interface CallBack { + fun changeTo(searchBook: SearchBook) + fun curBookUrl(): String + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt index 8ae5c0857..9646a922d 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt @@ -13,6 +13,7 @@ import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.R import io.legado.app.data.entities.Book +import io.legado.app.data.entities.SearchBook import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.dialog_change_source.* @@ -22,11 +23,12 @@ class ChangeSourceDialog : DialogFragment() { companion object { const val tag = "changeSourceDialog" - fun newInstance(name: String, author: String): ChangeSourceDialog { + fun newInstance(name: String, author: String, bookUrl: String? = null): ChangeSourceDialog { val changeSourceDialog = ChangeSourceDialog() val bundle = Bundle() bundle.putString("name", name) bundle.putString("author", author) + bundle.putString("bookUrl", bookUrl) changeSourceDialog.arguments = bundle return changeSourceDialog } @@ -50,6 +52,9 @@ class ChangeSourceDialog : DialogFragment() { bundle.getString("author")?.let { viewModel.author = it } + bundle.getString("bookUrl")?.let { + viewModel.curBookUrl = it + } } tool_bar.inflateMenu(R.menu.search_view) showTitle() @@ -72,6 +77,17 @@ class ChangeSourceDialog : DialogFragment() { private fun initRecyclerView() { changeSourceAdapter = ChangeSourceAdapter(requireContext()) + changeSourceAdapter.callBack = object : ChangeSourceAdapter.CallBack { + override fun changeTo(searchBook: SearchBook) { + callBack?.changeTo(searchBook.toBook()) + dismiss() + } + + override fun curBookUrl(): String { + return viewModel.curBookUrl + } + + } recycler_view.layoutManager = LinearLayoutManager(context) recycler_view.addItemDecoration(DividerItemDecoration(requireContext(), LinearLayout.VERTICAL)) recycler_view.adapter = changeSourceAdapter diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt index c95189097..be95f7065 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt @@ -7,7 +7,7 @@ import io.legado.app.base.BaseViewModel import io.legado.app.data.entities.SearchBook class ChangeSourceViewModel(application: Application) : BaseViewModel(application) { - + var curBookUrl = "" var name: String = "" var author: String = "" val searchBookData = MutableLiveData>() From 9483e0346cda013a50fc703fbc048c26acaad088 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 15 Aug 2019 16:12:26 +0800 Subject: [PATCH 0687/1997] up --- app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt | 2 +- app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index 92e5c15c3..a4bb266bd 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -133,6 +133,6 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo } override fun changeTo(book: Book) { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 16b35573a..55266c02e 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -202,6 +202,6 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } override fun changeTo(book: Book) { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } } \ No newline at end of file From 65ad0e1f497f79204ce1b5489682f084fc7a4713 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 15 Aug 2019 16:42:57 +0800 Subject: [PATCH 0688/1997] up --- .../main/java/io/legado/app/ui/main/MainActivity.kt | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt index 41dd8574a..af8765812 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt @@ -29,7 +29,7 @@ import kotlinx.coroutines.withContext class MainActivity : VMBaseActivity(R.layout.activity_main), BottomNavigationView.OnNavigationItemSelectedListener, - ViewPager.OnPageChangeListener { + ViewPager.OnPageChangeListener by ViewPager.SimpleOnPageChangeListener() { override val viewModel: MainViewModel get() = getViewModel(MainViewModel::class.java) @@ -73,16 +73,6 @@ class MainActivity : VMBaseActivity(R.layout.activity_main), } } - override fun onPageScrollStateChanged(state: Int) { - - } - - - override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) { - - } - - override fun onPageSelected(position: Int) { bottom_navigation_view.menu.getItem(position).isChecked = true } From 28791a18fae21000d4a2ac4a90d82ac0a0040e67 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 15 Aug 2019 17:38:57 +0800 Subject: [PATCH 0689/1997] up --- .../java/io/legado/app/base/BaseService.kt | 21 +++++ .../io/legado/app/service/ReadAloudService.kt | 87 +++++++++++++++++-- 2 files changed, 103 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/io/legado/app/base/BaseService.kt diff --git a/app/src/main/java/io/legado/app/base/BaseService.kt b/app/src/main/java/io/legado/app/base/BaseService.kt new file mode 100644 index 000000000..c67acb95c --- /dev/null +++ b/app/src/main/java/io/legado/app/base/BaseService.kt @@ -0,0 +1,21 @@ +package io.legado.app.base + +import android.app.Service +import android.content.Intent +import android.os.IBinder +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.MainScope +import kotlinx.coroutines.cancel + +abstract class BaseService : Service(), CoroutineScope by MainScope() { + + override fun onBind(intent: Intent?): IBinder? { + return null + } + + + override fun onDestroy() { + super.onDestroy() + cancel() + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index 2735e54be..04f4670ee 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -1,12 +1,89 @@ package io.legado.app.service -import android.app.Service import android.content.Intent -import android.os.IBinder +import android.speech.tts.TextToSpeech +import io.legado.app.R +import io.legado.app.base.BaseService +import io.legado.app.utils.toast +import kotlinx.coroutines.launch +import java.util.* -class ReadAloudService : Service() { - override fun onBind(intent: Intent?): IBinder? { - return null +class ReadAloudService : BaseService(), TextToSpeech.OnInitListener { + + companion object { + fun paly() { + + } + + fun pause() { + + } + + fun resume() { + + } + + fun stop() { + + } + } + + private var textToSpeech: TextToSpeech? = null + private var ttsIsSuccess: Boolean = false + + override fun onCreate() { + super.onCreate() + textToSpeech = TextToSpeech(this, this) + + } + + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + intent?.action?.let { action -> + when (action) { + "play" -> { + + } + "pause" -> { + + } + "resume" -> { + + } + "stop" -> { + + } + } + } + return super.onStartCommand(intent, flags, startId) + } + + override fun onInit(status: Int) { + launch { + if (status == TextToSpeech.SUCCESS) { + val result = textToSpeech?.setLanguage(Locale.CHINA) + if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) { + toast(R.string.tts_fix) + toTTSSetting() + } else { + ttsIsSuccess = true + } + } else { + toast(R.string.tts_init_failed) + } + } + } + + private fun toTTSSetting() { + //跳转到文字转语音设置界面 + + try { + val intent = Intent() + intent.action = "com.android.settings.TTS_SETTINGS" + intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK + startActivity(intent) + } catch (ignored: Exception) { + toast(R.string.tip_cannot_jump_setting_page) + } } } \ No newline at end of file From 830f485188726e469dee0d818e8fb8655a3834d6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 15 Aug 2019 19:13:43 +0800 Subject: [PATCH 0690/1997] up --- .../io/legado/app/service/ReadAloudService.kt | 83 ++++++++++++++++--- 1 file changed, 73 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index 04f4670ee..d3d28a16d 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -1,30 +1,46 @@ package io.legado.app.service +import android.content.Context import android.content.Intent +import android.media.AudioManager import android.speech.tts.TextToSpeech +import android.speech.tts.UtteranceProgressListener import io.legado.app.R import io.legado.app.base.BaseService import io.legado.app.utils.toast import kotlinx.coroutines.launch import java.util.* -class ReadAloudService : BaseService(), TextToSpeech.OnInitListener { +class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManager.OnAudioFocusChangeListener { companion object { - fun paly() { + var isRun = false + fun paly(context: Context, title: String, body: String) { } - fun pause() { - + fun pause(context: Context) { + if (isRun) { + val intent = Intent(context, ReadAloudService::class.java) + intent.action = "pause" + context.startService(intent) + } } - fun resume() { - + fun resume(context: Context) { + if (isRun) { + val intent = Intent(context, ReadAloudService::class.java) + intent.action = "resume" + context.startService(intent) + } } - fun stop() { - + fun stop(context: Context) { + if (isRun) { + val intent = Intent(context, ReadAloudService::class.java) + intent.action = "stop" + context.startService(intent) + } } } @@ -33,10 +49,16 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener { override fun onCreate() { super.onCreate() + isRun = true textToSpeech = TextToSpeech(this, this) } + override fun onDestroy() { + super.onDestroy() + isRun = false + } + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { intent?.action?.let { action -> when (action) { @@ -50,7 +72,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener { } "stop" -> { - + stopSelf() } } } @@ -65,6 +87,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener { toast(R.string.tts_fix) toTTSSetting() } else { + textToSpeech?.setOnUtteranceProgressListener(TTSUtteranceListener()) ttsIsSuccess = true } } else { @@ -73,9 +96,26 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener { } } + override fun onAudioFocusChange(focusChange: Int) { + when (focusChange) { + AudioManager.AUDIOFOCUS_GAIN -> { + // 重新获得焦点, 可做恢复播放,恢复后台音量的操作 + } + + AudioManager.AUDIOFOCUS_LOSS -> { + // 永久丢失焦点除非重新主动获取,这种情况是被其他播放器抢去了焦点, 为避免与其他播放器混音,可将音乐暂停 + } + AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> { + // 暂时丢失焦点,这种情况是被其他应用申请了短暂的焦点,可压低后台音量 + } + AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> { + // 短暂丢失焦点,这种情况是被其他应用申请了短暂的焦点希望其他声音能压低音量(或者关闭声音)凸显这个声音(比如短信提示音), + } + } + } + private fun toTTSSetting() { //跳转到文字转语音设置界面 - try { val intent = Intent() intent.action = "com.android.settings.TTS_SETTINGS" @@ -86,4 +126,27 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener { } } + /** + * 朗读监听 + */ + private inner class TTSUtteranceListener : UtteranceProgressListener() { + + override fun onStart(s: String) { + + } + + override fun onDone(s: String) { + + } + + override fun onError(s: String) { + + } + + override fun onRangeStart(utteranceId: String, start: Int, end: Int, frame: Int) { + super.onRangeStart(utteranceId, start, end, frame) + + } + } + } \ No newline at end of file From 124d8e8dbd8623c47f7ae33fb938b19098177861 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 15 Aug 2019 20:24:11 +0800 Subject: [PATCH 0691/1997] up --- app/build.gradle | 4 +- .../app/receiver/MediaButtonIntentReceiver.kt | 55 +++++++++++++++ .../io/legado/app/service/ReadAloudService.kt | 67 ++++++++++++++++++- 3 files changed, 124 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/io/legado/app/receiver/MediaButtonIntentReceiver.kt diff --git a/app/build.gradle b/app/build.gradle index ec7a99bee..a70965c2b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -79,11 +79,12 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" //androidX - implementation 'androidx.core:core-ktx:1.2.0-alpha02' + implementation 'androidx.core:core-ktx:1.2.0-alpha03' implementation 'androidx.appcompat:appcompat:1.1.0-rc01' implementation 'androidx.preference:preference:1.1.0-rc01' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0' + implementation 'androidx.media:media:1.1.0-rc01' implementation 'com.google.android.material:material:1.1.0-alpha09' implementation 'com.google.android:flexbox:1.1.0' @@ -134,4 +135,5 @@ dependencies { //颜色选择 implementation 'com.jaredrummler:colorpicker:1.1.0' + } diff --git a/app/src/main/java/io/legado/app/receiver/MediaButtonIntentReceiver.kt b/app/src/main/java/io/legado/app/receiver/MediaButtonIntentReceiver.kt new file mode 100644 index 000000000..829a4d40d --- /dev/null +++ b/app/src/main/java/io/legado/app/receiver/MediaButtonIntentReceiver.kt @@ -0,0 +1,55 @@ +package io.legado.app.receiver + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.view.KeyEvent + + +/** + * Created by GKF on 2018/1/6. + * 监听耳机键 + */ + +class MediaButtonIntentReceiver : BroadcastReceiver() { + + companion object { + val TAG = MediaButtonIntentReceiver::class.java.simpleName + + fun handleIntent(context: Context, intent: Intent): Boolean { + val intentAction = intent.action + if (Intent.ACTION_MEDIA_BUTTON == intentAction) { + val event = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT) ?: return false + + val keycode = event.keyCode + val action = event.action + + val command: String? = null + when (keycode) { + KeyEvent.KEYCODE_MEDIA_STOP, KeyEvent.KEYCODE_MEDIA_PAUSE, KeyEvent.KEYCODE_MEDIA_PLAY, KeyEvent.KEYCODE_HEADSETHOOK, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE -> { + } + else -> { + } + }// command = ReadAloudService.ActionMediaButton; + if (command != null) { + if (action == KeyEvent.ACTION_DOWN) { + readAloud(context, command) + return true + } + } + } + return false + } + + private fun readAloud(context: Context, command: String?) { + + } + } + + override fun onReceive(context: Context, intent: Intent) { + if (handleIntent(context, intent) && isOrderedBroadcast) { + abortBroadcast() + } + } + +} diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index d3d28a16d..bbfa3525d 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -1,12 +1,19 @@ package io.legado.app.service +import android.app.PendingIntent +import android.content.ComponentName import android.content.Context import android.content.Intent +import android.media.AudioAttributes +import android.media.AudioFocusRequest import android.media.AudioManager +import android.os.Build import android.speech.tts.TextToSpeech import android.speech.tts.UtteranceProgressListener +import android.support.v4.media.session.MediaSessionCompat import io.legado.app.R import io.legado.app.base.BaseService +import io.legado.app.receiver.MediaButtonIntentReceiver import io.legado.app.utils.toast import kotlinx.coroutines.launch import java.util.* @@ -14,6 +21,7 @@ import java.util.* class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManager.OnAudioFocusChangeListener { companion object { + val tag = ReadAloudService::class.java.simpleName var isRun = false fun paly(context: Context, title: String, body: String) { @@ -46,11 +54,17 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage private var textToSpeech: TextToSpeech? = null private var ttsIsSuccess: Boolean = false + private lateinit var audioManager: AudioManager + private lateinit var mFocusRequest: AudioFocusRequest + private var mediaSessionCompat: MediaSessionCompat? = null override fun onCreate() { super.onCreate() isRun = true textToSpeech = TextToSpeech(this, this) + audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager + initFocusRequest() + initMediaSession() } @@ -96,12 +110,63 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage } } + /** + * 初始化MediaSession + */ + private fun initMediaSession() { + val mComponent = ComponentName(packageName, MediaButtonIntentReceiver::class.java.name) + val mediaButtonIntent = Intent(Intent.ACTION_MEDIA_BUTTON) + mediaButtonIntent.component = mComponent + val mediaButtonReceiverPendingIntent = PendingIntent.getBroadcast( + this, 0, + mediaButtonIntent, PendingIntent.FLAG_CANCEL_CURRENT + ) + + mediaSessionCompat = MediaSessionCompat(this, tag, mComponent, mediaButtonReceiverPendingIntent) + mediaSessionCompat?.setCallback(object : MediaSessionCompat.Callback() { + override fun onMediaButtonEvent(mediaButtonEvent: Intent): Boolean { + return MediaButtonIntentReceiver.handleIntent(this@ReadAloudService, mediaButtonEvent) + } + }) + mediaSessionCompat?.setMediaButtonReceiver(mediaButtonReceiverPendingIntent) + } + + private fun initFocusRequest() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val mPlaybackAttributes = AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_MEDIA) + .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) + .build() + mFocusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN) + .setAudioAttributes(mPlaybackAttributes) + .setAcceptsDelayedFocusGain(true) + .setOnAudioFocusChangeListener(this) + .build() + } + } + + /** + * @return 音频焦点 + */ + private fun requestFocus(): Boolean { + val request: Int = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + audioManager.requestAudioFocus(mFocusRequest) + } else { + @Suppress("DEPRECATION") + audioManager.requestAudioFocus( + this, + AudioManager.STREAM_MUSIC, + AudioManager.AUDIOFOCUS_GAIN + ) + } + return request == AudioManager.AUDIOFOCUS_REQUEST_GRANTED + } + override fun onAudioFocusChange(focusChange: Int) { when (focusChange) { AudioManager.AUDIOFOCUS_GAIN -> { // 重新获得焦点, 可做恢复播放,恢复后台音量的操作 } - AudioManager.AUDIOFOCUS_LOSS -> { // 永久丢失焦点除非重新主动获取,这种情况是被其他播放器抢去了焦点, 为避免与其他播放器混音,可将音乐暂停 } From a4004d4a979e66f4e896a14aa71763aa3606f915 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 15 Aug 2019 20:34:09 +0800 Subject: [PATCH 0692/1997] up --- app/src/main/AndroidManifest.xml | 16 ++++++++++++++++ app/src/main/res/xml/file_paths.xml | 9 +++++++++ 2 files changed, 25 insertions(+) create mode 100644 app/src/main/res/xml/file_paths.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 0e4a258e1..b30a3d6ff 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,6 +63,22 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/file_paths.xml b/app/src/main/res/xml/file_paths.xml new file mode 100644 index 000000000..cdcf27e1b --- /dev/null +++ b/app/src/main/res/xml/file_paths.xml @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file From a353d8cbd1a602a423e744d66c8e004bb6c3d8e5 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 15 Aug 2019 22:17:01 +0800 Subject: [PATCH 0693/1997] up --- .../main/java/io/legado/app/constant/Bus.kt | 1 + .../java/io/legado/app/constant/Status.kt | 5 + .../io/legado/app/help/PendingIntentHelp.kt | 23 +++ .../io/legado/app/service/ReadAloudService.kt | 135 ++++++++++++++++-- 4 files changed, 155 insertions(+), 9 deletions(-) create mode 100644 app/src/main/java/io/legado/app/constant/Status.kt create mode 100644 app/src/main/java/io/legado/app/help/PendingIntentHelp.kt diff --git a/app/src/main/java/io/legado/app/constant/Bus.kt b/app/src/main/java/io/legado/app/constant/Bus.kt index ab7d44c84..4e90b7d82 100644 --- a/app/src/main/java/io/legado/app/constant/Bus.kt +++ b/app/src/main/java/io/legado/app/constant/Bus.kt @@ -3,4 +3,5 @@ package io.legado.app.constant object Bus { const val RECREATE = "RECREATE" const val UP_BOOK = "sourceDebugLog" + const val ALOUD_STATE = "aloud_state" } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/constant/Status.kt b/app/src/main/java/io/legado/app/constant/Status.kt new file mode 100644 index 000000000..605b37e51 --- /dev/null +++ b/app/src/main/java/io/legado/app/constant/Status.kt @@ -0,0 +1,5 @@ +package io.legado.app.constant + +object Status { + const val NEXT = 2 +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/help/PendingIntentHelp.kt b/app/src/main/java/io/legado/app/help/PendingIntentHelp.kt new file mode 100644 index 000000000..2105aa68e --- /dev/null +++ b/app/src/main/java/io/legado/app/help/PendingIntentHelp.kt @@ -0,0 +1,23 @@ +package io.legado.app.help + +import android.app.PendingIntent +import android.content.Context +import android.content.Intent +import io.legado.app.ui.readbook.ReadBookActivity + +object PendingIntentHelp { + + fun readBookActivityPendingIntent(context: Context): PendingIntent { + val intent = Intent(context, ReadBookActivity::class.java) + intent.action = "" + return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) + } + + fun aloudServicePendingIntent(context: Context, actionStr: String): PendingIntent { + val intent = Intent(context, this.javaClass) + intent.action = actionStr + return PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) + } + + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index bbfa3525d..d2f2506b3 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -1,9 +1,8 @@ package io.legado.app.service import android.app.PendingIntent -import android.content.ComponentName -import android.content.Context -import android.content.Intent +import android.content.* +import android.graphics.BitmapFactory import android.media.AudioAttributes import android.media.AudioFocusRequest import android.media.AudioManager @@ -11,9 +10,16 @@ import android.os.Build import android.speech.tts.TextToSpeech import android.speech.tts.UtteranceProgressListener import android.support.v4.media.session.MediaSessionCompat +import android.support.v4.media.session.PlaybackStateCompat +import androidx.core.app.NotificationCompat import io.legado.app.R import io.legado.app.base.BaseService +import io.legado.app.constant.AppConst +import io.legado.app.constant.Bus +import io.legado.app.constant.Status +import io.legado.app.help.PendingIntentHelp import io.legado.app.receiver.MediaButtonIntentReceiver +import io.legado.app.utils.postEvent import io.legado.app.utils.toast import kotlinx.coroutines.launch import java.util.* @@ -21,8 +27,16 @@ import java.util.* class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManager.OnAudioFocusChangeListener { companion object { - val tag = ReadAloudService::class.java.simpleName + val tag: String = ReadAloudService::class.java.simpleName var isRun = false + const val MEDIA_SESSION_ACTIONS = (PlaybackStateCompat.ACTION_PLAY + or PlaybackStateCompat.ACTION_PAUSE + or PlaybackStateCompat.ACTION_PLAY_PAUSE + or PlaybackStateCompat.ACTION_SKIP_TO_NEXT + or PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS + or PlaybackStateCompat.ACTION_STOP + or PlaybackStateCompat.ACTION_SEEK_TO) + fun paly(context: Context, title: String, body: String) { } @@ -52,11 +66,20 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage } } + private val notificationId = 112201 private var textToSpeech: TextToSpeech? = null private var ttsIsSuccess: Boolean = false private lateinit var audioManager: AudioManager private lateinit var mFocusRequest: AudioFocusRequest private var mediaSessionCompat: MediaSessionCompat? = null + private var broadcastReceiver: BroadcastReceiver? = null + private var speak: Boolean = true + private var nowSpeak: Int = 0 + private val contentList = arrayListOf() + private var pause = false + private var title: String = "" + private var subtitle: String = "" + private var timeMinute: Int = 0 override fun onCreate() { super.onCreate() @@ -65,12 +88,15 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager initFocusRequest() initMediaSession() - + initBroadcastReceiver() + upMediaSessionPlaybackState() + upNotification() } override fun onDestroy() { super.onDestroy() isRun = false + unregisterReceiver(broadcastReceiver) } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { @@ -145,6 +171,37 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage } } + private fun initBroadcastReceiver() { + broadcastReceiver = object : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + val action = intent.action + if (AudioManager.ACTION_AUDIO_BECOMING_NOISY == action) { + pauseReadAloud(true) + } + } + } + val intentFilter = IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY) + registerReceiver(broadcastReceiver, intentFilter) + } + + private fun pauseReadAloud(pause: Boolean) { + textToSpeech?.stop() + } + + private fun resumeReadAloud() { + + } + + private fun playTTS() { + if (contentList.size < 1) { + postEvent(Bus.ALOUD_STATE, Status.NEXT) + return + } + if (ttsIsSuccess && !speak && requestFocus()) { + + } + } + /** * @return 音频焦点 */ @@ -162,6 +219,18 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage return request == AudioManager.AUDIOFOCUS_REQUEST_GRANTED } + private fun upMediaSessionPlaybackState() { + mediaSessionCompat?.setPlaybackState( + PlaybackStateCompat.Builder() + .setActions(MEDIA_SESSION_ACTIONS) + .setState( + if (speak) PlaybackStateCompat.STATE_PLAYING else PlaybackStateCompat.STATE_PAUSED, + nowSpeak.toLong(), 1f + ) + .build() + ) + } + override fun onAudioFocusChange(focusChange: Int) { when (focusChange) { AudioManager.AUDIOFOCUS_GAIN -> { @@ -191,6 +260,58 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage } } + /** + * 更新通知 + */ + private fun upNotification() { + var nTitle: String = when { + pause -> getString(R.string.read_aloud_pause) + timeMinute in 1..60 -> getString(R.string.read_aloud_timer, timeMinute) + else -> getString(R.string.read_aloud_t) + } + nTitle += ": $title" + if (subtitle.isEmpty()) + subtitle = getString(R.string.read_aloud_s) + val builder = NotificationCompat.Builder(this, AppConst.channelIdReadAloud) + .setSmallIcon(R.drawable.ic_volume_up) + .setLargeIcon(BitmapFactory.decodeResource(resources, R.drawable.icon_read_book)) + .setOngoing(true) + .setContentTitle(nTitle) + .setContentText(subtitle) + .setContentIntent(PendingIntentHelp.readBookActivityPendingIntent(this)) + if (pause) { + builder.addAction( + R.drawable.ic_play_24dp, + getString(R.string.resume), + PendingIntentHelp.aloudServicePendingIntent(this, "resume") + ) + } else { + builder.addAction( + R.drawable.ic_pause_24dp, + getString(R.string.pause), + PendingIntentHelp.aloudServicePendingIntent(this, "pause") + ) + } + builder.addAction( + R.drawable.ic_stop_black_24dp, + getString(R.string.stop), + PendingIntentHelp.aloudServicePendingIntent(this, "stop") + ) + builder.addAction( + R.drawable.ic_time_add_24dp, + getString(R.string.set_timer), + PendingIntentHelp.aloudServicePendingIntent(this, "setTimer") + ) + builder.setStyle( + androidx.media.app.NotificationCompat.MediaStyle() + .setMediaSession(mediaSessionCompat?.sessionToken) + .setShowActionsInCompactView(0, 1, 2) + ) + builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) + val notification = builder.build() + startForeground(notificationId, notification) + } + /** * 朗读监听 */ @@ -208,10 +329,6 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage } - override fun onRangeStart(utteranceId: String, start: Int, end: Int, frame: Int) { - super.onRangeStart(utteranceId, start, end, frame) - - } } } \ No newline at end of file From 7fee8d0952262ee2bfde764b90e74c072811cda0 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 15 Aug 2019 22:38:52 +0800 Subject: [PATCH 0694/1997] up --- .../main/java/io/legado/app/ui/readbook/ReadBottomMenu.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBottomMenu.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBottomMenu.kt index ba13a07aa..461396919 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBottomMenu.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBottomMenu.kt @@ -5,10 +5,12 @@ import android.util.AttributeSet import android.widget.FrameLayout import android.widget.SeekBar import io.legado.app.R +import io.legado.app.service.ReadAloudService import io.legado.app.utils.gone import io.legado.app.utils.visible import kotlinx.android.synthetic.main.view_read_bottom_menu.view.* import org.jetbrains.anko.sdk27.listeners.onClick +import org.jetbrains.anko.sdk27.listeners.onLongClick class ReadBottomMenu : FrameLayout { @@ -69,7 +71,8 @@ class ReadBottomMenu : FrameLayout { //朗读 fab_read_aloud.onClick { callback?.onMediaButton() } //长按停止朗读 - fab_read_aloud.onClick { + fab_read_aloud.onLongClick { + ReadAloudService.stop(context) true } From d359571c6cff54225539b8a4d68a9fec515cf9c9 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 15 Aug 2019 22:40:48 +0800 Subject: [PATCH 0695/1997] up --- app/src/main/java/io/legado/app/constant/AppConst.kt | 3 ++- app/src/main/java/io/legado/app/constant/Pattern.kt | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/constant/AppConst.kt b/app/src/main/java/io/legado/app/constant/AppConst.kt index ab152e8a4..bc2b8d4b3 100644 --- a/app/src/main/java/io/legado/app/constant/AppConst.kt +++ b/app/src/main/java/io/legado/app/constant/AppConst.kt @@ -2,6 +2,7 @@ package io.legado.app.constant import io.legado.app.App import io.legado.app.R +import javax.script.ScriptEngine import javax.script.ScriptEngineManager object AppConst { @@ -14,7 +15,7 @@ object AppConst { const val userAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.2357.134 Safari/537.36" - val SCRIPT_ENGINE = ScriptEngineManager().getEngineByName("rhino") + val SCRIPT_ENGINE: ScriptEngine = ScriptEngineManager().getEngineByName("rhino") val NOT_AVAILABLE = App.INSTANCE.getString(R.string.not_available) diff --git a/app/src/main/java/io/legado/app/constant/Pattern.kt b/app/src/main/java/io/legado/app/constant/Pattern.kt index 917f4d52e..fd623bf69 100644 --- a/app/src/main/java/io/legado/app/constant/Pattern.kt +++ b/app/src/main/java/io/legado/app/constant/Pattern.kt @@ -3,6 +3,6 @@ package io.legado.app.constant import java.util.regex.Pattern object Pattern { - val JS_PATTERN = Pattern.compile("([\\w\\W]*?|@js:[\\w\\W]*$)", Pattern.CASE_INSENSITIVE) - val EXP_PATTERN = Pattern.compile("\\{\\{([\\w\\W]*?)\\}\\}") + val JS_PATTERN: Pattern = Pattern.compile("([\\w\\W]*?|@js:[\\w\\W]*$)", Pattern.CASE_INSENSITIVE) + val EXP_PATTERN: Pattern = Pattern.compile("\\{\\{([\\w\\W]*?)\\}\\}") } \ No newline at end of file From 664c48af0f1c2caa09ce6327fdfb6727686cffa7 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 15 Aug 2019 22:44:40 +0800 Subject: [PATCH 0696/1997] up --- app/src/main/java/io/legado/app/constant/AppConst.kt | 7 +++++++ app/src/main/java/io/legado/app/constant/AppUtils.kt | 12 ------------ app/src/main/java/io/legado/app/constant/Status.kt | 3 +++ 3 files changed, 10 insertions(+), 12 deletions(-) delete mode 100644 app/src/main/java/io/legado/app/constant/AppUtils.kt diff --git a/app/src/main/java/io/legado/app/constant/AppConst.kt b/app/src/main/java/io/legado/app/constant/AppConst.kt index bc2b8d4b3..b414786c6 100644 --- a/app/src/main/java/io/legado/app/constant/AppConst.kt +++ b/app/src/main/java/io/legado/app/constant/AppConst.kt @@ -1,5 +1,7 @@ package io.legado.app.constant +import com.google.gson.Gson +import com.google.gson.GsonBuilder import io.legado.app.App import io.legado.app.R import javax.script.ScriptEngine @@ -19,4 +21,9 @@ object AppConst { val NOT_AVAILABLE = App.INSTANCE.getString(R.string.not_available) + val GSON_CONVERTER: Gson = GsonBuilder() + .disableHtmlEscaping() + .setPrettyPrinting() + .setDateFormat("yyyy-MM-dd HH:mm:ssZ") + .create() } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/constant/AppUtils.kt b/app/src/main/java/io/legado/app/constant/AppUtils.kt deleted file mode 100644 index 4910553be..000000000 --- a/app/src/main/java/io/legado/app/constant/AppUtils.kt +++ /dev/null @@ -1,12 +0,0 @@ -package io.legado.app.constant - -import com.google.gson.Gson -import com.google.gson.GsonBuilder - -object AppUtils { - val GSON_CONVERTER: Gson = GsonBuilder() - .disableHtmlEscaping() - .setPrettyPrinting() - .setDateFormat("yyyy-MM-dd HH:mm:ssZ") - .create() -} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/constant/Status.kt b/app/src/main/java/io/legado/app/constant/Status.kt index 605b37e51..0f1bff978 100644 --- a/app/src/main/java/io/legado/app/constant/Status.kt +++ b/app/src/main/java/io/legado/app/constant/Status.kt @@ -1,5 +1,8 @@ package io.legado.app.constant object Status { + const val STOP = 0 + const val PLAY = 1 const val NEXT = 2 + } \ No newline at end of file From debf517d1dddf072b1b315ea54adf588dad5ef37 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 15 Aug 2019 23:00:55 +0800 Subject: [PATCH 0697/1997] up --- app/build.gradle | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/build.gradle b/app/build.gradle index a70965c2b..4704be08a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -61,6 +61,9 @@ android { targetCompatibility = '1.8' } + kotlinOptions { + jvmTarget = "1.8" + } } From 43530e2246fca090ad93ab0950cf9fada7dd0108 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 16 Aug 2019 07:59:02 +0800 Subject: [PATCH 0698/1997] up --- app/src/main/AndroidManifest.xml | 2 +- ...{MediaButtonIntentReceiver.kt => MediaButtonReceiver.kt} | 4 ++-- app/src/main/java/io/legado/app/service/ReadAloudService.kt | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) rename app/src/main/java/io/legado/app/receiver/{MediaButtonIntentReceiver.kt => MediaButtonReceiver.kt} (92%) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b30a3d6ff..225fe2ea1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -64,7 +64,7 @@ - + diff --git a/app/src/main/java/io/legado/app/receiver/MediaButtonIntentReceiver.kt b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt similarity index 92% rename from app/src/main/java/io/legado/app/receiver/MediaButtonIntentReceiver.kt rename to app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt index 829a4d40d..9b6d62035 100644 --- a/app/src/main/java/io/legado/app/receiver/MediaButtonIntentReceiver.kt +++ b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt @@ -11,10 +11,10 @@ import android.view.KeyEvent * 监听耳机键 */ -class MediaButtonIntentReceiver : BroadcastReceiver() { +class MediaButtonReceiver : BroadcastReceiver() { companion object { - val TAG = MediaButtonIntentReceiver::class.java.simpleName + val TAG = MediaButtonReceiver::class.java.simpleName fun handleIntent(context: Context, intent: Intent): Boolean { val intentAction = intent.action diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index d2f2506b3..bc798a77b 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -18,7 +18,7 @@ import io.legado.app.constant.AppConst import io.legado.app.constant.Bus import io.legado.app.constant.Status import io.legado.app.help.PendingIntentHelp -import io.legado.app.receiver.MediaButtonIntentReceiver +import io.legado.app.receiver.MediaButtonReceiver import io.legado.app.utils.postEvent import io.legado.app.utils.toast import kotlinx.coroutines.launch @@ -140,7 +140,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage * 初始化MediaSession */ private fun initMediaSession() { - val mComponent = ComponentName(packageName, MediaButtonIntentReceiver::class.java.name) + val mComponent = ComponentName(packageName, MediaButtonReceiver::class.java.name) val mediaButtonIntent = Intent(Intent.ACTION_MEDIA_BUTTON) mediaButtonIntent.component = mComponent val mediaButtonReceiverPendingIntent = PendingIntent.getBroadcast( @@ -151,7 +151,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage mediaSessionCompat = MediaSessionCompat(this, tag, mComponent, mediaButtonReceiverPendingIntent) mediaSessionCompat?.setCallback(object : MediaSessionCompat.Callback() { override fun onMediaButtonEvent(mediaButtonEvent: Intent): Boolean { - return MediaButtonIntentReceiver.handleIntent(this@ReadAloudService, mediaButtonEvent) + return MediaButtonReceiver.handleIntent(this@ReadAloudService, mediaButtonEvent) } }) mediaSessionCompat?.setMediaButtonReceiver(mediaButtonReceiverPendingIntent) From 9035e15c3eccf3d7d05e46c649a090cf5a7c8878 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 16 Aug 2019 08:04:54 +0800 Subject: [PATCH 0699/1997] up --- .../main/java/io/legado/app/help/MediaHelp.kt | 20 ++++++++++++++++++ .../io/legado/app/service/ReadAloudService.kt | 2 ++ app/src/main/res/raw/silent_sound.mp3 | Bin 0 -> 6336 bytes 3 files changed, 22 insertions(+) create mode 100644 app/src/main/java/io/legado/app/help/MediaHelp.kt create mode 100644 app/src/main/res/raw/silent_sound.mp3 diff --git a/app/src/main/java/io/legado/app/help/MediaHelp.kt b/app/src/main/java/io/legado/app/help/MediaHelp.kt new file mode 100644 index 000000000..377fd5fbd --- /dev/null +++ b/app/src/main/java/io/legado/app/help/MediaHelp.kt @@ -0,0 +1,20 @@ +package io.legado.app.help + +import android.content.Context +import android.media.MediaPlayer +import io.legado.app.R + +object MediaHelp { + + + fun playSilentSound(mContext: Context) { + try { + // Stupid Android 8 "Oreo" hack to make media buttons work + val mMediaPlayer = MediaPlayer.create(mContext, R.raw.silent_sound) + mMediaPlayer.setOnCompletionListener { it.release() } + mMediaPlayer.start() + } catch (ignored: Exception) { + } + + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index bc798a77b..bd48eefed 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -17,6 +17,7 @@ import io.legado.app.base.BaseService import io.legado.app.constant.AppConst import io.legado.app.constant.Bus import io.legado.app.constant.Status +import io.legado.app.help.MediaHelp import io.legado.app.help.PendingIntentHelp import io.legado.app.receiver.MediaButtonReceiver import io.legado.app.utils.postEvent @@ -206,6 +207,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage * @return 音频焦点 */ private fun requestFocus(): Boolean { + MediaHelp.playSilentSound(this) val request: Int = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { audioManager.requestAudioFocus(mFocusRequest) } else { diff --git a/app/src/main/res/raw/silent_sound.mp3 b/app/src/main/res/raw/silent_sound.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..ce236a279400c386632265b9e43395e1c37e5f9f GIT binary patch literal 6336 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 Cijidi literal 0 HcmV?d00001 From 8c456a8b62b45b9c350fb3604c5a2d502392153a Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 16 Aug 2019 08:10:58 +0800 Subject: [PATCH 0700/1997] up --- app/src/main/java/io/legado/app/help/MediaHelp.kt | 9 ++++++++- .../main/java/io/legado/app/service/ReadAloudService.kt | 9 +-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/MediaHelp.kt b/app/src/main/java/io/legado/app/help/MediaHelp.kt index 377fd5fbd..d2de56c2d 100644 --- a/app/src/main/java/io/legado/app/help/MediaHelp.kt +++ b/app/src/main/java/io/legado/app/help/MediaHelp.kt @@ -2,10 +2,17 @@ package io.legado.app.help import android.content.Context import android.media.MediaPlayer +import android.support.v4.media.session.PlaybackStateCompat import io.legado.app.R object MediaHelp { - + const val MEDIA_SESSION_ACTIONS = (PlaybackStateCompat.ACTION_PLAY + or PlaybackStateCompat.ACTION_PAUSE + or PlaybackStateCompat.ACTION_PLAY_PAUSE + or PlaybackStateCompat.ACTION_SKIP_TO_NEXT + or PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS + or PlaybackStateCompat.ACTION_STOP + or PlaybackStateCompat.ACTION_SEEK_TO) fun playSilentSound(mContext: Context) { try { diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index bd48eefed..f1d4d61cb 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -30,13 +30,6 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage companion object { val tag: String = ReadAloudService::class.java.simpleName var isRun = false - const val MEDIA_SESSION_ACTIONS = (PlaybackStateCompat.ACTION_PLAY - or PlaybackStateCompat.ACTION_PAUSE - or PlaybackStateCompat.ACTION_PLAY_PAUSE - or PlaybackStateCompat.ACTION_SKIP_TO_NEXT - or PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS - or PlaybackStateCompat.ACTION_STOP - or PlaybackStateCompat.ACTION_SEEK_TO) fun paly(context: Context, title: String, body: String) { @@ -224,7 +217,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage private fun upMediaSessionPlaybackState() { mediaSessionCompat?.setPlaybackState( PlaybackStateCompat.Builder() - .setActions(MEDIA_SESSION_ACTIONS) + .setActions(MediaHelp.MEDIA_SESSION_ACTIONS) .setState( if (speak) PlaybackStateCompat.STATE_PLAYING else PlaybackStateCompat.STATE_PAUSED, nowSpeak.toLong(), 1f From ef0d366e2632baa3637bea355431f7a086a69837 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 16 Aug 2019 08:28:48 +0800 Subject: [PATCH 0701/1997] up --- .../main/java/io/legado/app/help/MediaHelp.kt | 19 +++++++++++++++++++ .../io/legado/app/service/ReadAloudService.kt | 19 +++---------------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/MediaHelp.kt b/app/src/main/java/io/legado/app/help/MediaHelp.kt index d2de56c2d..a7235a342 100644 --- a/app/src/main/java/io/legado/app/help/MediaHelp.kt +++ b/app/src/main/java/io/legado/app/help/MediaHelp.kt @@ -1,8 +1,13 @@ package io.legado.app.help import android.content.Context +import android.media.AudioAttributes +import android.media.AudioFocusRequest +import android.media.AudioManager import android.media.MediaPlayer +import android.os.Build import android.support.v4.media.session.PlaybackStateCompat +import androidx.annotation.RequiresApi import io.legado.app.R object MediaHelp { @@ -14,6 +19,20 @@ object MediaHelp { or PlaybackStateCompat.ACTION_STOP or PlaybackStateCompat.ACTION_SEEK_TO) + + @RequiresApi(Build.VERSION_CODES.O) + fun getFocusRequest(audioFocusChangeListener: AudioManager.OnAudioFocusChangeListener): AudioFocusRequest { + val mPlaybackAttributes = AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_MEDIA) + .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) + .build() + return AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN) + .setAudioAttributes(mPlaybackAttributes) + .setAcceptsDelayedFocusGain(true) + .setOnAudioFocusChangeListener(audioFocusChangeListener) + .build() + } + fun playSilentSound(mContext: Context) { try { // Stupid Android 8 "Oreo" hack to make media buttons work diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index f1d4d61cb..0edc9c55d 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -3,7 +3,6 @@ package io.legado.app.service import android.app.PendingIntent import android.content.* import android.graphics.BitmapFactory -import android.media.AudioAttributes import android.media.AudioFocusRequest import android.media.AudioManager import android.os.Build @@ -80,7 +79,9 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage isRun = true textToSpeech = TextToSpeech(this, this) audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager - initFocusRequest() + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + mFocusRequest = MediaHelp.getFocusRequest(this) + } initMediaSession() initBroadcastReceiver() upMediaSessionPlaybackState() @@ -151,20 +152,6 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage mediaSessionCompat?.setMediaButtonReceiver(mediaButtonReceiverPendingIntent) } - private fun initFocusRequest() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - val mPlaybackAttributes = AudioAttributes.Builder() - .setUsage(AudioAttributes.USAGE_MEDIA) - .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) - .build() - mFocusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN) - .setAudioAttributes(mPlaybackAttributes) - .setAcceptsDelayedFocusGain(true) - .setOnAudioFocusChangeListener(this) - .build() - } - } - private fun initBroadcastReceiver() { broadcastReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { From bfeffb6014675eb8615f70c6705c301193f426af Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 16 Aug 2019 08:34:34 +0800 Subject: [PATCH 0702/1997] up --- app/src/main/java/io/legado/app/help/PendingIntentHelp.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/help/PendingIntentHelp.kt b/app/src/main/java/io/legado/app/help/PendingIntentHelp.kt index 2105aa68e..5684390f2 100644 --- a/app/src/main/java/io/legado/app/help/PendingIntentHelp.kt +++ b/app/src/main/java/io/legado/app/help/PendingIntentHelp.kt @@ -9,7 +9,7 @@ object PendingIntentHelp { fun readBookActivityPendingIntent(context: Context): PendingIntent { val intent = Intent(context, ReadBookActivity::class.java) - intent.action = "" + intent.action = "readBookActivity" return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) } From 22a8c6a9809bf0f357abc2c340ed2241bba87b18 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 16 Aug 2019 09:11:13 +0800 Subject: [PATCH 0703/1997] up --- .../java/io/legado/app/help/IntentHelp.kt | 22 +++++ .../io/legado/app/service/ReadAloudService.kt | 98 +++++-------------- .../notification/ReadAloudNotification.kt | 72 ++++++++++++++ 3 files changed, 116 insertions(+), 76 deletions(-) create mode 100644 app/src/main/java/io/legado/app/help/IntentHelp.kt create mode 100644 app/src/main/java/io/legado/app/service/notification/ReadAloudNotification.kt diff --git a/app/src/main/java/io/legado/app/help/IntentHelp.kt b/app/src/main/java/io/legado/app/help/IntentHelp.kt new file mode 100644 index 000000000..8d77301c5 --- /dev/null +++ b/app/src/main/java/io/legado/app/help/IntentHelp.kt @@ -0,0 +1,22 @@ +package io.legado.app.help + +import android.content.Context +import android.content.Intent +import io.legado.app.R +import io.legado.app.utils.toast + +object IntentHelp { + + + fun toTTSSetting(context: Context) { + //跳转到文字转语音设置界面 + try { + val intent = Intent() + intent.action = "com.android.settings.TTS_SETTINGS" + intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK + context.startActivity(intent) + } catch (ignored: Exception) { + context.toast(R.string.tip_cannot_jump_setting_page) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index 0edc9c55d..1abfe74bf 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -2,7 +2,6 @@ package io.legado.app.service import android.app.PendingIntent import android.content.* -import android.graphics.BitmapFactory import android.media.AudioFocusRequest import android.media.AudioManager import android.os.Build @@ -10,15 +9,14 @@ import android.speech.tts.TextToSpeech import android.speech.tts.UtteranceProgressListener import android.support.v4.media.session.MediaSessionCompat import android.support.v4.media.session.PlaybackStateCompat -import androidx.core.app.NotificationCompat import io.legado.app.R import io.legado.app.base.BaseService -import io.legado.app.constant.AppConst import io.legado.app.constant.Bus import io.legado.app.constant.Status +import io.legado.app.help.IntentHelp import io.legado.app.help.MediaHelp -import io.legado.app.help.PendingIntentHelp import io.legado.app.receiver.MediaButtonReceiver +import io.legado.app.service.notification.ReadAloudNotification import io.legado.app.utils.postEvent import io.legado.app.utils.toast import kotlinx.coroutines.launch @@ -30,8 +28,13 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage val tag: String = ReadAloudService::class.java.simpleName var isRun = false - fun paly(context: Context, title: String, body: String) { - + fun paly(context: Context, title: String, subtitle: String, body: String) { + val readAloudIntent = Intent(context, ReadAloudService::class.java) + readAloudIntent.action = "play" + readAloudIntent.putExtra("title", title) + readAloudIntent.putExtra("subtitle", subtitle) + readAloudIntent.putExtra("body", body) + context.startService(readAloudIntent) } fun pause(context: Context) { @@ -59,7 +62,6 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage } } - private val notificationId = 112201 private var textToSpeech: TextToSpeech? = null private var ttsIsSuccess: Boolean = false private lateinit var audioManager: AudioManager @@ -85,7 +87,13 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage initMediaSession() initBroadcastReceiver() upMediaSessionPlaybackState() - upNotification() + ReadAloudNotification.upNotification( + this, + mediaSessionCompat, + pause, + title, + subtitle + ) } override fun onDestroy() { @@ -98,13 +106,15 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage intent?.action?.let { action -> when (action) { "play" -> { + title = intent.getStringExtra("title") + subtitle = intent.getStringExtra("subtitle") } "pause" -> { - + pauseReadAloud(true) } "resume" -> { - + resumeReadAloud() } "stop" -> { stopSelf() @@ -120,7 +130,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage val result = textToSpeech?.setLanguage(Locale.CHINA) if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) { toast(R.string.tts_fix) - toTTSSetting() + IntentHelp.toTTSSetting(this@ReadAloudService) } else { textToSpeech?.setOnUtteranceProgressListener(TTSUtteranceListener()) ttsIsSuccess = true @@ -170,7 +180,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage } private fun resumeReadAloud() { - + playTTS() } private fun playTTS() { @@ -230,70 +240,6 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage } } - private fun toTTSSetting() { - //跳转到文字转语音设置界面 - try { - val intent = Intent() - intent.action = "com.android.settings.TTS_SETTINGS" - intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK - startActivity(intent) - } catch (ignored: Exception) { - toast(R.string.tip_cannot_jump_setting_page) - } - } - - /** - * 更新通知 - */ - private fun upNotification() { - var nTitle: String = when { - pause -> getString(R.string.read_aloud_pause) - timeMinute in 1..60 -> getString(R.string.read_aloud_timer, timeMinute) - else -> getString(R.string.read_aloud_t) - } - nTitle += ": $title" - if (subtitle.isEmpty()) - subtitle = getString(R.string.read_aloud_s) - val builder = NotificationCompat.Builder(this, AppConst.channelIdReadAloud) - .setSmallIcon(R.drawable.ic_volume_up) - .setLargeIcon(BitmapFactory.decodeResource(resources, R.drawable.icon_read_book)) - .setOngoing(true) - .setContentTitle(nTitle) - .setContentText(subtitle) - .setContentIntent(PendingIntentHelp.readBookActivityPendingIntent(this)) - if (pause) { - builder.addAction( - R.drawable.ic_play_24dp, - getString(R.string.resume), - PendingIntentHelp.aloudServicePendingIntent(this, "resume") - ) - } else { - builder.addAction( - R.drawable.ic_pause_24dp, - getString(R.string.pause), - PendingIntentHelp.aloudServicePendingIntent(this, "pause") - ) - } - builder.addAction( - R.drawable.ic_stop_black_24dp, - getString(R.string.stop), - PendingIntentHelp.aloudServicePendingIntent(this, "stop") - ) - builder.addAction( - R.drawable.ic_time_add_24dp, - getString(R.string.set_timer), - PendingIntentHelp.aloudServicePendingIntent(this, "setTimer") - ) - builder.setStyle( - androidx.media.app.NotificationCompat.MediaStyle() - .setMediaSession(mediaSessionCompat?.sessionToken) - .setShowActionsInCompactView(0, 1, 2) - ) - builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) - val notification = builder.build() - startForeground(notificationId, notification) - } - /** * 朗读监听 */ diff --git a/app/src/main/java/io/legado/app/service/notification/ReadAloudNotification.kt b/app/src/main/java/io/legado/app/service/notification/ReadAloudNotification.kt new file mode 100644 index 000000000..3fab8f239 --- /dev/null +++ b/app/src/main/java/io/legado/app/service/notification/ReadAloudNotification.kt @@ -0,0 +1,72 @@ +package io.legado.app.service.notification + +import android.app.Service +import android.graphics.BitmapFactory +import android.support.v4.media.session.MediaSessionCompat +import androidx.core.app.NotificationCompat +import io.legado.app.R +import io.legado.app.constant.AppConst +import io.legado.app.help.PendingIntentHelp + +object ReadAloudNotification { + + /** + * 更新通知 + */ + fun upNotification( + context: Service, + mediaSessionCompat: MediaSessionCompat?, + pause: Boolean, + title: String, + subtitle: String, + timeMinute: Int = 0 + ) { + var nTitle: String = when { + pause -> context.getString(R.string.read_aloud_pause) + timeMinute in 1..60 -> context.getString(R.string.read_aloud_timer, timeMinute) + else -> context.getString(R.string.read_aloud_t) + } + nTitle += ": $title" + var nSubtitle = subtitle + if (subtitle.isEmpty()) + nSubtitle = context.getString(R.string.read_aloud_s) + val builder = NotificationCompat.Builder(context, AppConst.channelIdReadAloud) + .setSmallIcon(R.drawable.ic_volume_up) + .setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.icon_read_book)) + .setOngoing(true) + .setContentTitle(nTitle) + .setContentText(nSubtitle) + .setContentIntent(PendingIntentHelp.readBookActivityPendingIntent(context)) + if (pause) { + builder.addAction( + R.drawable.ic_play_24dp, + context.getString(R.string.resume), + PendingIntentHelp.aloudServicePendingIntent(context, "resume") + ) + } else { + builder.addAction( + R.drawable.ic_pause_24dp, + context.getString(R.string.pause), + PendingIntentHelp.aloudServicePendingIntent(context, "pause") + ) + } + builder.addAction( + R.drawable.ic_stop_black_24dp, + context.getString(R.string.stop), + PendingIntentHelp.aloudServicePendingIntent(context, "stop") + ) + builder.addAction( + R.drawable.ic_time_add_24dp, + context.getString(R.string.set_timer), + PendingIntentHelp.aloudServicePendingIntent(context, "setTimer") + ) + builder.setStyle( + androidx.media.app.NotificationCompat.MediaStyle() + .setMediaSession(mediaSessionCompat?.sessionToken) + .setShowActionsInCompactView(0, 1, 2) + ) + builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) + val notification = builder.build() + context.startForeground(112201, notification) + } +} \ No newline at end of file From f5c2cf40a5479e47d3b7fca58b376d26ceca2562 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 16 Aug 2019 10:15:02 +0800 Subject: [PATCH 0704/1997] up --- .../io/legado/app/service/ReadAloudService.kt | 59 ++++++++++--------- .../notification/ReadAloudNotification.kt | 54 ++++++++--------- 2 files changed, 54 insertions(+), 59 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index 1abfe74bf..ba8a124db 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -11,13 +11,10 @@ import android.support.v4.media.session.MediaSessionCompat import android.support.v4.media.session.PlaybackStateCompat import io.legado.app.R import io.legado.app.base.BaseService -import io.legado.app.constant.Bus -import io.legado.app.constant.Status import io.legado.app.help.IntentHelp import io.legado.app.help.MediaHelp import io.legado.app.receiver.MediaButtonReceiver import io.legado.app.service.notification.ReadAloudNotification -import io.legado.app.utils.postEvent import io.legado.app.utils.toast import kotlinx.coroutines.launch import java.util.* @@ -66,15 +63,16 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage private var ttsIsSuccess: Boolean = false private lateinit var audioManager: AudioManager private lateinit var mFocusRequest: AudioFocusRequest - private var mediaSessionCompat: MediaSessionCompat? = null + var mediaSessionCompat: MediaSessionCompat? = null private var broadcastReceiver: BroadcastReceiver? = null private var speak: Boolean = true private var nowSpeak: Int = 0 private val contentList = arrayListOf() - private var pause = false - private var title: String = "" - private var subtitle: String = "" - private var timeMinute: Int = 0 + var pause = false + var title: String = "" + var subtitle: String = "" + private var readAloudNumber: Int = 0 + var timeMinute: Int = 0 override fun onCreate() { super.onCreate() @@ -87,13 +85,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage initMediaSession() initBroadcastReceiver() upMediaSessionPlaybackState() - ReadAloudNotification.upNotification( - this, - mediaSessionCompat, - pause, - title, - subtitle - ) + ReadAloudNotification.upNotification(this) } override fun onDestroy() { @@ -106,9 +98,9 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage intent?.action?.let { action -> when (action) { "play" -> { - title = intent.getStringExtra("title") - subtitle = intent.getStringExtra("subtitle") - + title = intent.getStringExtra("title") ?: "" + subtitle = intent.getStringExtra("subtitle") ?: "" + newReadAloud(intent.getStringExtra("body")) } "pause" -> { pauseReadAloud(true) @@ -134,6 +126,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage } else { textToSpeech?.setOnUtteranceProgressListener(TTSUtteranceListener()) ttsIsSuccess = true + playTTS() } } else { toast(R.string.tts_init_failed) @@ -141,6 +134,26 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage } } + private fun newReadAloud(body: String?) { + if (body.isNullOrEmpty()) { + stopSelf() + } else { + nowSpeak = 0 + readAloudNumber = 0 + contentList.clear() + contentList.addAll(body.split("\n")) + } + } + + private fun playTTS() { + if (contentList.size < 1 || !ttsIsSuccess) { + return + } + if (!pause && requestFocus()) { + ReadAloudNotification.upNotification(this) + } + } + /** * 初始化MediaSession */ @@ -183,16 +196,6 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage playTTS() } - private fun playTTS() { - if (contentList.size < 1) { - postEvent(Bus.ALOUD_STATE, Status.NEXT) - return - } - if (ttsIsSuccess && !speak && requestFocus()) { - - } - } - /** * @return 音频焦点 */ diff --git a/app/src/main/java/io/legado/app/service/notification/ReadAloudNotification.kt b/app/src/main/java/io/legado/app/service/notification/ReadAloudNotification.kt index 3fab8f239..5d980ad4f 100644 --- a/app/src/main/java/io/legado/app/service/notification/ReadAloudNotification.kt +++ b/app/src/main/java/io/legado/app/service/notification/ReadAloudNotification.kt @@ -1,72 +1,64 @@ package io.legado.app.service.notification -import android.app.Service import android.graphics.BitmapFactory -import android.support.v4.media.session.MediaSessionCompat import androidx.core.app.NotificationCompat import io.legado.app.R import io.legado.app.constant.AppConst import io.legado.app.help.PendingIntentHelp +import io.legado.app.service.ReadAloudService object ReadAloudNotification { /** * 更新通知 */ - fun upNotification( - context: Service, - mediaSessionCompat: MediaSessionCompat?, - pause: Boolean, - title: String, - subtitle: String, - timeMinute: Int = 0 - ) { + fun upNotification(service: ReadAloudService) { var nTitle: String = when { - pause -> context.getString(R.string.read_aloud_pause) - timeMinute in 1..60 -> context.getString(R.string.read_aloud_timer, timeMinute) - else -> context.getString(R.string.read_aloud_t) + service.pause -> service.getString(R.string.read_aloud_pause) + service.timeMinute in 1..60 -> service.getString(R.string.read_aloud_timer, service.timeMinute) + else -> service.getString(R.string.read_aloud_t) } - nTitle += ": $title" - var nSubtitle = subtitle - if (subtitle.isEmpty()) - nSubtitle = context.getString(R.string.read_aloud_s) - val builder = NotificationCompat.Builder(context, AppConst.channelIdReadAloud) + nTitle += ": ${service.title}" + var nSubtitle = service.subtitle + if (service.subtitle.isEmpty()) + nSubtitle = service.getString(R.string.read_aloud_s) + val builder = NotificationCompat.Builder(service, AppConst.channelIdReadAloud) .setSmallIcon(R.drawable.ic_volume_up) - .setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.icon_read_book)) + .setLargeIcon(BitmapFactory.decodeResource(service.resources, R.drawable.icon_read_book)) .setOngoing(true) .setContentTitle(nTitle) .setContentText(nSubtitle) - .setContentIntent(PendingIntentHelp.readBookActivityPendingIntent(context)) - if (pause) { + .setContentIntent(PendingIntentHelp.readBookActivityPendingIntent(service)) + if (service.pause) { builder.addAction( R.drawable.ic_play_24dp, - context.getString(R.string.resume), - PendingIntentHelp.aloudServicePendingIntent(context, "resume") + service.getString(R.string.resume), + PendingIntentHelp.aloudServicePendingIntent(service, "resume") ) } else { builder.addAction( R.drawable.ic_pause_24dp, - context.getString(R.string.pause), - PendingIntentHelp.aloudServicePendingIntent(context, "pause") + service.getString(R.string.pause), + PendingIntentHelp.aloudServicePendingIntent(service, "pause") ) } builder.addAction( R.drawable.ic_stop_black_24dp, - context.getString(R.string.stop), - PendingIntentHelp.aloudServicePendingIntent(context, "stop") + service.getString(R.string.stop), + PendingIntentHelp.aloudServicePendingIntent(service, "stop") ) builder.addAction( R.drawable.ic_time_add_24dp, - context.getString(R.string.set_timer), - PendingIntentHelp.aloudServicePendingIntent(context, "setTimer") + service.getString(R.string.set_timer), + PendingIntentHelp.aloudServicePendingIntent(service, "setTimer") ) builder.setStyle( androidx.media.app.NotificationCompat.MediaStyle() - .setMediaSession(mediaSessionCompat?.sessionToken) + .setMediaSession(service.mediaSessionCompat?.sessionToken) .setShowActionsInCompactView(0, 1, 2) ) builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) val notification = builder.build() - context.startForeground(112201, notification) + service.startForeground(112201, notification) } } \ No newline at end of file From f4805c6c8d9c23b97f14c460705ba366b5a50b40 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 16 Aug 2019 10:43:40 +0800 Subject: [PATCH 0705/1997] up --- .../io/legado/app/service/ReadAloudService.kt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index ba8a124db..392901820 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -11,10 +11,13 @@ import android.support.v4.media.session.MediaSessionCompat import android.support.v4.media.session.PlaybackStateCompat import io.legado.app.R import io.legado.app.base.BaseService +import io.legado.app.constant.Bus +import io.legado.app.constant.Status import io.legado.app.help.IntentHelp import io.legado.app.help.MediaHelp import io.legado.app.receiver.MediaButtonReceiver import io.legado.app.service.notification.ReadAloudNotification +import io.legado.app.utils.postEvent import io.legado.app.utils.toast import kotlinx.coroutines.launch import java.util.* @@ -145,12 +148,21 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage } } + @Suppress("DEPRECATION") private fun playTTS() { if (contentList.size < 1 || !ttsIsSuccess) { return } if (!pause && requestFocus()) { + postEvent(Bus.ALOUD_STATE, Status.PLAY) ReadAloudNotification.upNotification(this) + for (i in nowSpeak until contentList.size) { + if (i == 0) { + textToSpeech?.speak(contentList[i], TextToSpeech.QUEUE_FLUSH, null, "content") + } else { + textToSpeech?.speak(contentList[i], TextToSpeech.QUEUE_ADD, null, "content") + } + } } } @@ -189,6 +201,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage } private fun pauseReadAloud(pause: Boolean) { + this.pause = pause textToSpeech?.stop() } @@ -230,12 +243,18 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage when (focusChange) { AudioManager.AUDIOFOCUS_GAIN -> { // 重新获得焦点, 可做恢复播放,恢复后台音量的操作 + if (!pause) { + resumeReadAloud() + } } AudioManager.AUDIOFOCUS_LOSS -> { // 永久丢失焦点除非重新主动获取,这种情况是被其他播放器抢去了焦点, 为避免与其他播放器混音,可将音乐暂停 } AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> { // 暂时丢失焦点,这种情况是被其他应用申请了短暂的焦点,可压低后台音量 + if (!pause) { + pauseReadAloud(false) + } } AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> { // 短暂丢失焦点,这种情况是被其他应用申请了短暂的焦点希望其他声音能压低音量(或者关闭声音)凸显这个声音(比如短信提示音), From 1dfda8ffde8d1c635839c10489390c7cc53fd89d Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 16 Aug 2019 10:52:53 +0800 Subject: [PATCH 0706/1997] up --- app/src/main/java/io/legado/app/constant/Bus.kt | 2 ++ .../java/io/legado/app/service/ReadAloudService.kt | 12 +++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/constant/Bus.kt b/app/src/main/java/io/legado/app/constant/Bus.kt index 4e90b7d82..e680d1e8c 100644 --- a/app/src/main/java/io/legado/app/constant/Bus.kt +++ b/app/src/main/java/io/legado/app/constant/Bus.kt @@ -4,4 +4,6 @@ object Bus { const val RECREATE = "RECREATE" const val UP_BOOK = "sourceDebugLog" const val ALOUD_STATE = "aloud_state" + const val TTS_START = "ttsStart" + const val TTS_RANGE_START = "readAloudNumber" } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index 392901820..ebb4513da 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -268,11 +268,21 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage private inner class TTSUtteranceListener : UtteranceProgressListener() { override fun onStart(s: String) { - + postEvent(Bus.TTS_START, readAloudNumber + 1) + postEvent(Bus.TTS_RANGE_START, readAloudNumber + 1) } override fun onDone(s: String) { + readAloudNumber += contentList[nowSpeak].length + 1 + nowSpeak += 1 + if (nowSpeak >= contentList.size) { + postEvent(Bus.ALOUD_STATE, Status.NEXT) + } + } + override fun onRangeStart(utteranceId: String?, start: Int, end: Int, frame: Int) { + super.onRangeStart(utteranceId, start, end, frame) + postEvent(Bus.TTS_RANGE_START, readAloudNumber + start) } override fun onError(s: String) { From 4cdeb061cadee1e1e72fbe9c7f53dbc8cf39c4cd Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 16 Aug 2019 11:20:46 +0800 Subject: [PATCH 0707/1997] up --- .../java/io/legado/app/constant/Status.kt | 2 +- .../app/ui/readbook/ReadBookActivity.kt | 26 ++++++++++- .../legado/app/ui/readbook/ReadBottomMenu.kt | 4 +- .../java/io/legado/app/utils/SystemUtils.kt | 45 +++++++++++++++++++ 4 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/io/legado/app/utils/SystemUtils.kt diff --git a/app/src/main/java/io/legado/app/constant/Status.kt b/app/src/main/java/io/legado/app/constant/Status.kt index 0f1bff978..a20ee0e34 100644 --- a/app/src/main/java/io/legado/app/constant/Status.kt +++ b/app/src/main/java/io/legado/app/constant/Status.kt @@ -4,5 +4,5 @@ object Status { const val STOP = 0 const val PLAY = 1 const val NEXT = 2 - + const val PAUSE = 3 } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 55266c02e..26dd7ed36 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -10,7 +10,10 @@ import androidx.core.view.isVisible import io.legado.app.App import io.legado.app.R import io.legado.app.base.VMBaseActivity +import io.legado.app.constant.Bus +import io.legado.app.constant.Status import io.legado.app.data.entities.Book +import io.legado.app.service.ReadAloudService import io.legado.app.ui.changesource.ChangeSourceDialog import io.legado.app.ui.chapterlist.ChapterListActivity import io.legado.app.ui.replacerule.ReplaceRuleActivity @@ -30,6 +33,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea private lateinit var menuTopOut: Animation private lateinit var menuBottomIn: Animation private lateinit var menuBottomOut: Animation + private var readAloudStatus = Status.STOP override fun onActivityCreated(savedInstanceState: Bundle?) { setSupportActionBar(toolbar) @@ -92,8 +96,8 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } - override fun onMediaButton() { - + override fun clickReadAloud() { + onClickReadAloud() } override fun autoPage() { @@ -204,4 +208,22 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea override fun changeTo(book: Book) { } + + private fun onClickReadAloud() { + if (!ReadAloudService.isRun) { + readAloudStatus = Status.STOP + SystemUtils.ignoreBatteryOptimization(this) + } + when (readAloudStatus) { + Status.STOP -> { + } + Status.PLAY -> ReadAloudService.pause(this) + Status.PAUSE -> ReadAloudService.resume(this) + } + } + + override fun observeLiveBus() { + super.observeLiveBus() + observeEvent(Bus.ALOUD_STATE) { readAloudStatus = it } + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBottomMenu.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBottomMenu.kt index 461396919..82461268c 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBottomMenu.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBottomMenu.kt @@ -69,7 +69,7 @@ class ReadBottomMenu : FrameLayout { fab_read_aloud_timer.onClick { } //朗读 - fab_read_aloud.onClick { callback?.onMediaButton() } + fab_read_aloud.onClick { callback?.clickReadAloud() } //长按停止朗读 fab_read_aloud.onLongClick { ReadAloudService.stop(context) @@ -155,7 +155,7 @@ class ReadBottomMenu : FrameLayout { interface Callback { fun skipToPage(page: Int) - fun onMediaButton() + fun clickReadAloud() fun autoPage() diff --git a/app/src/main/java/io/legado/app/utils/SystemUtils.kt b/app/src/main/java/io/legado/app/utils/SystemUtils.kt new file mode 100644 index 000000000..91121c000 --- /dev/null +++ b/app/src/main/java/io/legado/app/utils/SystemUtils.kt @@ -0,0 +1,45 @@ +package io.legado.app.utils + +import android.annotation.SuppressLint +import android.app.Activity +import android.content.Context +import android.content.Context.POWER_SERVICE +import android.content.Intent +import android.net.Uri +import android.os.PowerManager +import android.provider.Settings + +object SystemUtils { + + fun getScreenOffTime(context: Context): Int { + var screenOffTime = 0 + try { + screenOffTime = Settings.System.getInt( + context.contentResolver, + Settings.System.SCREEN_OFF_TIMEOUT + ) + } catch (e: Exception) { + e.printStackTrace() + } + + return screenOffTime + } + + fun ignoreBatteryOptimization(activity: Activity) { + if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M) return + + val powerManager = activity.getSystemService(POWER_SERVICE) as PowerManager + val hasIgnored = powerManager.isIgnoringBatteryOptimizations(activity.packageName) + // 判断当前APP是否有加入电池优化的白名单,如果没有,弹出加入电池优化的白名单的设置对话框。 + if (!hasIgnored) { + try { + @SuppressLint("BatteryLife") + val intent = Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS) + intent.data = Uri.parse("package:" + activity.packageName) + activity.startActivity(intent) + } catch (ignored: Throwable) { + } + + } + } +} From bf79cf628929ccaab557147b34931e7947e9a837 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 16 Aug 2019 11:25:38 +0800 Subject: [PATCH 0708/1997] up --- app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 26dd7ed36..d4a8f128a 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -225,5 +225,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea override fun observeLiveBus() { super.observeLiveBus() observeEvent(Bus.ALOUD_STATE) { readAloudStatus = it } + observeEvent(Bus.TTS_START) {} + observeEvent(Bus.TTS_RANGE_START) {} } } \ No newline at end of file From a399a32b3ab94024dafbbc77f0a06effdcbb9110 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 16 Aug 2019 11:39:17 +0800 Subject: [PATCH 0709/1997] up --- .../main/java/io/legado/app/help/BookHelp.kt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/app/src/main/java/io/legado/app/help/BookHelp.kt b/app/src/main/java/io/legado/app/help/BookHelp.kt index db0b27222..fa42f9cfe 100644 --- a/app/src/main/java/io/legado/app/help/BookHelp.kt +++ b/app/src/main/java/io/legado/app/help/BookHelp.kt @@ -1,7 +1,26 @@ package io.legado.app.help +import io.legado.app.data.entities.Book +import io.legado.app.data.entities.BookChapter + object BookHelp { + fun saveContent(book: Book, bookChapter: BookChapter, content: String) { + + } + + fun hasContent(book: Book, bookChapter: BookChapter): Boolean { + + + return false + } + + fun getContent(book: Book, bookChapter: BookChapter): String? { + + + return null + } + fun formatAuthor(author: String?): String { return author ?.replace("作\\s*者[\\s::]*".toRegex(), "") From d78f7596381e089f2f19c388b30ff2466201c8d1 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 16 Aug 2019 14:24:43 +0800 Subject: [PATCH 0710/1997] up --- .../main/java/io/legado/app/help/BookHelp.kt | 36 +++++++++++++++++++ .../main/java/io/legado/app/help/FileHelp.kt | 35 ++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 app/src/main/java/io/legado/app/help/FileHelp.kt diff --git a/app/src/main/java/io/legado/app/help/BookHelp.kt b/app/src/main/java/io/legado/app/help/BookHelp.kt index fa42f9cfe..965096352 100644 --- a/app/src/main/java/io/legado/app/help/BookHelp.kt +++ b/app/src/main/java/io/legado/app/help/BookHelp.kt @@ -1,11 +1,35 @@ package io.legado.app.help +import io.legado.app.App import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter +import io.legado.app.utils.getPrefString +import java.io.BufferedWriter +import java.io.File +import java.io.FileWriter +import java.io.IOException object BookHelp { + var downloadPath = App.INSTANCE.getPrefString("downloadPath") ?: App.INSTANCE.getExternalFilesDir(null) + fun saveContent(book: Book, bookChapter: BookChapter, content: String) { + if (content.isEmpty()) { + return + } + val filePath = getChapterPath(book, bookChapter) + val file = FileHelp.getFile(filePath) + //获取流并存储 + try { + BufferedWriter(FileWriter(file)).use { writer -> + writer.write(bookChapter.title + "\n\n") + writer.write(content) + writer.write("\n\n") + writer.flush() + } + } catch (e: IOException) { + e.printStackTrace() + } } @@ -21,6 +45,18 @@ object BookHelp { return null } + private fun getChapterPath(book: Book, bookChapter: BookChapter): String { + val bookFolder = formatFolderName(book.name + book.bookUrl) + val chapterFile = String.format("%05d-%s", bookChapter.index, formatFolderName(bookChapter.title)) + return "$downloadPath${File.separator}book_cache${File.separator}$bookFolder${File.separator}$chapterFile.nb" + } + + private fun formatFolderName(folderName: String): String { + return folderName.replace("/", "") + .replace(":", "") + .replace(".", "") + } + fun formatAuthor(author: String?): String { return author ?.replace("作\\s*者[\\s::]*".toRegex(), "") diff --git a/app/src/main/java/io/legado/app/help/FileHelp.kt b/app/src/main/java/io/legado/app/help/FileHelp.kt new file mode 100644 index 000000000..123f31172 --- /dev/null +++ b/app/src/main/java/io/legado/app/help/FileHelp.kt @@ -0,0 +1,35 @@ +package io.legado.app.help + +import java.io.File +import java.io.IOException + +object FileHelp { + + + //获取文件夹 + fun getFolder(filePath: String): File { + val file = File(filePath) + //如果文件夹不存在,就创建它 + if (!file.exists()) { + file.mkdirs() + } + return file + } + + //获取文件 + @Synchronized + fun getFile(filePath: String): File { + val file = File(filePath) + try { + if (!file.exists()) { + //创建父类文件夹 + getFolder(file.parent) + //创建文件 + file.createNewFile() + } + } catch (e: IOException) { + } + + return file + } +} \ No newline at end of file From 6a3b93ef8ae5a055420aa916472b6bdc206d1fef Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 16 Aug 2019 14:40:24 +0800 Subject: [PATCH 0711/1997] up --- .../main/java/io/legado/app/help/BookHelp.kt | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/BookHelp.kt b/app/src/main/java/io/legado/app/help/BookHelp.kt index 965096352..69c95140d 100644 --- a/app/src/main/java/io/legado/app/help/BookHelp.kt +++ b/app/src/main/java/io/legado/app/help/BookHelp.kt @@ -8,6 +8,7 @@ import java.io.BufferedWriter import java.io.File import java.io.FileWriter import java.io.IOException +import java.nio.charset.StandardCharsets object BookHelp { @@ -34,14 +35,24 @@ object BookHelp { } fun hasContent(book: Book, bookChapter: BookChapter): Boolean { - - + val filePath = getChapterPath(book, bookChapter) + runCatching { + val file = File(filePath) + if (file.exists()) { + return true + } + } return false } fun getContent(book: Book, bookChapter: BookChapter): String? { - - + val filePath = getChapterPath(book, bookChapter) + runCatching { + val file = File(filePath) + if (file.exists()) { + return String(file.readBytes(), StandardCharsets.UTF_8) + } + } return null } From 0d6f013f9b0a11b20e0a425534dcc9dcffaefd6d Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 16 Aug 2019 15:21:47 +0800 Subject: [PATCH 0712/1997] up --- .../main/java/io/legado/app/help/BookHelp.kt | 6 +++- .../app/ui/readbook/ReadBookViewModel.kt | 32 +++++++++++++------ 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/BookHelp.kt b/app/src/main/java/io/legado/app/help/BookHelp.kt index 69c95140d..b71c3dfe9 100644 --- a/app/src/main/java/io/legado/app/help/BookHelp.kt +++ b/app/src/main/java/io/legado/app/help/BookHelp.kt @@ -12,7 +12,11 @@ import java.nio.charset.StandardCharsets object BookHelp { - var downloadPath = App.INSTANCE.getPrefString("downloadPath") ?: App.INSTANCE.getExternalFilesDir(null) + private var downloadPath = App.INSTANCE.getPrefString("downloadPath") ?: App.INSTANCE.getExternalFilesDir(null) + + fun upDownloadPath() { + downloadPath = App.INSTANCE.getPrefString("downloadPath") ?: App.INSTANCE.getExternalFilesDir(null) + } fun saveContent(book: Book, bookChapter: BookChapter, content: String) { if (content.isEmpty()) { diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index d793c0cb0..029be993e 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -7,13 +7,16 @@ import io.legado.app.App import io.legado.app.base.BaseViewModel import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookSource +import io.legado.app.help.BookHelp import io.legado.app.model.WebBook +import kotlinx.coroutines.Dispatchers.IO class ReadBookViewModel(application: Application) : BaseViewModel(application) { var book: Book? = null var bookSource: BookSource? = null var chapterMaxIndex = MediatorLiveData() + var webBook: WebBook? = null fun initData(intent: Intent) { val bookUrl = intent.getStringExtra("bookUrl") @@ -21,20 +24,20 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { execute { book = App.db.bookDao().getBook(bookUrl) book?.let { book -> - val count = App.db.bookChapterDao().getChapterCount(bookUrl) - if (count == 0) { - App.db.bookSourceDao().getBookSource(book.origin)?.let { - WebBook(it).getChapterList(book) - .onSuccess { cList -> + bookSource = App.db.bookSourceDao().getBookSource(book.origin) + bookSource?.let { + webBook = WebBook(it) + val count = App.db.bookChapterDao().getChapterCount(bookUrl) + if (count == 0) { + webBook?.getChapterList(book) + ?.onSuccess { cList -> cList?.let { App.db.bookChapterDao().insert(*cList.toTypedArray()) } } - } ?: let { - + } else { + chapterMaxIndex.postValue(count) } - } else { - chapterMaxIndex.postValue(count) } } @@ -42,4 +45,15 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } } + + fun download(book: Book, index: Int) { + App.db.bookChapterDao().getChapter(book.bookUrl, index)?.let { chapter -> + webBook?.getContent(book, chapter) + ?.onSuccess(IO) { content -> + content?.let { + BookHelp.saveContent(book, chapter, it) + } + } + } + } } \ No newline at end of file From 5d63e56aa878a994f8cb710806a2e57aa506ee84 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 16 Aug 2019 15:22:47 +0800 Subject: [PATCH 0713/1997] up --- app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index 029be993e..0daa33437 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -33,6 +33,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { ?.onSuccess { cList -> cList?.let { App.db.bookChapterDao().insert(*cList.toTypedArray()) + chapterMaxIndex.postValue(cList.size) } } } else { From 488df49270203090cd1bbce534b3dbc8c12e9843 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 16 Aug 2019 15:54:30 +0800 Subject: [PATCH 0714/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 2 ++ .../app/ui/readbook/ReadBookViewModel.kt | 21 ++++++++++++------- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index d4a8f128a..7c6c2d780 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -7,6 +7,7 @@ import android.view.MenuItem import android.view.animation.Animation import android.view.animation.AnimationUtils import androidx.core.view.isVisible +import androidx.lifecycle.Observer import io.legado.app.App import io.legado.app.R import io.legado.app.base.VMBaseActivity @@ -39,6 +40,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea setSupportActionBar(toolbar) initAnimation() initView() + viewModel.chapterMaxIndex.observe(this, Observer { }) viewModel.initData(intent) savedInstanceState?.let { changeSourceDialog = supportFragmentManager.findFragmentByTag(ChangeSourceDialog.tag) as? ChangeSourceDialog diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index 0daa33437..da91edc8a 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -6,6 +6,7 @@ import androidx.lifecycle.MediatorLiveData import io.legado.app.App import io.legado.app.base.BaseViewModel import io.legado.app.data.entities.Book +import io.legado.app.data.entities.BookChapter import io.legado.app.data.entities.BookSource import io.legado.app.help.BookHelp import io.legado.app.model.WebBook @@ -47,14 +48,20 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } - fun download(book: Book, index: Int) { + fun getContent(book: Book, index: Int) { App.db.bookChapterDao().getChapter(book.bookUrl, index)?.let { chapter -> - webBook?.getContent(book, chapter) - ?.onSuccess(IO) { content -> - content?.let { - BookHelp.saveContent(book, chapter, it) - } - } + BookHelp.getContent(book, chapter)?.let { + + } ?: download(book, chapter) } } + + private fun download(book: Book, chapter: BookChapter) { + webBook?.getContent(book, chapter) + ?.onSuccess(IO) { content -> + content?.let { + BookHelp.saveContent(book, chapter, it) + } + } + } } \ No newline at end of file From 1ca339c19420264613424e2b9ef185d65405dfc7 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 16 Aug 2019 16:39:02 +0800 Subject: [PATCH 0715/1997] up --- .../app/receiver/TimeElectricityReceiver.kt | 36 +++++++++++++++++++ .../app/ui/readbook/ReadBookActivity.kt | 15 ++++++++ 2 files changed, 51 insertions(+) create mode 100644 app/src/main/java/io/legado/app/receiver/TimeElectricityReceiver.kt diff --git a/app/src/main/java/io/legado/app/receiver/TimeElectricityReceiver.kt b/app/src/main/java/io/legado/app/receiver/TimeElectricityReceiver.kt new file mode 100644 index 000000000..59d0424ee --- /dev/null +++ b/app/src/main/java/io/legado/app/receiver/TimeElectricityReceiver.kt @@ -0,0 +1,36 @@ +package io.legado.app.receiver + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter + + +class TimeElectricityReceiver : BroadcastReceiver() { + + companion object { + + fun register(context: Context): TimeElectricityReceiver { + val receiver = TimeElectricityReceiver() + val filter = IntentFilter() + filter.addAction(Intent.ACTION_TIME_TICK) + filter.addAction(Intent.ACTION_BATTERY_CHANGED) + context.registerReceiver(receiver, filter) + return receiver + } + + } + + override fun onReceive(context: Context?, intent: Intent?) { + intent?.action?.let { + when (it) { + Intent.ACTION_TIME_TICK -> { + + } + Intent.ACTION_BATTERY_CHANGED -> { + } + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 7c6c2d780..629a0bfeb 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -14,6 +14,7 @@ import io.legado.app.base.VMBaseActivity import io.legado.app.constant.Bus import io.legado.app.constant.Status import io.legado.app.data.entities.Book +import io.legado.app.receiver.TimeElectricityReceiver import io.legado.app.service.ReadAloudService import io.legado.app.ui.changesource.ChangeSourceDialog import io.legado.app.ui.chapterlist.ChapterListActivity @@ -29,6 +30,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea get() = getViewModel(ReadBookViewModel::class.java) private var changeSourceDialog: ChangeSourceDialog? = null + private var timeElectricityReceiver: TimeElectricityReceiver? = null private var menuBarShow: Boolean = false private lateinit var menuTopIn: Animation private lateinit var menuTopOut: Animation @@ -48,6 +50,19 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } + override fun onResume() { + super.onResume() + timeElectricityReceiver = TimeElectricityReceiver.register(this) + } + + override fun onPause() { + super.onPause() + timeElectricityReceiver?.let { + unregisterReceiver(it) + timeElectricityReceiver = null + } + } + private fun initAnimation() { menuTopIn = AnimationUtils.loadAnimation(this, R.anim.anim_readbook_top_in) menuBottomIn = AnimationUtils.loadAnimation(this, R.anim.anim_readbook_bottom_in) From ff95f864ef7b274a36e3a1a08cb4c4f0942b6a2f Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 16 Aug 2019 16:53:23 +0800 Subject: [PATCH 0716/1997] up --- app/src/main/java/io/legado/app/constant/Bus.kt | 2 ++ .../app/receiver/TimeElectricityReceiver.kt | 7 ++++++- .../java/io/legado/app/utils/BatteryUtils.kt | 16 ++++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/io/legado/app/utils/BatteryUtils.kt diff --git a/app/src/main/java/io/legado/app/constant/Bus.kt b/app/src/main/java/io/legado/app/constant/Bus.kt index e680d1e8c..6d7c7b872 100644 --- a/app/src/main/java/io/legado/app/constant/Bus.kt +++ b/app/src/main/java/io/legado/app/constant/Bus.kt @@ -6,4 +6,6 @@ object Bus { const val ALOUD_STATE = "aloud_state" const val TTS_START = "ttsStart" const val TTS_RANGE_START = "readAloudNumber" + const val BATTERY_CHANGED = "batteryChanged" + const val TIME_CHANGED = "timeChanged" } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/receiver/TimeElectricityReceiver.kt b/app/src/main/java/io/legado/app/receiver/TimeElectricityReceiver.kt index 59d0424ee..613db4fe4 100644 --- a/app/src/main/java/io/legado/app/receiver/TimeElectricityReceiver.kt +++ b/app/src/main/java/io/legado/app/receiver/TimeElectricityReceiver.kt @@ -4,6 +4,9 @@ import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.content.IntentFilter +import android.os.BatteryManager +import io.legado.app.constant.Bus +import io.legado.app.utils.postEvent class TimeElectricityReceiver : BroadcastReceiver() { @@ -25,9 +28,11 @@ class TimeElectricityReceiver : BroadcastReceiver() { intent?.action?.let { when (it) { Intent.ACTION_TIME_TICK -> { - + postEvent(Bus.TIME_CHANGED, "") } Intent.ACTION_BATTERY_CHANGED -> { + val level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) + postEvent(Bus.BATTERY_CHANGED, level) } } } diff --git a/app/src/main/java/io/legado/app/utils/BatteryUtils.kt b/app/src/main/java/io/legado/app/utils/BatteryUtils.kt new file mode 100644 index 000000000..c7d49a3aa --- /dev/null +++ b/app/src/main/java/io/legado/app/utils/BatteryUtils.kt @@ -0,0 +1,16 @@ +package io.legado.app.utils + +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.os.BatteryManager + +object BatteryUtils { + + fun getLevel(context: Context): Int { + val iFilter = IntentFilter(Intent.ACTION_BATTERY_CHANGED) + val batteryStatus = context.registerReceiver(null, iFilter) + + return batteryStatus?.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) ?: -1 + } +} From 03b89125ccda04e453364eca97c9c2405f43180a Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 16 Aug 2019 16:58:54 +0800 Subject: [PATCH 0717/1997] up --- app/src/main/java/io/legado/app/constant/Bus.kt | 1 + .../main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 3 +++ 2 files changed, 4 insertions(+) diff --git a/app/src/main/java/io/legado/app/constant/Bus.kt b/app/src/main/java/io/legado/app/constant/Bus.kt index 6d7c7b872..12e72949d 100644 --- a/app/src/main/java/io/legado/app/constant/Bus.kt +++ b/app/src/main/java/io/legado/app/constant/Bus.kt @@ -8,4 +8,5 @@ object Bus { const val TTS_RANGE_START = "readAloudNumber" const val BATTERY_CHANGED = "batteryChanged" const val TIME_CHANGED = "timeChanged" + const val READ_ALOUD = "readAloud" } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 629a0bfeb..f0389a93e 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -244,5 +244,8 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea observeEvent(Bus.ALOUD_STATE) { readAloudStatus = it } observeEvent(Bus.TTS_START) {} observeEvent(Bus.TTS_RANGE_START) {} + observeEvent(Bus.TIME_CHANGED) {} + observeEvent(Bus.BATTERY_CHANGED) {} + observeEvent(Bus.READ_ALOUD) { onClickReadAloud() } } } \ No newline at end of file From 0ff5d733e6b482eb11b7ac64b3f10bcc6b7a8eb8 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 16 Aug 2019 17:16:42 +0800 Subject: [PATCH 0718/1997] up --- .../java/io/legado/app/help/ActivityHelp.kt | 108 ++++++++++++++++++ .../app/receiver/MediaButtonReceiver.kt | 13 +-- 2 files changed, 114 insertions(+), 7 deletions(-) create mode 100644 app/src/main/java/io/legado/app/help/ActivityHelp.kt diff --git a/app/src/main/java/io/legado/app/help/ActivityHelp.kt b/app/src/main/java/io/legado/app/help/ActivityHelp.kt new file mode 100644 index 000000000..83705f0ed --- /dev/null +++ b/app/src/main/java/io/legado/app/help/ActivityHelp.kt @@ -0,0 +1,108 @@ +package io.legado.app.help + +import android.app.Activity +import java.lang.ref.WeakReference +import java.util.* + +/** + * Activity管理器,管理项目中Activity的状态 + */ +class ActivityHelp private constructor() { + + companion object { + + private var activities: MutableList> = arrayListOf() + + @Volatile + private var instance: ActivityHelp? = null + + fun getInstance(): ActivityHelp? { + if (null == instance) { + synchronized(ActivityHelp::class.java) { + if (null == instance) { + instance = ActivityHelp() + } + } + } + return instance + } + } + + fun getActivities(): List> { + return activities + } + + /** + * 添加Activity + */ + fun add(activity: Activity) { + activities.add(WeakReference(activity)) + } + + /** + * 移除Activity + */ + fun remove(activity: Activity) { + for (temp in activities) { + if (null != temp.get() && temp.get() === activity) { + activities.remove(temp) + break + } + } + } + + /** + * 移除Activity + */ + fun remove(activityClass: Class<*>) { + val iterator = activities.iterator() + while (iterator.hasNext()) { + val item = iterator.next() + if (item.get()?.javaClass == activityClass) { + iterator.remove() + } + } + } + + /** + * 关闭指定 activity + */ + fun finishActivity(vararg activities: Activity) { + for (activity in activities) { + activity?.finish() + } + } + + /** + * 关闭指定 activity(class) + */ + fun finishActivity(vararg activityClasses: Class<*>) { + val waitFinish = ArrayList>() + for (temp in activities) { + for (activityClass in activityClasses) { + if (temp.get()?.javaClass == activityClass) { + waitFinish.add(temp) + break + } + } + } + for (activityWeakReference in waitFinish) { + activityWeakReference.get()?.finish() + } + } + + /** + * 判断指定Activity是否存在 + */ + fun isExist(activityClass: Class<*>): Boolean? { + var result = false + for (item in activities) { + if (item.get()?.javaClass == activityClass) { + result = true + break + } + } + return result + } + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt index 9b6d62035..e58743086 100644 --- a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt +++ b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt @@ -24,16 +24,15 @@ class MediaButtonReceiver : BroadcastReceiver() { val keycode = event.keyCode val action = event.action - val command: String? = null + var command = false when (keycode) { KeyEvent.KEYCODE_MEDIA_STOP, KeyEvent.KEYCODE_MEDIA_PAUSE, KeyEvent.KEYCODE_MEDIA_PLAY, KeyEvent.KEYCODE_HEADSETHOOK, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE -> { + command = true } - else -> { - } - }// command = ReadAloudService.ActionMediaButton; - if (command != null) { + } + if (command) { if (action == KeyEvent.ACTION_DOWN) { - readAloud(context, command) + readAloud(context) return true } } @@ -41,7 +40,7 @@ class MediaButtonReceiver : BroadcastReceiver() { return false } - private fun readAloud(context: Context, command: String?) { + private fun readAloud(context: Context) { } } From 91acb0234057f28dbd6de3013331e98b61dfe2dc Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 16 Aug 2019 17:21:27 +0800 Subject: [PATCH 0719/1997] up --- app/src/main/java/io/legado/app/base/BaseActivity.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/java/io/legado/app/base/BaseActivity.kt b/app/src/main/java/io/legado/app/base/BaseActivity.kt index 96d3d21d5..b769f54f4 100644 --- a/app/src/main/java/io/legado/app/base/BaseActivity.kt +++ b/app/src/main/java/io/legado/app/base/BaseActivity.kt @@ -8,6 +8,7 @@ import android.view.View import android.view.WindowManager import androidx.appcompat.app.AppCompatActivity import io.legado.app.R +import io.legado.app.help.ActivityHelp import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.ColorUtils import io.legado.app.lib.theme.ThemeStore @@ -26,6 +27,7 @@ abstract class BaseActivity(private val layoutID: Int, private val fullScreen: B initTheme() setupSystemBar() super.onCreate(savedInstanceState) + ActivityHelp.getInstance()?.add(this) setContentView(layoutID) onActivityCreated(savedInstanceState) observeLiveBus() @@ -34,6 +36,7 @@ abstract class BaseActivity(private val layoutID: Int, private val fullScreen: B override fun onDestroy() { super.onDestroy() cancel() + ActivityHelp.getInstance()?.remove(this) } abstract fun onActivityCreated(savedInstanceState: Bundle?) From 866b2988d830b9180036b586ee8083683d71c844 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 16 Aug 2019 17:32:40 +0800 Subject: [PATCH 0720/1997] up --- app/src/main/java/io/legado/app/help/ActivityHelp.kt | 2 +- .../io/legado/app/receiver/MediaButtonReceiver.kt | 12 +++++++++++- .../io/legado/app/ui/readbook/ReadBookActivity.kt | 2 +- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/ActivityHelp.kt b/app/src/main/java/io/legado/app/help/ActivityHelp.kt index 83705f0ed..c9eccea96 100644 --- a/app/src/main/java/io/legado/app/help/ActivityHelp.kt +++ b/app/src/main/java/io/legado/app/help/ActivityHelp.kt @@ -94,7 +94,7 @@ class ActivityHelp private constructor() { /** * 判断指定Activity是否存在 */ - fun isExist(activityClass: Class<*>): Boolean? { + fun isExist(activityClass: Class<*>): Boolean { var result = false for (item in activities) { if (item.get()?.javaClass == activityClass) { diff --git a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt index e58743086..796734c43 100644 --- a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt +++ b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt @@ -4,6 +4,11 @@ import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.view.KeyEvent +import io.legado.app.constant.Bus +import io.legado.app.help.ActivityHelp +import io.legado.app.ui.readbook.ReadBookActivity +import io.legado.app.utils.postEvent +import org.jetbrains.anko.startActivity /** @@ -41,7 +46,12 @@ class MediaButtonReceiver : BroadcastReceiver() { } private fun readAloud(context: Context) { - + ActivityHelp.getInstance()?.isExist(ReadBookActivity::class.java)?.let { + if (!it) { + context.startActivity() + } + } + postEvent(Bus.READ_ALOUD, "") } } diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index f0389a93e..b556af0ea 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -246,6 +246,6 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea observeEvent(Bus.TTS_RANGE_START) {} observeEvent(Bus.TIME_CHANGED) {} observeEvent(Bus.BATTERY_CHANGED) {} - observeEvent(Bus.READ_ALOUD) { onClickReadAloud() } + observeEventSticky(Bus.READ_ALOUD) { onClickReadAloud() } } } \ No newline at end of file From edd3ab77f9d15c014c8c14b9aefb826b628a4dca Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 16 Aug 2019 17:37:13 +0800 Subject: [PATCH 0721/1997] up --- .../main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index b556af0ea..4d44842f0 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -233,6 +233,9 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } when (readAloudStatus) { Status.STOP -> { + viewModel.book?.let { + ReadAloudService.paly(this, it.name, "", "") + } } Status.PLAY -> ReadAloudService.pause(this) Status.PAUSE -> ReadAloudService.resume(this) From 04b471f7c1d2d429fc127054325f27d921908bd4 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 16 Aug 2019 18:29:19 +0800 Subject: [PATCH 0722/1997] up --- .../app/ui/widget/page/ChapterProvider.kt | 19 +++++++++ .../app/ui/widget/page/ContentTextView.kt | 41 +++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt create mode 100644 app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt new file mode 100644 index 000000000..32e4dc66f --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt @@ -0,0 +1,19 @@ +package io.legado.app.ui.widget.page + +import android.widget.TextView + + +class ChapterProvider { + + + fun getTextChapter(textView: TextView, content: String) { + + textView.text = content + val layout = textView.layout + val topOfLastLine = textView.height - textView.paddingTop - textView.paddingBottom - textView.lineHeight + val lineNum = layout.getLineForVertical(topOfLastLine) + val lastCharNum = layout.getLineEnd(lineNum) + } + + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt new file mode 100644 index 000000000..4e6c22138 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt @@ -0,0 +1,41 @@ +package io.legado.app.ui.widget.page + +import android.content.Context +import android.util.AttributeSet +import androidx.appcompat.widget.AppCompatTextView + + +class ContentTextView : AppCompatTextView { + constructor(context: Context) : super(context) + + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) + + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) + + /** + * 去除当前页无法显示的字 + * @return 去掉的字数 + */ + fun resize(): Int { + val oldContent = text + val newContent = oldContent.subSequence(0, getCharNum()) + text = newContent + return oldContent.length - newContent.length + } + + /** + * 获取当前页总字数 + */ + fun getCharNum(): Int { + return layout.getLineEnd(getLineNum()) + } + + /** + * 获取当前页总行数 + */ + fun getLineNum(): Int { + val layout = layout + val topOfLastLine = height - paddingTop - paddingBottom - lineHeight + return layout.getLineForVertical(topOfLastLine) + } +} From 20fd00f165056cf650217459289d00caa5959231 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 16 Aug 2019 19:59:37 +0800 Subject: [PATCH 0723/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 8 +++++++- .../app/ui/readbook/ReadBookViewModel.kt | 2 +- .../app/ui/widget/page/ChapterProvider.kt | 20 +++++++++++-------- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 4d44842f0..be1a968ab 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -42,7 +42,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea setSupportActionBar(toolbar) initAnimation() initView() - viewModel.chapterMaxIndex.observe(this, Observer { }) + viewModel.chapterMaxIndex.observe(this, Observer { bookLoadFinish() }) viewModel.initData(intent) savedInstanceState?.let { changeSourceDialog = supportFragmentManager.findFragmentByTag(ChangeSourceDialog.tag) as? ChangeSourceDialog @@ -222,6 +222,12 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } + private fun bookLoadFinish() { + viewModel.book?.let { + viewModel.loadContent(it, it.durChapterIndex) + } + } + override fun changeTo(book: Book) { } diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index da91edc8a..7e470f80a 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -48,7 +48,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } - fun getContent(book: Book, index: Int) { + fun loadContent(book: Book, index: Int) { App.db.bookChapterDao().getChapter(book.bookUrl, index)?.let { chapter -> BookHelp.getContent(book, chapter)?.let { diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt index 32e4dc66f..3832a42c6 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt @@ -1,18 +1,22 @@ package io.legado.app.ui.widget.page -import android.widget.TextView +import io.legado.app.data.entities.BookChapter class ChapterProvider { - fun getTextChapter(textView: TextView, content: String) { - - textView.text = content - val layout = textView.layout - val topOfLastLine = textView.height - textView.paddingTop - textView.paddingBottom - textView.lineHeight - val lineNum = layout.getLineForVertical(topOfLastLine) - val lastCharNum = layout.getLineEnd(lineNum) + fun getTextChapter(textView: ContentTextView, bookChapter: BookChapter, content: String): TextChapter { + val textPages = arrayListOf() + var surplusText = content + var pageIndex = 0 + while (surplusText.isNotEmpty()) { + textView.text = surplusText + textPages.add(TextPage(pageIndex, surplusText.substring(0, textView.getCharNum()))) + surplusText = surplusText.substring(textView.getCharNum()) + pageIndex++ + } + return TextChapter(bookChapter.index, textPages) } From 9b8a78debf18880e565c07b10fdd46f6b6532aa6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 16 Aug 2019 20:08:28 +0800 Subject: [PATCH 0724/1997] up --- .../app/ui/readbook/ReadBookViewModel.kt | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index 7e470f80a..adc311adc 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -28,18 +28,18 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { bookSource = App.db.bookSourceDao().getBookSource(book.origin) bookSource?.let { webBook = WebBook(it) - val count = App.db.bookChapterDao().getChapterCount(bookUrl) - if (count == 0) { - webBook?.getChapterList(book) - ?.onSuccess { cList -> - cList?.let { - App.db.bookChapterDao().insert(*cList.toTypedArray()) - chapterMaxIndex.postValue(cList.size) - } + } + val count = App.db.bookChapterDao().getChapterCount(bookUrl) + if (count == 0) { + webBook?.getChapterList(book) + ?.onSuccess { cList -> + cList?.let { + App.db.bookChapterDao().insert(*cList.toTypedArray()) + chapterMaxIndex.postValue(cList.size) } - } else { - chapterMaxIndex.postValue(count) - } + } + } else { + chapterMaxIndex.postValue(count) } } From 00dbba38985ce1d1327c4f51f49568ae628fb576 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 16 Aug 2019 20:19:47 +0800 Subject: [PATCH 0725/1997] up --- .../main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index adc311adc..e618f96d6 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -32,7 +32,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { val count = App.db.bookChapterDao().getChapterCount(bookUrl) if (count == 0) { webBook?.getChapterList(book) - ?.onSuccess { cList -> + ?.onSuccess(IO) { cList -> cList?.let { App.db.bookChapterDao().insert(*cList.toTypedArray()) chapterMaxIndex.postValue(cList.size) From 811191e153dbdd7acb87a0a7b4e13b52567171f3 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 16 Aug 2019 20:24:53 +0800 Subject: [PATCH 0726/1997] up --- .../java/io/legado/app/ui/readbook/ReadBookViewModel.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index e618f96d6..1288583a8 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -49,10 +49,12 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { fun loadContent(book: Book, index: Int) { - App.db.bookChapterDao().getChapter(book.bookUrl, index)?.let { chapter -> - BookHelp.getContent(book, chapter)?.let { + execute { + App.db.bookChapterDao().getChapter(book.bookUrl, index)?.let { chapter -> + BookHelp.getContent(book, chapter)?.let { - } ?: download(book, chapter) + } ?: download(book, chapter) + } } } From 9c7e2c74889b5df463e691ccb0b56775b24d5cfc Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 16 Aug 2019 20:35:38 +0800 Subject: [PATCH 0727/1997] up --- .../java/io/legado/app/ui/readbook/ReadBookViewModel.kt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index 1288583a8..65af68269 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -48,21 +48,22 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } - fun loadContent(book: Book, index: Int) { + fun loadContent(book: Book, index: Int, success: ((content: String) -> Unit)) { execute { App.db.bookChapterDao().getChapter(book.bookUrl, index)?.let { chapter -> BookHelp.getContent(book, chapter)?.let { - - } ?: download(book, chapter) + success(it) + } ?: download(book, chapter, success) } } } - private fun download(book: Book, chapter: BookChapter) { + fun download(book: Book, chapter: BookChapter, success: ((content: String) -> Unit)? = null) { webBook?.getContent(book, chapter) ?.onSuccess(IO) { content -> content?.let { BookHelp.saveContent(book, chapter, it) + success?.invoke(it) } } } From 4cbfc02dabcff2038f357bc58c2584fb1a15a3e0 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 16 Aug 2019 21:01:51 +0800 Subject: [PATCH 0728/1997] up --- .../legado/app/ui/readbook/ReadBookActivity.kt | 12 +++++++++++- .../legado/app/ui/readbook/ReadBookViewModel.kt | 16 +++++++++++----- app/src/main/res/layout/view_book_page.xml | 10 ++++------ 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index be1a968ab..f8945670c 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -14,18 +14,22 @@ import io.legado.app.base.VMBaseActivity import io.legado.app.constant.Bus import io.legado.app.constant.Status import io.legado.app.data.entities.Book +import io.legado.app.data.entities.BookChapter import io.legado.app.receiver.TimeElectricityReceiver import io.legado.app.service.ReadAloudService import io.legado.app.ui.changesource.ChangeSourceDialog import io.legado.app.ui.chapterlist.ChapterListActivity import io.legado.app.ui.replacerule.ReplaceRuleActivity +import io.legado.app.ui.widget.page.ChapterProvider import io.legado.app.utils.* import kotlinx.android.synthetic.main.activity_read_book.* +import kotlinx.android.synthetic.main.view_book_page.* import kotlinx.android.synthetic.main.view_title_bar.* import org.jetbrains.anko.sdk27.listeners.onClick import org.jetbrains.anko.startActivity -class ReadBookActivity : VMBaseActivity(R.layout.activity_read_book), ChangeSourceDialog.CallBack { +class ReadBookActivity : VMBaseActivity(R.layout.activity_read_book), ChangeSourceDialog.CallBack, + ReadBookViewModel.CallBack { override val viewModel: ReadBookViewModel get() = getViewModel(ReadBookViewModel::class.java) @@ -42,6 +46,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea setSupportActionBar(toolbar) initAnimation() initView() + viewModel.callBack = this viewModel.chapterMaxIndex.observe(this, Observer { bookLoadFinish() }) viewModel.initData(intent) savedInstanceState?.let { @@ -228,6 +233,11 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } + override fun loadContentFinish(bookChapter: BookChapter, content: String) { + val textChapter = ChapterProvider().getTextChapter(content_text_view, bookChapter, content) + print(textChapter.pages.size) + } + override fun changeTo(book: Book) { } diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index 65af68269..4bc182165 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -18,6 +18,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { var bookSource: BookSource? = null var chapterMaxIndex = MediatorLiveData() var webBook: WebBook? = null + var callBack: CallBack? = null fun initData(intent: Intent) { val bookUrl = intent.getStringExtra("bookUrl") @@ -48,23 +49,28 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } - fun loadContent(book: Book, index: Int, success: ((content: String) -> Unit)) { + fun loadContent(book: Book, index: Int) { execute { App.db.bookChapterDao().getChapter(book.bookUrl, index)?.let { chapter -> BookHelp.getContent(book, chapter)?.let { - success(it) - } ?: download(book, chapter, success) + callBack?.loadContentFinish(chapter, it) + } ?: download(book, chapter) } } } - fun download(book: Book, chapter: BookChapter, success: ((content: String) -> Unit)? = null) { + fun download(book: Book, chapter: BookChapter) { webBook?.getContent(book, chapter) ?.onSuccess(IO) { content -> content?.let { BookHelp.saveContent(book, chapter, it) - success?.invoke(it) + callBack?.loadContentFinish(chapter, it) } } } + + + interface CallBack { + fun loadContentFinish(bookChapter: BookChapter, content: String) + } } \ No newline at end of file diff --git a/app/src/main/res/layout/view_book_page.xml b/app/src/main/res/layout/view_book_page.xml index ec9423495..9ed52c863 100644 --- a/app/src/main/res/layout/view_book_page.xml +++ b/app/src/main/res/layout/view_book_page.xml @@ -21,12 +21,10 @@ android:layout_height="0dp" android:layout_weight="1"> - - + Date: Fri, 16 Aug 2019 22:11:09 +0800 Subject: [PATCH 0729/1997] up --- .../java/io/legado/app/ui/readbook/ReadBookActivity.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index f8945670c..3ac82b10d 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -25,6 +25,7 @@ import io.legado.app.utils.* import kotlinx.android.synthetic.main.activity_read_book.* import kotlinx.android.synthetic.main.view_book_page.* import kotlinx.android.synthetic.main.view_title_bar.* +import kotlinx.coroutines.launch import org.jetbrains.anko.sdk27.listeners.onClick import org.jetbrains.anko.startActivity @@ -234,8 +235,10 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } override fun loadContentFinish(bookChapter: BookChapter, content: String) { - val textChapter = ChapterProvider().getTextChapter(content_text_view, bookChapter, content) - print(textChapter.pages.size) + launch { + val textChapter = ChapterProvider().getTextChapter(content_text_view, bookChapter, content) + print(textChapter.pages.size) + } } override fun changeTo(book: Book) { From 95bbd594620102fb80c58f0686a2080a9da571a9 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 16 Aug 2019 22:14:06 +0800 Subject: [PATCH 0730/1997] up --- app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 3ac82b10d..082e60f9c 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -237,7 +237,6 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea override fun loadContentFinish(bookChapter: BookChapter, content: String) { launch { val textChapter = ChapterProvider().getTextChapter(content_text_view, bookChapter, content) - print(textChapter.pages.size) } } From 0061ab721a5018be3dac6038e284f3880fe83ee6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 16 Aug 2019 22:18:00 +0800 Subject: [PATCH 0731/1997] up --- app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 082e60f9c..1d70e294a 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -237,6 +237,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea override fun loadContentFinish(bookChapter: BookChapter, content: String) { launch { val textChapter = ChapterProvider().getTextChapter(content_text_view, bookChapter, content) + content_text_view.text = textChapter.pages[0].text } } From 471a08a7b19cd672332b5f53724a24ee1679e5ec Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 16 Aug 2019 22:52:25 +0800 Subject: [PATCH 0732/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 9 +++++---- .../app/ui/readbook/ReadBookViewModel.kt | 19 ++++++++++++++----- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 1d70e294a..ab6e1b036 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -49,6 +49,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea initView() viewModel.callBack = this viewModel.chapterMaxIndex.observe(this, Observer { bookLoadFinish() }) + viewModel.bookData.observe(this, Observer { title_bar.title = it.name }) viewModel.initData(intent) savedInstanceState?.let { changeSourceDialog = supportFragmentManager.findFragmentByTag(ChangeSourceDialog.tag) as? ChangeSourceDialog @@ -145,7 +146,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } override fun openChapterList() { - viewModel.book?.let { + viewModel.bookData.value?.let { startActivity(Pair("bookUrl", it.bookUrl)) } } @@ -182,7 +183,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea when (item.itemId) { R.id.menu_change_source -> { if (changeSourceDialog == null) { - viewModel.book?.let { + viewModel.bookData.value?.let { changeSourceDialog = ChangeSourceDialog.newInstance(it.name, it.author) changeSourceDialog?.callBack = this } @@ -229,7 +230,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } private fun bookLoadFinish() { - viewModel.book?.let { + viewModel.bookData.value?.let { viewModel.loadContent(it, it.durChapterIndex) } } @@ -252,7 +253,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } when (readAloudStatus) { Status.STOP -> { - viewModel.book?.let { + viewModel.bookData.value?.let { ReadAloudService.paly(this, it.name, "", "") } } diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index 4bc182165..c345cccbc 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -3,6 +3,7 @@ package io.legado.app.ui.readbook import android.app.Application import android.content.Intent import androidx.lifecycle.MediatorLiveData +import androidx.lifecycle.MutableLiveData import io.legado.app.App import io.legado.app.base.BaseViewModel import io.legado.app.data.entities.Book @@ -14,7 +15,7 @@ import kotlinx.coroutines.Dispatchers.IO class ReadBookViewModel(application: Application) : BaseViewModel(application) { - var book: Book? = null + var bookData = MutableLiveData() var bookSource: BookSource? = null var chapterMaxIndex = MediatorLiveData() var webBook: WebBook? = null @@ -24,8 +25,10 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { val bookUrl = intent.getStringExtra("bookUrl") if (!bookUrl.isNullOrEmpty()) { execute { - book = App.db.bookDao().getBook(bookUrl) - book?.let { book -> + App.db.bookDao().getBook(bookUrl).let { + bookData.postValue(it) + } + bookData.value?.let { book -> bookSource = App.db.bookSourceDao().getBookSource(book.origin) bookSource?.let { webBook = WebBook(it) @@ -34,11 +37,17 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { if (count == 0) { webBook?.getChapterList(book) ?.onSuccess(IO) { cList -> - cList?.let { + if (!cList.isNullOrEmpty()) { App.db.bookChapterDao().insert(*cList.toTypedArray()) chapterMaxIndex.postValue(cList.size) + } else { + } - } + }?.onError { + + } ?: let { + + } } else { chapterMaxIndex.postValue(count) } From a41346b6dea54be354684bd9c0460e22e7a40977 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 17 Aug 2019 08:43:10 +0800 Subject: [PATCH 0733/1997] up --- app/src/main/java/io/legado/app/base/BaseViewModel.kt | 4 ++++ .../io/legado/app/ui/readbook/ReadBookViewModel.kt | 11 +++++++---- app/src/main/res/values/strings.xml | 1 + 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/base/BaseViewModel.kt b/app/src/main/java/io/legado/app/base/BaseViewModel.kt index 655cd7097..e14fa7a3d 100644 --- a/app/src/main/java/io/legado/app/base/BaseViewModel.kt +++ b/app/src/main/java/io/legado/app/base/BaseViewModel.kt @@ -24,4 +24,8 @@ open class BaseViewModel(application: Application) : AndroidViewModel(applicatio super.onCleared() cancel() } + + open fun toast(message: Int) { + + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index c345cccbc..6b023c7a0 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -5,12 +5,14 @@ import android.content.Intent import androidx.lifecycle.MediatorLiveData import androidx.lifecycle.MutableLiveData import io.legado.app.App +import io.legado.app.R import io.legado.app.base.BaseViewModel import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter import io.legado.app.data.entities.BookSource import io.legado.app.help.BookHelp import io.legado.app.model.WebBook +import io.legado.app.utils.toast import kotlinx.coroutines.Dispatchers.IO class ReadBookViewModel(application: Application) : BaseViewModel(application) { @@ -44,10 +46,8 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } }?.onError { - - } ?: let { - - } + getApplication().toast(R.string.load_toc_error) + } ?: autoChangeSource() } else { chapterMaxIndex.postValue(count) } @@ -78,6 +78,9 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } } + private fun autoChangeSource() { + + } interface CallBack { fun loadContentFinish(bookChapter: BookChapter, content: String) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6caf136b6..51172e3ed 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -474,4 +474,5 @@ ]]> 阅读 + 加载目录失败 From f78616d6056757a2fcb09d1cdfe82501529b46be Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 17 Aug 2019 09:47:46 +0800 Subject: [PATCH 0734/1997] up --- .../java/io/legado/app/base/BaseViewModel.kt | 27 ++++++++++++++++--- .../app/ui/readbook/ReadBookViewModel.kt | 5 ++-- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/io/legado/app/base/BaseViewModel.kt b/app/src/main/java/io/legado/app/base/BaseViewModel.kt index e14fa7a3d..df58bf2cb 100644 --- a/app/src/main/java/io/legado/app/base/BaseViewModel.kt +++ b/app/src/main/java/io/legado/app/base/BaseViewModel.kt @@ -2,12 +2,11 @@ package io.legado.app.base import android.app.Application import androidx.lifecycle.AndroidViewModel +import io.legado.app.App import io.legado.app.help.coroutine.Coroutine -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Deferred -import kotlinx.coroutines.MainScope -import kotlinx.coroutines.cancel +import kotlinx.coroutines.* import org.jetbrains.anko.AnkoLogger +import org.jetbrains.anko.toast open class BaseViewModel(application: Application) : AndroidViewModel(application), CoroutineScope by MainScope(), AnkoLogger { @@ -26,6 +25,26 @@ open class BaseViewModel(application: Application) : AndroidViewModel(applicatio } open fun toast(message: Int) { + launch { + getApplication().toast(message) + } + } + + open fun toast(message: CharSequence) { + launch { + getApplication().toast(message) + } + } + + open fun longToast(message: Int) { + launch { + getApplication().toast(message) + } + } + open fun longToast(message: CharSequence) { + launch { + getApplication().toast(message) + } } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index 6b023c7a0..69e0d11b7 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -12,7 +12,6 @@ import io.legado.app.data.entities.BookChapter import io.legado.app.data.entities.BookSource import io.legado.app.help.BookHelp import io.legado.app.model.WebBook -import io.legado.app.utils.toast import kotlinx.coroutines.Dispatchers.IO class ReadBookViewModel(application: Application) : BaseViewModel(application) { @@ -43,10 +42,10 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { App.db.bookChapterDao().insert(*cList.toTypedArray()) chapterMaxIndex.postValue(cList.size) } else { - + toast(R.string.load_toc_error) } }?.onError { - getApplication().toast(R.string.load_toc_error) + toast(R.string.load_toc_error) } ?: autoChangeSource() } else { chapterMaxIndex.postValue(count) From 88e1a4023a4a7d4776406fd6f047fd4928faf98e Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 17 Aug 2019 09:49:27 +0800 Subject: [PATCH 0735/1997] up --- app/src/main/res/menu/read_book.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/menu/read_book.xml b/app/src/main/res/menu/read_book.xml index f6b5a1bb4..8b95f1d3a 100644 --- a/app/src/main/res/menu/read_book.xml +++ b/app/src/main/res/menu/read_book.xml @@ -35,6 +35,7 @@ android:id="@+id/menu_set_regex" android:icon="@drawable/ic_exchange" android:title="@string/txt_chapter_regex" + android:visible="false" app:showAsAction="always" /> From 45fe6caea59a000aa55c46b17d0d9ddebb64ca93 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 17 Aug 2019 10:13:23 +0800 Subject: [PATCH 0736/1997] up --- .../main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 2 +- .../main/java/io/legado/app/ui/widget/page/ChapterProvider.kt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index ab6e1b036..d817b5357 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -237,7 +237,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea override fun loadContentFinish(bookChapter: BookChapter, content: String) { launch { - val textChapter = ChapterProvider().getTextChapter(content_text_view, bookChapter, content) + val textChapter = ChapterProvider.getTextChapter(content_text_view, bookChapter, content) content_text_view.text = textChapter.pages[0].text } } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt index 3832a42c6..c80c4bd2b 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt @@ -3,9 +3,9 @@ package io.legado.app.ui.widget.page import io.legado.app.data.entities.BookChapter -class ChapterProvider { - +object ChapterProvider { + @Synchronized fun getTextChapter(textView: ContentTextView, bookChapter: BookChapter, content: String): TextChapter { val textPages = arrayListOf() var surplusText = content From 21adbcdca27773cb5327a008126986eb8213a450 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 17 Aug 2019 11:41:53 +0800 Subject: [PATCH 0737/1997] up --- .../legado/app/ui/readbook/ReadBookActivity.kt | 2 +- .../app/ui/widget/page/ChapterProvider.kt | 17 +++++++++++++++-- .../io/legado/app/ui/widget/page/TextPage.kt | 4 +++- .../app/ui/widget/page/TextPageFactory.kt | 6 ++++-- 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index d817b5357..5faef48df 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -238,7 +238,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea override fun loadContentFinish(bookChapter: BookChapter, content: String) { launch { val textChapter = ChapterProvider.getTextChapter(content_text_view, bookChapter, content) - content_text_view.text = textChapter.pages[0].text + content_text_view.text = textChapter.pages[0].stringBuilder } } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt index c80c4bd2b..8083b02ab 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt @@ -1,5 +1,8 @@ package io.legado.app.ui.widget.page +import android.text.Spannable +import android.text.SpannableStringBuilder +import android.text.style.RelativeSizeSpan import io.legado.app.data.entities.BookChapter @@ -11,8 +14,18 @@ object ChapterProvider { var surplusText = content var pageIndex = 0 while (surplusText.isNotEmpty()) { - textView.text = surplusText - textPages.add(TextPage(pageIndex, surplusText.substring(0, textView.getCharNum()))) + val spannableStringBuilder = SpannableStringBuilder(surplusText) + if (pageIndex == 0) { + val span = RelativeSizeSpan(1.5f) + spannableStringBuilder.setSpan(span, 0, surplusText.indexOf("\n"), Spannable.SPAN_INCLUSIVE_EXCLUSIVE) + } + textView.text = spannableStringBuilder + textPages.add( + TextPage( + pageIndex, + spannableStringBuilder.delete(textView.getCharNum(), spannableStringBuilder.length) + ) + ) surplusText = surplusText.substring(textView.getCharNum()) pageIndex++ } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextPage.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextPage.kt index 186eb757e..4feeaf64e 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextPage.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextPage.kt @@ -1,3 +1,5 @@ package io.legado.app.ui.widget.page -data class TextPage(val index: Int, val text: String) +import android.text.SpannableStringBuilder + +data class TextPage(val index: Int, val stringBuilder: SpannableStringBuilder) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt index 2fd3d951c..e42895454 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt @@ -1,5 +1,7 @@ package io.legado.app.ui.widget.page +import android.text.SpannableStringBuilder + class TextPageFactory private constructor(dataSource: DataSource) : PageFactory(dataSource) { companion object{ @@ -15,11 +17,11 @@ class TextPageFactory private constructor(dataSource: DataSource) : PageFactory< } override fun nextPage(): TextPage { - return TextPage(index.plus(1), "index:$index") + return TextPage(index.plus(1), SpannableStringBuilder("index:$index")) } override fun previousPage(): TextPage { - return TextPage(index.minus(1), "index:$index") + return TextPage(index.minus(1), SpannableStringBuilder("index:$index")) } From f484edbfaab7899ce9d4a1ef2ec02c44468713bc Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 17 Aug 2019 11:50:18 +0800 Subject: [PATCH 0738/1997] up --- .../java/io/legado/app/ui/readbook/ReadBookViewModel.kt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index 69e0d11b7..faf91f119 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -26,10 +26,8 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { val bookUrl = intent.getStringExtra("bookUrl") if (!bookUrl.isNullOrEmpty()) { execute { - App.db.bookDao().getBook(bookUrl).let { - bookData.postValue(it) - } - bookData.value?.let { book -> + App.db.bookDao().getBook(bookUrl)?.let { book -> + bookData.postValue(book) bookSource = App.db.bookSourceDao().getBookSource(book.origin) bookSource?.let { webBook = WebBook(it) From 83fc40af336aaedf83ed4812c7700bd2fb59725c Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 17 Aug 2019 12:01:47 +0800 Subject: [PATCH 0739/1997] up --- app/src/main/res/layout/view_book_page.xml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/app/src/main/res/layout/view_book_page.xml b/app/src/main/res/layout/view_book_page.xml index 9ed52c863..c86b9d3b7 100644 --- a/app/src/main/res/layout/view_book_page.xml +++ b/app/src/main/res/layout/view_book_page.xml @@ -14,7 +14,6 @@ android:layout_width="match_parent" android:layout_height="25dp"/> - - Date: Sat, 17 Aug 2019 13:37:14 +0800 Subject: [PATCH 0740/1997] up --- .../io/legado/app/ui/widget/page/ContentTextView.kt | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt index 4e6c22138..788ecc77e 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt @@ -12,17 +12,6 @@ class ContentTextView : AppCompatTextView { constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) - /** - * 去除当前页无法显示的字 - * @return 去掉的字数 - */ - fun resize(): Int { - val oldContent = text - val newContent = oldContent.subSequence(0, getCharNum()) - text = newContent - return oldContent.length - newContent.length - } - /** * 获取当前页总字数 */ From 515b537c9dd746e0b71aff6aeb76705f16debdf9 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 17 Aug 2019 14:27:37 +0800 Subject: [PATCH 0741/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 8 ++++++++ .../app/ui/readbook/ReadBookViewModel.kt | 7 ++++++- .../app/ui/widget/page/ContentTextView.kt | 4 ++-- .../legado/app/ui/widget/page/ContentView.kt | 20 +++++++++++++++++++ .../main/res/layout/activity_read_book.xml | 18 +++++++++-------- 5 files changed, 46 insertions(+), 11 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 5faef48df..ac969136e 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -237,6 +237,14 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea override fun loadContentFinish(bookChapter: BookChapter, content: String) { launch { + if (viewModel.durChapterIndex == bookChapter.index) { + tv_chapter_name.text = bookChapter.title + tv_chapter_name.visible() + if (!viewModel.isLocalBook) { + tv_chapter_url.text = bookChapter.url + tv_chapter_url.visible() + } + } val textChapter = ChapterProvider.getTextChapter(content_text_view, bookChapter, content) content_text_view.text = textChapter.pages[0].stringBuilder } diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index faf91f119..978a06ab2 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -7,6 +7,7 @@ import androidx.lifecycle.MutableLiveData import io.legado.app.App import io.legado.app.R import io.legado.app.base.BaseViewModel +import io.legado.app.constant.BookType import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter import io.legado.app.data.entities.BookSource @@ -17,10 +18,12 @@ import kotlinx.coroutines.Dispatchers.IO class ReadBookViewModel(application: Application) : BaseViewModel(application) { var bookData = MutableLiveData() - var bookSource: BookSource? = null var chapterMaxIndex = MediatorLiveData() + var bookSource: BookSource? = null var webBook: WebBook? = null var callBack: CallBack? = null + var durChapterIndex = 0 + var isLocalBook = true fun initData(intent: Intent) { val bookUrl = intent.getStringExtra("bookUrl") @@ -28,6 +31,8 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { execute { App.db.bookDao().getBook(bookUrl)?.let { book -> bookData.postValue(book) + durChapterIndex = book.durChapterIndex + isLocalBook = book.origin == BookType.local bookSource = App.db.bookSourceDao().getBookSource(book.origin) bookSource?.let { webBook = WebBook(it) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt index 788ecc77e..680627567 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt @@ -8,9 +8,9 @@ import androidx.appcompat.widget.AppCompatTextView class ContentTextView : AppCompatTextView { constructor(context: Context) : super(context) - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) /** * 获取当前页总字数 diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt new file mode 100644 index 000000000..4f8abfa55 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -0,0 +1,20 @@ +package io.legado.app.ui.widget.page + +import android.content.Context +import android.util.AttributeSet +import android.widget.FrameLayout +import io.legado.app.R + + +class ContentView : FrameLayout { + + constructor(context: Context) : super(context) + + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) + + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) + + init { + inflate(context, R.layout.view_book_page, this) + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_read_book.xml b/app/src/main/res/layout/activity_read_book.xml index e59480522..5c666055d 100644 --- a/app/src/main/res/layout/activity_read_book.xml +++ b/app/src/main/res/layout/activity_read_book.xml @@ -1,12 +1,12 @@ + android:layout_height="match_parent" + android:orientation="vertical"> + android:layout_width="match_parent" + android:layout_height="match_parent" /> + android:theme="?attr/actionBarStyle" + android:visibility="gone"> + android:textSize="12sp" + android:visibility="gone" /> + android:textSize="12sp" + android:visibility="gone" /> From 88c66a83b7f2a42bc704b0193aa8a6f283f90e67 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 17 Aug 2019 14:43:44 +0800 Subject: [PATCH 0742/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 23 ++++++++++++------- .../app/ui/readbook/ReadBookViewModel.kt | 4 ++++ .../app/ui/widget/page/ChapterProvider.kt | 2 +- .../legado/app/ui/widget/page/TextChapter.kt | 2 +- 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index ac969136e..202eb3c69 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -237,16 +237,23 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea override fun loadContentFinish(bookChapter: BookChapter, content: String) { launch { - if (viewModel.durChapterIndex == bookChapter.index) { - tv_chapter_name.text = bookChapter.title - tv_chapter_name.visible() - if (!viewModel.isLocalBook) { - tv_chapter_url.text = bookChapter.url - tv_chapter_url.visible() + when (bookChapter.index) { + viewModel.durChapterIndex -> { + tv_chapter_name.text = bookChapter.title + tv_chapter_name.visible() + if (!viewModel.isLocalBook) { + tv_chapter_url.text = bookChapter.url + tv_chapter_url.visible() + } + viewModel.curTextChapter = ChapterProvider.getTextChapter(content_text_view, bookChapter, content) + } + viewModel.durChapterIndex - 1 -> { + viewModel.prevTextChapter = ChapterProvider.getTextChapter(content_text_view, bookChapter, content) + } + viewModel.durChapterIndex + 1 -> { + viewModel.nextTextChapter = ChapterProvider.getTextChapter(content_text_view, bookChapter, content) } } - val textChapter = ChapterProvider.getTextChapter(content_text_view, bookChapter, content) - content_text_view.text = textChapter.pages[0].stringBuilder } } diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index 978a06ab2..4c331cf46 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -13,6 +13,7 @@ import io.legado.app.data.entities.BookChapter import io.legado.app.data.entities.BookSource import io.legado.app.help.BookHelp import io.legado.app.model.WebBook +import io.legado.app.ui.widget.page.TextChapter import kotlinx.coroutines.Dispatchers.IO class ReadBookViewModel(application: Application) : BaseViewModel(application) { @@ -24,6 +25,9 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { var callBack: CallBack? = null var durChapterIndex = 0 var isLocalBook = true + var prevTextChapter: TextChapter? = null + var curTextChapter: TextChapter? = null + var nextTextChapter: TextChapter? = null fun initData(intent: Intent) { val bookUrl = intent.getStringExtra("bookUrl") diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt index 8083b02ab..e0a675d15 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt @@ -29,7 +29,7 @@ object ChapterProvider { surplusText = surplusText.substring(textView.getCharNum()) pageIndex++ } - return TextChapter(bookChapter.index, textPages) + return TextChapter(bookChapter.index, bookChapter.title, textPages) } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt index b4414c19b..837f1b2da 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt @@ -1,3 +1,3 @@ package io.legado.app.ui.widget.page -data class TextChapter(val position: Int, val pages: List) +data class TextChapter(val position: Int, val title: String, val pages: List) From 22b1238bd2b43db87391bea0484ce2984c069cf8 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 17 Aug 2019 14:57:21 +0800 Subject: [PATCH 0743/1997] up --- .../io/legado/app/ui/widget/page/TextChapter.kt | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt index 837f1b2da..bf529acbd 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt @@ -1,3 +1,15 @@ package io.legado.app.ui.widget.page -data class TextChapter(val position: Int, val title: String, val pages: List) +data class TextChapter( + val position: Int, + val title: String, + val pages: List +) { + fun getPage(index: Int): TextPage? { + if (index >= 0 && index < pages.size) { + return pages[index] + } + return null + } +} + From 63641f47d911080f1a618d7f4bf0fde65cce35cb Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 17 Aug 2019 14:59:45 +0800 Subject: [PATCH 0744/1997] up --- .../main/java/io/legado/app/ui/widget/page/TextChapter.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt index bf529acbd..df1643b17 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt @@ -5,11 +5,15 @@ data class TextChapter( val title: String, val pages: List ) { - fun getPage(index: Int): TextPage? { + fun page(index: Int): TextPage? { if (index >= 0 && index < pages.size) { return pages[index] } return null } + + fun pageSize(): Int { + return pages.size + } } From 576678bacb4bd430ea61db60b2e894068f6c0b77 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 17 Aug 2019 15:05:48 +0800 Subject: [PATCH 0745/1997] up --- .../main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 1 + app/src/main/java/io/legado/app/ui/widget/page/TextPage.kt | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 202eb3c69..eca831f27 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -246,6 +246,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea tv_chapter_url.visible() } viewModel.curTextChapter = ChapterProvider.getTextChapter(content_text_view, bookChapter, content) + content_text_view.text = viewModel.curTextChapter?.page(0)?.stringBuilder } viewModel.durChapterIndex - 1 -> { viewModel.prevTextChapter = ChapterProvider.getTextChapter(content_text_view, bookChapter, content) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextPage.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextPage.kt index 4feeaf64e..5c6dc6cdc 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextPage.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextPage.kt @@ -2,4 +2,7 @@ package io.legado.app.ui.widget.page import android.text.SpannableStringBuilder -data class TextPage(val index: Int, val stringBuilder: SpannableStringBuilder) +data class TextPage( + val index: Int, + val stringBuilder: SpannableStringBuilder +) From 8f8b302fb24f41df51eef6af21469f6cb1d18a3e Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 17 Aug 2019 15:17:30 +0800 Subject: [PATCH 0746/1997] up --- .../java/io/legado/app/ui/widget/page/ChapterProvider.kt | 9 ++++++--- .../java/io/legado/app/ui/widget/page/TextChapter.kt | 3 ++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt index e0a675d15..2c6afd592 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt @@ -11,6 +11,7 @@ object ChapterProvider { @Synchronized fun getTextChapter(textView: ContentTextView, bookChapter: BookChapter, content: String): TextChapter { val textPages = arrayListOf() + val pageLengths = arrayListOf() var surplusText = content var pageIndex = 0 while (surplusText.isNotEmpty()) { @@ -20,16 +21,18 @@ object ChapterProvider { spannableStringBuilder.setSpan(span, 0, surplusText.indexOf("\n"), Spannable.SPAN_INCLUSIVE_EXCLUSIVE) } textView.text = spannableStringBuilder + pageLengths.add(textView.getCharNum()) textPages.add( TextPage( pageIndex, - spannableStringBuilder.delete(textView.getCharNum(), spannableStringBuilder.length) + spannableStringBuilder.delete(pageLengths[pageIndex], spannableStringBuilder.length) ) ) - surplusText = surplusText.substring(textView.getCharNum()) + surplusText = surplusText.substring(pageLengths[pageIndex]) + pageIndex++ } - return TextChapter(bookChapter.index, bookChapter.title, textPages) + return TextChapter(bookChapter.index, bookChapter.title, textPages, pageLengths) } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt index df1643b17..032a732c1 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt @@ -3,7 +3,8 @@ package io.legado.app.ui.widget.page data class TextChapter( val position: Int, val title: String, - val pages: List + val pages: List, + val pageLengths: List ) { fun page(index: Int): TextPage? { if (index >= 0 && index < pages.size) { From f4fc8d0eead57a30a95653327b4a782e47b3cf0a Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 17 Aug 2019 15:20:35 +0800 Subject: [PATCH 0747/1997] up --- app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index eca831f27..ddf06c871 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -232,6 +232,8 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea private fun bookLoadFinish() { viewModel.bookData.value?.let { viewModel.loadContent(it, it.durChapterIndex) + viewModel.loadContent(it, it.durChapterIndex + 1) + viewModel.loadContent(it, it.durChapterIndex - 1) } } From 9af3c5afbd56db53de5ec8ae61ea40539eaa16a5 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 17 Aug 2019 16:48:41 +0800 Subject: [PATCH 0748/1997] up --- .../app/ui/readbook/ReadBookViewModel.kt | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index 4c331cf46..c0f0fa3e7 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -28,6 +28,8 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { var prevTextChapter: TextChapter? = null var curTextChapter: TextChapter? = null var nextTextChapter: TextChapter? = null + private val loadingChapters = arrayListOf() + private val loadingLock = "loadingLock" fun initData(intent: Intent) { val bookUrl = intent.getStringExtra("bookUrl") @@ -65,21 +67,45 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { fun loadContent(book: Book, index: Int) { + synchronized(loadingLock) { + if (loadingChapters.contains(index)) return + loadingChapters.add(index) + } execute { App.db.bookChapterDao().getChapter(book.bookUrl, index)?.let { chapter -> BookHelp.getContent(book, chapter)?.let { callBack?.loadContentFinish(chapter, it) + synchronized(loadingLock) { + loadingChapters.remove(index) + } } ?: download(book, chapter) } } } - fun download(book: Book, chapter: BookChapter) { + fun downLoad(book: Book, index: Int) { + synchronized(loadingLock) { + if (loadingChapters.contains(index)) return + loadingChapters.add(index) + } + execute { + App.db.bookChapterDao().getChapter(book.bookUrl, index)?.let { chapter -> + if (!BookHelp.hasContent(book, chapter)) { + download(book, chapter) + } + } + } + } + + private fun download(book: Book, chapter: BookChapter) { webBook?.getContent(book, chapter) ?.onSuccess(IO) { content -> content?.let { BookHelp.saveContent(book, chapter, it) callBack?.loadContentFinish(chapter, it) + synchronized(loadingLock) { + loadingChapters.remove(chapter.index) + } } } } From e97b2630ceff9d598169822d53405c7d245235fc Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 17 Aug 2019 16:50:52 +0800 Subject: [PATCH 0749/1997] up --- .../io/legado/app/ui/readbook/ReadBookViewModel.kt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index c0f0fa3e7..046ebd51e 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -80,6 +80,10 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } } ?: download(book, chapter) } + }.onError { + synchronized(loadingLock) { + loadingChapters.remove(index) + } } } @@ -94,6 +98,10 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { download(book, chapter) } } + }.onError { + synchronized(loadingLock) { + loadingChapters.remove(index) + } } } @@ -107,6 +115,10 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { loadingChapters.remove(chapter.index) } } + }?.onError { + synchronized(loadingLock) { + loadingChapters.remove(chapter.index) + } } } From b4eb0d095847f953ad28cf92fd0dafb00696df9f Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 17 Aug 2019 17:33:29 +0800 Subject: [PATCH 0750/1997] up --- .../main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index 046ebd51e..4d5233e7b 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -87,7 +87,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } } - fun downLoad(book: Book, index: Int) { + fun download(book: Book, index: Int) { synchronized(loadingLock) { if (loadingChapters.contains(index)) return loadingChapters.add(index) From 8b3d956e7ecf53c56ae2ae6c3deae25000944b10 Mon Sep 17 00:00:00 2001 From: Administrator <1760316362@qq.com> Date: Sat, 17 Aug 2019 18:10:25 +0800 Subject: [PATCH 0751/1997] update --- app/src/main/java/io/legado/app/App.kt | 33 +++ .../java/io/legado/app/base/BaseActivity.kt | 3 - .../java/io/legado/app/help/ActivityHelp.kt | 6 +- .../io/legado/app/ui/main/my/MyFragment.kt | 4 +- .../legado/app/ui/widget/page/DataSource.kt | 10 +- .../app/ui/widget/page/PageAnimDelegate.kt | 39 --- .../legado/app/ui/widget/page/PageFactory.kt | 10 +- .../io/legado/app/ui/widget/page/PageView.kt | 109 +++----- .../app/ui/widget/page/TextPageFactory.kt | 8 + .../widget/page/delegate/CoverPageDelegate.kt | 75 ++++++ .../ui/widget/page/delegate/PageDelegate.kt | 247 ++++++++++++++++++ 11 files changed, 414 insertions(+), 130 deletions(-) delete mode 100644 app/src/main/java/io/legado/app/ui/widget/page/PageAnimDelegate.kt create mode 100644 app/src/main/java/io/legado/app/ui/widget/page/delegate/CoverPageDelegate.kt create mode 100644 app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt diff --git a/app/src/main/java/io/legado/app/App.kt b/app/src/main/java/io/legado/app/App.kt index a6c6d9514..f0bf61b89 100644 --- a/app/src/main/java/io/legado/app/App.kt +++ b/app/src/main/java/io/legado/app/App.kt @@ -1,10 +1,12 @@ package io.legado.app +import android.app.Activity import android.app.Application import android.app.NotificationChannel import android.app.NotificationManager import android.content.Context import android.os.Build +import android.os.Bundle import androidx.annotation.RequiresApi import androidx.appcompat.app.AppCompatDelegate import com.jeremyliao.liveeventbus.LiveEventBus @@ -12,6 +14,7 @@ import io.legado.app.constant.AppConst.channelIdDownload import io.legado.app.constant.AppConst.channelIdReadAloud import io.legado.app.constant.AppConst.channelIdWeb import io.legado.app.data.AppDatabase +import io.legado.app.help.ActivityHelp import io.legado.app.lib.theme.ThemeStore import io.legado.app.utils.getCompatColor import io.legado.app.utils.getPrefInt @@ -53,6 +56,8 @@ class App : Application() { .supportBroadcast(this) .lifecycleObserverAlwaysActive(true) .autoClear(false) + + registerActivityLife() } /** @@ -134,4 +139,32 @@ class App : Application() { it.createNotificationChannels(listOf(downloadChannel, readAloudChannel, webChannel)) } } + + private fun registerActivityLife(){ + registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks{ + override fun onActivityPaused(activity: Activity) { + ActivityHelp.getInstance().add(activity) + } + + override fun onActivityResumed(activity: Activity) { + } + + override fun onActivityStarted(activity: Activity) { + } + + override fun onActivityDestroyed(activity: Activity) { + ActivityHelp.getInstance().remove(activity) + } + + override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle?) { + } + + override fun onActivityStopped(activity: Activity) { + } + + override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) { + } + + }) + } } diff --git a/app/src/main/java/io/legado/app/base/BaseActivity.kt b/app/src/main/java/io/legado/app/base/BaseActivity.kt index b769f54f4..96d3d21d5 100644 --- a/app/src/main/java/io/legado/app/base/BaseActivity.kt +++ b/app/src/main/java/io/legado/app/base/BaseActivity.kt @@ -8,7 +8,6 @@ import android.view.View import android.view.WindowManager import androidx.appcompat.app.AppCompatActivity import io.legado.app.R -import io.legado.app.help.ActivityHelp import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.ColorUtils import io.legado.app.lib.theme.ThemeStore @@ -27,7 +26,6 @@ abstract class BaseActivity(private val layoutID: Int, private val fullScreen: B initTheme() setupSystemBar() super.onCreate(savedInstanceState) - ActivityHelp.getInstance()?.add(this) setContentView(layoutID) onActivityCreated(savedInstanceState) observeLiveBus() @@ -36,7 +34,6 @@ abstract class BaseActivity(private val layoutID: Int, private val fullScreen: B override fun onDestroy() { super.onDestroy() cancel() - ActivityHelp.getInstance()?.remove(this) } abstract fun onActivityCreated(savedInstanceState: Bundle?) diff --git a/app/src/main/java/io/legado/app/help/ActivityHelp.kt b/app/src/main/java/io/legado/app/help/ActivityHelp.kt index c9eccea96..a1e535bfe 100644 --- a/app/src/main/java/io/legado/app/help/ActivityHelp.kt +++ b/app/src/main/java/io/legado/app/help/ActivityHelp.kt @@ -16,7 +16,7 @@ class ActivityHelp private constructor() { @Volatile private var instance: ActivityHelp? = null - fun getInstance(): ActivityHelp? { + fun getInstance(): ActivityHelp { if (null == instance) { synchronized(ActivityHelp::class.java) { if (null == instance) { @@ -24,7 +24,7 @@ class ActivityHelp private constructor() { } } } - return instance + return instance!! } } @@ -69,7 +69,7 @@ class ActivityHelp private constructor() { */ fun finishActivity(vararg activities: Activity) { for (activity in activities) { - activity?.finish() + activity.finish() } } diff --git a/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt b/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt index d64f3c6f0..d88b87669 100644 --- a/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt @@ -6,7 +6,7 @@ import android.view.MenuItem import android.view.View import io.legado.app.R import io.legado.app.base.BaseFragment -import io.legado.app.ui.chapterlist.ChapterListActivity +import io.legado.app.ui.readbook.ReadBookActivity import io.legado.app.utils.startActivity import kotlinx.android.synthetic.main.view_title_bar.* @@ -26,7 +26,7 @@ class MyFragment : BaseFragment(R.layout.fragment_my_config) { override fun onCompatOptionsItemSelected(item: MenuItem) { when (item.itemId) { - R.id.action_settings -> startActivity() + R.id.action_settings -> startActivity() } } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt b/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt index f4cb075ed..f13cea296 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt @@ -4,9 +4,13 @@ interface DataSource { fun getChapterPosition() - fun getChapter(position: Int): TextChapter + fun getChapter(position: Int): TextChapter? - fun getNextChapter(): TextChapter + fun getNextChapter(): TextChapter? - fun getPreviousChapter(): TextChapter + fun getPreviousChapter(): TextChapter? + + fun hasNextChapter(): Boolean + + fun hasPrevChapter(): Boolean } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageAnimDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageAnimDelegate.kt deleted file mode 100644 index eb4301588..000000000 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageAnimDelegate.kt +++ /dev/null @@ -1,39 +0,0 @@ -package io.legado.app.ui.widget.page - -import android.widget.Scroller -import androidx.interpolator.view.animation.FastOutLinearInInterpolator - -abstract class PageAnimDelegate(protected val pageView: PageView) { - - protected val scroller: Scroller = Scroller(pageView.context, FastOutLinearInInterpolator()) - - //起始点 - protected var startX: Float = 0.toFloat() - protected var startY: Float = 0.toFloat() - //触碰点 - protected var touchX: Float = 0.toFloat() - protected var touchY: Float = 0.toFloat() - //上一个触碰点 - protected var lastX: Float = 0.toFloat() - protected var lastY: Float = 0.toFloat() - - protected var isRunning = false - protected var isStarted = false - - - fun setStartPoint(x: Float, y: Float) { - startX = x - startY = y - - lastX = startX - lastY = startY - } - - fun setTouchPoint(x: Float, y: Float) { - lastX = touchX - lastY = touchY - - touchX = x - touchY = y - } -} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageFactory.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageFactory.kt index f2bebfbf5..d99e2976d 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageFactory.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageFactory.kt @@ -2,10 +2,14 @@ package io.legado.app.ui.widget.page abstract class PageFactory(protected val dataSource: DataSource) { - abstract fun pageAt(index: Int): DATA + abstract fun pageAt(index: Int): DATA? - abstract fun nextPage(): DATA + abstract fun nextPage(): DATA? - abstract fun previousPage(): DATA + abstract fun previousPage(): DATA? + + abstract fun hasNext(): Boolean + + abstract fun hasPrev(): Boolean } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 353087726..e96545c68 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -1,44 +1,30 @@ package io.legado.app.ui.widget.page +import android.annotation.SuppressLint import android.content.Context -import android.graphics.* -import android.graphics.drawable.GradientDrawable +import android.graphics.Canvas +import android.graphics.Color import android.util.AttributeSet import android.view.MotionEvent import android.widget.FrameLayout import io.legado.app.R +import io.legado.app.ui.widget.page.delegate.CoverPageDelegate +import io.legado.app.ui.widget.page.delegate.PageDelegate import io.legado.app.utils.dp -import io.legado.app.utils.screenshot import kotlinx.android.synthetic.main.view_book_page.view.* import org.jetbrains.anko.backgroundColor import org.jetbrains.anko.horizontalPadding -class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, attrs) { +class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, attrs), PageDelegate.PageInterface { - private var bitmap: Bitmap? = null - private var downX: Float = 0.toFloat() - private var offset: Float = 0.toFloat() + private var pageDelegate: PageDelegate? = null - private val shadowDrawableR: GradientDrawable - private val shadowDrawableL: GradientDrawable - - private val bitmapMatrix = Matrix() - - private var cover: Boolean = true + private var prevPage: ContentView? = null + private var curPage: ContentView? = null + private var nextPage: ContentView? = null init { - val shadowColors = intArrayOf(0x66111111, 0x00000000) - shadowDrawableR = GradientDrawable( - GradientDrawable.Orientation.LEFT_RIGHT, shadowColors - ) - shadowDrawableR.gradientType = GradientDrawable.LINEAR_GRADIENT - - shadowDrawableL = GradientDrawable( - GradientDrawable.Orientation.RIGHT_LEFT, shadowColors - ) - shadowDrawableL.gradientType = GradientDrawable.LINEAR_GRADIENT - inflate(context, R.layout.view_book_page, this) setWillNotDraw(false) @@ -47,72 +33,41 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att page_panel.horizontalPadding = 16.dp + pageDelegate = CoverPageDelegate(this) } - override fun dispatchDraw(canvas: Canvas?) { - super.dispatchDraw(canvas) + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + super.onSizeChanged(w, h, oldw, oldh) - bitmap?.let { - val dx = if (offset > 0) offset - width else offset + width + pageDelegate?.setViewSize(w, h) + } - bitmapMatrix.setTranslate(dx, 0.toFloat()) - canvas?.drawBitmap(it, bitmapMatrix, null) + override fun dispatchDraw(canvas: Canvas) { + super.dispatchDraw(canvas) - if (cover) { - addShadow(dx.toInt(), canvas) - } - } - } +// bringChildToFront(prevPage) - private fun addShadow(left: Int, canvas: Canvas?) { - canvas?.let { - if (left < 0) { - shadowDrawableR.setBounds(left + width, 0, left+ width + 30, height) - shadowDrawableR.draw(it) - } else { - shadowDrawableL.setBounds(left - 30, 0, left, height) - shadowDrawableL.draw(it) - } - } + pageDelegate?.onPerform(canvas) } - override fun onTouchEvent(event: MotionEvent?): Boolean { - when (event?.action) { - MotionEvent.ACTION_DOWN -> { - bitmap = page_panel.screenshot() - downX = event.x - offset = 0.toFloat() - if (!cover) { - page_panel.translationX = 0.toFloat() - } - invalidate() - } - - MotionEvent.ACTION_MOVE -> { - offset = event.x - downX - if (!cover) { - page_panel.translationX = offset - } - invalidate() - } - - MotionEvent.ACTION_UP -> { - bitmap = null - if (!cover) { - page_panel.translationX = 0.toFloat() - } - invalidate() - } - } - return true + override fun computeScroll() { + pageDelegate?.scroll() } - fun setTranslate(translationX: Float, translationY: Float) { - page_panel.translationX = translationX - page_panel.translationY = translationY + @SuppressLint("ClickableViewAccessibility") + override fun onTouchEvent(event: MotionEvent): Boolean { + return pageDelegate?.onTouch(event) ?: super.onTouchEvent(event) } fun setPageFactory(factory: PageFactory<*>) { } + + override fun hasNext(): Boolean { + return true + } + + override fun hasPrev(): Boolean { + return true + } } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt index e42895454..0799d97c2 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt @@ -12,6 +12,14 @@ class TextPageFactory private constructor(dataSource: DataSource) : PageFactory< private var index: Int = 0 + override fun hasPrev(): Boolean { + return true + } + + override fun hasNext(): Boolean { + return true + } + override fun pageAt(index: Int): TextPage { TODO("todo...") } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/CoverPageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/CoverPageDelegate.kt new file mode 100644 index 000000000..68b3f67c9 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/CoverPageDelegate.kt @@ -0,0 +1,75 @@ +package io.legado.app.ui.widget.page.delegate + +import android.graphics.Canvas +import android.graphics.Matrix +import android.graphics.drawable.GradientDrawable +import io.legado.app.ui.widget.page.PageView + +class CoverPageDelegate(pageView: PageView) : PageDelegate(pageView) { + + private val shadowDrawableR: GradientDrawable + private val shadowDrawableL: GradientDrawable + private val bitmapMatrix = Matrix() + + init { + val shadowColors = intArrayOf(0x66111111, 0x00000000) + shadowDrawableR = GradientDrawable( + GradientDrawable.Orientation.LEFT_RIGHT, shadowColors + ) + shadowDrawableR.gradientType = GradientDrawable.LINEAR_GRADIENT + + shadowDrawableL = GradientDrawable( + GradientDrawable.Orientation.RIGHT_LEFT, shadowColors + ) + shadowDrawableL.gradientType = GradientDrawable.LINEAR_GRADIENT + } + + override fun onStart() { + val distanceX: Float + when (direction) { + Direction.NEXT -> if (isCancel) { + var dis = viewWidth - startX + touchX + if (dis > viewWidth) { + dis = viewWidth.toFloat() + } + distanceX = viewWidth - dis + } else { + distanceX = -(touchX + (viewWidth - startX)) + } + else -> distanceX = if (isCancel) { + -(touchX - startX) + } else { + viewWidth - (touchX - startX) + } + } + + scroller.startScroll(touchX.toInt(), 0, distanceX.toInt(), 0, getDuration(distanceX)) + start() + } + + override fun onPerform(canvas: Canvas) { + val offsetX = touchX - startX + + if(offsetX == 0.toFloat()) return + + val distanceX = if (offsetX > 0) offsetX - viewWidth else offsetX + viewWidth + bitmap?.let { + bitmapMatrix.setTranslate(distanceX, 0.toFloat()) + canvas.drawBitmap(it, bitmapMatrix, null) + + addShadow(distanceX.toInt(), canvas) + } + } + + private fun addShadow(left: Int, canvas: Canvas?) { + canvas?.let { + if (left < 0) { + shadowDrawableR.setBounds(left + viewWidth, 0, left+ viewWidth + 30, viewHeight) + shadowDrawableR.draw(it) + } else { + shadowDrawableL.setBounds(left - 30, 0, left, viewHeight) + shadowDrawableL.draw(it) + } + } + } +} diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt new file mode 100644 index 000000000..3c1130c9e --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt @@ -0,0 +1,247 @@ +package io.legado.app.ui.widget.page.delegate + +import android.graphics.Bitmap +import android.graphics.Canvas +import android.view.GestureDetector +import android.view.MotionEvent +import android.view.View +import android.widget.Scroller +import androidx.interpolator.view.animation.FastOutLinearInInterpolator +import io.legado.app.ui.widget.page.PageView +import io.legado.app.utils.screenshot +import kotlinx.android.synthetic.main.view_book_page.view.* +import kotlin.math.abs + +abstract class PageDelegate(private val pageView: PageView) { + + //起始点 + protected var startX: Float = 0.toFloat() + protected var startY: Float = 0.toFloat() + //触碰点 + protected var touchX: Float = 0.toFloat() + protected var touchY: Float = 0.toFloat() + + protected val view: View + get() = pageView.page_panel + + protected var bitmap: Bitmap? = null + + protected var viewWidth: Int = pageView.width + protected var viewHeight: Int = pageView.height + + protected val scroller: Scroller by lazy { Scroller(pageView.context, FastOutLinearInInterpolator()) } + + private val detector: GestureDetector by lazy { GestureDetector(pageView.context, GestureListener()) } + + private var isMoved = false + private var noNext = true + + //移动方向 + var direction = Direction.NONE + var isCancel = false + var isRunning = false + var isStarted = false + + protected fun setStartPoint(x: Float, y: Float, invalidate: Boolean = true) { + startX = x + startY = y + + if (invalidate) { + invalidate() + } + } + + protected fun setTouchPoint(x: Float, y: Float, invalidate: Boolean = true) { + touchX = x + touchY = y + + if (invalidate) { + invalidate() + } + } + + fun setViewSize(width: Int, height: Int) { + viewWidth = width + viewHeight = height + invalidate() + } + + fun invalidate() { + pageView.invalidate() + } + + fun start() { + isRunning = true + isStarted = true + invalidate() + } + + fun stop() { + isRunning = false + isStarted = false + bitmap = null + invalidate() + } + + fun scroll() { + if (scroller.computeScrollOffset()) { + setTouchPoint(scroller.currX.toFloat(), scroller.currY.toFloat()) + } else if(isStarted){ + setTouchPoint(scroller.finalX.toFloat(), scroller.finalY.toFloat(), false) + stop() + } + } + + fun abort() { + if (!scroller.isFinished) { + scroller.abortAnimation() + } + } + + fun start(direction: Direction) { + if (isStarted) return + this.direction = direction + if (direction === Direction.NEXT) { + val x = viewWidth.toFloat() + val y = viewHeight.toFloat() + //初始化动画 + setStartPoint(x, y, false) + //设置点击点 + setTouchPoint(x, y, false) + //设置方向 + val hasNext = pageView.hasNext() + if (!hasNext) { + return + } + } else { + val x = 0.toFloat() + val y = viewHeight.toFloat() + //初始化动画 + setStartPoint(x, y, false) + //设置点击点 + setTouchPoint(x, y, false) + //设置方向方向 + val hashPrev = pageView.hasPrev() + if (!hashPrev) { + return + } + } + onStart() + } + + fun onTouch(event: MotionEvent): Boolean { + if (isMoved && event.action == MotionEvent.ACTION_UP) { + // 开启翻页效果 + if (!noNext) { + onStart() + } + return true + } + return detector.onTouchEvent(event) + } + + fun getDuration(distance: Float): Int { + val duration = 300 * abs(distance) / viewWidth + return duration.toInt() + } + + abstract fun onStart() + + abstract fun onPerform(canvas: Canvas) + + enum class Direction { + NONE, PREV, NEXT + } + + private inner class GestureListener : GestureDetector.OnGestureListener { + + override fun onDown(e: MotionEvent): Boolean { + abort() + //是否移动 + isMoved = false + //是否存在下一章 + noNext = false + //是否正在执行动画 + isRunning = false + //取消 + isCancel = false + //是下一章还是前一章 + direction = Direction.NONE + //设置起始位置的触摸点 + setStartPoint(e.x, e.y) + return true + } + + override fun onShowPress(e: MotionEvent) {} + + override fun onSingleTapUp(e: MotionEvent): Boolean { + val x = e.x + val y = e.y + direction = if (x > viewWidth / 2) Direction.NEXT else Direction.PREV + if (direction == Direction.NEXT) { + //判断是否下一页存在 + val hasNext = pageView.hasNext() + //设置动画方向 + if (!hasNext) { + return true + } + } else { + val hasPrev = pageView.hasPrev() + if (!hasPrev) { + return true + } + } + setTouchPoint(x, y) + return true + } + + override fun onScroll(e1: MotionEvent, e2: MotionEvent, distanceX: Float, distanceY: Float): Boolean { + if (!isMoved && abs(distanceX) > abs(distanceY)) { + //上一页或下一页截图,还未处理 + bitmap = pageView.screenshot() + if (distanceX < 0) { + //上一页的参数配置 + direction = Direction.PREV + //判断是否上一页存在 + val hasPrev = pageView.hasPrev() + //如果上一页不存在 + if (!hasPrev) { + noNext = true + return true + } + } else { + //进行下一页的配置 + direction = Direction.NEXT + //判断是否下一页存在 + val hasNext = pageView.hasNext() + //如果不存在表示没有下一页了 + if (!hasNext) { + noNext = true + return true + } + } + isMoved = true + } + if (isMoved) { + isCancel = if (direction == Direction.NEXT) distanceX < 0 else distanceX > 0 + isRunning = true + //设置触摸点 + setTouchPoint(e2.x, e2.y) + } + return isMoved + } + + override fun onLongPress(e: MotionEvent) { + + } + + override fun onFling(e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean { + return false + } + } + + interface PageInterface { + fun hasNext(): Boolean + fun hasPrev(): Boolean + } +} \ No newline at end of file From 5c85dd67a603953d814b4028e67d7a2726cb521c Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 17 Aug 2019 19:03:22 +0800 Subject: [PATCH 0752/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 22 +++++++++++++++++-- .../io/legado/app/ui/widget/page/PageView.kt | 13 ++++++++++- .../main/res/layout/activity_read_book.xml | 6 +++++ 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index ddf06c871..46f2fa8b4 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -21,6 +21,8 @@ import io.legado.app.ui.changesource.ChangeSourceDialog import io.legado.app.ui.chapterlist.ChapterListActivity import io.legado.app.ui.replacerule.ReplaceRuleActivity import io.legado.app.ui.widget.page.ChapterProvider +import io.legado.app.ui.widget.page.PageView +import io.legado.app.ui.widget.page.TextChapter import io.legado.app.utils.* import kotlinx.android.synthetic.main.activity_read_book.* import kotlinx.android.synthetic.main.view_book_page.* @@ -29,7 +31,9 @@ import kotlinx.coroutines.launch import org.jetbrains.anko.sdk27.listeners.onClick import org.jetbrains.anko.startActivity -class ReadBookActivity : VMBaseActivity(R.layout.activity_read_book), ChangeSourceDialog.CallBack, +class ReadBookActivity : VMBaseActivity(R.layout.activity_read_book), + PageView.CallBack, + ChangeSourceDialog.CallBack, ReadBookViewModel.CallBack { override val viewModel: ReadBookViewModel get() = getViewModel(ReadBookViewModel::class.java) @@ -47,6 +51,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea setSupportActionBar(toolbar) initAnimation() initView() + page_view.callBack = this viewModel.callBack = this viewModel.chapterMaxIndex.observe(this, Observer { bookLoadFinish() }) viewModel.bookData.observe(this, Observer { title_bar.title = it.name }) @@ -248,7 +253,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea tv_chapter_url.visible() } viewModel.curTextChapter = ChapterProvider.getTextChapter(content_text_view, bookChapter, content) - content_text_view.text = viewModel.curTextChapter?.page(0)?.stringBuilder + page_view.chapterLoadFinish() } viewModel.durChapterIndex - 1 -> { viewModel.prevTextChapter = ChapterProvider.getTextChapter(content_text_view, bookChapter, content) @@ -264,6 +269,19 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } + override fun durChapterIndex(): Int { + return viewModel.durChapterIndex + } + + override fun textChapter(chapterOnDur: Int): TextChapter? { + return when (chapterOnDur) { + 0 -> viewModel.curTextChapter + 1 -> viewModel.nextTextChapter + -1 -> viewModel.prevTextChapter + else -> null + } + } + private fun onClickReadAloud() { if (!ReadAloudService.isRun) { readAloudStatus = Status.STOP diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index e96545c68..8c44b7dd7 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -17,7 +17,7 @@ import org.jetbrains.anko.horizontalPadding class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, attrs), PageDelegate.PageInterface { - + var callBack: CallBack? = null private var pageDelegate: PageDelegate? = null private var prevPage: ContentView? = null @@ -59,6 +59,12 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att return pageDelegate?.onTouch(event) ?: super.onTouchEvent(event) } + fun chapterLoadFinish() { + callBack?.textChapter()?.let { + content_text_view.text = it.page(0)?.stringBuilder + } + } + fun setPageFactory(factory: PageFactory<*>) { } @@ -70,4 +76,9 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att override fun hasPrev(): Boolean { return true } + + interface CallBack { + fun durChapterIndex(): Int + fun textChapter(chapterOnDur: Int = 0): TextChapter? + } } diff --git a/app/src/main/res/layout/activity_read_book.xml b/app/src/main/res/layout/activity_read_book.xml index 5c666055d..76e164e93 100644 --- a/app/src/main/res/layout/activity_read_book.xml +++ b/app/src/main/res/layout/activity_read_book.xml @@ -4,7 +4,13 @@ android:layout_height="match_parent" android:orientation="vertical"> + + From 4bd9d45b94444f147bdc729968914d3ab991c0a2 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 17 Aug 2019 19:07:14 +0800 Subject: [PATCH 0753/1997] up --- .../main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index 4d5233e7b..a19467341 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -24,6 +24,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { var webBook: WebBook? = null var callBack: CallBack? = null var durChapterIndex = 0 + var durPageIndex = 0 var isLocalBook = true var prevTextChapter: TextChapter? = null var curTextChapter: TextChapter? = null @@ -38,6 +39,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { App.db.bookDao().getBook(bookUrl)?.let { book -> bookData.postValue(book) durChapterIndex = book.durChapterIndex + durPageIndex = book.durChapterPos isLocalBook = book.origin == BookType.local bookSource = App.db.bookSourceDao().getBookSource(book.origin) bookSource?.let { From f89ebc0860dbe637f76b8fe03e04b9118e51c55b Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 17 Aug 2019 20:21:27 +0800 Subject: [PATCH 0754/1997] up --- app/src/main/AndroidManifest.xml | 2 +- .../io/legado/app/data/dao/BookChapterDao.kt | 3 +++ .../app/ui/bookinfo/BookInfoActivity.kt | 21 +++++++++++++++++-- .../app/ui/bookinfo/BookInfoViewModel.kt | 13 ++++++++++-- .../app/ui/bookinfo/ChapterListAdapter.kt | 18 ++++++++++++++++ .../{ => edit}/BookInfoEditActivity.kt | 2 +- .../{ => edit}/BookInfoEditViewModel.kt | 2 +- 7 files changed, 54 insertions(+), 7 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/bookinfo/ChapterListAdapter.kt rename app/src/main/java/io/legado/app/ui/bookinfo/{ => edit}/BookInfoEditActivity.kt (98%) rename app/src/main/java/io/legado/app/ui/bookinfo/{ => edit}/BookInfoEditViewModel.kt (95%) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 225fe2ea1..bd15cad0a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -51,7 +51,7 @@ - + diff --git a/app/src/main/java/io/legado/app/data/dao/BookChapterDao.kt b/app/src/main/java/io/legado/app/data/dao/BookChapterDao.kt index 20d233149..6473da76f 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookChapterDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookChapterDao.kt @@ -13,6 +13,9 @@ interface BookChapterDao { @Query("select * from chapters where bookUrl = :bookUrl") fun observeByBook(bookUrl: String): DataSource.Factory + @Query("select * from chapters where bookUrl = :bookUrl") + fun getChapterList(bookUrl: String): List + @Query("select * from chapters where bookUrl = :bookUrl and `index` = :index") fun getChapter(bookUrl: String, index: Int): BookChapter? diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index a4bb266bd..f0e3215c8 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -4,10 +4,13 @@ import android.os.Bundle import android.view.Menu import android.view.MenuItem import androidx.lifecycle.Observer +import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.R import io.legado.app.base.VMBaseActivity import io.legado.app.data.entities.Book +import io.legado.app.data.entities.BookChapter import io.legado.app.help.ImageLoader +import io.legado.app.ui.bookinfo.edit.BookInfoEditActivity import io.legado.app.ui.changesource.ChangeSourceDialog import io.legado.app.utils.getViewModel import io.legado.app.utils.gone @@ -22,13 +25,16 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo get() = getViewModel(BookInfoViewModel::class.java) private var changeSourceDialog: ChangeSourceDialog? = null + private lateinit var adapter: ChapterListAdapter override fun onActivityCreated(savedInstanceState: Bundle?) { setSupportActionBar(toolbar) + initRecyclerView() viewModel.bookData.observe(this, Observer { showBook(it) }) viewModel.isLoadingData.observe(this, Observer { upLoading(it) }) + viewModel.chapterListData.observe(this, Observer { showChapter(it) }) viewModel.loadBook(intent) - initView() + initOnClick() savedInstanceState?.let { changeSourceDialog = supportFragmentManager.findFragmentByTag(ChangeSourceDialog.tag) as? ChangeSourceDialog changeSourceDialog?.callBack = this @@ -98,6 +104,11 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo } } + private fun showChapter(chapterList: List) { + adapter.clearItems() + adapter.addItems(chapterList) + } + private fun upLoading(isLoading: Boolean) { if (isLoading) { tv_loading.visible() @@ -111,7 +122,13 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo } } - private fun initView() { + private fun initRecyclerView() { + adapter = ChapterListAdapter(this) + rv_chapter_list.layoutManager = LinearLayoutManager(this) + rv_chapter_list.adapter = adapter + } + + private fun initOnClick() { tv_read.onClick { } diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt index af4291452..7efde2b00 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt @@ -21,6 +21,12 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { App.db.bookDao().getBook(it)?.let { book -> inBookshelf = true bookData.postValue(book) + val chapterList = App.db.bookChapterDao().getChapterList(it) + if (chapterList.isNotEmpty()) { + chapterListData.postValue(chapterList) + } else { + loadChapter(book) + } } } ?: intent.getStringExtra("searchBookUrl")?.let { App.db.searchBookDao().getSearchBook(it)?.toBook()?.let { book -> @@ -28,7 +34,7 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { if (book.tocUrl.isEmpty()) { loadBookInfo() } else { - loadChapter() + loadChapter(book) } } } @@ -39,8 +45,11 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { isLoadingData.postValue(false) } - fun loadChapter() { + fun loadChapter(book: Book) { isLoadingData.postValue(false) + App.db.bookSourceDao().getBookSource(book.origin)?.let { + + } } fun saveBook(success: (() -> Unit)?) { diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/ChapterListAdapter.kt b/app/src/main/java/io/legado/app/ui/bookinfo/ChapterListAdapter.kt new file mode 100644 index 000000000..b6fd0cdfc --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/bookinfo/ChapterListAdapter.kt @@ -0,0 +1,18 @@ +package io.legado.app.ui.bookinfo + +import android.content.Context +import io.legado.app.R +import io.legado.app.base.adapter.ItemViewHolder +import io.legado.app.base.adapter.SimpleRecyclerAdapter +import io.legado.app.data.entities.BookChapter +import kotlinx.android.synthetic.main.item_chapter_list.view.* + +class ChapterListAdapter(context: Context) : SimpleRecyclerAdapter(context, R.layout.item_chapter_list) { + + override fun convert(holder: ItemViewHolder, item: BookChapter, payloads: MutableList) { + holder.itemView.apply { + tv_chapter_name + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoEditActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/edit/BookInfoEditActivity.kt similarity index 98% rename from app/src/main/java/io/legado/app/ui/bookinfo/BookInfoEditActivity.kt rename to app/src/main/java/io/legado/app/ui/bookinfo/edit/BookInfoEditActivity.kt index 11cbbe490..779cf962a 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/edit/BookInfoEditActivity.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.bookinfo +package io.legado.app.ui.bookinfo.edit import android.os.Bundle import android.view.Menu diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoEditViewModel.kt b/app/src/main/java/io/legado/app/ui/bookinfo/edit/BookInfoEditViewModel.kt similarity index 95% rename from app/src/main/java/io/legado/app/ui/bookinfo/BookInfoEditViewModel.kt rename to app/src/main/java/io/legado/app/ui/bookinfo/edit/BookInfoEditViewModel.kt index b331b8a78..fb33a22e7 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoEditViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/edit/BookInfoEditViewModel.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.bookinfo +package io.legado.app.ui.bookinfo.edit import android.app.Application import androidx.lifecycle.MutableLiveData From 585c19f7a729a113a7a65ebac83d36a982f13f16 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 17 Aug 2019 21:04:06 +0800 Subject: [PATCH 0755/1997] up --- .../app/model/webbook/BookChapterList.kt | 2 +- .../legado/app/model/webbook/BookContent.kt | 2 +- .../io/legado/app/model/webbook/BookInfo.kt | 2 +- .../io/legado/app/model/webbook/BookList.kt | 2 +- .../app/ui/bookinfo/BookInfoActivity.kt | 12 ++++++- .../app/ui/bookinfo/BookInfoViewModel.kt | 27 +++++++++++++--- .../app/ui/readbook/ReadBookViewModel.kt | 4 +-- app/src/main/res/values/strings.xml | 32 ++++++++++++------- 8 files changed, 60 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt b/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt index c387008a7..03e29ea95 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt @@ -28,7 +28,7 @@ object BookChapterList { val body: String? = response.body() body ?: throw Exception( App.INSTANCE.getString( - R.string.get_web_content_error, + R.string.error_get_web_content, baseUrl ) ) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookContent.kt b/app/src/main/java/io/legado/app/model/webbook/BookContent.kt index 0b77b10a4..bfa7f76a3 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookContent.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookContent.kt @@ -29,7 +29,7 @@ object BookContent { val body: String? = response.body() body ?: throw Exception( App.INSTANCE.getString( - R.string.get_web_content_error, + R.string.error_get_web_content, baseUrl ) ) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt b/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt index d3d043a0b..05dfc0fc6 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt @@ -19,7 +19,7 @@ object BookInfo { val baseUrl = analyzeUrl.url body ?: throw Exception( App.INSTANCE.getString( - R.string.get_web_content_error, + R.string.error_get_web_content, baseUrl ) ) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookList.kt b/app/src/main/java/io/legado/app/model/webbook/BookList.kt index b5af7027f..4ee99bb7c 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookList.kt @@ -24,7 +24,7 @@ object BookList { val body: String? = response.body() body ?: throw Exception( App.INSTANCE.getString( - R.string.get_web_content_error, + R.string.error_get_web_content, baseUrl ) ) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index f0e3215c8..058fbe950 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -12,6 +12,7 @@ import io.legado.app.data.entities.BookChapter import io.legado.app.help.ImageLoader import io.legado.app.ui.bookinfo.edit.BookInfoEditActivity import io.legado.app.ui.changesource.ChangeSourceDialog +import io.legado.app.ui.readbook.ReadBookActivity import io.legado.app.utils.getViewModel import io.legado.app.utils.gone import io.legado.app.utils.visible @@ -105,6 +106,7 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo } private fun showChapter(chapterList: List) { + adapter.clearItems() adapter.addItems(chapterList) } @@ -130,7 +132,15 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo private fun initOnClick() { tv_read.onClick { - + viewModel.bookData.value?.let { + if (!viewModel.inBookshelf) { + viewModel.saveBook { + startActivity(Pair("bookUrl", it.bookUrl)) + } + } else { + startActivity(Pair("bookUrl", it.bookUrl)) + } + } } tv_shelf.onClick { viewModel.saveBook { diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt index 7efde2b00..8958c84d1 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt @@ -4,9 +4,12 @@ import android.app.Application import android.content.Intent import androidx.lifecycle.MutableLiveData import io.legado.app.App +import io.legado.app.R import io.legado.app.base.BaseViewModel import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter +import io.legado.app.model.WebBook +import kotlinx.coroutines.Dispatchers.IO class BookInfoViewModel(application: Application) : BaseViewModel(application) { @@ -32,7 +35,7 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { App.db.searchBookDao().getSearchBook(it)?.toBook()?.let { book -> bookData.postValue(book) if (book.tocUrl.isEmpty()) { - loadBookInfo() + loadBookInfo(book) } else { loadChapter(book) } @@ -41,15 +44,31 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { } } - fun loadBookInfo() { + fun loadBookInfo(book: Book) { isLoadingData.postValue(false) + App.db.bookSourceDao().getBookSource(book.origin)?.let { bookSource -> + WebBook(bookSource).getBookInfo(book) + .onSuccess { + it?.let { loadChapter(it) } + }.onError { + toast(R.string.error_get_book_info) + } + } ?: toast(R.string.error_no_source) } fun loadChapter(book: Book) { isLoadingData.postValue(false) - App.db.bookSourceDao().getBookSource(book.origin)?.let { + App.db.bookSourceDao().getBookSource(book.origin)?.let { bookSource -> + WebBook(bookSource).getChapterList(book) + .onSuccess(IO) { + if (inBookshelf) { - } + } + chapterListData.postValue(it) + }.onError { + toast(R.string.error_get_chapter_list) + } + } ?: toast(R.string.error_no_source) } fun saveBook(success: (() -> Unit)?) { diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index a19467341..7ed316cfc 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -53,10 +53,10 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { App.db.bookChapterDao().insert(*cList.toTypedArray()) chapterMaxIndex.postValue(cList.size) } else { - toast(R.string.load_toc_error) + toast(R.string.error_load_toc) } }?.onError { - toast(R.string.load_toc_error) + toast(R.string.error_load_toc) } ?: autoChangeSource() } else { chapterMaxIndex.postValue(count) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 51172e3ed..8a70911dd 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -59,9 +59,6 @@ 版本 本地 搜索 - 没有网络 - 网络连接超时 - 数据解析失败 来源: %s 最近: %s 书名 @@ -69,7 +66,6 @@ 是否将《%s》放入书架? 共%s个Text文件 加载中… - 获取数据失败! 重试 web服务 web编辑书源 @@ -142,7 +138,6 @@ 背景 作者 作者:%s - 站点暂时不支持解析,请反馈 朗读停止 清除缓存 保存 @@ -347,6 +342,7 @@ 成功 当前源没有配置登陆地址 + 书源名称(bookSourceName) 书源URL(bookSourceUrl) 书源分组(bookSourceGroup) @@ -371,6 +367,23 @@ 章节URL规则(chapterUrl) 正文规则(content) 正文下一页URL规则(nextContentUrl) + + + + 没有书源 + 书籍信息获取失败 + 内容获取失败 + 目录获取失败 + 访问网站失败:%s + 文件读取失败 + 加载目录失败 + 获取数据失败! + 加载失败\n%s + 没有网络 + 网络连接超时 + 数据解析失败 + + header 调试书源 二维码导入 @@ -382,7 +395,6 @@ 默认主题 恢复主题为默认配色 加入QQ群 - 文件读取失败 获取背景图片需存储权限 输入书源网址 删除文件 @@ -408,10 +420,6 @@ 输入编码 TXT目录规则 打开外部书籍需获取存储权限 - 书籍信息获取失败 - 内容获取失败 - 目录获取失败 - 访问网站失败:%s 未获取到书名 输入替换规则网址 搜索列表获取成功%d @@ -439,7 +447,6 @@ 文章内容为空 正在换源请等待… 目录列表为空 - 加载失败\n%s 正文边距 Tip边距 字距 @@ -474,5 +481,6 @@ ]]> 阅读 - 加载目录失败 + + From a214afd1cbe954d8a35b34115ea57b94b9f00108 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 17 Aug 2019 21:06:37 +0800 Subject: [PATCH 0756/1997] up --- .../java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt index 8958c84d1..35776ef93 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt @@ -61,10 +61,12 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { App.db.bookSourceDao().getBookSource(book.origin)?.let { bookSource -> WebBook(bookSource).getChapterList(book) .onSuccess(IO) { - if (inBookshelf) { - + it?.let { + if (inBookshelf) { + App.db.bookChapterDao().insert(*it.toTypedArray()) + } + chapterListData.postValue(it) } - chapterListData.postValue(it) }.onError { toast(R.string.error_get_chapter_list) } From c10aefd3cd556343876eb57e160f230780226f3d Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 17 Aug 2019 21:21:35 +0800 Subject: [PATCH 0757/1997] up --- .../io/legado/app/ui/bookinfo/BookInfoActivity.kt | 13 ++++++++++++- .../io/legado/app/ui/bookinfo/BookInfoViewModel.kt | 8 +++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index 058fbe950..a797e39ff 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -106,7 +106,13 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo } private fun showChapter(chapterList: List) { - + viewModel.bookData.value?.let { + if (it.durChapterIndex < chapterList.size) { + tv_current_chapter_info.text = chapterList[it.durChapterIndex].title + } else { + tv_current_chapter_info.text = chapterList.last().title + } + } adapter.clearItems() adapter.addItems(chapterList) } @@ -157,6 +163,11 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo } changeSourceDialog?.show(supportFragmentManager, ChangeSourceDialog.tag) } + tv_current_chapter_info.onClick { + viewModel.bookData.value?.let { + rv_chapter_list.scrollToPosition(it.durChapterIndex) + } + } } override fun changeTo(book: Book) { diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt index 35776ef93..ac68bea13 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt @@ -62,10 +62,12 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { WebBook(bookSource).getChapterList(book) .onSuccess(IO) { it?.let { - if (inBookshelf) { - App.db.bookChapterDao().insert(*it.toTypedArray()) + if (it.isNotEmpty()) { + if (inBookshelf) { + App.db.bookChapterDao().insert(*it.toTypedArray()) + } + chapterListData.postValue(it) } - chapterListData.postValue(it) } }.onError { toast(R.string.error_get_chapter_list) From 4fd86336fd866c306d501d3f35bee5bbf26a176b Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 17 Aug 2019 22:30:37 +0800 Subject: [PATCH 0758/1997] up --- .../main/java/io/legado/app/model/analyzeRule/AnalyzeByXPath.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByXPath.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByXPath.kt index 0989f88d5..42e6bd9f6 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByXPath.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByXPath.kt @@ -150,7 +150,7 @@ class AnalyzeByXPath { if (rules.size == 1) { val jxNodes = jxDocument?.selN(rule) jxNodes?.let { - TextUtils.join(",", jxNodes) + return TextUtils.join(",", jxNodes) } return null } else { From b1394e507696b0590c9ee7eea87f1f26fe48fc8d Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 17 Aug 2019 22:36:56 +0800 Subject: [PATCH 0759/1997] up --- .../main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt index 47c0bea3b..2689f7366 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt @@ -465,7 +465,9 @@ class AnalyzeRule(private var book: BaseBook? = null) { //get替换 rule = replaceGet(rule) // 拆分表达式替换规则 - AnalyzeByRegex.splitRegexRule(rule, ruleParam, ruleType) + if (mode != Mode.Js) { + AnalyzeByRegex.splitRegexRule(rule, ruleParam, ruleType) + } } fun makeUpRule(result: Any?) { From 6a85aad6844d2407afc2652fd707675d6aca225d Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 17 Aug 2019 22:44:08 +0800 Subject: [PATCH 0760/1997] up --- app/src/main/java/io/legado/app/utils/GsonExtensions.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/utils/GsonExtensions.kt b/app/src/main/java/io/legado/app/utils/GsonExtensions.kt index bccf6e6ba..e1a099eba 100644 --- a/app/src/main/java/io/legado/app/utils/GsonExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/GsonExtensions.kt @@ -2,11 +2,15 @@ package io.legado.app.utils import com.google.gson.Gson import com.google.gson.GsonBuilder -import com.google.gson.JsonParser import com.google.gson.reflect.TypeToken import org.jetbrains.anko.attempt -val GSON: Gson by lazy { GsonBuilder().create() } +val GSON: Gson by lazy { + GsonBuilder() + .disableHtmlEscaping() + .setPrettyPrinting() + .create() +} inline fun genericType() = object : TypeToken() {}.type From 6b1690b4eafb7b93db320196dec2a9c739189c34 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 17 Aug 2019 22:47:05 +0800 Subject: [PATCH 0761/1997] up --- app/src/main/java/io/legado/app/help/BookHelp.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/BookHelp.kt b/app/src/main/java/io/legado/app/help/BookHelp.kt index b71c3dfe9..50478943a 100644 --- a/app/src/main/java/io/legado/app/help/BookHelp.kt +++ b/app/src/main/java/io/legado/app/help/BookHelp.kt @@ -27,9 +27,7 @@ object BookHelp { //获取流并存储 try { BufferedWriter(FileWriter(file)).use { writer -> - writer.write(bookChapter.title + "\n\n") writer.write(content) - writer.write("\n\n") writer.flush() } } catch (e: IOException) { From 9750eaeabc9777add3851d9fdd9c529e87450492 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 17 Aug 2019 22:57:26 +0800 Subject: [PATCH 0762/1997] up --- .../main/java/io/legado/app/model/webbook/BookContent.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookContent.kt b/app/src/main/java/io/legado/app/model/webbook/BookContent.kt index bfa7f76a3..69f1f9425 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookContent.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookContent.kt @@ -80,9 +80,15 @@ object BookContent { content.append(item.content) } } + if (content.isNotEmpty()) { + if (!content[0].toString().startsWith(bookChapter.title)) { + content.insert(0, bookChapter.title) + } + } return content.toString() } + @Throws(Exception::class) private fun analyzeContent( body: String, contentRule: ContentRule, From 7395f84e0d7ab2442245ca7ce14b021f9969636c Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 17 Aug 2019 23:00:21 +0800 Subject: [PATCH 0763/1997] up --- app/src/main/java/io/legado/app/model/webbook/BookContent.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookContent.kt b/app/src/main/java/io/legado/app/model/webbook/BookContent.kt index 69f1f9425..77fb14ebc 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookContent.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookContent.kt @@ -82,7 +82,9 @@ object BookContent { } if (content.isNotEmpty()) { if (!content[0].toString().startsWith(bookChapter.title)) { - content.insert(0, bookChapter.title) + content + .insert(0, "\n") + .insert(0, bookChapter.title) } } return content.toString() From 03ec05297af8a74ca7a0e1b08aebbaeb64f03d91 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 18 Aug 2019 07:16:43 +0800 Subject: [PATCH 0764/1997] up --- .../java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt index ac68bea13..6479ce005 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt @@ -27,6 +27,7 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { val chapterList = App.db.bookChapterDao().getChapterList(it) if (chapterList.isNotEmpty()) { chapterListData.postValue(chapterList) + isLoadingData.postValue(false) } else { loadChapter(book) } @@ -45,7 +46,7 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { } fun loadBookInfo(book: Book) { - isLoadingData.postValue(false) + isLoadingData.postValue(true) App.db.bookSourceDao().getBookSource(book.origin)?.let { bookSource -> WebBook(bookSource).getBookInfo(book) .onSuccess { @@ -57,7 +58,7 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { } fun loadChapter(book: Book) { - isLoadingData.postValue(false) + isLoadingData.postValue(true) App.db.bookSourceDao().getBookSource(book.origin)?.let { bookSource -> WebBook(bookSource).getChapterList(book) .onSuccess(IO) { @@ -67,6 +68,7 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { App.db.bookChapterDao().insert(*it.toTypedArray()) } chapterListData.postValue(it) + isLoadingData.postValue(false) } } }.onError { From 057ece8aec7665137d938f4aed1750425243f460 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 18 Aug 2019 07:30:15 +0800 Subject: [PATCH 0765/1997] up --- app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index a797e39ff..443ef2bf8 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -10,6 +10,7 @@ import io.legado.app.base.VMBaseActivity import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter import io.legado.app.help.ImageLoader +import io.legado.app.lib.theme.ATH import io.legado.app.ui.bookinfo.edit.BookInfoEditActivity import io.legado.app.ui.changesource.ChangeSourceDialog import io.legado.app.ui.readbook.ReadBookActivity @@ -131,6 +132,7 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo } private fun initRecyclerView() { + ATH.applyEdgeEffectColor(rv_chapter_list) adapter = ChapterListAdapter(this) rv_chapter_list.layoutManager = LinearLayoutManager(this) rv_chapter_list.adapter = adapter From 2a93dc2ba3d8e7ec3f3febdf4a5f94a4adbe7ed1 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 18 Aug 2019 07:55:47 +0800 Subject: [PATCH 0766/1997] up --- .../main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt | 5 ++++- .../java/io/legado/app/ui/bookinfo/ChapterListAdapter.kt | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index 443ef2bf8..f66635458 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -3,7 +3,9 @@ package io.legado.app.ui.bookinfo import android.os.Bundle import android.view.Menu import android.view.MenuItem +import android.widget.LinearLayout import androidx.lifecycle.Observer +import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.R import io.legado.app.base.VMBaseActivity @@ -132,9 +134,10 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo } private fun initRecyclerView() { - ATH.applyEdgeEffectColor(rv_chapter_list) adapter = ChapterListAdapter(this) + ATH.applyEdgeEffectColor(rv_chapter_list) rv_chapter_list.layoutManager = LinearLayoutManager(this) + rv_chapter_list.addItemDecoration(DividerItemDecoration(this, LinearLayout.VERTICAL)) rv_chapter_list.adapter = adapter } diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/ChapterListAdapter.kt b/app/src/main/java/io/legado/app/ui/bookinfo/ChapterListAdapter.kt index b6fd0cdfc..5969d0b37 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/ChapterListAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/ChapterListAdapter.kt @@ -11,7 +11,7 @@ class ChapterListAdapter(context: Context) : SimpleRecyclerAdapter( override fun convert(holder: ItemViewHolder, item: BookChapter, payloads: MutableList) { holder.itemView.apply { - tv_chapter_name + tv_chapter_name.text = item.title } } From 8551379fd801193a0a0d35126764d528a2aeb9fe Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 18 Aug 2019 07:59:06 +0800 Subject: [PATCH 0767/1997] up --- .../java/io/legado/app/ui/bookinfo/ChapterListAdapter.kt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/ChapterListAdapter.kt b/app/src/main/java/io/legado/app/ui/bookinfo/ChapterListAdapter.kt index 5969d0b37..db2797eb2 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/ChapterListAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/ChapterListAdapter.kt @@ -6,13 +6,21 @@ import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.data.entities.BookChapter import kotlinx.android.synthetic.main.item_chapter_list.view.* +import org.jetbrains.anko.sdk27.listeners.onClick class ChapterListAdapter(context: Context) : SimpleRecyclerAdapter(context, R.layout.item_chapter_list) { + var callBack: CallBack? = null override fun convert(holder: ItemViewHolder, item: BookChapter, payloads: MutableList) { holder.itemView.apply { tv_chapter_name.text = item.title + this.onClick { + callBack?.skipToChapter(item.index) + } } } + interface CallBack { + fun skipToChapter(index: Int) + } } \ No newline at end of file From 507b35a8db9e0acc253f0a85740b00a8a1fce307 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 18 Aug 2019 08:02:36 +0800 Subject: [PATCH 0768/1997] up --- .../java/io/legado/app/ui/bookinfo/BookInfoActivity.kt | 10 ++++++++-- .../io/legado/app/ui/bookinfo/ChapterListAdapter.kt | 6 +++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index f66635458..d22b3bbaa 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -24,7 +24,9 @@ import kotlinx.android.synthetic.main.view_title_bar.* import org.jetbrains.anko.sdk27.listeners.onClick import org.jetbrains.anko.startActivity -class BookInfoActivity : VMBaseActivity(R.layout.activity_book_info), ChangeSourceDialog.CallBack { +class BookInfoActivity : VMBaseActivity(R.layout.activity_book_info), + ChapterListAdapter.CallBack, + ChangeSourceDialog.CallBack { override val viewModel: BookInfoViewModel get() = getViewModel(BookInfoViewModel::class.java) @@ -134,7 +136,7 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo } private fun initRecyclerView() { - adapter = ChapterListAdapter(this) + adapter = ChapterListAdapter(this, this) ATH.applyEdgeEffectColor(rv_chapter_list) rv_chapter_list.layoutManager = LinearLayoutManager(this) rv_chapter_list.addItemDecoration(DividerItemDecoration(this, LinearLayout.VERTICAL)) @@ -178,4 +180,8 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo override fun changeTo(book: Book) { } + + override fun skipToChapter(index: Int) { + + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/ChapterListAdapter.kt b/app/src/main/java/io/legado/app/ui/bookinfo/ChapterListAdapter.kt index db2797eb2..cd5a759db 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/ChapterListAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/ChapterListAdapter.kt @@ -8,14 +8,14 @@ import io.legado.app.data.entities.BookChapter import kotlinx.android.synthetic.main.item_chapter_list.view.* import org.jetbrains.anko.sdk27.listeners.onClick -class ChapterListAdapter(context: Context) : SimpleRecyclerAdapter(context, R.layout.item_chapter_list) { - var callBack: CallBack? = null +class ChapterListAdapter(context: Context, var callBack: CallBack) : + SimpleRecyclerAdapter(context, R.layout.item_chapter_list) { override fun convert(holder: ItemViewHolder, item: BookChapter, payloads: MutableList) { holder.itemView.apply { tv_chapter_name.text = item.title this.onClick { - callBack?.skipToChapter(item.index) + callBack.skipToChapter(item.index) } } } From a6b5de1b7a6d399fa9ecc6127659069f9ef45a44 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 18 Aug 2019 09:02:24 +0800 Subject: [PATCH 0769/1997] up --- app/src/main/java/io/legado/app/help/BookHelp.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/BookHelp.kt b/app/src/main/java/io/legado/app/help/BookHelp.kt index 50478943a..6f15036b0 100644 --- a/app/src/main/java/io/legado/app/help/BookHelp.kt +++ b/app/src/main/java/io/legado/app/help/BookHelp.kt @@ -65,9 +65,7 @@ object BookHelp { } private fun formatFolderName(folderName: String): String { - return folderName.replace("/", "") - .replace(":", "") - .replace(".", "") + return folderName.replace("[\\\\/:*?\"<>|.]".toRegex(), "") } fun formatAuthor(author: String?): String { From be3b85a3d911bcd941a5caa2b1e79ba36f8de15d Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 18 Aug 2019 09:15:21 +0800 Subject: [PATCH 0770/1997] up --- .../main/java/io/legado/app/data/dao/BookSourceDao.kt | 9 --------- .../main/java/io/legado/app/data/dao/SearchBookDao.kt | 3 +++ 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt index 5270d3c5f..f39599888 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt @@ -34,21 +34,12 @@ interface BookSourceDao { @Query("select count(*) from book_sources") fun allCount(): Int - @Insert(onConflict = OnConflictStrategy.REPLACE) - fun insert(bookSource: BookSource): Long - @Insert(onConflict = OnConflictStrategy.REPLACE) fun insert(vararg bookSource: BookSource) - @Update - fun update(bookSource: BookSource) - @Update fun update(vararg bookSource: BookSource) - @Delete - fun delete(bookSource: BookSource) - @Delete fun delete(vararg bookSource: BookSource) diff --git a/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt b/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt index a5f76d907..13fa0700e 100644 --- a/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt @@ -29,6 +29,9 @@ interface SearchBookDao { @Query("select * from searchBooks where name = :name and author = :author order by originOrder") fun getByNameAuthor(name: String, author: String): List + @Query("select * from searchBooks where name = :name and author = :author order by originOrder") + fun getByNameAuthorEnable(name: String, author: String): List + @Insert(onConflict = OnConflictStrategy.REPLACE) fun insert(vararg searchBook: SearchBook): List From cc2d7be3373a13043ee5c4cbca136c26b1481145 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 18 Aug 2019 09:38:49 +0800 Subject: [PATCH 0771/1997] up --- app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt | 2 +- .../java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt b/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt index 13fa0700e..a197b0e51 100644 --- a/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt @@ -29,7 +29,7 @@ interface SearchBookDao { @Query("select * from searchBooks where name = :name and author = :author order by originOrder") fun getByNameAuthor(name: String, author: String): List - @Query("select * from searchBooks where name = :name and author = :author order by originOrder") + @Query("select * from searchBooks where name = :name and author = :author and origin in (select bookSourceUrl from book_sources where enabled = 1) order by originOrder") fun getByNameAuthorEnable(name: String, author: String): List @Insert(onConflict = OnConflictStrategy.REPLACE) diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt index be95f7065..579d79bb2 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt @@ -14,7 +14,7 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio fun startSearch() { execute { - App.db.searchBookDao().getByNameAuthor(name, author).let { + App.db.searchBookDao().getByNameAuthorEnable(name, author).let { searchBookData.postValue(it) } } From cdb4bcf5df63482297dd6ab2994ebe4ca6804831 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 18 Aug 2019 12:00:46 +0800 Subject: [PATCH 0772/1997] up --- .../java/io/legado/app/ui/readbook/ReadBookActivity.kt | 4 ++-- .../java/io/legado/app/ui/widget/page/ContentView.kt | 10 ++++++++++ .../main/java/io/legado/app/ui/widget/page/PageView.kt | 10 +++------- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 46f2fa8b4..fc8c07d49 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -237,8 +237,8 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea private fun bookLoadFinish() { viewModel.bookData.value?.let { viewModel.loadContent(it, it.durChapterIndex) - viewModel.loadContent(it, it.durChapterIndex + 1) - viewModel.loadContent(it, it.durChapterIndex - 1) +// viewModel.loadContent(it, it.durChapterIndex + 1) +// viewModel.loadContent(it, it.durChapterIndex - 1) } } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index 4f8abfa55..c9df8dcd8 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -4,6 +4,9 @@ import android.content.Context import android.util.AttributeSet import android.widget.FrameLayout import io.legado.app.R +import io.legado.app.utils.dp +import kotlinx.android.synthetic.main.view_book_page.view.* +import org.jetbrains.anko.horizontalPadding class ContentView : FrameLayout { @@ -16,5 +19,12 @@ class ContentView : FrameLayout { init { inflate(context, R.layout.view_book_page, this) + + page_panel.horizontalPadding = 16.dp + } + + + fun setContent(text: CharSequence?) { + content_text_view.text = text } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 8c44b7dd7..f8d08a7e2 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -7,13 +7,10 @@ import android.graphics.Color import android.util.AttributeSet import android.view.MotionEvent import android.widget.FrameLayout -import io.legado.app.R import io.legado.app.ui.widget.page.delegate.CoverPageDelegate import io.legado.app.ui.widget.page.delegate.PageDelegate -import io.legado.app.utils.dp import kotlinx.android.synthetic.main.view_book_page.view.* import org.jetbrains.anko.backgroundColor -import org.jetbrains.anko.horizontalPadding class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, attrs), PageDelegate.PageInterface { @@ -25,14 +22,13 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att private var nextPage: ContentView? = null init { - inflate(context, R.layout.view_book_page, this) + curPage = ContentView(context) + addView(curPage) setWillNotDraw(false) page_panel.backgroundColor = Color.WHITE - page_panel.horizontalPadding = 16.dp - pageDelegate = CoverPageDelegate(this) } @@ -61,7 +57,7 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att fun chapterLoadFinish() { callBack?.textChapter()?.let { - content_text_view.text = it.page(0)?.stringBuilder + curPage?.setContent(it.page(0)?.stringBuilder) } } From 2ef5fbc987dd63137eae55945299776f3bffbcbd Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 18 Aug 2019 12:02:05 +0800 Subject: [PATCH 0773/1997] up --- .../main/java/io/legado/app/ui/widget/page/ContentView.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index c9df8dcd8..08db472a9 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -20,9 +20,12 @@ class ContentView : FrameLayout { init { inflate(context, R.layout.view_book_page, this) - page_panel.horizontalPadding = 16.dp + upStyle() } + fun upStyle() { + page_panel.horizontalPadding = 16.dp + } fun setContent(text: CharSequence?) { content_text_view.text = text From 1b1ea3767934a7a0c8ae7df23cd4bfde77e5d100 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 18 Aug 2019 12:13:31 +0800 Subject: [PATCH 0774/1997] up --- .../java/io/legado/app/ui/readbook/ReadBookActivity.kt | 5 +++++ .../main/java/io/legado/app/ui/widget/page/PageView.kt | 10 ++++++++++ app/src/main/res/layout/activity_read_book.xml | 1 + 3 files changed, 16 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index fc8c07d49..01264d61d 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -282,6 +282,11 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } + fun upStyle() { + content_view.upStyle() + page_view.upStyle() + } + private fun onClickReadAloud() { if (!ReadAloudService.isRun) { readAloudStatus = Status.STOP diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index f8d08a7e2..e567a3090 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -22,6 +22,10 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att private var nextPage: ContentView? = null init { + prevPage = ContentView(context) + addView(prevPage) + nextPage = ContentView(context) + addView(nextPage) curPage = ContentView(context) addView(curPage) @@ -73,6 +77,12 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att return true } + fun upStyle() { + curPage?.upStyle() + prevPage?.upStyle() + nextPage?.upStyle() + } + interface CallBack { fun durChapterIndex(): Int fun textChapter(chapterOnDur: Int = 0): TextChapter? diff --git a/app/src/main/res/layout/activity_read_book.xml b/app/src/main/res/layout/activity_read_book.xml index 76e164e93..7e72bc822 100644 --- a/app/src/main/res/layout/activity_read_book.xml +++ b/app/src/main/res/layout/activity_read_book.xml @@ -5,6 +5,7 @@ android:orientation="vertical"> From 56671dab43c84feb07b95c43c9b0845b8e12e8cd Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 18 Aug 2019 15:50:26 +0800 Subject: [PATCH 0775/1997] up --- .../main/java/io/legado/app/model/WebBook.kt | 24 +++++-- .../app/ui/bookinfo/BookInfoViewModel.kt | 4 +- .../app/ui/changesource/ChangeSourceDialog.kt | 3 +- .../ui/changesource/ChangeSourceViewModel.kt | 68 ++++++++++++++++++- 4 files changed, 87 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/WebBook.kt b/app/src/main/java/io/legado/app/model/WebBook.kt index f8b7148c9..972ec4b87 100644 --- a/app/src/main/java/io/legado/app/model/WebBook.kt +++ b/app/src/main/java/io/legado/app/model/WebBook.kt @@ -17,7 +17,12 @@ class WebBook(private val bookSource: BookSource) { val sourceUrl: String get() = bookSource.bookSourceUrl - fun searchBook(key: String, page: Int?, isSearch: Boolean = true, scope: CoroutineScope = Coroutine.DEFAULT): Coroutine> { + fun searchBook( + key: String, + page: Int? = 1, + isSearch: Boolean = true, + scope: CoroutineScope = Coroutine.DEFAULT + ): Coroutine> { return Coroutine.async(scope) { bookSource.getSearchRule().searchUrl?.let { searchUrl -> val analyzeUrl = AnalyzeUrl(searchUrl, key, page, baseUrl = sourceUrl) @@ -27,8 +32,8 @@ class WebBook(private val bookSource: BookSource) { } } - fun getBookInfo(book: Book): Coroutine { - return Coroutine.async { + fun getBookInfo(book: Book, scope: CoroutineScope = Coroutine.DEFAULT): Coroutine { + return Coroutine.async(scope) { val analyzeUrl = AnalyzeUrl(book = book, ruleUrl = book.bookUrl, baseUrl = sourceUrl) val response = analyzeUrl.getResponseAsync().await() BookInfo.analyzeBookInfo(book, response.body(), bookSource, analyzeUrl) @@ -36,16 +41,21 @@ class WebBook(private val bookSource: BookSource) { } } - fun getChapterList(book: Book): Coroutine> { - return Coroutine.async { + fun getChapterList(book: Book, scope: CoroutineScope = Coroutine.DEFAULT): Coroutine> { + return Coroutine.async(scope) { val analyzeUrl = AnalyzeUrl(book = book, ruleUrl = book.tocUrl, baseUrl = book.bookUrl) val response = analyzeUrl.getResponseAsync().await() BookChapterList.analyzeChapterList(this, book, response, bookSource, analyzeUrl) } } - fun getContent(book: Book, bookChapter: BookChapter, nextChapterUrl: String? = null): Coroutine { - return Coroutine.async { + fun getContent( + book: Book, + bookChapter: BookChapter, + nextChapterUrl: String? = null, + scope: CoroutineScope = Coroutine.DEFAULT + ): Coroutine { + return Coroutine.async(scope) { val analyzeUrl = AnalyzeUrl(book = book, ruleUrl = bookChapter.url, baseUrl = book.tocUrl) val response = analyzeUrl.getResponseAsync().await() BookContent.analyzeContent(this, response, book, bookChapter, bookSource, nextChapterUrl) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt index 6479ce005..43c409212 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt @@ -48,7 +48,7 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { fun loadBookInfo(book: Book) { isLoadingData.postValue(true) App.db.bookSourceDao().getBookSource(book.origin)?.let { bookSource -> - WebBook(bookSource).getBookInfo(book) + WebBook(bookSource).getBookInfo(book, this) .onSuccess { it?.let { loadChapter(it) } }.onError { @@ -60,7 +60,7 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { fun loadChapter(book: Book) { isLoadingData.postValue(true) App.db.bookSourceDao().getBookSource(book.origin)?.let { bookSource -> - WebBook(bookSource).getChapterList(book) + WebBook(bookSource).getChapterList(book, this) .onSuccess(IO) { it?.let { if (it.isNotEmpty()) { diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt index 9646a922d..775b1e33b 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt @@ -60,7 +60,7 @@ class ChangeSourceDialog : DialogFragment() { showTitle() initRecyclerView() initSearchView() - viewModel.startSearch() + viewModel.initData() } override fun onStart() { @@ -112,6 +112,7 @@ class ChangeSourceDialog : DialogFragment() { } override fun onQueryTextChange(newText: String?): Boolean { + viewModel.screen(newText) return false } diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt index 579d79bb2..49d602256 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt @@ -3,20 +3,84 @@ package io.legado.app.ui.changesource import android.app.Application import androidx.lifecycle.MutableLiveData import io.legado.app.App +import io.legado.app.R import io.legado.app.base.BaseViewModel +import io.legado.app.data.entities.Book import io.legado.app.data.entities.SearchBook +import io.legado.app.model.WebBook +import kotlinx.coroutines.Dispatchers class ChangeSourceViewModel(application: Application) : BaseViewModel(application) { var curBookUrl = "" var name: String = "" var author: String = "" val searchBookData = MutableLiveData>() + private val searchBooks = arrayListOf() - fun startSearch() { + fun initData() { execute { App.db.searchBookDao().getByNameAuthorEnable(name, author).let { - searchBookData.postValue(it) + searchBooks.addAll(it) + searchBookData.postValue(searchBooks) } } } + + fun search() { + execute { + val bookSourceList = App.db.bookSourceDao().allEnabled + for (item in bookSourceList) { + //task取消时自动取消 by (scope = this@execute) + WebBook(item).searchBook(name, scope = this@execute) + .timeout(30000L) + .onSuccess(Dispatchers.IO) { + it?.let { list -> + list.map { searchBook -> + if (searchBook.name == name && searchBook.author == author) { + if (searchBook.tocUrl.isEmpty()) { + loadBookInfo(searchBook.toBook()) + } else { + loadChapter(searchBook.toBook()) + } + } + } + } + } + } + } + } + + private fun loadBookInfo(book: Book) { + App.db.bookSourceDao().getBookSource(book.origin)?.let { bookSource -> + WebBook(bookSource).getBookInfo(book, this) + .onSuccess { + it?.let { loadChapter(it) } + }.onError { + toast(R.string.error_get_book_info) + } + } ?: toast(R.string.error_no_source) + } + + private fun loadChapter(book: Book) { + App.db.bookSourceDao().getBookSource(book.origin)?.let { bookSource -> + WebBook(bookSource).getChapterList(book, this) + .onSuccess(Dispatchers.IO) { + it?.let { + if (it.isNotEmpty()) { + + } + } + }.onError { + toast(R.string.error_get_chapter_list) + } + } ?: toast(R.string.error_no_source) + } + + fun screen(key: String?) { + if (key.isNullOrEmpty()) { + searchBookData.postValue(searchBooks) + } else { + + } + } } \ No newline at end of file From f1d5d0330dba8b2bd47286fda43543b30c154751 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 18 Aug 2019 16:06:38 +0800 Subject: [PATCH 0776/1997] up --- .../java/io/legado/app/data/entities/Book.kt | 16 ++++++++++++ .../io/legado/app/data/entities/SearchBook.kt | 26 +++++++++---------- .../ui/changesource/ChangeSourceViewModel.kt | 3 ++- 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/Book.kt b/app/src/main/java/io/legado/app/data/entities/Book.kt index fb3027435..08a7eb13c 100644 --- a/app/src/main/java/io/legado/app/data/entities/Book.kt +++ b/app/src/main/java/io/legado/app/data/entities/Book.kt @@ -89,4 +89,20 @@ data class Book( } return kindList } + + fun toSearchBook(): SearchBook { + return SearchBook( + name = name, + author = author, + kind = kind, + bookUrl = bookUrl, + origin = origin, + originName = originName, + wordCount = wordCount, + latestChapterTitle = latestChapterTitle, + coverUrl = coverUrl, + intro = intro, + tocUrl = tocUrl + ) + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt index 45e905847..40b0b6317 100644 --- a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt +++ b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt @@ -57,18 +57,18 @@ data class SearchBook( } fun toBook(): Book { - val book = Book() - book.name = name - book.author = author - book.kind = kind - book.bookUrl = bookUrl - book.origin = origin - book.originName = originName - book.wordCount = wordCount - book.latestChapterTitle = latestChapterTitle - book.coverUrl = coverUrl - book.intro = intro - book.tocUrl = tocUrl - return book + return Book( + name = name, + author = author, + kind = kind, + bookUrl = bookUrl, + origin = origin, + originName = originName, + wordCount = wordCount, + latestChapterTitle = latestChapterTitle, + coverUrl = coverUrl, + intro = intro, + tocUrl = tocUrl + ) } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt index 49d602256..f190fe973 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt @@ -67,7 +67,8 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio .onSuccess(Dispatchers.IO) { it?.let { if (it.isNotEmpty()) { - + book.latestChapterTitle = it.last().title + searchBooks.add(book.toSearchBook()) } } }.onError { From c942873352b1f9bdaee51ba1c720eb57d5b6b811 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 18 Aug 2019 16:09:10 +0800 Subject: [PATCH 0777/1997] up --- .../main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index 7ed316cfc..4184ee895 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -47,7 +47,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } val count = App.db.bookChapterDao().getChapterCount(bookUrl) if (count == 0) { - webBook?.getChapterList(book) + webBook?.getChapterList(book, this) ?.onSuccess(IO) { cList -> if (!cList.isNullOrEmpty()) { App.db.bookChapterDao().insert(*cList.toTypedArray()) @@ -108,7 +108,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } private fun download(book: Book, chapter: BookChapter) { - webBook?.getContent(book, chapter) + webBook?.getContent(book, chapter, scope = this) ?.onSuccess(IO) { content -> content?.let { BookHelp.saveContent(book, chapter, it) From 04376419c3399026c66edc1faf97c6740915d672 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 18 Aug 2019 17:11:32 +0800 Subject: [PATCH 0778/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 7 ++++ .../io/legado/app/ui/widget/page/PageView.kt | 33 +++++++++++++--- .../io/legado/app/ui/widget/page/TextPage.kt | 4 +- .../app/ui/widget/page/TextPageFactory.kt | 6 +-- .../ui/widget/page/delegate/PageDelegate.kt | 3 +- app/src/main/res/layout/view_book_page.xml | 38 +++++++++---------- 6 files changed, 58 insertions(+), 33 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 01264d61d..dd3965889 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -273,6 +273,13 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea return viewModel.durChapterIndex } + override fun durChapterPos(pageSize: Int): Int { + if (viewModel.durPageIndex < pageSize) { + return viewModel.durPageIndex + } + return pageSize - 1 + } + override fun textChapter(chapterOnDur: Int): TextChapter? { return when (chapterOnDur) { 0 -> viewModel.curTextChapter diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index e567a3090..e02bc8b6d 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -17,9 +17,9 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att var callBack: CallBack? = null private var pageDelegate: PageDelegate? = null - private var prevPage: ContentView? = null - private var curPage: ContentView? = null - private var nextPage: ContentView? = null + var prevPage: ContentView? = null + var curPage: ContentView? = null + var nextPage: ContentView? = null init { prevPage = ContentView(context) @@ -59,9 +59,29 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att return pageDelegate?.onTouch(event) ?: super.onTouchEvent(event) } - fun chapterLoadFinish() { - callBack?.textChapter()?.let { - curPage?.setContent(it.page(0)?.stringBuilder) + fun chapterLoadFinish(chapterOnDur: Int = 0) { + callBack?.let { cb -> + when (chapterOnDur) { + 0 -> { + cb.textChapter()?.let { + curPage?.setContent(it.page(cb.durChapterPos(it.pageSize()))?.text) + if (cb.durChapterPos(it.pageSize()) > 0) { + prevPage?.setContent(it.page(cb.durChapterPos(it.pageSize()) - 1)?.text) + } + if (cb.durChapterPos(it.pageSize()) < it.pageSize() - 1) { + nextPage?.setContent(it.page(cb.durChapterPos(it.pageSize()) + 1)?.text) + } + } + } + 1 -> { + + } + -1 -> { + + } + else -> { + } + } } } @@ -85,6 +105,7 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att interface CallBack { fun durChapterIndex(): Int + fun durChapterPos(pageSize: Int): Int fun textChapter(chapterOnDur: Int = 0): TextChapter? } } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextPage.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextPage.kt index 5c6dc6cdc..202529ca8 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextPage.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextPage.kt @@ -1,8 +1,6 @@ package io.legado.app.ui.widget.page -import android.text.SpannableStringBuilder - data class TextPage( val index: Int, - val stringBuilder: SpannableStringBuilder + val text: CharSequence ) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt index 0799d97c2..922423acb 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt @@ -1,7 +1,5 @@ package io.legado.app.ui.widget.page -import android.text.SpannableStringBuilder - class TextPageFactory private constructor(dataSource: DataSource) : PageFactory(dataSource) { companion object{ @@ -25,11 +23,11 @@ class TextPageFactory private constructor(dataSource: DataSource) : PageFactory< } override fun nextPage(): TextPage { - return TextPage(index.plus(1), SpannableStringBuilder("index:$index")) + return TextPage(index.plus(1), "index:$index") } override fun previousPage(): TextPage { - return TextPage(index.minus(1), SpannableStringBuilder("index:$index")) + return TextPage(index.minus(1), "index:$index") } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt index 3c1130c9e..14a34e284 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt @@ -198,8 +198,8 @@ abstract class PageDelegate(private val pageView: PageView) { override fun onScroll(e1: MotionEvent, e2: MotionEvent, distanceX: Float, distanceY: Float): Boolean { if (!isMoved && abs(distanceX) > abs(distanceY)) { //上一页或下一页截图,还未处理 - bitmap = pageView.screenshot() if (distanceX < 0) { + bitmap = pageView.prevPage?.screenshot() //上一页的参数配置 direction = Direction.PREV //判断是否上一页存在 @@ -210,6 +210,7 @@ abstract class PageDelegate(private val pageView: PageView) { return true } } else { + bitmap = pageView.nextPage?.screenshot() //进行下一页的配置 direction = Direction.NEXT //判断是否下一页存在 diff --git a/app/src/main/res/layout/view_book_page.xml b/app/src/main/res/layout/view_book_page.xml index c86b9d3b7..63efc398b 100644 --- a/app/src/main/res/layout/view_book_page.xml +++ b/app/src/main/res/layout/view_book_page.xml @@ -1,24 +1,24 @@ - + + android:id="@+id/top_status_bar" + android:layout_width="match_parent" + android:layout_height="25dp" /> + android:id="@+id/content_panel" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1"> + android:id="@+id/bottom_status_bar" + android:layout_width="match_parent" + android:layout_height="25dp" /> \ No newline at end of file From 945217f505d6c8661b1d4189ee152d8d68f6b955 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 18 Aug 2019 17:27:27 +0800 Subject: [PATCH 0779/1997] up --- .../io/legado/app/ui/readbook/ReadBookActivity.kt | 6 ++++-- .../java/io/legado/app/ui/widget/page/PageView.kt | 12 ++++++++++-- .../java/io/legado/app/ui/widget/page/TextChapter.kt | 7 +++++++ 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index dd3965889..ba77137cc 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -237,8 +237,8 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea private fun bookLoadFinish() { viewModel.bookData.value?.let { viewModel.loadContent(it, it.durChapterIndex) -// viewModel.loadContent(it, it.durChapterIndex + 1) -// viewModel.loadContent(it, it.durChapterIndex - 1) + viewModel.loadContent(it, it.durChapterIndex + 1) + viewModel.loadContent(it, it.durChapterIndex - 1) } } @@ -257,9 +257,11 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } viewModel.durChapterIndex - 1 -> { viewModel.prevTextChapter = ChapterProvider.getTextChapter(content_text_view, bookChapter, content) + page_view.chapterLoadFinish(-1) } viewModel.durChapterIndex + 1 -> { viewModel.nextTextChapter = ChapterProvider.getTextChapter(content_text_view, bookChapter, content) + page_view.chapterLoadFinish(1) } } } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index e02bc8b6d..25f9eefcb 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -74,10 +74,18 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att } } 1 -> { - + cb.textChapter()?.let { + if (cb.durChapterPos(it.pageSize()) == it.pageSize() - 1) { + nextPage?.setContent(cb.textChapter(1)?.page(0)?.text) + } + } } -1 -> { - + cb.textChapter()?.let { + if (cb.durChapterPos(it.pageSize()) == 0) { + prevPage?.setContent(cb.textChapter(-1)?.lastPage()?.text) + } + } } else -> { } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt index 032a732c1..8f913d92c 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt @@ -13,6 +13,13 @@ data class TextChapter( return null } + fun lastPage(): TextPage? { + if (pages.isNotEmpty()) { + return pages[pages.lastIndex] + } + return null + } + fun pageSize(): Int { return pages.size } From fdf12315f4a4035cdbda3fb3ed3b094306a52f83 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 18 Aug 2019 17:51:10 +0800 Subject: [PATCH 0780/1997] up --- .../io/legado/app/ui/readbook/ReadBookActivity.kt | 4 ++-- .../java/io/legado/app/ui/widget/page/ContentView.kt | 8 ++++++++ .../java/io/legado/app/ui/widget/page/PageView.kt | 12 ++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index ba77137cc..cea8c77d1 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -317,8 +317,8 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea observeEvent(Bus.ALOUD_STATE) { readAloudStatus = it } observeEvent(Bus.TTS_START) {} observeEvent(Bus.TTS_RANGE_START) {} - observeEvent(Bus.TIME_CHANGED) {} - observeEvent(Bus.BATTERY_CHANGED) {} + observeEvent(Bus.TIME_CHANGED) { page_view.upTime() } + observeEvent(Bus.BATTERY_CHANGED) { page_view.upBattery(it) } observeEventSticky(Bus.READ_ALOUD) { onClickReadAloud() } } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index 08db472a9..a8bc37183 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -27,6 +27,14 @@ class ContentView : FrameLayout { page_panel.horizontalPadding = 16.dp } + fun upTime() { + + } + + fun upBattery(battery: Int) { + + } + fun setContent(text: CharSequence?) { content_text_view.text = text } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 25f9eefcb..255068c07 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -111,6 +111,18 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att nextPage?.upStyle() } + fun upTime() { + curPage?.upTime() + prevPage?.upTime() + nextPage?.upTime() + } + + fun upBattery(battery: Int) { + curPage?.upBattery(battery) + prevPage?.upBattery(battery) + nextPage?.upBattery(battery) + } + interface CallBack { fun durChapterIndex(): Int fun durChapterPos(pageSize: Int): Int From 729979f76374a4ac9523c5a0146414704aa5c92a Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 18 Aug 2019 19:19:19 +0800 Subject: [PATCH 0781/1997] up --- .../main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 6 +++--- .../java/io/legado/app/ui/readbook/ReadBookViewModel.kt | 5 +++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index cea8c77d1..724d7b2c7 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -236,9 +236,9 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea private fun bookLoadFinish() { viewModel.bookData.value?.let { - viewModel.loadContent(it, it.durChapterIndex) - viewModel.loadContent(it, it.durChapterIndex + 1) - viewModel.loadContent(it, it.durChapterIndex - 1) + viewModel.loadContent(it, viewModel.durChapterIndex) + viewModel.loadContent(it, viewModel.durChapterIndex + 1) + viewModel.loadContent(it, viewModel.durChapterIndex - 1) } } diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index 4184ee895..5fad1c557 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -59,6 +59,9 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { toast(R.string.error_load_toc) } ?: autoChangeSource() } else { + if (durChapterIndex > count - 1) { + durChapterIndex = count - 1 + } chapterMaxIndex.postValue(count) } } @@ -81,6 +84,8 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { loadingChapters.remove(index) } } ?: download(book, chapter) + } ?: synchronized(loadingLock) { + loadingChapters.remove(index) } }.onError { synchronized(loadingLock) { From c309ec57164e9d14f33655d269e3b5813a6eed54 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 18 Aug 2019 19:30:12 +0800 Subject: [PATCH 0782/1997] up --- .../main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index d22b3bbaa..d0d673d9f 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -16,6 +16,7 @@ import io.legado.app.lib.theme.ATH import io.legado.app.ui.bookinfo.edit.BookInfoEditActivity import io.legado.app.ui.changesource.ChangeSourceDialog import io.legado.app.ui.readbook.ReadBookActivity +import io.legado.app.ui.sourceedit.SourceEditActivity import io.legado.app.utils.getViewModel import io.legado.app.utils.gone import io.legado.app.utils.visible @@ -161,6 +162,11 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo } } tv_loading.onClick { } + tv_origin.onClick { + viewModel.bookData.value?.let { + startActivity(Pair("data", it.origin)) + } + } tv_change_source.onClick { if (changeSourceDialog == null) { viewModel.bookData.value?.let { From d70b0d0de64c2fcd2f30771ffed0ba6283927c4b Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 18 Aug 2019 19:33:43 +0800 Subject: [PATCH 0783/1997] up --- app/src/main/res/layout/activity_book_info.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/layout/activity_book_info.xml b/app/src/main/res/layout/activity_book_info.xml index 5ab89bd2b..b4ef77e07 100644 --- a/app/src/main/res/layout/activity_book_info.xml +++ b/app/src/main/res/layout/activity_book_info.xml @@ -78,6 +78,7 @@ android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" + android:visibility="gone" android:orientation="horizontal"> Date: Sun, 18 Aug 2019 19:49:24 +0800 Subject: [PATCH 0784/1997] up --- .../app/model/analyzeRule/AnalyzeRule.kt | 41 ++++++++++--------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt index 2689f7366..38bda7e0d 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt @@ -472,31 +472,32 @@ class AnalyzeRule(private var book: BaseBook? = null) { fun makeUpRule(result: Any?) { val infoVal = StringBuilder() - var j = ruleParam.size - while (j-- > 0) { - val regType = ruleType[j] - if (regType > 0) { - @Suppress("UNCHECKED_CAST") - val resultList = result as List - if (resultList.size > regType) { - infoVal.insert(0, resultList[regType]) - } - } else if (regType < 0) { - val jsEval: Any = evalJS(ruleParam[j], result) - if (jsEval is String) { - infoVal.insert(0, jsEval) - } else if (jsEval is Double && jsEval % 1.0 == 0.0) { - infoVal.insert(0, String.format("%.0f", jsEval)) + if (ruleParam.isNotEmpty()) { + var j = ruleParam.size + while (j-- > 0) { + val regType = ruleType[j] + if (regType > 0) { + @Suppress("UNCHECKED_CAST") + val resultList = result as List + if (resultList.size > regType) { + infoVal.insert(0, resultList[regType]) + } + } else if (regType < 0) { + val jsEval: Any = evalJS(ruleParam[j], result) + if (jsEval is String) { + infoVal.insert(0, jsEval) + } else if (jsEval is Double && jsEval % 1.0 == 0.0) { + infoVal.insert(0, String.format("%.0f", jsEval)) + } else { + infoVal.insert(0, jsEval.toString()) + } } else { - infoVal.insert(0, jsEval.toString()) + infoVal.insert(0, ruleParam[j]) } - } else { - infoVal.insert(0, ruleParam[j]) } + rule = infoVal.toString() } - rule = infoVal.toString() } - } enum class Mode { From 2c51e1453f2a97fcac03a951d738d3aa2a4d86dc Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 18 Aug 2019 19:52:30 +0800 Subject: [PATCH 0785/1997] up --- app/src/main/java/io/legado/app/model/webbook/BookList.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookList.kt b/app/src/main/java/io/legado/app/model/webbook/BookList.kt index 4ee99bb7c..421d9cdd7 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookList.kt @@ -113,7 +113,7 @@ object BookList { SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取书名") searchBook.name = analyzeRule.getString(name ?: "") ?: "" SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.name ?: "") - if (!searchBook.name.isNullOrEmpty()) { + if (searchBook.name.isNotEmpty()) { SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取作者") searchBook.author = BookHelp.formatAuthor(analyzeRule.getString(author ?: "")) SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.author ?: "") @@ -163,7 +163,7 @@ object BookList { SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取书名", printLog) searchBook.name = analyzeRule.getString(ruleName) SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.name, printLog) - if (!searchBook.name.isNullOrEmpty()) { + if (searchBook.name.isNotEmpty()) { SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取书籍Url", printLog) searchBook.bookUrl = analyzeRule.getString(ruleBookUrl, true) SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.bookUrl, printLog) From c56587894b3b0915688a231fce158b34f6d06dde Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 18 Aug 2019 21:33:35 +0800 Subject: [PATCH 0786/1997] up --- .../main/java/io/legado/app/data/dao/SearchBookDao.kt | 2 -- .../main/java/io/legado/app/model/webbook/BookList.kt | 6 +++--- .../app/ui/changesource/ChangeSourceViewModel.kt | 10 +++++----- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt b/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt index a197b0e51..75e6ae895 100644 --- a/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt @@ -35,6 +35,4 @@ interface SearchBookDao { @Insert(onConflict = OnConflictStrategy.REPLACE) fun insert(vararg searchBook: SearchBook): List - @Insert(onConflict = OnConflictStrategy.REPLACE) - fun insert(searchBook: SearchBook): Long } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/model/webbook/BookList.kt b/app/src/main/java/io/legado/app/model/webbook/BookList.kt index 421d9cdd7..61e86f568 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookList.kt @@ -112,11 +112,11 @@ object BookList { } SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取书名") searchBook.name = analyzeRule.getString(name ?: "") ?: "" - SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.name ?: "") + SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.name) if (searchBook.name.isNotEmpty()) { SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取作者") searchBook.author = BookHelp.formatAuthor(analyzeRule.getString(author ?: "")) - SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.author ?: "") + SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.author) SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取分类") searchBook.kind = analyzeRule.getString(kind ?: "") SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.kind ?: "") @@ -169,7 +169,7 @@ object BookList { SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.bookUrl, printLog) SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取作者", printLog) searchBook.author = BookHelp.formatAuthor(analyzeRule.getString(ruleAuthor)) - SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.author ?: "", printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.author, printLog) SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取分类", printLog) searchBook.kind = analyzeRule.getString(ruleKind) SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.kind ?: "", printLog) diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt index f190fe973..998fab1e7 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt @@ -65,11 +65,11 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio App.db.bookSourceDao().getBookSource(book.origin)?.let { bookSource -> WebBook(bookSource).getChapterList(book, this) .onSuccess(Dispatchers.IO) { - it?.let { - if (it.isNotEmpty()) { - book.latestChapterTitle = it.last().title - searchBooks.add(book.toSearchBook()) - } + it?.map { chapter -> + book.latestChapterTitle = chapter.title + val searchBook = book.toSearchBook() + searchBooks.add(searchBook) + App.db.searchBookDao().insert(searchBook) } }.onError { toast(R.string.error_get_chapter_list) From 507ac06777ffaf3fb417d5c62bfde8e117d2066c Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 19 Aug 2019 09:23:02 +0800 Subject: [PATCH 0787/1997] up --- app/src/main/java/io/legado/app/base/BaseViewModel.kt | 3 +++ .../legado/app/ui/changesource/ChangeSourceViewModel.kt | 9 +++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/base/BaseViewModel.kt b/app/src/main/java/io/legado/app/base/BaseViewModel.kt index df58bf2cb..096c6d562 100644 --- a/app/src/main/java/io/legado/app/base/BaseViewModel.kt +++ b/app/src/main/java/io/legado/app/base/BaseViewModel.kt @@ -1,6 +1,7 @@ package io.legado.app.base import android.app.Application +import android.content.Context import androidx.lifecycle.AndroidViewModel import io.legado.app.App import io.legado.app.help.coroutine.Coroutine @@ -11,6 +12,8 @@ import org.jetbrains.anko.toast open class BaseViewModel(application: Application) : AndroidViewModel(application), CoroutineScope by MainScope(), AnkoLogger { + val context: Context = this.getApplication() + fun execute(scope: CoroutineScope = this, block: suspend CoroutineScope.() -> T): Coroutine { return Coroutine.async(scope) { block() } } diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt index 998fab1e7..b4e889b96 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt @@ -9,6 +9,7 @@ import io.legado.app.data.entities.Book import io.legado.app.data.entities.SearchBook import io.legado.app.model.WebBook import kotlinx.coroutines.Dispatchers +import org.jetbrains.anko.debug class ChangeSourceViewModel(application: Application) : BaseViewModel(application) { var curBookUrl = "" @@ -56,9 +57,9 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio .onSuccess { it?.let { loadChapter(it) } }.onError { - toast(R.string.error_get_book_info) + debug { context.getString(R.string.error_get_book_info) } } - } ?: toast(R.string.error_no_source) + } ?: debug { context.getString(R.string.error_no_source) } } private fun loadChapter(book: Book) { @@ -72,9 +73,9 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio App.db.searchBookDao().insert(searchBook) } }.onError { - toast(R.string.error_get_chapter_list) + debug { context.getString(R.string.error_get_chapter_list) } } - } ?: toast(R.string.error_no_source) + } ?: debug { R.string.error_no_source } } fun screen(key: String?) { From 4e0efb4e4571c0273f3acd427d6c29e755f7e8d2 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 19 Aug 2019 10:17:21 +0800 Subject: [PATCH 0788/1997] up --- .../java/io/legado/app/data/entities/SearchBook.kt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt index 40b0b6317..f679ff10e 100644 --- a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt +++ b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt @@ -32,6 +32,19 @@ data class SearchBook( var originOrder: Int = 0 ) : Parcelable, BaseBook { + override fun equals(other: Any?): Boolean { + if (other is SearchBook) { + if (other.bookUrl == bookUrl) { + return true + } + } + return false + } + + override fun hashCode(): Int { + return bookUrl.hashCode() + } + @IgnoredOnParcel @Ignore override var variableMap: HashMap? = null From dacc76e2eb2324295e7bee4a0acd6e33bfad67a2 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 19 Aug 2019 10:56:54 +0800 Subject: [PATCH 0789/1997] up --- .../ui/changesource/ChangeSourceViewModel.kt | 11 +++++--- .../app/ui/changesource/DiffCallBack.kt | 27 +++++++++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/changesource/DiffCallBack.kt diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt index b4e889b96..58d687f3f 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt @@ -16,17 +16,22 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio var name: String = "" var author: String = "" val searchBookData = MutableLiveData>() - private val searchBooks = arrayListOf() + private val searchBooks = linkedSetOf() fun initData() { execute { App.db.searchBookDao().getByNameAuthorEnable(name, author).let { searchBooks.addAll(it) - searchBookData.postValue(searchBooks) + searchBookData.postValue(it) + search() } } } + fun upAdapter() { + + } + fun search() { execute { val bookSourceList = App.db.bookSourceDao().allEnabled @@ -80,7 +85,7 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio fun screen(key: String?) { if (key.isNullOrEmpty()) { - searchBookData.postValue(searchBooks) + searchBookData.postValue(searchBooks.toList()) } else { } diff --git a/app/src/main/java/io/legado/app/ui/changesource/DiffCallBack.kt b/app/src/main/java/io/legado/app/ui/changesource/DiffCallBack.kt new file mode 100644 index 000000000..2183c51e5 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/changesource/DiffCallBack.kt @@ -0,0 +1,27 @@ +package io.legado.app.ui.changesource + +import androidx.recyclerview.widget.DiffUtil +import io.legado.app.data.entities.SearchBook + +class DiffCallBack(private val oldItems: List, private val newItems: List) : + DiffUtil.Callback() { + + + override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { + return oldItems[oldItemPosition].bookUrl == newItems[newItemPosition].bookUrl + } + + override fun getOldListSize(): Int { + return oldItems.size + } + + override fun getNewListSize(): Int { + return newItems.size + } + + override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { + return oldItems[oldItemPosition].originName == newItems[newItemPosition].originName + && oldItems[oldItemPosition].latestChapterTitle == newItems[newItemPosition].originName + } + +} \ No newline at end of file From dfaad579eed05136c7fa900e0b843fccfe7407dc Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 19 Aug 2019 11:18:44 +0800 Subject: [PATCH 0790/1997] up --- .../app/ui/changesource/ChangeSourceDialog.kt | 10 +++++----- .../ui/changesource/ChangeSourceViewModel.kt | 18 +++++++++++++----- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt index 775b1e33b..b5d0e565a 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt @@ -8,7 +8,6 @@ import android.view.ViewGroup import android.widget.LinearLayout import androidx.appcompat.widget.SearchView import androidx.fragment.app.DialogFragment -import androidx.lifecycle.Observer import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.R @@ -18,7 +17,7 @@ import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.dialog_change_source.* -class ChangeSourceDialog : DialogFragment() { +class ChangeSourceDialog : DialogFragment(), ChangeSourceViewModel.CallBack { companion object { const val tag = "changeSourceDialog" @@ -91,9 +90,7 @@ class ChangeSourceDialog : DialogFragment() { recycler_view.layoutManager = LinearLayoutManager(context) recycler_view.addItemDecoration(DividerItemDecoration(requireContext(), LinearLayout.VERTICAL)) recycler_view.adapter = changeSourceAdapter - viewModel.searchBookData.observe(viewLifecycleOwner, Observer { - changeSourceAdapter.addItems(it) - }) + viewModel.callBack = this } private fun initSearchView() { @@ -119,6 +116,9 @@ class ChangeSourceDialog : DialogFragment() { }) } + override fun adapter(): ChangeSourceAdapter { + return changeSourceAdapter + } interface CallBack { fun changeTo(book: Book) diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt index 58d687f3f..de6f4681a 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt @@ -1,7 +1,7 @@ package io.legado.app.ui.changesource import android.app.Application -import androidx.lifecycle.MutableLiveData +import androidx.recyclerview.widget.DiffUtil import io.legado.app.App import io.legado.app.R import io.legado.app.base.BaseViewModel @@ -12,24 +12,27 @@ import kotlinx.coroutines.Dispatchers import org.jetbrains.anko.debug class ChangeSourceViewModel(application: Application) : BaseViewModel(application) { + var callBack: CallBack? = null var curBookUrl = "" var name: String = "" var author: String = "" - val searchBookData = MutableLiveData>() private val searchBooks = linkedSetOf() fun initData() { execute { App.db.searchBookDao().getByNameAuthorEnable(name, author).let { searchBooks.addAll(it) - searchBookData.postValue(it) + upAdapter() search() } } } fun upAdapter() { - + val diffResult = DiffUtil.calculateDiff(DiffCallBack(arrayListOf(), searchBooks.toList())) + callBack?.adapter()?.let { + diffResult.dispatchUpdatesTo(it) + } } fun search() { @@ -75,6 +78,7 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio book.latestChapterTitle = chapter.title val searchBook = book.toSearchBook() searchBooks.add(searchBook) + upAdapter() App.db.searchBookDao().insert(searchBook) } }.onError { @@ -85,9 +89,13 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio fun screen(key: String?) { if (key.isNullOrEmpty()) { - searchBookData.postValue(searchBooks.toList()) + } else { } } + + interface CallBack { + fun adapter(): ChangeSourceAdapter + } } \ No newline at end of file From 73a18481fc59ca29b40f315b397f9bfb8ec92161 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 19 Aug 2019 11:19:43 +0800 Subject: [PATCH 0791/1997] up --- .../java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt index de6f4681a..13799eecf 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt @@ -29,8 +29,8 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio } fun upAdapter() { - val diffResult = DiffUtil.calculateDiff(DiffCallBack(arrayListOf(), searchBooks.toList())) callBack?.adapter()?.let { + val diffResult = DiffUtil.calculateDiff(DiffCallBack(it.getItems(), searchBooks.toList())) diffResult.dispatchUpdatesTo(it) } } From aee0503868e5e74fc114f6e32d70cec0870eabb9 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 19 Aug 2019 11:20:15 +0800 Subject: [PATCH 0792/1997] up --- .../java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt index 13799eecf..e392ffc13 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt @@ -28,7 +28,7 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio } } - fun upAdapter() { + private fun upAdapter() { callBack?.adapter()?.let { val diffResult = DiffUtil.calculateDiff(DiffCallBack(it.getItems(), searchBooks.toList())) diffResult.dispatchUpdatesTo(it) From 88182d93f02311d5d87c1ca2f1c7489fd24afb4c Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 19 Aug 2019 11:36:47 +0800 Subject: [PATCH 0793/1997] up --- .../legado/app/base/adapter/CommonRecyclerAdapter.kt | 11 +++++++++++ .../app/ui/changesource/ChangeSourceViewModel.kt | 7 ++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/base/adapter/CommonRecyclerAdapter.kt b/app/src/main/java/io/legado/app/base/adapter/CommonRecyclerAdapter.kt index d39022f7e..16108e2f9 100644 --- a/app/src/main/java/io/legado/app/base/adapter/CommonRecyclerAdapter.kt +++ b/app/src/main/java/io/legado/app/base/adapter/CommonRecyclerAdapter.kt @@ -122,6 +122,17 @@ abstract class CommonRecyclerAdapter(protected val context: Context) : Rec } } + fun setItemsNoNotify(items: List?) { + synchronized(lock) { + if (this.items.isNotEmpty()) { + this.items.clear() + } + if (items != null) { + this.items.addAll(items) + } + } + } + fun setItems(items: List?) { synchronized(lock) { if (this.items.isNotEmpty()) { diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt index e392ffc13..7c77397d3 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt @@ -9,6 +9,7 @@ import io.legado.app.data.entities.Book import io.legado.app.data.entities.SearchBook import io.legado.app.model.WebBook import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch import org.jetbrains.anko.debug class ChangeSourceViewModel(application: Application) : BaseViewModel(application) { @@ -30,8 +31,12 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio private fun upAdapter() { callBack?.adapter()?.let { + val books = searchBooks.toList() val diffResult = DiffUtil.calculateDiff(DiffCallBack(it.getItems(), searchBooks.toList())) - diffResult.dispatchUpdatesTo(it) + launch { + it.setItemsNoNotify(books) + diffResult.dispatchUpdatesTo(it) + } } } From 184142c35c92e64e566be2c68db092d45e95bc7c Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 19 Aug 2019 11:49:33 +0800 Subject: [PATCH 0794/1997] up --- .../io/legado/app/ui/changesource/ChangeSourceViewModel.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt index 7c77397d3..a1c8d5bd8 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt @@ -49,13 +49,14 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio .timeout(30000L) .onSuccess(Dispatchers.IO) { it?.let { list -> - list.map { searchBook -> + for (searchBook in list) { if (searchBook.name == name && searchBook.author == author) { if (searchBook.tocUrl.isEmpty()) { loadBookInfo(searchBook.toBook()) } else { loadChapter(searchBook.toBook()) } + break } } } From 091755b50d9c4f281592611e7685c4a91b06848d Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 19 Aug 2019 14:12:23 +0800 Subject: [PATCH 0795/1997] up --- .../ui/changesource/ChangeSourceViewModel.kt | 49 +++++++++++-------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt index a1c8d5bd8..bfb71d5ad 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt @@ -9,6 +9,7 @@ import io.legado.app.data.entities.Book import io.legado.app.data.entities.SearchBook import io.legado.app.model.WebBook import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.launch import org.jetbrains.anko.debug @@ -66,31 +67,37 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio } private fun loadBookInfo(book: Book) { - App.db.bookSourceDao().getBookSource(book.origin)?.let { bookSource -> - WebBook(bookSource).getBookInfo(book, this) - .onSuccess { - it?.let { loadChapter(it) } - }.onError { - debug { context.getString(R.string.error_get_book_info) } - } - } ?: debug { context.getString(R.string.error_no_source) } + execute { + App.db.bookSourceDao().getBookSource(book.origin)?.let { bookSource -> + WebBook(bookSource).getBookInfo(book, this) + .onSuccess { + it?.let { loadChapter(it) } + }.onError { + debug { context.getString(R.string.error_get_book_info) } + } + } ?: debug { context.getString(R.string.error_no_source) } + } } private fun loadChapter(book: Book) { - App.db.bookSourceDao().getBookSource(book.origin)?.let { bookSource -> - WebBook(bookSource).getChapterList(book, this) - .onSuccess(Dispatchers.IO) { - it?.map { chapter -> - book.latestChapterTitle = chapter.title - val searchBook = book.toSearchBook() - searchBooks.add(searchBook) - upAdapter() - App.db.searchBookDao().insert(searchBook) + execute { + App.db.bookSourceDao().getBookSource(book.origin)?.let { bookSource -> + WebBook(bookSource).getChapterList(book, this) + .onSuccess(IO) { + it?.let { chapters -> + if (chapters.isNotEmpty()) { + book.latestChapterTitle = chapters.last().title + val searchBook = book.toSearchBook() + searchBooks.add(searchBook) + upAdapter() + App.db.searchBookDao().insert(searchBook) + } + } + }.onError { + debug { context.getString(R.string.error_get_chapter_list) } } - }.onError { - debug { context.getString(R.string.error_get_chapter_list) } - } - } ?: debug { R.string.error_no_source } + } ?: debug { R.string.error_no_source } + } } fun screen(key: String?) { From b3b4bf656f835631fe89081e98ee67fd5c19f973 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 19 Aug 2019 14:13:04 +0800 Subject: [PATCH 0796/1997] up --- .../io/legado/app/ui/changesource/ChangeSourceViewModel.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt index bfb71d5ad..9d161099b 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt @@ -8,7 +8,6 @@ import io.legado.app.base.BaseViewModel import io.legado.app.data.entities.Book import io.legado.app.data.entities.SearchBook import io.legado.app.model.WebBook -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.launch import org.jetbrains.anko.debug @@ -48,7 +47,7 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio //task取消时自动取消 by (scope = this@execute) WebBook(item).searchBook(name, scope = this@execute) .timeout(30000L) - .onSuccess(Dispatchers.IO) { + .onSuccess(IO) { it?.let { list -> for (searchBook in list) { if (searchBook.name == name && searchBook.author == author) { From e47c703d9530585ccca0ba65691483e8f0615da7 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 19 Aug 2019 14:17:24 +0800 Subject: [PATCH 0797/1997] up --- .../legado/app/ui/changesource/ChangeSourceDialog.kt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt index b5d0e565a..0fcd83683 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt @@ -17,7 +17,9 @@ import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.dialog_change_source.* -class ChangeSourceDialog : DialogFragment(), ChangeSourceViewModel.CallBack { +class ChangeSourceDialog : DialogFragment(), + ChangeSourceViewModel.CallBack, + ChangeSourceAdapter.CallBack { companion object { const val tag = "changeSourceDialog" @@ -116,6 +118,14 @@ class ChangeSourceDialog : DialogFragment(), ChangeSourceViewModel.CallBack { }) } + override fun changeTo(searchBook: SearchBook) { + callBack?.changeTo(searchBook.toBook()) + } + + override fun curBookUrl(): String { + return viewModel.curBookUrl + } + override fun adapter(): ChangeSourceAdapter { return changeSourceAdapter } From b81650bf1f4b26f3b681a42901206548c87f6781 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 19 Aug 2019 14:18:53 +0800 Subject: [PATCH 0798/1997] up --- .../app/ui/changesource/ChangeSourceDialog.kt | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt index 0fcd83683..a7d457c1f 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt @@ -78,17 +78,7 @@ class ChangeSourceDialog : DialogFragment(), private fun initRecyclerView() { changeSourceAdapter = ChangeSourceAdapter(requireContext()) - changeSourceAdapter.callBack = object : ChangeSourceAdapter.CallBack { - override fun changeTo(searchBook: SearchBook) { - callBack?.changeTo(searchBook.toBook()) - dismiss() - } - - override fun curBookUrl(): String { - return viewModel.curBookUrl - } - - } + changeSourceAdapter.callBack = this recycler_view.layoutManager = LinearLayoutManager(context) recycler_view.addItemDecoration(DividerItemDecoration(requireContext(), LinearLayout.VERTICAL)) recycler_view.adapter = changeSourceAdapter @@ -120,6 +110,7 @@ class ChangeSourceDialog : DialogFragment(), override fun changeTo(searchBook: SearchBook) { callBack?.changeTo(searchBook.toBook()) + dismiss() } override fun curBookUrl(): String { From b9f4d7952741babaab1196a3aa3d73fb9a93d8dc Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 19 Aug 2019 14:35:09 +0800 Subject: [PATCH 0799/1997] up --- .../java/io/legado/app/ui/bookinfo/BookInfoActivity.kt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index d0d673d9f..259b0eba3 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -40,7 +40,13 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo viewModel.bookData.observe(this, Observer { showBook(it) }) viewModel.isLoadingData.observe(this, Observer { upLoading(it) }) viewModel.chapterListData.observe(this, Observer { showChapter(it) }) - viewModel.loadBook(intent) + viewModel.bookData.value?.let { + showBook(it) + upLoading(false) + viewModel.chapterListData.value?.let { chapters -> + showChapter(chapters) + } + } ?: viewModel.loadBook(intent) initOnClick() savedInstanceState?.let { changeSourceDialog = supportFragmentManager.findFragmentByTag(ChangeSourceDialog.tag) as? ChangeSourceDialog @@ -184,7 +190,7 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo } override fun changeTo(book: Book) { - + viewModel.bookData.postValue(book) } override fun skipToChapter(index: Int) { From 73d2c01ebd41a78dce0a7fa6fc006a7f672d570e Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 19 Aug 2019 14:36:58 +0800 Subject: [PATCH 0800/1997] up --- .../main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index 259b0eba3..34d923d3d 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -191,6 +191,11 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo override fun changeTo(book: Book) { viewModel.bookData.postValue(book) + if (book.tocUrl.isEmpty()) { + viewModel.loadBookInfo(book) + } else { + viewModel.loadChapter(book) + } } override fun skipToChapter(index: Int) { From 0f313824a3df0984b72a56824f90bd601439186d Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 19 Aug 2019 15:00:55 +0800 Subject: [PATCH 0801/1997] up --- .../res/layout-land/activity_book_info.xml | 289 ++++++++++++++++++ 1 file changed, 289 insertions(+) create mode 100644 app/src/main/res/layout-land/activity_book_info.xml diff --git a/app/src/main/res/layout-land/activity_book_info.xml b/app/src/main/res/layout-land/activity_book_info.xml new file mode 100644 index 000000000..239f2961a --- /dev/null +++ b/app/src/main/res/layout-land/activity_book_info.xml @@ -0,0 +1,289 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From a0b7529dc9c9a46b0f11cfbeaf5aeba67f0cc962 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 19 Aug 2019 15:32:55 +0800 Subject: [PATCH 0802/1997] up --- app/src/main/res/layout/activity_book_info.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/layout/activity_book_info.xml b/app/src/main/res/layout/activity_book_info.xml index b4ef77e07..0caa32566 100644 --- a/app/src/main/res/layout/activity_book_info.xml +++ b/app/src/main/res/layout/activity_book_info.xml @@ -131,7 +131,7 @@ Date: Mon, 19 Aug 2019 15:36:21 +0800 Subject: [PATCH 0803/1997] up --- app/src/main/res/layout/activity_book_info.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/layout/activity_book_info.xml b/app/src/main/res/layout/activity_book_info.xml index 0caa32566..8ddbb5cd7 100644 --- a/app/src/main/res/layout/activity_book_info.xml +++ b/app/src/main/res/layout/activity_book_info.xml @@ -131,7 +131,7 @@ Date: Mon, 19 Aug 2019 16:31:52 +0800 Subject: [PATCH 0804/1997] up --- .../java/io/legado/app/data/entities/Book.kt | 4 +++- .../io/legado/app/data/entities/SearchBook.kt | 3 ++- .../ui/changesource/ChangeSourceViewModel.kt | 17 ++++++++++------- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/Book.kt b/app/src/main/java/io/legado/app/data/entities/Book.kt index 08a7eb13c..0add9736b 100644 --- a/app/src/main/java/io/legado/app/data/entities/Book.kt +++ b/app/src/main/java/io/legado/app/data/entities/Book.kt @@ -45,6 +45,7 @@ data class Book( var wordCount: String? = null, var canUpdate: Boolean = true, // 刷新书架时更新书籍信息 var order: Int = 0, // 手动排序 + var originOrder: Int = 0, //书源排序 var useReplaceRule: Boolean = true, // 正文使用净化替换规则 var variable: String? = null // 自定义书籍变量信息(用于书源规则检索书籍信息) ) : Parcelable, BaseBook { @@ -102,7 +103,8 @@ data class Book( latestChapterTitle = latestChapterTitle, coverUrl = coverUrl, intro = intro, - tocUrl = tocUrl + tocUrl = tocUrl, + originOrder = originOrder ) } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt index f679ff10e..e86fd12fc 100644 --- a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt +++ b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt @@ -81,7 +81,8 @@ data class SearchBook( latestChapterTitle = latestChapterTitle, coverUrl = coverUrl, intro = intro, - tocUrl = tocUrl + tocUrl = tocUrl, + originOrder = originOrder ) } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt index 9d161099b..ac58feae8 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt @@ -9,7 +9,8 @@ import io.legado.app.data.entities.Book import io.legado.app.data.entities.SearchBook import io.legado.app.model.WebBook import kotlinx.coroutines.Dispatchers.IO -import kotlinx.coroutines.launch +import kotlinx.coroutines.Dispatchers.Main +import kotlinx.coroutines.withContext import org.jetbrains.anko.debug class ChangeSourceViewModel(application: Application) : BaseViewModel(application) { @@ -30,12 +31,14 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio } private fun upAdapter() { - callBack?.adapter()?.let { - val books = searchBooks.toList() - val diffResult = DiffUtil.calculateDiff(DiffCallBack(it.getItems(), searchBooks.toList())) - launch { - it.setItemsNoNotify(books) - diffResult.dispatchUpdatesTo(it) + execute { + callBack?.adapter()?.let { + val books = searchBooks.toList() + val diffResult = DiffUtil.calculateDiff(DiffCallBack(it.getItems(), searchBooks.toList())) + withContext(Main) { + it.setItemsNoNotify(books) + diffResult.dispatchUpdatesTo(it) + } } } } From 421099e6836b8e294959a30d32ff684b51e8bc45 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 19 Aug 2019 16:33:19 +0800 Subject: [PATCH 0805/1997] up --- app/src/main/java/io/legado/app/model/webbook/BookList.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookList.kt b/app/src/main/java/io/legado/app/model/webbook/BookList.kt index 61e86f568..02c817f6d 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookList.kt @@ -104,6 +104,7 @@ object BookList { searchBook.bookUrl = baseUrl searchBook.origin = bookSource.bookSourceUrl searchBook.originName = bookSource.bookSourceName + searchBook.originOrder = bookSource.customOrder analyzeRule.setBook(searchBook) with(bookSource.getBookInfoRule()) { init?.let { @@ -158,6 +159,7 @@ object BookList { val searchBook = SearchBook() searchBook.origin = bookSource.bookSourceUrl searchBook.originName = bookSource.bookSourceName + searchBook.originOrder = bookSource.customOrder analyzeRule.setBook(searchBook) analyzeRule.setContent(item) SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取书名", printLog) From 428061ec3ccfc74cbdb7bb2ea28c75386b7999f8 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 19 Aug 2019 16:39:28 +0800 Subject: [PATCH 0806/1997] up --- app/src/main/java/io/legado/app/data/entities/SearchBook.kt | 2 +- app/src/main/java/io/legado/app/model/webbook/BookList.kt | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt index e86fd12fc..8abef8eca 100644 --- a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt +++ b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt @@ -26,7 +26,7 @@ data class SearchBook( var wordCount: String? = null, var latestChapterTitle: String? = null, var tocUrl: String = "", // 目录页Url (toc=table of Contents) - var time: Long = 0L, + var time: Long = System.currentTimeMillis(), var variable: String? = null, var bookInfoHtml: String? = null, var originOrder: Int = 0 diff --git a/app/src/main/java/io/legado/app/model/webbook/BookList.kt b/app/src/main/java/io/legado/app/model/webbook/BookList.kt index 02c817f6d..b24e414f4 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookList.kt @@ -133,8 +133,6 @@ object BookList { SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取最新章节") searchBook.latestChapterTitle = analyzeRule.getString(lastChapter ?: "") SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.latestChapterTitle ?: "") - searchBook.time = System.currentTimeMillis() - searchBook.originOrder = bookSource.customOrder return searchBook } } @@ -187,8 +185,6 @@ object BookList { SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取最新章节", printLog) searchBook.latestChapterTitle = analyzeRule.getString(ruleLastChapter) SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.latestChapterTitle ?: "", printLog) - searchBook.time = System.currentTimeMillis() - searchBook.originOrder = bookSource.customOrder return searchBook } return null From b7798d8910f28824f874bf02b9d396a1a5521706 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 19 Aug 2019 16:50:17 +0800 Subject: [PATCH 0807/1997] up --- .../app/ui/bookinfo/BookInfoViewModel.kt | 50 ++++++++++--------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt index 43c409212..77af4ea0d 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt @@ -46,35 +46,39 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { } fun loadBookInfo(book: Book) { - isLoadingData.postValue(true) - App.db.bookSourceDao().getBookSource(book.origin)?.let { bookSource -> - WebBook(bookSource).getBookInfo(book, this) - .onSuccess { - it?.let { loadChapter(it) } - }.onError { - toast(R.string.error_get_book_info) - } - } ?: toast(R.string.error_no_source) + execute { + isLoadingData.postValue(true) + App.db.bookSourceDao().getBookSource(book.origin)?.let { bookSource -> + WebBook(bookSource).getBookInfo(book, this) + .onSuccess { + it?.let { loadChapter(it) } + }.onError { + toast(R.string.error_get_book_info) + } + } ?: toast(R.string.error_no_source) + } } fun loadChapter(book: Book) { - isLoadingData.postValue(true) - App.db.bookSourceDao().getBookSource(book.origin)?.let { bookSource -> - WebBook(bookSource).getChapterList(book, this) - .onSuccess(IO) { - it?.let { - if (it.isNotEmpty()) { - if (inBookshelf) { - App.db.bookChapterDao().insert(*it.toTypedArray()) + execute { + isLoadingData.postValue(true) + App.db.bookSourceDao().getBookSource(book.origin)?.let { bookSource -> + WebBook(bookSource).getChapterList(book, this) + .onSuccess(IO) { + it?.let { + if (it.isNotEmpty()) { + if (inBookshelf) { + App.db.bookChapterDao().insert(*it.toTypedArray()) + } + chapterListData.postValue(it) + isLoadingData.postValue(false) } - chapterListData.postValue(it) - isLoadingData.postValue(false) } + }.onError { + toast(R.string.error_get_chapter_list) } - }.onError { - toast(R.string.error_get_chapter_list) - } - } ?: toast(R.string.error_no_source) + } ?: toast(R.string.error_no_source) + } } fun saveBook(success: (() -> Unit)?) { From 33a0424a333ce0e62390fe5756f3de3d0a63e844 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 19 Aug 2019 16:59:35 +0800 Subject: [PATCH 0808/1997] up --- .../main/java/io/legado/app/data/dao/BookDao.kt | 3 +++ .../legado/app/ui/bookinfo/BookInfoActivity.kt | 7 +------ .../legado/app/ui/bookinfo/BookInfoViewModel.kt | 17 +++++++++++++++++ 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/BookDao.kt b/app/src/main/java/io/legado/app/data/dao/BookDao.kt index 2e30f937d..21bad031b 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookDao.kt @@ -47,4 +47,7 @@ interface BookDao { @Update fun update(vararg books: Book) + + @Query("delete from books where bookUrl = :bookUrl") + fun delete(bookUrl: String) } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index 34d923d3d..36ed1d254 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -190,12 +190,7 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo } override fun changeTo(book: Book) { - viewModel.bookData.postValue(book) - if (book.tocUrl.isEmpty()) { - viewModel.loadBookInfo(book) - } else { - viewModel.loadChapter(book) - } + viewModel.changeTo(book) } override fun skipToChapter(index: Int) { diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt index 77af4ea0d..a4f7a1b53 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt @@ -81,6 +81,23 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { } } + fun changeTo(book: Book) { + execute { + if (inBookshelf) { + bookData.value?.let { + App.db.bookDao().delete(it.bookUrl) + } + App.db.bookDao().insert(book) + } + bookData.postValue(book) + if (book.tocUrl.isEmpty()) { + loadBookInfo(book) + } else { + loadChapter(book) + } + } + } + fun saveBook(success: (() -> Unit)?) { execute { bookData.value?.let { book -> From 7e586fc400192bc089503cf15b4152da0d6283f2 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 19 Aug 2019 17:03:29 +0800 Subject: [PATCH 0809/1997] up --- .../java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt index a4f7a1b53..b1e316d6c 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt @@ -82,6 +82,12 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { } fun changeTo(book: Book) { + bookData.value?.let { + book.customCoverUrl = it.customCoverUrl + book.durChapterIndex = it.durChapterIndex + book.durChapterPos = it.durChapterPos + book.customIntro = it.customIntro + } execute { if (inBookshelf) { bookData.value?.let { From 773c329d2b1cbfd65c8734ca5c1a0b4773f84733 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 19 Aug 2019 17:04:31 +0800 Subject: [PATCH 0810/1997] up --- .../main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt index b1e316d6c..672f36d01 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt @@ -83,9 +83,9 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { fun changeTo(book: Book) { bookData.value?.let { - book.customCoverUrl = it.customCoverUrl book.durChapterIndex = it.durChapterIndex book.durChapterPos = it.durChapterPos + book.customCoverUrl = it.customCoverUrl book.customIntro = it.customIntro } execute { From 7f694ccdad7b916c393489371d41fcdc2d4d196b Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 19 Aug 2019 17:12:40 +0800 Subject: [PATCH 0811/1997] up --- .../io/legado/app/ui/bookinfo/BookInfoActivity.kt | 4 ++++ .../io/legado/app/ui/bookinfo/BookInfoViewModel.kt | 6 ------ .../legado/app/ui/changesource/ChangeSourceDialog.kt | 12 +++++++++++- .../io/legado/app/ui/readbook/ReadBookActivity.kt | 4 ++++ 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index 36ed1d254..c2a8de623 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -189,6 +189,10 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo } } + override fun oldBook(): Book? { + return viewModel.bookData.value + } + override fun changeTo(book: Book) { viewModel.changeTo(book) } diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt index 672f36d01..a4f7a1b53 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt @@ -82,12 +82,6 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { } fun changeTo(book: Book) { - bookData.value?.let { - book.durChapterIndex = it.durChapterIndex - book.durChapterPos = it.durChapterPos - book.customCoverUrl = it.customCoverUrl - book.customIntro = it.customIntro - } execute { if (inBookshelf) { bookData.value?.let { diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt index a7d457c1f..c66e7ba9c 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt @@ -109,7 +109,16 @@ class ChangeSourceDialog : DialogFragment(), } override fun changeTo(searchBook: SearchBook) { - callBack?.changeTo(searchBook.toBook()) + callBack?.let { + val book = searchBook.toBook() + it.oldBook()?.let { oldBook -> + book.durChapterIndex = oldBook.durChapterIndex + book.durChapterPos = oldBook.durChapterPos + book.customCoverUrl = oldBook.customCoverUrl + book.customIntro = oldBook.customIntro + } + it.changeTo(book) + } dismiss() } @@ -122,6 +131,7 @@ class ChangeSourceDialog : DialogFragment(), } interface CallBack { + fun oldBook(): Book? fun changeTo(book: Book) } diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 724d7b2c7..204c7f9e9 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -267,6 +267,10 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } + override fun oldBook(): Book? { + return viewModel.bookData.value + } + override fun changeTo(book: Book) { } From 27f108f8e2d40b01b584ba77350cd098e5039d69 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 19 Aug 2019 17:29:29 +0800 Subject: [PATCH 0812/1997] up --- .../java/io/legado/app/ui/changesource/ChangeSourceDialog.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt index c66e7ba9c..c02604376 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt @@ -116,6 +116,7 @@ class ChangeSourceDialog : DialogFragment(), book.durChapterPos = oldBook.durChapterPos book.customCoverUrl = oldBook.customCoverUrl book.customIntro = oldBook.customIntro + book.order = oldBook.order } it.changeTo(book) } From 452cbb0ab5eeacf5a6b0cee12bf0cc1f1e5c385d Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 19 Aug 2019 17:35:21 +0800 Subject: [PATCH 0813/1997] up --- app/src/main/java/io/legado/app/data/entities/Book.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/data/entities/Book.kt b/app/src/main/java/io/legado/app/data/entities/Book.kt index 0add9736b..b7b2e3e34 100644 --- a/app/src/main/java/io/legado/app/data/entities/Book.kt +++ b/app/src/main/java/io/legado/app/data/entities/Book.kt @@ -68,7 +68,7 @@ data class Book( variableMap = if (isEmpty(variable)) { HashMap() } else { - GSON.fromJsonObject>(variable) + GSON.fromJsonObject(variable) } } } From 53272442730b129942f5592af24faf04f9f48f56 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 19 Aug 2019 17:47:15 +0800 Subject: [PATCH 0814/1997] up --- .../java/io/legado/app/ui/changesource/ChangeSourceDialog.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt index c02604376..ab8e5be74 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt @@ -117,6 +117,9 @@ class ChangeSourceDialog : DialogFragment(), book.customCoverUrl = oldBook.customCoverUrl book.customIntro = oldBook.customIntro book.order = oldBook.order + if (book.coverUrl.isNullOrEmpty()) { + book.coverUrl = oldBook.getDisplayCover() + } } it.changeTo(book) } From f3922f0e320ca3c09c2e09e1cf3cf079bdbaa2f5 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 19 Aug 2019 17:58:32 +0800 Subject: [PATCH 0815/1997] up --- app/src/main/java/io/legado/app/data/entities/Book.kt | 6 +++--- .../java/io/legado/app/model/webbook/BookChapterList.kt | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/Book.kt b/app/src/main/java/io/legado/app/data/entities/Book.kt index b7b2e3e34..ebd007a10 100644 --- a/app/src/main/java/io/legado/app/data/entities/Book.kt +++ b/app/src/main/java/io/legado/app/data/entities/Book.kt @@ -34,14 +34,14 @@ data class Book( var type: Int = 0, // @BookType var group: Int = 0, // 自定义分组索引号 var latestChapterTitle: String? = null, // 最新章节标题 - var latestChapterTime: Long = 0, // 最新章节标题更新时间 - var lastCheckTime: Long = 0, // 最近一次更新书籍信息的时间 + var latestChapterTime: Long = System.currentTimeMillis(), // 最新章节标题更新时间 + var lastCheckTime: Long = System.currentTimeMillis(), // 最近一次更新书籍信息的时间 var lastCheckCount: Int = 0, // 最近一次发现新章节的数量 var totalChapterNum: Int = 0, // 书籍目录总数 var durChapterTitle: String? = null, // 当前章节名称 var durChapterIndex: Int = 0, // 当前章节索引 var durChapterPos: Int = 0, // 当前阅读的进度(首行字符的索引位置) - var durChapterTime: Long = 0, // 最近一次阅读书籍的时间(打开正文的时间) + var durChapterTime: Long = System.currentTimeMillis(), // 最近一次阅读书籍的时间(打开正文的时间) var wordCount: String? = null, var canUpdate: Boolean = true, // 刷新书架时更新书籍信息 var order: Int = 0, // 手动排序 diff --git a/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt b/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt index 03e29ea95..57c8635ba 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt @@ -98,6 +98,7 @@ object BookChapterList { for ((index, item) in chapterList.withIndex()) { item.index = index } + book.latestChapterTitle = chapterList.last().title return chapterList } From 2cfdb364b6621760a8910db214cb0fd8c454ff98 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 19 Aug 2019 17:59:16 +0800 Subject: [PATCH 0816/1997] up --- app/src/main/java/io/legado/app/data/dao/BookDao.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/BookDao.kt b/app/src/main/java/io/legado/app/data/dao/BookDao.kt index 21bad031b..4f5401c4c 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookDao.kt @@ -36,10 +36,10 @@ interface BookDao { @get:Query("SELECT COUNT(*) FROM books") val allBookCount: Int - @Query("SELECT * FROM books ORDER BY durChapterTime DESC limit 0,10") + @Query("SELECT * FROM books ORDER BY durChapterTime DESC limit 0,20") fun recentRead(): DataSource.Factory - @Query("SELECT * FROM books ORDER BY durChapterTime DESC limit 0,10") + @Query("SELECT * FROM books ORDER BY durChapterTime DESC limit 0,20") fun getRecentRead(): List @Insert(onConflict = OnConflictStrategy.REPLACE) From 70e7c91fa6f8fd5514574df49dfacc79bab0d9fe Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 19 Aug 2019 18:01:38 +0800 Subject: [PATCH 0817/1997] up --- .../java/io/legado/app/ui/changesource/ChangeSourceDialog.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt index ab8e5be74..854532d17 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt @@ -114,6 +114,7 @@ class ChangeSourceDialog : DialogFragment(), it.oldBook()?.let { oldBook -> book.durChapterIndex = oldBook.durChapterIndex book.durChapterPos = oldBook.durChapterPos + book.durChapterTitle = oldBook.durChapterTitle book.customCoverUrl = oldBook.customCoverUrl book.customIntro = oldBook.customIntro book.order = oldBook.order From 5b0669922df1d892008b2bb50e5ed274608e9eb2 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 19 Aug 2019 20:34:05 +0800 Subject: [PATCH 0818/1997] up --- .../legado/app/ui/widget/page/ContentView.kt | 4 +++- app/src/main/res/drawable/bg1.jpg | Bin 0 -> 319831 bytes 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 app/src/main/res/drawable/bg1.jpg diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index a8bc37183..e2bf5ba3f 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -1,6 +1,7 @@ package io.legado.app.ui.widget.page import android.content.Context +import android.graphics.Color import android.util.AttributeSet import android.widget.FrameLayout import io.legado.app.R @@ -19,12 +20,13 @@ class ContentView : FrameLayout { init { inflate(context, R.layout.view_book_page, this) - + setBackgroundColor(Color.WHITE) upStyle() } fun upStyle() { page_panel.horizontalPadding = 16.dp + page_panel.setBackgroundResource(R.drawable.bg1) } fun upTime() { diff --git a/app/src/main/res/drawable/bg1.jpg b/app/src/main/res/drawable/bg1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3e46c8e0f7364d46772b70b115811ab1d61f73ff GIT binary patch literal 319831 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

9Z{#oiw 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 -$-YjAuLOKo-*x2dkoPwFzIfu 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%0D(<$?3&2n}a`}_rgi#jy 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

;6uz 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 Date: Mon, 19 Aug 2019 21:38:42 +0800 Subject: [PATCH 0819/1997] up --- app/src/main/res/layout/item_book_source.xml | 8 ++++---- app/src/main/res/layout/item_bookmark.xml | 3 ++- app/src/main/res/layout/item_bookshelf_list.xml | 10 +++++++++- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/app/src/main/res/layout/item_book_source.xml b/app/src/main/res/layout/item_book_source.xml index cc6889cfb..fb6263705 100644 --- a/app/src/main/res/layout/item_book_source.xml +++ b/app/src/main/res/layout/item_book_source.xml @@ -1,12 +1,12 @@ + android:padding="16dp"> + android:layout_height="wrap_content" + android:background="?android:attr/selectableItemBackground"> + + Date: Mon, 19 Aug 2019 21:43:51 +0800 Subject: [PATCH 0820/1997] up --- .../java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt | 2 ++ app/src/main/res/layout/item_bookshelf_list.xml | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt index b67ad32cf..341de51ff 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt @@ -11,6 +11,7 @@ import io.legado.app.constant.BookType import io.legado.app.data.entities.Book import io.legado.app.help.ImageLoader import io.legado.app.lib.theme.ThemeStore +import io.legado.app.utils.getCompatColor import kotlinx.android.synthetic.main.item_bookshelf_list.view.* import kotlinx.android.synthetic.main.item_relace_rule.view.tv_name import org.jetbrains.anko.sdk27.listeners.onClick @@ -61,6 +62,7 @@ class BookshelfAdapter : PagedListAdapter(D } fun bind(book: Book, callBack: CallBack?) = with(itemView) { + this.setBackgroundColor(context.getCompatColor(R.color.background)) tv_name.text = book.name tv_author.text = book.author tv_read.text = book.durChapterTitle diff --git a/app/src/main/res/layout/item_bookshelf_list.xml b/app/src/main/res/layout/item_bookshelf_list.xml index 7e397b9c0..72376cda3 100644 --- a/app/src/main/res/layout/item_bookshelf_list.xml +++ b/app/src/main/res/layout/item_bookshelf_list.xml @@ -162,7 +162,6 @@ android:layout_width="match_parent" android:layout_height="0dp" android:background="?android:attr/selectableItemBackground" - android:visibility="gone" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" /> From 909c6028f2f2ed3d83e49c44fc5a4d52fcf56bdf Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 20 Aug 2019 08:24:48 +0800 Subject: [PATCH 0821/1997] up --- .../ui/changesource/ChangeSourceAdapter.kt | 27 +++++++++++-------- .../ui/changesource/ChangeSourceViewModel.kt | 6 +++-- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceAdapter.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceAdapter.kt index 368527d4f..45e9da565 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceAdapter.kt @@ -17,18 +17,23 @@ class ChangeSourceAdapter(context: Context) : SimpleRecyclerAdapter( override fun convert(holder: ItemViewHolder, item: SearchBook, payloads: MutableList) { holder.itemView.apply { - this.onClick { - callBack?.changeTo(item) - } - tv_origin.text = item.originName - tv_last.text = item.latestChapterTitle - callBack?.let { - if (it.curBookUrl() == item.bookUrl) { - iv_checked.visible() - } else { - iv_checked.invisible() + if (payloads.isEmpty()) { + this.onClick { + callBack?.changeTo(item) } - } ?: iv_checked.invisible() + tv_origin.text = item.originName + tv_last.text = item.latestChapterTitle + callBack?.let { + if (it.curBookUrl() == item.bookUrl) { + iv_checked.visible() + } else { + iv_checked.invisible() + } + } ?: iv_checked.invisible() + } else { + tv_origin.text = item.originName + tv_last.text = item.latestChapterTitle + } } } diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt index ac58feae8..b64d559f8 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt @@ -36,8 +36,10 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio val books = searchBooks.toList() val diffResult = DiffUtil.calculateDiff(DiffCallBack(it.getItems(), searchBooks.toList())) withContext(Main) { - it.setItemsNoNotify(books) - diffResult.dispatchUpdatesTo(it) + synchronized(this) { + it.setItemsNoNotify(books) + diffResult.dispatchUpdatesTo(it) + } } } } From d033b4e68dd84144383a6fe4f7102f3d73d43d8a Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 20 Aug 2019 09:05:07 +0800 Subject: [PATCH 0822/1997] up --- .../io/legado/app/ui/changesource/DiffCallBack.kt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/changesource/DiffCallBack.kt b/app/src/main/java/io/legado/app/ui/changesource/DiffCallBack.kt index 2183c51e5..2cb911204 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/DiffCallBack.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/DiffCallBack.kt @@ -21,7 +21,16 @@ class DiffCallBack(private val oldItems: List, private val newItems: override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { return oldItems[oldItemPosition].originName == newItems[newItemPosition].originName - && oldItems[oldItemPosition].latestChapterTitle == newItems[newItemPosition].originName + && oldItems[oldItemPosition].latestChapterTitle == newItems[newItemPosition].latestChapterTitle + } + + override fun getChangePayload(oldItemPosition: Int, newItemPosition: Int): Any? { + val oldItem = oldItems[oldItemPosition] + val newItem = newItems[newItemPosition] + if (oldItem.originName != newItem.originName || oldItem.latestChapterTitle != newItem.latestChapterTitle) { + return true + } + return null } } \ No newline at end of file From f82a31387445ce4e66c4c3efbcae49963773a044 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 20 Aug 2019 11:12:15 +0800 Subject: [PATCH 0823/1997] up --- app/src/main/java/io/legado/app/data/entities/SearchBook.kt | 6 +++++- .../io/legado/app/ui/changesource/ChangeSourceViewModel.kt | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt index 8abef8eca..4423ff6f8 100644 --- a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt +++ b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt @@ -30,7 +30,7 @@ data class SearchBook( var variable: String? = null, var bookInfoHtml: String? = null, var originOrder: Int = 0 -) : Parcelable, BaseBook { +) : Parcelable, BaseBook, Comparable { override fun equals(other: Any?): Boolean { if (other is SearchBook) { @@ -45,6 +45,10 @@ data class SearchBook( return bookUrl.hashCode() } + override fun compareTo(other: SearchBook): Int { + return other.originOrder - this.originOrder + } + @IgnoredOnParcel @Ignore override var variableMap: HashMap? = null diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt index b64d559f8..df3041c6c 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt @@ -34,6 +34,7 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio execute { callBack?.adapter()?.let { val books = searchBooks.toList() + books.sorted() val diffResult = DiffUtil.calculateDiff(DiffCallBack(it.getItems(), searchBooks.toList())) withContext(Main) { synchronized(this) { From c41cfb070c927f64e1e20af5a5f9f3ebc17c341d Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 20 Aug 2019 12:23:45 +0800 Subject: [PATCH 0824/1997] up --- .../io/legado/app/ui/search/DiffCallBack.kt | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 app/src/main/java/io/legado/app/ui/search/DiffCallBack.kt diff --git a/app/src/main/java/io/legado/app/ui/search/DiffCallBack.kt b/app/src/main/java/io/legado/app/ui/search/DiffCallBack.kt new file mode 100644 index 000000000..b38514f50 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/search/DiffCallBack.kt @@ -0,0 +1,28 @@ +package io.legado.app.ui.search + +import androidx.recyclerview.widget.DiffUtil +import io.legado.app.data.entities.SearchShow + +class DiffCallBack(private val oldItems: List, private val newItems: List) : + DiffUtil.Callback() { + override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { + return oldItems[oldItemPosition].name == newItems[newItemPosition].name + && oldItems[oldItemPosition].author == newItems[newItemPosition].author + } + + override fun getOldListSize(): Int { + return oldItems.size + } + + override fun getNewListSize(): Int { + return newItems.size + } + + override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { + return oldItems[oldItemPosition].originCount == newItems[newItemPosition].originCount + } + + override fun getChangePayload(oldItemPosition: Int, newItemPosition: Int): Any? { + return super.getChangePayload(oldItemPosition, newItemPosition) + } +} \ No newline at end of file From 6efa706a663acb1837f8a6026e5b3b82f290eab0 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 20 Aug 2019 14:39:50 +0800 Subject: [PATCH 0825/1997] up --- app/build.gradle | 4 ++-- app/src/main/java/io/legado/app/lib/webdav/WebDav.kt | 11 ++++++----- .../io/legado/app/model/analyzeRule/AnalyzeUrl.kt | 5 ++--- app/src/main/java/io/legado/app/utils/NetworkUtils.kt | 6 +++--- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 4704be08a..990b59760 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -127,8 +127,8 @@ dependencies { implementation 'com.github.gedoor:rhino-android:1.3' //Retrofit - implementation 'com.squareup.okhttp3:logging-interceptor:3.14.0' - implementation 'com.squareup.retrofit2:retrofit:2.6.0' + implementation 'com.squareup.okhttp3:logging-interceptor:4.1.0' + implementation 'com.squareup.retrofit2:retrofit:2.6.1' //Glide implementation 'com.github.bumptech.glide:glide:4.9.0' diff --git a/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt b/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt index 452f07c15..4ca1966c8 100644 --- a/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt +++ b/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt @@ -4,6 +4,7 @@ import io.legado.app.lib.webdav.http.Handler import io.legado.app.lib.webdav.http.HttpAuth import io.legado.app.lib.webdav.http.OkHttp import okhttp3.* +import okhttp3.MediaType.Companion.toMediaTypeOrNull import org.jsoup.Jsoup import java.io.File import java.io.IOException @@ -42,7 +43,7 @@ constructor(url: String) { HttpAuth.auth?.let { request.header("Authorization", Credentials.basic(it.user, it.pass)) } try { - return okHttpClient.newCall(request.build()).execute().body()?.byteStream() + return okHttpClient.newCall(request.build()).execute().body?.byteStream() } catch (e: IOException) { e.printStackTrace() } catch (e: IllegalArgumentException) { @@ -82,7 +83,7 @@ constructor(url: String) { this.exists = false return false } - response.body()?.let { + response.body?.let { if (it.string().isNotEmpty()) { return true } @@ -102,7 +103,7 @@ constructor(url: String) { fun listFiles(propsList: ArrayList = ArrayList()): List { propFindResponse(propsList)?.let { response -> if (response.isSuccessful) { - response.body()?.let { body -> + response.body?.let { body -> return parseDir(body.string()) } } @@ -128,7 +129,7 @@ constructor(url: String) { .url(url) // 添加RequestBody对象,可以只返回的属性。如果设为null,则会返回全部属性 // 注意:尽量手动指定需要返回的属性。若返回全部属性,可能后由于Prop.java里没有该属性名,而崩溃。 - .method("PROPFIND", RequestBody.create(MediaType.parse("text/plain"), requestPropsStr)) + .method("PROPFIND", RequestBody.create("text/plain".toMediaTypeOrNull(), requestPropsStr)) HttpAuth.auth?.let { request.header("Authorization", Credentials.basic(it.user, it.pass)) } @@ -206,7 +207,7 @@ constructor(url: String) { fun upload(localPath: String, contentType: String? = null): Boolean { val file = File(localPath) if (!file.exists()) return false - val mediaType = if (contentType == null) null else MediaType.parse(contentType) + val mediaType = if (contentType == null) null else contentType.toMediaTypeOrNull() // 务必注意RequestBody不要嵌套,不然上传时内容可能会被追加多余的文件信息 val fileBody = RequestBody.create(mediaType, file) getUrl()?.let { diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt index c2950aae0..95487bfe6 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt @@ -12,9 +12,8 @@ import io.legado.app.help.http.HttpHelper import io.legado.app.utils.* import kotlinx.coroutines.Deferred import okhttp3.FormBody -import okhttp3.MediaType +import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.RequestBody -import retrofit2.Call import retrofit2.Response import java.net.URLEncoder import java.util.* @@ -38,7 +37,7 @@ class AnalyzeUrl( ) { companion object { private val pagePattern = Pattern.compile("<(.*?)>") - private val jsonType = MediaType.parse("application/json; charset=utf-8") + private val jsonType = "application/json; charset=utf-8".toMediaTypeOrNull() } private var baseUrl: String = "" diff --git a/app/src/main/java/io/legado/app/utils/NetworkUtils.kt b/app/src/main/java/io/legado/app/utils/NetworkUtils.kt index 90e68f004..7b1b23b32 100644 --- a/app/src/main/java/io/legado/app/utils/NetworkUtils.kt +++ b/app/src/main/java/io/legado/app/utils/NetworkUtils.kt @@ -7,9 +7,9 @@ import java.util.* object NetworkUtils { fun getUrl(response: Response<*>): String { - val networkResponse = response.raw().networkResponse() - return networkResponse?.request()?.url()?.toString() - ?: response.raw().request().url().toString() + val networkResponse = response.raw().networkResponse + return networkResponse?.request?.url?.toString() + ?: response.raw().request.url.toString() } private val notNeedEncoding: BitSet by lazy { From df0542b6eff9799fffc22f049dc08f3244a83ca8 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 20 Aug 2019 14:45:16 +0800 Subject: [PATCH 0826/1997] up --- app/src/main/java/io/legado/app/lib/theme/ATH.kt | 1 + app/src/main/java/io/legado/app/model/webbook/BookInfo.kt | 4 ++-- .../main/java/io/legado/app/receiver/MediaButtonReceiver.kt | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/theme/ATH.kt b/app/src/main/java/io/legado/app/lib/theme/ATH.kt index 512b2ffa7..c5d284064 100644 --- a/app/src/main/java/io/legado/app/lib/theme/ATH.kt +++ b/app/src/main/java/io/legado/app/lib/theme/ATH.kt @@ -100,6 +100,7 @@ object ATH { val color1: Int if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { color1 = ColorUtils.stripAlpha(color) + @Suppress("DEPRECATION") activity.setTaskDescription(ActivityManager.TaskDescription(activity.title as String, null, color1)) } } diff --git a/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt b/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt index 05dfc0fc6..1ad81cf11 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt @@ -37,12 +37,12 @@ object BookInfo { analyzeRule.getString(infoRule.name ?: "")?.let { if (it.isNotEmpty()) book.name = it } - SourceDebug.printLog(bookSource.bookSourceUrl, 1, book.name ?: "") + SourceDebug.printLog(bookSource.bookSourceUrl, 1, book.name) SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取作者") analyzeRule.getString(infoRule.author ?: "")?.let { if (it.isNotEmpty()) book.author = it } - SourceDebug.printLog(bookSource.bookSourceUrl, 1, book.author ?: "") + SourceDebug.printLog(bookSource.bookSourceUrl, 1, book.author) SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取分类") analyzeRule.getString(infoRule.kind ?: "")?.let { if (it.isNotEmpty()) book.kind = it diff --git a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt index 796734c43..d64df95e2 100644 --- a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt +++ b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt @@ -46,7 +46,7 @@ class MediaButtonReceiver : BroadcastReceiver() { } private fun readAloud(context: Context) { - ActivityHelp.getInstance()?.isExist(ReadBookActivity::class.java)?.let { + ActivityHelp.getInstance().isExist(ReadBookActivity::class.java).let { if (!it) { context.startActivity() } From 6f3f8f5f00e911fd45c21be5188aac66e4d36963 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 20 Aug 2019 15:35:19 +0800 Subject: [PATCH 0827/1997] up --- .../main/java/io/legado/app/lib/theme/TintHelper.kt | 3 ++- .../legado/app/lib/theme/prefs/IconListPreference.kt | 1 + .../legado/app/lib/theme/view/ATEAccentBgTextView.kt | 8 ++++---- .../app/lib/theme/view/ATEAccentStrokeTextView.kt | 9 +++++---- .../java/io/legado/app/lib/theme/view/ATECheckBox.kt | 8 ++++---- .../legado/app/lib/theme/view/ATEPrimaryTextView.kt | 8 ++++---- .../io/legado/app/lib/theme/view/ATERadioButton.kt | 12 ++++++------ .../app/lib/theme/view/ATESecondaryTextView.kt | 8 ++++---- 8 files changed, 30 insertions(+), 27 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt b/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt index 0ab6fcfc4..ba416c992 100644 --- a/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt +++ b/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt @@ -326,7 +326,8 @@ object TintHelper { private fun modifySwitchDrawable( context: Context, - from: Drawable, @ColorInt tint: Int, + from: Drawable, + @ColorInt tint: Int, thumb: Boolean, compatSwitch: Boolean, useDarker: Boolean diff --git a/app/src/main/java/io/legado/app/lib/theme/prefs/IconListPreference.kt b/app/src/main/java/io/legado/app/lib/theme/prefs/IconListPreference.kt index f1389a989..d78849b3e 100644 --- a/app/src/main/java/io/legado/app/lib/theme/prefs/IconListPreference.kt +++ b/app/src/main/java/io/legado/app/lib/theme/prefs/IconListPreference.kt @@ -36,6 +36,7 @@ class IconListPreference(context: Context, attrs: AttributeSet) : ListPreference for (drawable in drawables) { val resId = context.resources.getIdentifier(drawable.toString(), "mipmap", context.packageName) + @Suppress("DEPRECATION") val d = context.resources.getDrawable(resId) mEntryDrawables.add(d) diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATEAccentBgTextView.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATEAccentBgTextView.kt index fbc849d6c..6de1037b9 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATEAccentBgTextView.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATEAccentBgTextView.kt @@ -11,18 +11,18 @@ import io.legado.app.utils.dp class ATEAccentBgTextView : AppCompatTextView { constructor(context: Context) : super(context) { - init(context, null) + init(context) } constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { - init(context, attrs) + init(context) } constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { - init(context, attrs) + init(context) } - private fun init(context: Context, attrs: AttributeSet?) { + private fun init(context: Context) { background = Selector.shapeBuild() .setCornerRadius(3.dp) .setDefaultBgColor(ThemeStore.accentColor(context)) diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATEAccentStrokeTextView.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATEAccentStrokeTextView.kt index def0146f3..c6aea80f0 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATEAccentStrokeTextView.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATEAccentStrokeTextView.kt @@ -10,18 +10,19 @@ import io.legado.app.utils.dp class ATEAccentStrokeTextView : AppCompatTextView { constructor(context: Context) : super(context) { - init(context, null) + init(context) } constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { - init(context, attrs) + init(context) } constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { - init(context, attrs) + init(context) } - private fun init(context: Context, attrs: AttributeSet?) { + @Suppress("DEPRECATION") + private fun init(context: Context) { background = Selector.shapeBuild() .setCornerRadius(3.dp) .setStrokeWidth(1.dp) diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATECheckBox.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATECheckBox.kt index 15e3b5f14..643299f35 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATECheckBox.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATECheckBox.kt @@ -12,18 +12,18 @@ import io.legado.app.lib.theme.ThemeStore class ATECheckBox : AppCompatCheckBox { constructor(context: Context) : super(context) { - init(context, null) + init(context) } constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { - init(context, attrs) + init(context) } constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { - init(context, attrs) + init(context) } - private fun init(context: Context, attrs: AttributeSet?) { + private fun init(context: Context) { ATH.setTint(this, ThemeStore.accentColor(context)) } } diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATEPrimaryTextView.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATEPrimaryTextView.kt index b39385688..97d4d08b1 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATEPrimaryTextView.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATEPrimaryTextView.kt @@ -11,18 +11,18 @@ import io.legado.app.lib.theme.ThemeStore class ATEPrimaryTextView : AppCompatTextView { constructor(context: Context) : super(context) { - init(context, null) + init(context) } constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { - init(context, attrs) + init(context) } constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { - init(context, attrs) + init(context) } - private fun init(context: Context, attrs: AttributeSet?) { + private fun init(context: Context) { setTextColor(ThemeStore.textColorPrimary(context)) } } diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATERadioButton.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATERadioButton.kt index 583d5e054..8af025c2f 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATERadioButton.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATERadioButton.kt @@ -4,7 +4,7 @@ import android.content.Context import android.util.AttributeSet import androidx.appcompat.widget.AppCompatRadioButton import io.legado.app.lib.theme.ATH -import io.legado.app.lib.theme.ThemeStore +import io.legado.app.lib.theme.accentColor /** * @author Aidan Follestad (afollestad) @@ -12,18 +12,18 @@ import io.legado.app.lib.theme.ThemeStore class ATERadioButton : AppCompatRadioButton { constructor(context: Context) : super(context) { - init(context, null) + init(context) } constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { - init(context, attrs) + init(context) } constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { - init(context, attrs) + init(context) } - private fun init(context: Context, attrs: AttributeSet?) { - ATH.setTint(this, ThemeStore.accentColor(context)) + private fun init(context: Context) { + ATH.setTint(this@ATERadioButton, context.accentColor) } } diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATESecondaryTextView.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATESecondaryTextView.kt index dec5d938e..f84814b90 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATESecondaryTextView.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATESecondaryTextView.kt @@ -11,18 +11,18 @@ import io.legado.app.lib.theme.ThemeStore class ATESecondaryTextView : AppCompatTextView { constructor(context: Context) : super(context) { - init(context, null) + init(context) } constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { - init(context, attrs) + init(context) } constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { - init(context, attrs) + init(context) } - private fun init(context: Context, attrs: AttributeSet?) { + private fun init(context: Context) { setTextColor(ThemeStore.textColorSecondary(context)) } } From 162bd16922646e97fe5fad383c48d6e3c85e18e0 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 20 Aug 2019 15:36:40 +0800 Subject: [PATCH 0828/1997] up --- app/src/main/java/io/legado/app/lib/dialogs/AndroidDialogs.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/lib/dialogs/AndroidDialogs.kt b/app/src/main/java/io/legado/app/lib/dialogs/AndroidDialogs.kt index e14a2730f..10716da17 100644 --- a/app/src/main/java/io/legado/app/lib/dialogs/AndroidDialogs.kt +++ b/app/src/main/java/io/legado/app/lib/dialogs/AndroidDialogs.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -@file:Suppress("NOTHING_TO_INLINE", "unused") +@file:Suppress("NOTHING_TO_INLINE", "unused", "DEPRECATION") package io.legado.app.lib.dialogs From 91eff38e8b060215d1fcb7a7943b567288cc83b4 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 20 Aug 2019 15:39:53 +0800 Subject: [PATCH 0829/1997] up --- .../io/legado/app/lib/theme/TintHelper.kt | 26 +++++++++---------- .../app/model/analyzeRule/AnalyzeUrl.kt | 3 ++- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt b/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt index ba416c992..cbff84976 100644 --- a/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt +++ b/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt @@ -332,11 +332,11 @@ object TintHelper { compatSwitch: Boolean, useDarker: Boolean ): Drawable? { - var tint = tint + var tint1 = tint if (useDarker) { - tint = ColorUtils.shiftColor(tint, 1.1f) + tint1 = ColorUtils.shiftColor(tint1, 1.1f) } - tint = ColorUtils.adjustAlpha(tint, if (compatSwitch && !thumb) 0.5f else 1.0f) + tint1 = ColorUtils.adjustAlpha(tint1, if (compatSwitch && !thumb) 0.5f else 1.0f) val disabled: Int var normal: Int if (thumb) { @@ -375,7 +375,7 @@ object TintHelper { intArrayOf(android.R.attr.state_enabled, android.R.attr.state_activated), intArrayOf(android.R.attr.state_enabled, android.R.attr.state_checked) ), - intArrayOf(disabled, normal, tint, tint) + intArrayOf(disabled, normal, tint1, tint1) ) return createTintedDrawable(from, sl) } @@ -414,20 +414,20 @@ object TintHelper { // This returns a NEW Drawable because of the mutate() call. The mutate() call is necessary because Drawables with the same resource have shared states otherwise. @CheckResult fun createTintedDrawable(drawable: Drawable?, @ColorInt color: Int): Drawable? { - var drawable: Drawable? = drawable ?: return null - drawable = DrawableCompat.wrap(drawable!!.mutate()) - DrawableCompat.setTintMode(drawable!!, PorterDuff.Mode.SRC_IN) - DrawableCompat.setTint(drawable, color) - return drawable + var drawable1: Drawable? = drawable ?: return null + drawable1 = DrawableCompat.wrap(drawable1!!.mutate()) + DrawableCompat.setTintMode(drawable1!!, PorterDuff.Mode.SRC_IN) + DrawableCompat.setTint(drawable1, color) + return drawable1 } // This returns a NEW Drawable because of the mutate() call. The mutate() call is necessary because Drawables with the same resource have shared states otherwise. @CheckResult fun createTintedDrawable(drawable: Drawable?, sl: ColorStateList): Drawable? { - var drawable: Drawable? = drawable ?: return null - drawable = DrawableCompat.wrap(drawable!!.mutate()) - DrawableCompat.setTintList(drawable!!, sl) - return drawable + var drawable1: Drawable? = drawable ?: return null + drawable1 = DrawableCompat.wrap(drawable1!!.mutate()) + DrawableCompat.setTintList(drawable1!!, sl) + return drawable1 } fun setCursorTint(editText: EditText, @ColorInt color: Int) { diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt index 95487bfe6..075c72aca 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt @@ -14,6 +14,7 @@ import kotlinx.coroutines.Deferred import okhttp3.FormBody import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.toRequestBody import retrofit2.Response import java.net.URLEncoder import java.util.* @@ -148,7 +149,7 @@ class AnalyzeUrl( Method.POST -> { bodyTxt?.let { if (it.isJson()) { - body = RequestBody.create(jsonType, it) + body = it.toRequestBody(jsonType) } else { analyzeFields(it) } From 5b8d4f9f6ac02ed3f80be8a9586a14c19b659533 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 20 Aug 2019 16:16:59 +0800 Subject: [PATCH 0830/1997] up --- .../java/io/legado/app/ui/widget/page/ContentView.kt | 11 ++++++++++- .../java/io/legado/app/ui/widget/page/PageView.kt | 10 +++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index e2bf5ba3f..7e26ae1dd 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -2,6 +2,7 @@ package io.legado.app.ui.widget.page import android.content.Context import android.graphics.Color +import android.graphics.drawable.Drawable import android.util.AttributeSet import android.widget.FrameLayout import io.legado.app.R @@ -26,7 +27,15 @@ class ContentView : FrameLayout { fun upStyle() { page_panel.horizontalPadding = 16.dp - page_panel.setBackgroundResource(R.drawable.bg1) + + } + + fun setBg(bg: Drawable?) { + page_panel.background = bg + } + + fun setBgColor(color: Int) { + page_panel.setBackgroundColor(color) } fun upTime() { diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 255068c07..bb8ba6cd1 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -7,6 +7,7 @@ import android.graphics.Color import android.util.AttributeSet import android.view.MotionEvent import android.widget.FrameLayout +import io.legado.app.R import io.legado.app.ui.widget.page.delegate.CoverPageDelegate import io.legado.app.ui.widget.page.delegate.PageDelegate import kotlinx.android.synthetic.main.view_book_page.view.* @@ -28,7 +29,7 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att addView(nextPage) curPage = ContentView(context) addView(curPage) - + upBg() setWillNotDraw(false) page_panel.backgroundColor = Color.WHITE @@ -111,6 +112,13 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att nextPage?.upStyle() } + fun upBg() { + val bg = context.getDrawable(R.drawable.bg1) + curPage?.setBg(bg) + prevPage?.setBg(bg) + nextPage?.setBg(bg) + } + fun upTime() { curPage?.upTime() prevPage?.upTime() From 2254cffef8dc1223584bfeddf4c8ead73b9fc546 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 20 Aug 2019 16:21:14 +0800 Subject: [PATCH 0831/1997] up --- .../main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 204c7f9e9..5b22e5154 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -300,6 +300,10 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea page_view.upStyle() } + fun upBg() { + page_view.upBg() + } + private fun onClickReadAloud() { if (!ReadAloudService.isRun) { readAloudStatus = Status.STOP From 62bd71ac256ee66229ddadd645f736176142e58b Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 20 Aug 2019 16:30:56 +0800 Subject: [PATCH 0832/1997] up --- .../java/io/legado/app/ui/readbook/ReadBookViewModel.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index 5fad1c557..ade57d777 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -13,6 +13,7 @@ import io.legado.app.data.entities.BookChapter import io.legado.app.data.entities.BookSource import io.legado.app.help.BookHelp import io.legado.app.model.WebBook +import io.legado.app.service.ReadAloudService import io.legado.app.ui.widget.page.TextChapter import kotlinx.coroutines.Dispatchers.IO @@ -133,6 +134,11 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } + override fun onCleared() { + super.onCleared() + ReadAloudService.stop(context) + } + interface CallBack { fun loadContentFinish(bookChapter: BookChapter, content: String) } From e5f27fbe97f11aa8df20400963e10ee1facdd152 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 20 Aug 2019 18:39:01 +0800 Subject: [PATCH 0833/1997] up --- app/src/main/java/io/legado/app/App.kt | 4 ++-- .../java/io/legado/app/help/ActivityHelp.kt | 21 ++----------------- .../java/io/legado/app/help/ReadBookHelp.kt | 10 +++++++++ .../app/receiver/MediaButtonReceiver.kt | 2 +- .../io/legado/app/ui/widget/page/PageView.kt | 5 ----- 5 files changed, 15 insertions(+), 27 deletions(-) create mode 100644 app/src/main/java/io/legado/app/help/ReadBookHelp.kt diff --git a/app/src/main/java/io/legado/app/App.kt b/app/src/main/java/io/legado/app/App.kt index f0bf61b89..7994ac212 100644 --- a/app/src/main/java/io/legado/app/App.kt +++ b/app/src/main/java/io/legado/app/App.kt @@ -143,7 +143,7 @@ class App : Application() { private fun registerActivityLife(){ registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks{ override fun onActivityPaused(activity: Activity) { - ActivityHelp.getInstance().add(activity) + ActivityHelp.add(activity) } override fun onActivityResumed(activity: Activity) { @@ -153,7 +153,7 @@ class App : Application() { } override fun onActivityDestroyed(activity: Activity) { - ActivityHelp.getInstance().remove(activity) + ActivityHelp.remove(activity) } override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle?) { diff --git a/app/src/main/java/io/legado/app/help/ActivityHelp.kt b/app/src/main/java/io/legado/app/help/ActivityHelp.kt index a1e535bfe..709bdd305 100644 --- a/app/src/main/java/io/legado/app/help/ActivityHelp.kt +++ b/app/src/main/java/io/legado/app/help/ActivityHelp.kt @@ -7,26 +7,9 @@ import java.util.* /** * Activity管理器,管理项目中Activity的状态 */ -class ActivityHelp private constructor() { +object ActivityHelp { - companion object { - - private var activities: MutableList> = arrayListOf() - - @Volatile - private var instance: ActivityHelp? = null - - fun getInstance(): ActivityHelp { - if (null == instance) { - synchronized(ActivityHelp::class.java) { - if (null == instance) { - instance = ActivityHelp() - } - } - } - return instance!! - } - } + private var activities: MutableList> = arrayListOf() fun getActivities(): List> { return activities diff --git a/app/src/main/java/io/legado/app/help/ReadBookHelp.kt b/app/src/main/java/io/legado/app/help/ReadBookHelp.kt new file mode 100644 index 000000000..2a79820f7 --- /dev/null +++ b/app/src/main/java/io/legado/app/help/ReadBookHelp.kt @@ -0,0 +1,10 @@ +package io.legado.app.help + +import android.graphics.drawable.Drawable + +object ReadBookHelp { + + var bg: Drawable? = null + + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt index d64df95e2..587471648 100644 --- a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt +++ b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt @@ -46,7 +46,7 @@ class MediaButtonReceiver : BroadcastReceiver() { } private fun readAloud(context: Context) { - ActivityHelp.getInstance().isExist(ReadBookActivity::class.java).let { + ActivityHelp.isExist(ReadBookActivity::class.java).let { if (!it) { context.startActivity() } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index bb8ba6cd1..848237a1e 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -3,15 +3,12 @@ package io.legado.app.ui.widget.page import android.annotation.SuppressLint import android.content.Context import android.graphics.Canvas -import android.graphics.Color import android.util.AttributeSet import android.view.MotionEvent import android.widget.FrameLayout import io.legado.app.R import io.legado.app.ui.widget.page.delegate.CoverPageDelegate import io.legado.app.ui.widget.page.delegate.PageDelegate -import kotlinx.android.synthetic.main.view_book_page.view.* -import org.jetbrains.anko.backgroundColor class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, attrs), PageDelegate.PageInterface { @@ -32,8 +29,6 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att upBg() setWillNotDraw(false) - page_panel.backgroundColor = Color.WHITE - pageDelegate = CoverPageDelegate(this) } From 17a90ab7eb773fe152e3ba21b173d4acd88bf332 Mon Sep 17 00:00:00 2001 From: Administrator <1760316362@qq.com> Date: Tue, 20 Aug 2019 18:42:29 +0800 Subject: [PATCH 0834/1997] update pageview --- .../java/io/legado/app/base/BaseViewModel.kt | 10 +-- .../app/ui/readbook/ReadBookActivity.kt | 3 +- .../app/ui/readbook/ReadBookViewModel.kt | 6 +- .../legado/app/ui/widget/page/ContentView.kt | 21 +++--- .../legado/app/ui/widget/page/DataSource.kt | 10 +++ .../legado/app/ui/widget/page/PageFactory.kt | 8 ++ .../io/legado/app/ui/widget/page/PageView.kt | 73 +++++++++++++++++-- .../app/ui/widget/page/ScrollContentView.kt | 3 + .../app/ui/widget/page/TextPageFactory.kt | 32 +++++++- .../widget/page/delegate/CoverPageDelegate.kt | 16 +++- .../ui/widget/page/delegate/PageDelegate.kt | 50 +++++++++---- .../widget/page/delegate/SlidePageDelegate.kt | 22 ++++++ app/src/main/res/layout/view_book_page.xml | 1 - 13 files changed, 204 insertions(+), 51 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/widget/page/ScrollContentView.kt create mode 100644 app/src/main/java/io/legado/app/ui/widget/page/delegate/SlidePageDelegate.kt diff --git a/app/src/main/java/io/legado/app/base/BaseViewModel.kt b/app/src/main/java/io/legado/app/base/BaseViewModel.kt index 096c6d562..1aa8452c9 100644 --- a/app/src/main/java/io/legado/app/base/BaseViewModel.kt +++ b/app/src/main/java/io/legado/app/base/BaseViewModel.kt @@ -12,7 +12,7 @@ import org.jetbrains.anko.toast open class BaseViewModel(application: Application) : AndroidViewModel(application), CoroutineScope by MainScope(), AnkoLogger { - val context: Context = this.getApplication() + val context: Context by lazy { this.getApplication() } fun execute(scope: CoroutineScope = this, block: suspend CoroutineScope.() -> T): Coroutine { return Coroutine.async(scope) { block() } @@ -29,25 +29,25 @@ open class BaseViewModel(application: Application) : AndroidViewModel(applicatio open fun toast(message: Int) { launch { - getApplication().toast(message) + context.toast(message) } } open fun toast(message: CharSequence) { launch { - getApplication().toast(message) + context.toast(message) } } open fun longToast(message: Int) { launch { - getApplication().toast(message) + context.toast(message) } } open fun longToast(message: CharSequence) { launch { - getApplication().toast(message) + context.toast(message) } } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 5b22e5154..191e93f2c 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -51,7 +51,6 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea setSupportActionBar(toolbar) initAnimation() initView() - page_view.callBack = this viewModel.callBack = this viewModel.chapterMaxIndex.observe(this, Observer { bookLoadFinish() }) viewModel.bookData.observe(this, Observer { title_bar.title = it.name }) @@ -242,7 +241,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } - override fun loadContentFinish(bookChapter: BookChapter, content: String) { + override fun onLoadFinish(bookChapter: BookChapter, content: String) { launch { when (bookChapter.index) { viewModel.durChapterIndex -> { diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index ade57d777..380c70988 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -80,7 +80,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { execute { App.db.bookChapterDao().getChapter(book.bookUrl, index)?.let { chapter -> BookHelp.getContent(book, chapter)?.let { - callBack?.loadContentFinish(chapter, it) + callBack?.onLoadFinish(chapter, it) synchronized(loadingLock) { loadingChapters.remove(index) } @@ -118,7 +118,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { ?.onSuccess(IO) { content -> content?.let { BookHelp.saveContent(book, chapter, it) - callBack?.loadContentFinish(chapter, it) + callBack?.onLoadFinish(chapter, it) synchronized(loadingLock) { loadingChapters.remove(chapter.index) } @@ -140,6 +140,6 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } interface CallBack { - fun loadContentFinish(bookChapter: BookChapter, content: String) + fun onLoadFinish(bookChapter: BookChapter, content: String) } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index 7e26ae1dd..8692a7b12 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -1,18 +1,21 @@ package io.legado.app.ui.widget.page import android.content.Context -import android.graphics.Color -import android.graphics.drawable.Drawable import android.util.AttributeSet import android.widget.FrameLayout +import androidx.appcompat.widget.AppCompatImageView import io.legado.app.R +import io.legado.app.help.ImageLoader import io.legado.app.utils.dp import kotlinx.android.synthetic.main.view_book_page.view.* import org.jetbrains.anko.horizontalPadding +import org.jetbrains.anko.matchParent class ContentView : FrameLayout { + private val bgImage: AppCompatImageView = AppCompatImageView(context) + constructor(context: Context) : super(context) constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) @@ -20,22 +23,16 @@ class ContentView : FrameLayout { constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) init { + addView(bgImage, LayoutParams(matchParent, matchParent)) inflate(context, R.layout.view_book_page, this) - setBackgroundColor(Color.WHITE) upStyle() } fun upStyle() { page_panel.horizontalPadding = 16.dp - - } - - fun setBg(bg: Drawable?) { - page_panel.background = bg - } - - fun setBgColor(color: Int) { - page_panel.setBackgroundColor(color) + ImageLoader.load(context, R.drawable.bg1) + .centerCrop() + .setAsDrawable(bgImage) } fun upTime() { diff --git a/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt b/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt index f13cea296..76c11a532 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt @@ -1,11 +1,17 @@ package io.legado.app.ui.widget.page +import io.legado.app.data.entities.BookChapter + interface DataSource { + fun isPrepared(): Boolean + fun getChapterPosition() fun getChapter(position: Int): TextChapter? + fun getCurrentChapter(): TextChapter? + fun getNextChapter(): TextChapter? fun getPreviousChapter(): TextChapter? @@ -13,4 +19,8 @@ interface DataSource { fun hasNextChapter(): Boolean fun hasPrevChapter(): Boolean + + interface CallBack { + fun onLoadFinish(bookChapter: BookChapter, content: String) + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageFactory.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageFactory.kt index d99e2976d..a0e0f32cd 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageFactory.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageFactory.kt @@ -4,10 +4,18 @@ abstract class PageFactory(protected val dataSource: DataSource) { abstract fun pageAt(index: Int): DATA? + abstract fun moveToFirst() + + abstract fun moveToNext():Boolean + + abstract fun moveToPrevious(): Boolean + abstract fun nextPage(): DATA? abstract fun previousPage(): DATA? + abstract fun currentPage(): DATA? + abstract fun hasNext(): Boolean abstract fun hasPrev(): Boolean diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 848237a1e..142153eee 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -12,8 +12,9 @@ import io.legado.app.ui.widget.page.delegate.PageDelegate class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, attrs), PageDelegate.PageInterface { - var callBack: CallBack? = null + var callback: CallBack? = null private var pageDelegate: PageDelegate? = null + private var pageFactory: TextPageFactory? = null var prevPage: ContentView? = null var curPage: ContentView? = null @@ -30,6 +31,40 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att setWillNotDraw(false) pageDelegate = CoverPageDelegate(this) + + setPageFactory(TextPageFactory.create(object : DataSource { + override fun isPrepared(): Boolean { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun getChapterPosition() { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun getChapter(position: Int): TextChapter? { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun getCurrentChapter(): TextChapter? { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun getNextChapter(): TextChapter? { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun getPreviousChapter(): TextChapter? { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun hasNextChapter(): Boolean { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun hasPrevChapter(): Boolean { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + })) } override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { @@ -41,9 +76,7 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att override fun dispatchDraw(canvas: Canvas) { super.dispatchDraw(canvas) -// bringChildToFront(prevPage) - - pageDelegate?.onPerform(canvas) + pageDelegate?.onDraw(canvas) } override fun computeScroll() { @@ -56,7 +89,7 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att } fun chapterLoadFinish(chapterOnDur: Int = 0) { - callBack?.let { cb -> + callback?.let { cb -> when (chapterOnDur) { 0 -> { cb.textChapter()?.let { @@ -89,8 +122,36 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att } } - fun setPageFactory(factory: PageFactory<*>) { + fun fillPage(direction: PageDelegate.Direction) { + pageFactory?.let { + when (direction) { + PageDelegate.Direction.PREV -> { + it.moveToPrevious() + } + + PageDelegate.Direction.NEXT -> { + it.moveToNext() + } + else -> { + + } + } + + prevPage?.setContent(it.previousPage()?.text) + curPage?.setContent(it.currentPage()?.text) + nextPage?.setContent(it.nextPage()?.text) + } + } + + fun setPageFactory(factory: TextPageFactory) { + this.pageFactory = factory + //可做成异步回调 + pageFactory?.let { + prevPage?.setContent(it.previousPage()?.text) + curPage?.setContent(it.currentPage()?.text) + nextPage?.setContent(it.nextPage()?.text) + } } override fun hasNext(): Boolean { diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ScrollContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ScrollContentView.kt new file mode 100644 index 000000000..0e1be1865 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/page/ScrollContentView.kt @@ -0,0 +1,3 @@ +package io.legado.app.ui.widget.page + +class ScrollContentView diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt index 922423acb..790981026 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt @@ -22,12 +22,36 @@ class TextPageFactory private constructor(dataSource: DataSource) : PageFactory< TODO("todo...") } - override fun nextPage(): TextPage { - return TextPage(index.plus(1), "index:$index") + override fun moveToFirst() { + index = 0 } - override fun previousPage(): TextPage { - return TextPage(index.minus(1), "index:$index") + override fun moveToNext(): Boolean { + return if(hasNext()){ + index = index.plus(1) + true + }else + false + } + + override fun moveToPrevious(): Boolean { + return if(hasPrev()){ + index = index.minus(1) + true + }else + false + } + + override fun currentPage(): TextPage? { + return TextPage(index, "index:$index") + } + + override fun nextPage(): TextPage? { + return TextPage(index + 1, "index:${index + 1}") + } + + override fun previousPage(): TextPage? { + return TextPage(index - 1, "index:${index - 1}") } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/CoverPageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/CoverPageDelegate.kt index 68b3f67c9..69130b5f8 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/CoverPageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/CoverPageDelegate.kt @@ -24,7 +24,7 @@ class CoverPageDelegate(pageView: PageView) : PageDelegate(pageView) { shadowDrawableL.gradientType = GradientDrawable.LINEAR_GRADIENT } - override fun onStart() { + override fun onScrollStart() { val distanceX: Float when (direction) { Direction.NEXT -> if (isCancel) { @@ -47,10 +47,18 @@ class CoverPageDelegate(pageView: PageView) : PageDelegate(pageView) { start() } - override fun onPerform(canvas: Canvas) { + override fun onScrollStop() { + if (!isCancel) { + pageView.fillPage(direction) + } + } + + override fun onDraw(canvas: Canvas) { val offsetX = touchX - startX - if(offsetX == 0.toFloat()) return + if ((direction == Direction.NEXT && offsetX > 0) + || (direction == Direction.PREV && offsetX < 0) + ) return val distanceX = if (offsetX > 0) offsetX - viewWidth else offsetX + viewWidth bitmap?.let { @@ -64,7 +72,7 @@ class CoverPageDelegate(pageView: PageView) : PageDelegate(pageView) { private fun addShadow(left: Int, canvas: Canvas?) { canvas?.let { if (left < 0) { - shadowDrawableR.setBounds(left + viewWidth, 0, left+ viewWidth + 30, viewHeight) + shadowDrawableR.setBounds(left + viewWidth, 0, left + viewWidth + 30, viewHeight) shadowDrawableR.draw(it) } else { shadowDrawableL.setBounds(left - 30, 0, left, viewHeight) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt index 14a34e284..5ce6345b7 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt @@ -4,15 +4,14 @@ import android.graphics.Bitmap import android.graphics.Canvas import android.view.GestureDetector import android.view.MotionEvent -import android.view.View import android.widget.Scroller import androidx.interpolator.view.animation.FastOutLinearInInterpolator +import io.legado.app.ui.widget.page.ContentView import io.legado.app.ui.widget.page.PageView import io.legado.app.utils.screenshot -import kotlinx.android.synthetic.main.view_book_page.view.* import kotlin.math.abs -abstract class PageDelegate(private val pageView: PageView) { +abstract class PageDelegate(protected val pageView: PageView) { //起始点 protected var startX: Float = 0.toFloat() @@ -21,8 +20,14 @@ abstract class PageDelegate(private val pageView: PageView) { protected var touchX: Float = 0.toFloat() protected var touchY: Float = 0.toFloat() - protected val view: View - get() = pageView.page_panel + protected val nextPage: ContentView? + get() = pageView.nextPage + + protected val curPage: ContentView? + get() = pageView.curPage + + protected val prevPage: ContentView? + get() = pageView.prevPage protected var bitmap: Bitmap? = null @@ -58,6 +63,8 @@ abstract class PageDelegate(private val pageView: PageView) { if (invalidate) { invalidate() } + + onScroll() } fun setViewSize(width: Int, height: Int) { @@ -86,9 +93,10 @@ abstract class PageDelegate(private val pageView: PageView) { fun scroll() { if (scroller.computeScrollOffset()) { setTouchPoint(scroller.currX.toFloat(), scroller.currY.toFloat()) - } else if(isStarted){ + } else if (isStarted) { setTouchPoint(scroller.finalX.toFloat(), scroller.finalY.toFloat(), false) stop() + onScrollStop() } } @@ -126,14 +134,16 @@ abstract class PageDelegate(private val pageView: PageView) { return } } - onStart() + onScrollStart() } fun onTouch(event: MotionEvent): Boolean { + if (isStarted) return false + if (isMoved && event.action == MotionEvent.ACTION_UP) { // 开启翻页效果 if (!noNext) { - onStart() + onScrollStart() } return true } @@ -145,9 +155,15 @@ abstract class PageDelegate(private val pageView: PageView) { return duration.toInt() } - abstract fun onStart() + abstract fun onScrollStart()//scroller start - abstract fun onPerform(canvas: Canvas) + abstract fun onDraw(canvas: Canvas)//绘制 + + abstract fun onScrollStop()//scroller finish + + open fun onScroll() {//移动contentView, slidePage + + } enum class Direction { NONE, PREV, NEXT @@ -156,7 +172,7 @@ abstract class PageDelegate(private val pageView: PageView) { private inner class GestureListener : GestureDetector.OnGestureListener { override fun onDown(e: MotionEvent): Boolean { - abort() +// abort() //是否移动 isMoved = false //是否存在下一章 @@ -185,21 +201,24 @@ abstract class PageDelegate(private val pageView: PageView) { if (!hasNext) { return true } + //下一页截图 + bitmap = nextPage?.screenshot() } else { val hasPrev = pageView.hasPrev() if (!hasPrev) { return true } + //上一页截图 + bitmap = prevPage?.screenshot() } setTouchPoint(x, y) + onScrollStart() return true } override fun onScroll(e1: MotionEvent, e2: MotionEvent, distanceX: Float, distanceY: Float): Boolean { if (!isMoved && abs(distanceX) > abs(distanceY)) { - //上一页或下一页截图,还未处理 if (distanceX < 0) { - bitmap = pageView.prevPage?.screenshot() //上一页的参数配置 direction = Direction.PREV //判断是否上一页存在 @@ -209,8 +228,9 @@ abstract class PageDelegate(private val pageView: PageView) { noNext = true return true } + //上一页截图 + bitmap = prevPage?.screenshot() } else { - bitmap = pageView.nextPage?.screenshot() //进行下一页的配置 direction = Direction.NEXT //判断是否下一页存在 @@ -220,6 +240,8 @@ abstract class PageDelegate(private val pageView: PageView) { noNext = true return true } + //下一页截图 + bitmap = nextPage?.screenshot() } isMoved = true } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/SlidePageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/SlidePageDelegate.kt new file mode 100644 index 000000000..d78eb9698 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/SlidePageDelegate.kt @@ -0,0 +1,22 @@ +package io.legado.app.ui.widget.page.delegate + +import android.graphics.Canvas +import io.legado.app.ui.widget.page.PageView + +class SlidePageDelegate(pageView: PageView) : PageDelegate(pageView) { + + override fun onScrollStart() { + + } + + override fun onDraw(canvas: Canvas) { + } + + override fun onScroll() { + + } + + override fun onScrollStop() { + + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/view_book_page.xml b/app/src/main/res/layout/view_book_page.xml index 63efc398b..db1dd5bf9 100644 --- a/app/src/main/res/layout/view_book_page.xml +++ b/app/src/main/res/layout/view_book_page.xml @@ -4,7 +4,6 @@ android:id="@+id/page_panel" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="@color/background" android:orientation="vertical" app:divider="@drawable/ic_divider" app:showDividers="middle"> From f5415575c1049bff62b264ec9cfdf17ad79766b6 Mon Sep 17 00:00:00 2001 From: Administrator <1760316362@qq.com> Date: Tue, 20 Aug 2019 18:45:22 +0800 Subject: [PATCH 0835/1997] update pageview --- .../java/io/legado/app/ui/widget/page/ContentView.kt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index 8692a7b12..b555c93c1 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -1,6 +1,7 @@ package io.legado.app.ui.widget.page import android.content.Context +import android.graphics.drawable.Drawable import android.util.AttributeSet import android.widget.FrameLayout import androidx.appcompat.widget.AppCompatImageView @@ -30,11 +31,18 @@ class ContentView : FrameLayout { fun upStyle() { page_panel.horizontalPadding = 16.dp - ImageLoader.load(context, R.drawable.bg1) + } + + fun setBg(bg: Drawable?) { + ImageLoader.load(context, bg) .centerCrop() .setAsDrawable(bgImage) } + fun setBgColor(color: Int) { + page_panel.setBackgroundColor(color) + } + fun upTime() { } From e360ea68ba75b2a236365be965bf0c5b35b04f4b Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 20 Aug 2019 20:42:32 +0800 Subject: [PATCH 0836/1997] up --- app/src/main/assets/defaultConfig.json | 75 +++++++++++++++++++ .../java/io/legado/app/help/ReadBookConfig.kt | 25 +++++++ .../java/io/legado/app/help/ReadBookHelp.kt | 10 --- 3 files changed, 100 insertions(+), 10 deletions(-) create mode 100644 app/src/main/assets/defaultConfig.json create mode 100644 app/src/main/java/io/legado/app/help/ReadBookConfig.kt delete mode 100644 app/src/main/java/io/legado/app/help/ReadBookHelp.kt diff --git a/app/src/main/assets/defaultConfig.json b/app/src/main/assets/defaultConfig.json new file mode 100644 index 000000000..24eb3c894 --- /dev/null +++ b/app/src/main/assets/defaultConfig.json @@ -0,0 +1,75 @@ +{ + "readBook": [ + { + "bg": "#F3F3F3", + "bgInt": 0, + "bgType": 0, + "darkStatusIcon": true, + "textColor": "#3E3D3B", + "textSize": 16, + "letterSpacing": 1, + "lineSpacingExtra": 15, + "lineSpacingMultiplier": 3 + }, + { + "bg": "#C6BAA1", + "bgInt": 0, + "bgType": 0, + "darkStatusIcon": true, + "textColor": "#3E3D3B", + "textSize": 16, + "letterSpacing": 1, + "lineSpacingExtra": 15, + "lineSpacingMultiplier": 3, + "paddingLeft": 16, + "paddingRight": 16, + "paddingTop": 0, + "paddingBottom": 0 + }, + { + "bg": "#E1F1DA", + "bgInt": 0, + "bgType": 0, + "darkStatusIcon": true, + "textColor": "#3E3D3B", + "textSize": 16, + "letterSpacing": 1, + "lineSpacingExtra": 15, + "lineSpacingMultiplier": 3, + "paddingLeft": 16, + "paddingRight": 16, + "paddingTop": 0, + "paddingBottom": 0 + }, + { + "bg": "#015A86", + "bgInt": 0, + "bgType": 0, + "darkStatusIcon": false, + "textColor": "#3E3D3B", + "textSize": 16, + "letterSpacing": 1, + "lineSpacingExtra": 15, + "lineSpacingMultiplier": 3, + "paddingLeft": 16, + "paddingRight": 16, + "paddingTop": 0, + "paddingBottom": 0 + }, + { + "bg": "#808080", + "bgInt": 0, + "bgType": 0, + "darkStatusIcon": false, + "textColor": "#3E3D3B", + "textSize": 16, + "letterSpacing": 1, + "lineSpacingExtra": 15, + "lineSpacingMultiplier": 3, + "paddingLeft": 16, + "paddingRight": 16, + "paddingTop": 0, + "paddingBottom": 0 + } + ] +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt new file mode 100644 index 000000000..30159af98 --- /dev/null +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -0,0 +1,25 @@ +package io.legado.app.help + +import android.graphics.drawable.Drawable + +object ReadBookConfig { + val configList = arrayListOf() + var bg: Drawable? = null + + init { + + } + + data class Config( + var bg: String = "#F3F3F3", + var bgInt: Int = 0, + var bgType: Int = 0, + var darkStatusIcon: Boolean = true, + var textColor: String = "#3E3D3B", + var textSize: Int = 16, + var letterSpacing: Int = 1, + var lineSpacingExtra: Int = 15, + var lineSpacingMultiplier: Int = 3 + ) + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/help/ReadBookHelp.kt b/app/src/main/java/io/legado/app/help/ReadBookHelp.kt deleted file mode 100644 index 2a79820f7..000000000 --- a/app/src/main/java/io/legado/app/help/ReadBookHelp.kt +++ /dev/null @@ -1,10 +0,0 @@ -package io.legado.app.help - -import android.graphics.drawable.Drawable - -object ReadBookHelp { - - var bg: Drawable? = null - - -} \ No newline at end of file From 55404365b8b6aa0a334b3ae328e37f37e347f46d Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 20 Aug 2019 20:44:14 +0800 Subject: [PATCH 0837/1997] up --- app/src/main/assets/defaultConfig.json | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/assets/defaultConfig.json b/app/src/main/assets/defaultConfig.json index 24eb3c894..089a4f3f7 100644 --- a/app/src/main/assets/defaultConfig.json +++ b/app/src/main/assets/defaultConfig.json @@ -1,4 +1,5 @@ { + "readBookSelect": 0, "readBook": [ { "bg": "#F3F3F3", From 359683804f6e144f11d858a20a4ba3bfaf35a77c Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 20 Aug 2019 20:47:28 +0800 Subject: [PATCH 0838/1997] up --- app/src/main/java/io/legado/app/help/ReadBookConfig.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index 30159af98..34183fe63 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -3,13 +3,18 @@ package io.legado.app.help import android.graphics.drawable.Drawable object ReadBookConfig { - val configList = arrayListOf() + private val configList = arrayListOf() + var styleSelect = 0 var bg: Drawable? = null init { } + fun getConfig(): Config { + return configList[styleSelect] + } + data class Config( var bg: String = "#F3F3F3", var bgInt: Int = 0, From 863568f309193b8ef02060b54df9832490b0a002 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 20 Aug 2019 21:32:17 +0800 Subject: [PATCH 0839/1997] up --- app/src/main/java/io/legado/app/help/BookHelp.kt | 3 +-- .../java/io/legado/app/help/ReadBookConfig.kt | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/BookHelp.kt b/app/src/main/java/io/legado/app/help/BookHelp.kt index 6f15036b0..cda999353 100644 --- a/app/src/main/java/io/legado/app/help/BookHelp.kt +++ b/app/src/main/java/io/legado/app/help/BookHelp.kt @@ -8,7 +8,6 @@ import java.io.BufferedWriter import java.io.File import java.io.FileWriter import java.io.IOException -import java.nio.charset.StandardCharsets object BookHelp { @@ -52,7 +51,7 @@ object BookHelp { runCatching { val file = File(filePath) if (file.exists()) { - return String(file.readBytes(), StandardCharsets.UTF_8) + return String(file.readBytes()) } } return null diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index 34183fe63..ed80686a6 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -1,6 +1,10 @@ package io.legado.app.help import android.graphics.drawable.Drawable +import com.jayway.jsonpath.JsonPath +import io.legado.app.App +import io.legado.app.utils.readInt +import java.io.File object ReadBookConfig { private val configList = arrayListOf() @@ -8,7 +12,17 @@ object ReadBookConfig { var bg: Drawable? = null init { - + val configFile = File(App.INSTANCE.filesDir.absolutePath + File.separator + "config") + val json = if (configFile.exists()) { + String(configFile.readBytes()) + } else { + String(App.INSTANCE.assets.open("defaultConfig.json").readBytes()) + } + JsonPath.parse(json).let { + styleSelect = it.readInt("$.readBookSelect") ?: 0 + configList.clear() + configList.addAll(it.read>("$.readBook")) + } } fun getConfig(): Config { From 507df7f39d4c8f944df398b6f951cbbe140eab00 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 20 Aug 2019 21:46:18 +0800 Subject: [PATCH 0840/1997] up --- app/src/main/assets/defaultConfig.json | 76 ------------------- app/src/main/assets/readConfig.json | 73 ++++++++++++++++++ .../java/io/legado/app/help/ReadBookConfig.kt | 34 +++++++-- 3 files changed, 102 insertions(+), 81 deletions(-) delete mode 100644 app/src/main/assets/defaultConfig.json create mode 100644 app/src/main/assets/readConfig.json diff --git a/app/src/main/assets/defaultConfig.json b/app/src/main/assets/defaultConfig.json deleted file mode 100644 index 089a4f3f7..000000000 --- a/app/src/main/assets/defaultConfig.json +++ /dev/null @@ -1,76 +0,0 @@ -{ - "readBookSelect": 0, - "readBook": [ - { - "bg": "#F3F3F3", - "bgInt": 0, - "bgType": 0, - "darkStatusIcon": true, - "textColor": "#3E3D3B", - "textSize": 16, - "letterSpacing": 1, - "lineSpacingExtra": 15, - "lineSpacingMultiplier": 3 - }, - { - "bg": "#C6BAA1", - "bgInt": 0, - "bgType": 0, - "darkStatusIcon": true, - "textColor": "#3E3D3B", - "textSize": 16, - "letterSpacing": 1, - "lineSpacingExtra": 15, - "lineSpacingMultiplier": 3, - "paddingLeft": 16, - "paddingRight": 16, - "paddingTop": 0, - "paddingBottom": 0 - }, - { - "bg": "#E1F1DA", - "bgInt": 0, - "bgType": 0, - "darkStatusIcon": true, - "textColor": "#3E3D3B", - "textSize": 16, - "letterSpacing": 1, - "lineSpacingExtra": 15, - "lineSpacingMultiplier": 3, - "paddingLeft": 16, - "paddingRight": 16, - "paddingTop": 0, - "paddingBottom": 0 - }, - { - "bg": "#015A86", - "bgInt": 0, - "bgType": 0, - "darkStatusIcon": false, - "textColor": "#3E3D3B", - "textSize": 16, - "letterSpacing": 1, - "lineSpacingExtra": 15, - "lineSpacingMultiplier": 3, - "paddingLeft": 16, - "paddingRight": 16, - "paddingTop": 0, - "paddingBottom": 0 - }, - { - "bg": "#808080", - "bgInt": 0, - "bgType": 0, - "darkStatusIcon": false, - "textColor": "#3E3D3B", - "textSize": 16, - "letterSpacing": 1, - "lineSpacingExtra": 15, - "lineSpacingMultiplier": 3, - "paddingLeft": 16, - "paddingRight": 16, - "paddingTop": 0, - "paddingBottom": 0 - } - ] -} \ No newline at end of file diff --git a/app/src/main/assets/readConfig.json b/app/src/main/assets/readConfig.json new file mode 100644 index 000000000..726668d1c --- /dev/null +++ b/app/src/main/assets/readConfig.json @@ -0,0 +1,73 @@ +[ + { + "bg": "#F3F3F3", + "bgInt": 0, + "bgType": 0, + "darkStatusIcon": true, + "textColor": "#3E3D3B", + "textSize": 16, + "letterSpacing": 1, + "lineSpacingExtra": 15, + "lineSpacingMultiplier": 3 + }, + { + "bg": "#C6BAA1", + "bgInt": 0, + "bgType": 0, + "darkStatusIcon": true, + "textColor": "#3E3D3B", + "textSize": 16, + "letterSpacing": 1, + "lineSpacingExtra": 15, + "lineSpacingMultiplier": 3, + "paddingLeft": 16, + "paddingRight": 16, + "paddingTop": 0, + "paddingBottom": 0 + }, + { + "bg": "#E1F1DA", + "bgInt": 0, + "bgType": 0, + "darkStatusIcon": true, + "textColor": "#3E3D3B", + "textSize": 16, + "letterSpacing": 1, + "lineSpacingExtra": 15, + "lineSpacingMultiplier": 3, + "paddingLeft": 16, + "paddingRight": 16, + "paddingTop": 0, + "paddingBottom": 0 + }, + { + "bg": "#015A86", + "bgInt": 0, + "bgType": 0, + "darkStatusIcon": false, + "textColor": "#3E3D3B", + "textSize": 16, + "letterSpacing": 1, + "lineSpacingExtra": 15, + "lineSpacingMultiplier": 3, + "paddingLeft": 16, + "paddingRight": 16, + "paddingTop": 0, + "paddingBottom": 0 + }, + { + "bg": "#808080", + "bgInt": 0, + "bgType": 0, + "darkStatusIcon": false, + "textColor": "#3E3D3B", + "textSize": 16, + "letterSpacing": 1, + "lineSpacingExtra": 15, + "lineSpacingMultiplier": 3, + "paddingLeft": 16, + "paddingRight": 16, + "paddingTop": 0, + "paddingBottom": 0 + } +] \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index ed80686a6..1d71b603f 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -3,12 +3,19 @@ package io.legado.app.help import android.graphics.drawable.Drawable import com.jayway.jsonpath.JsonPath import io.legado.app.App -import io.legado.app.utils.readInt +import io.legado.app.utils.GSON +import io.legado.app.utils.getPrefInt +import io.legado.app.utils.putPrefInt +import java.io.BufferedWriter import java.io.File +import java.io.FileWriter +import java.io.IOException object ReadBookConfig { private val configList = arrayListOf() - var styleSelect = 0 + var styleSelect + get() = App.INSTANCE.getPrefInt("readStyleSelect") + set(value) = App.INSTANCE.putPrefInt("readStyleSelect", value) var bg: Drawable? = null init { @@ -16,12 +23,11 @@ object ReadBookConfig { val json = if (configFile.exists()) { String(configFile.readBytes()) } else { - String(App.INSTANCE.assets.open("defaultConfig.json").readBytes()) + String(App.INSTANCE.assets.open("readConfig.json").readBytes()) } JsonPath.parse(json).let { - styleSelect = it.readInt("$.readBookSelect") ?: 0 configList.clear() - configList.addAll(it.read>("$.readBook")) + configList.addAll(it.read>("$")) } } @@ -29,6 +35,24 @@ object ReadBookConfig { return configList[styleSelect] } + fun save() { + val json = GSON.toJson(configList) + val configFile = File(App.INSTANCE.filesDir.absolutePath + File.separator + "config") + //获取流并存储 + try { + BufferedWriter(FileWriter(configFile)).use { writer -> + writer.write(json) + writer.flush() + } + } catch (e: IOException) { + e.printStackTrace() + } + } + + fun reset() { + + } + data class Config( var bg: String = "#F3F3F3", var bgInt: Int = 0, From 9a8cb5beb0cab0f77ef0381982560671f90258cc Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 20 Aug 2019 21:53:52 +0800 Subject: [PATCH 0841/1997] up --- .../java/io/legado/app/help/ReadBookConfig.kt | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index 1d71b603f..e94321e42 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -1,9 +1,9 @@ package io.legado.app.help import android.graphics.drawable.Drawable -import com.jayway.jsonpath.JsonPath import io.legado.app.App import io.legado.app.utils.GSON +import io.legado.app.utils.fromJsonArray import io.legado.app.utils.getPrefInt import io.legado.app.utils.putPrefInt import java.io.BufferedWriter @@ -25,16 +25,24 @@ object ReadBookConfig { } else { String(App.INSTANCE.assets.open("readConfig.json").readBytes()) } - JsonPath.parse(json).let { + GSON.fromJsonArray(json)?.let { configList.clear() - configList.addAll(it.read>("$")) - } + configList.addAll(it) + } ?: reset() } fun getConfig(): Config { return configList[styleSelect] } + fun upBg() { + getConfig().apply { + when (bgType) { + + } + } + } + fun save() { val json = GSON.toJson(configList) val configFile = File(App.INSTANCE.filesDir.absolutePath + File.separator + "config") @@ -50,7 +58,11 @@ object ReadBookConfig { } fun reset() { - + val json = String(App.INSTANCE.assets.open("readConfig.json").readBytes()) + GSON.fromJsonArray(json)?.let { + configList.clear() + configList.addAll(it) + } } data class Config( From 7d9adece7cdac4e5861bcbe0c12983aada24a4fa Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 20 Aug 2019 22:56:49 +0800 Subject: [PATCH 0842/1997] up --- app/src/main/assets/readConfig.json | 10 +++++----- .../main/java/io/legado/app/help/ReadBookConfig.kt | 7 +++++-- .../legado/app/ui/readbook/config/ReadAloudPopup.kt | 8 ++++++++ .../legado/app/ui/readbook/config/ReadStylePopup.kt | 12 ++++++++++++ 4 files changed, 30 insertions(+), 7 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudPopup.kt create mode 100644 app/src/main/java/io/legado/app/ui/readbook/config/ReadStylePopup.kt diff --git a/app/src/main/assets/readConfig.json b/app/src/main/assets/readConfig.json index 726668d1c..6ab073605 100644 --- a/app/src/main/assets/readConfig.json +++ b/app/src/main/assets/readConfig.json @@ -1,6 +1,6 @@ [ { - "bg": "#F3F3F3", + "bgStr": "#F3F3F3", "bgInt": 0, "bgType": 0, "darkStatusIcon": true, @@ -11,7 +11,7 @@ "lineSpacingMultiplier": 3 }, { - "bg": "#C6BAA1", + "bgStr": "#C6BAA1", "bgInt": 0, "bgType": 0, "darkStatusIcon": true, @@ -26,7 +26,7 @@ "paddingBottom": 0 }, { - "bg": "#E1F1DA", + "bgStr": "#E1F1DA", "bgInt": 0, "bgType": 0, "darkStatusIcon": true, @@ -41,7 +41,7 @@ "paddingBottom": 0 }, { - "bg": "#015A86", + "bgStr": "#015A86", "bgInt": 0, "bgType": 0, "darkStatusIcon": false, @@ -56,7 +56,7 @@ "paddingBottom": 0 }, { - "bg": "#808080", + "bgStr": "#808080", "bgInt": 0, "bgType": 0, "darkStatusIcon": false, diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index e94321e42..cb7805fbc 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -1,5 +1,7 @@ package io.legado.app.help +import android.graphics.Color +import android.graphics.drawable.ColorDrawable import android.graphics.drawable.Drawable import io.legado.app.App import io.legado.app.utils.GSON @@ -13,7 +15,7 @@ import java.io.IOException object ReadBookConfig { private val configList = arrayListOf() - var styleSelect + private var styleSelect get() = App.INSTANCE.getPrefInt("readStyleSelect") set(value) = App.INSTANCE.putPrefInt("readStyleSelect", value) var bg: Drawable? = null @@ -38,6 +40,7 @@ object ReadBookConfig { fun upBg() { getConfig().apply { when (bgType) { + 0 -> bg = ColorDrawable(Color.parseColor(bgStr)) } } @@ -66,7 +69,7 @@ object ReadBookConfig { } data class Config( - var bg: String = "#F3F3F3", + var bgStr: String = "#F3F3F3", var bgInt: Int = 0, var bgType: Int = 0, var darkStatusIcon: Boolean = true, diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudPopup.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudPopup.kt new file mode 100644 index 000000000..3c2863478 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudPopup.kt @@ -0,0 +1,8 @@ +package io.legado.app.ui.readbook.config + +import android.content.Context +import android.widget.PopupWindow + +class ReadAloudPopup(context: Context?) : PopupWindow(context) { + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStylePopup.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStylePopup.kt new file mode 100644 index 000000000..b0a533d3a --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStylePopup.kt @@ -0,0 +1,12 @@ +package io.legado.app.ui.readbook.config + +import android.content.Context +import android.widget.PopupWindow + +class ReadStylePopup(context: Context?) : PopupWindow(context) { + + init { + + } + +} \ No newline at end of file From 61cc1aba06aaa7914d164eeebd348e2d885689ed Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 21 Aug 2019 10:56:42 +0800 Subject: [PATCH 0843/1997] up --- .../main/{res/drawable => assets/bg}/bg1.jpg | Bin app/src/main/assets/readConfig.json | 11 ++- .../java/io/legado/app/help/ReadBookConfig.kt | 67 ++++++++++++------ .../legado/app/ui/widget/page/ContentView.kt | 16 +++-- .../io/legado/app/ui/widget/page/PageView.kt | 12 ++-- 5 files changed, 66 insertions(+), 40 deletions(-) rename app/src/main/{res/drawable => assets/bg}/bg1.jpg (100%) diff --git a/app/src/main/res/drawable/bg1.jpg b/app/src/main/assets/bg/bg1.jpg similarity index 100% rename from app/src/main/res/drawable/bg1.jpg rename to app/src/main/assets/bg/bg1.jpg diff --git a/app/src/main/assets/readConfig.json b/app/src/main/assets/readConfig.json index 6ab073605..617d671ab 100644 --- a/app/src/main/assets/readConfig.json +++ b/app/src/main/assets/readConfig.json @@ -1,18 +1,20 @@ [ { "bgStr": "#F3F3F3", - "bgInt": 0, "bgType": 0, "darkStatusIcon": true, "textColor": "#3E3D3B", "textSize": 16, "letterSpacing": 1, "lineSpacingExtra": 15, - "lineSpacingMultiplier": 3 + "lineSpacingMultiplier": 3, + "paddingLeft": 16, + "paddingRight": 16, + "paddingTop": 0, + "paddingBottom": 0 }, { "bgStr": "#C6BAA1", - "bgInt": 0, "bgType": 0, "darkStatusIcon": true, "textColor": "#3E3D3B", @@ -27,7 +29,6 @@ }, { "bgStr": "#E1F1DA", - "bgInt": 0, "bgType": 0, "darkStatusIcon": true, "textColor": "#3E3D3B", @@ -42,7 +43,6 @@ }, { "bgStr": "#015A86", - "bgInt": 0, "bgType": 0, "darkStatusIcon": false, "textColor": "#3E3D3B", @@ -57,7 +57,6 @@ }, { "bgStr": "#808080", - "bgInt": 0, "bgType": 0, "darkStatusIcon": false, "textColor": "#3E3D3B", diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index cb7805fbc..266b83731 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -3,9 +3,9 @@ package io.legado.app.help import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.graphics.drawable.Drawable +import com.google.gson.reflect.TypeToken import io.legado.app.App import io.legado.app.utils.GSON -import io.legado.app.utils.fromJsonArray import io.legado.app.utils.getPrefInt import io.legado.app.utils.putPrefInt import java.io.BufferedWriter @@ -14,25 +14,30 @@ import java.io.FileWriter import java.io.IOException object ReadBookConfig { - private val configList = arrayListOf() - private var styleSelect - get() = App.INSTANCE.getPrefInt("readStyleSelect") - set(value) = App.INSTANCE.putPrefInt("readStyleSelect", value) - var bg: Drawable? = null - - init { + private val configList: ArrayList by lazy { + val list: ArrayList = arrayListOf() val configFile = File(App.INSTANCE.filesDir.absolutePath + File.separator + "config") val json = if (configFile.exists()) { String(configFile.readBytes()) } else { String(App.INSTANCE.assets.open("readConfig.json").readBytes()) } - GSON.fromJsonArray(json)?.let { - configList.clear() - configList.addAll(it) - } ?: reset() + try { + val listType = object : TypeToken>() {}.type + GSON.fromJson>(json, listType)?.let { + list.addAll(it) + } + } catch (e: Exception) { + list.addAll(getOnError()) + } + list } + private var styleSelect + get() = App.INSTANCE.getPrefInt("readStyleSelect") + set(value) = App.INSTANCE.putPrefInt("readStyleSelect", value) + var bg: Drawable? = null + fun getConfig(): Config { return configList[styleSelect] } @@ -41,7 +46,8 @@ object ReadBookConfig { getConfig().apply { when (bgType) { 0 -> bg = ColorDrawable(Color.parseColor(bgStr)) - + 1 -> bg = Drawable.createFromStream(App.INSTANCE.assets.open("bg" + File.separator + bgStr), "bg") + 2 -> bg = Drawable.createFromPath(bgStr) } } } @@ -61,23 +67,40 @@ object ReadBookConfig { } fun reset() { - val json = String(App.INSTANCE.assets.open("readConfig.json").readBytes()) - GSON.fromJsonArray(json)?.let { + try { + val json = String(App.INSTANCE.assets.open("readConfig.json").readBytes()) + val listType = object : TypeToken>() {}.type + GSON.fromJson>(json, listType)?.let { + configList.clear() + configList.addAll(it) + } + } catch (e: Exception) { configList.clear() - configList.addAll(it) + configList.addAll(getOnError()) } } + private fun getOnError(): ArrayList { + val list = arrayListOf() + list.add(Config()) + list.add(Config()) + list.add(Config()) + list.add(Config()) + return list + } + data class Config( - var bgStr: String = "#F3F3F3", - var bgInt: Int = 0, + var bgStr: String = "#015A86", var bgType: Int = 0, var darkStatusIcon: Boolean = true, - var textColor: String = "#3E3D3B", - var textSize: Int = 16, var letterSpacing: Int = 1, var lineSpacingExtra: Int = 15, - var lineSpacingMultiplier: Int = 3 + var lineSpacingMultiplier: Int = 3, + var paddingBottom: Int = 0, + var paddingLeft: Int = 16, + var paddingRight: Int = 16, + var paddingTop: Int = 0, + var textColor: String = "#3E3D3B", + var textSize: Int = 15 ) - } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index b555c93c1..43125c38e 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -1,6 +1,7 @@ package io.legado.app.ui.widget.page import android.content.Context +import android.graphics.drawable.ColorDrawable import android.graphics.drawable.Drawable import android.util.AttributeSet import android.widget.FrameLayout @@ -34,13 +35,14 @@ class ContentView : FrameLayout { } fun setBg(bg: Drawable?) { - ImageLoader.load(context, bg) - .centerCrop() - .setAsDrawable(bgImage) - } - - fun setBgColor(color: Int) { - page_panel.setBackgroundColor(color) + if (bg is ColorDrawable) { + bgImage.background = bg + bgImage + } else { + ImageLoader.load(context, bg) + .centerCrop() + .setAsDrawable(bgImage) + } } fun upTime() { diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 142153eee..640d1578a 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -6,7 +6,7 @@ import android.graphics.Canvas import android.util.AttributeSet import android.view.MotionEvent import android.widget.FrameLayout -import io.legado.app.R +import io.legado.app.help.ReadBookConfig import io.legado.app.ui.widget.page.delegate.CoverPageDelegate import io.legado.app.ui.widget.page.delegate.PageDelegate @@ -169,10 +169,12 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att } fun upBg() { - val bg = context.getDrawable(R.drawable.bg1) - curPage?.setBg(bg) - prevPage?.setBg(bg) - nextPage?.setBg(bg) + ReadBookConfig.bg ?: let { + ReadBookConfig.upBg() + } + curPage?.setBg(ReadBookConfig.bg) + prevPage?.setBg(ReadBookConfig.bg) + nextPage?.setBg(ReadBookConfig.bg) } fun upTime() { From f09168ca98ee6748166bc57066892b29a159716b Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 21 Aug 2019 11:18:02 +0800 Subject: [PATCH 0844/1997] up --- .../main/java/io/legado/app/help/ReadBookConfig.kt | 5 +++-- .../java/io/legado/app/utils/GsonExtensions.kt | 14 ++++++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index 266b83731..72906baf8 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -6,6 +6,7 @@ import android.graphics.drawable.Drawable import com.google.gson.reflect.TypeToken import io.legado.app.App import io.legado.app.utils.GSON +import io.legado.app.utils.fromJsonArray import io.legado.app.utils.getPrefInt import io.legado.app.utils.putPrefInt import java.io.BufferedWriter @@ -23,8 +24,8 @@ object ReadBookConfig { String(App.INSTANCE.assets.open("readConfig.json").readBytes()) } try { - val listType = object : TypeToken>() {}.type - GSON.fromJson>(json, listType)?.let { +// val listType = object : TypeToken>() {}.type + GSON.fromJsonArray(json)?.let { list.addAll(it) } } catch (e: Exception) { diff --git a/app/src/main/java/io/legado/app/utils/GsonExtensions.kt b/app/src/main/java/io/legado/app/utils/GsonExtensions.kt index e1a099eba..1f3627873 100644 --- a/app/src/main/java/io/legado/app/utils/GsonExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/GsonExtensions.kt @@ -4,6 +4,8 @@ import com.google.gson.Gson import com.google.gson.GsonBuilder import com.google.gson.reflect.TypeToken import org.jetbrains.anko.attempt +import java.lang.reflect.ParameterizedType +import java.lang.reflect.Type val GSON: Gson by lazy { GsonBuilder() @@ -23,7 +25,15 @@ inline fun Gson.fromJsonObject(json: String?): T? {//可转成任意 inline fun Gson.fromJsonArray(json: String?): List? { return attempt { - val result: List? = fromJson(json, genericType>()) + val result: List? = fromJson(json, ParameterizedTypeImpl(T::class.java)) result }.value -} \ No newline at end of file +} + +class ParameterizedTypeImpl(val clz: Class<*>) : ParameterizedType { + override fun getRawType(): Type = List::class.java + + override fun getOwnerType(): Type? = null + + override fun getActualTypeArguments(): Array = arrayOf(clz) +} From ea5648a84806ecd8927786188bb8dfa561f25223 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 21 Aug 2019 11:23:02 +0800 Subject: [PATCH 0845/1997] up --- app/src/main/assets/readConfig.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/assets/readConfig.json b/app/src/main/assets/readConfig.json index 617d671ab..9616bd5c8 100644 --- a/app/src/main/assets/readConfig.json +++ b/app/src/main/assets/readConfig.json @@ -1,7 +1,7 @@ [ { - "bgStr": "#F3F3F3", - "bgType": 0, + "bgStr": "bg1.jpg", + "bgType": 1, "darkStatusIcon": true, "textColor": "#3E3D3B", "textSize": 16, From 5582df3669da1468d0ca32f339cb39112468f135 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 21 Aug 2019 11:27:23 +0800 Subject: [PATCH 0846/1997] up --- app/src/main/java/io/legado/app/help/ReadBookConfig.kt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index 72906baf8..5352a049d 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -3,7 +3,6 @@ package io.legado.app.help import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.graphics.drawable.Drawable -import com.google.gson.reflect.TypeToken import io.legado.app.App import io.legado.app.utils.GSON import io.legado.app.utils.fromJsonArray @@ -24,7 +23,6 @@ object ReadBookConfig { String(App.INSTANCE.assets.open("readConfig.json").readBytes()) } try { -// val listType = object : TypeToken>() {}.type GSON.fromJsonArray(json)?.let { list.addAll(it) } @@ -70,8 +68,7 @@ object ReadBookConfig { fun reset() { try { val json = String(App.INSTANCE.assets.open("readConfig.json").readBytes()) - val listType = object : TypeToken>() {}.type - GSON.fromJson>(json, listType)?.let { + GSON.fromJsonArray(json)?.let { configList.clear() configList.addAll(it) } From e10af99b795d08d92ecaa86fe404d562bd6044b6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 21 Aug 2019 11:40:46 +0800 Subject: [PATCH 0847/1997] up --- app/src/main/java/io/legado/app/help/ReadBookConfig.kt | 6 +++--- .../java/io/legado/app/ui/widget/page/ContentView.kt | 9 +++++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index 5352a049d..c54c0b6a7 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -91,9 +91,9 @@ object ReadBookConfig { var bgStr: String = "#015A86", var bgType: Int = 0, var darkStatusIcon: Boolean = true, - var letterSpacing: Int = 1, - var lineSpacingExtra: Int = 15, - var lineSpacingMultiplier: Int = 3, + var letterSpacing: Float = 1f, + var lineSpacingExtra: Float = 15f, + var lineSpacingMultiplier: Float = 3f, var paddingBottom: Int = 0, var paddingLeft: Int = 16, var paddingRight: Int = 16, diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index 43125c38e..38833feaf 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -8,9 +8,9 @@ import android.widget.FrameLayout import androidx.appcompat.widget.AppCompatImageView import io.legado.app.R import io.legado.app.help.ImageLoader +import io.legado.app.help.ReadBookConfig import io.legado.app.utils.dp import kotlinx.android.synthetic.main.view_book_page.view.* -import org.jetbrains.anko.horizontalPadding import org.jetbrains.anko.matchParent @@ -31,7 +31,12 @@ class ContentView : FrameLayout { } fun upStyle() { - page_panel.horizontalPadding = 16.dp + ReadBookConfig.getConfig().apply { + page_panel.setPadding(paddingLeft.dp, paddingTop.dp, paddingRight.dp, paddingBottom.dp) + content_text_view.textSize = textSize.toFloat() + content_text_view.setLineSpacing(lineSpacingExtra, lineSpacingMultiplier) + content_text_view.letterSpacing = letterSpacing + } } fun setBg(bg: Drawable?) { From 68a382a2614c4373d60023131d08c1cf919c8f24 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 21 Aug 2019 11:44:19 +0800 Subject: [PATCH 0848/1997] up --- app/src/main/assets/readConfig.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/assets/readConfig.json b/app/src/main/assets/readConfig.json index 9616bd5c8..74abbc986 100644 --- a/app/src/main/assets/readConfig.json +++ b/app/src/main/assets/readConfig.json @@ -5,7 +5,7 @@ "darkStatusIcon": true, "textColor": "#3E3D3B", "textSize": 16, - "letterSpacing": 1, + "letterSpacing": 0, "lineSpacingExtra": 15, "lineSpacingMultiplier": 3, "paddingLeft": 16, @@ -19,7 +19,7 @@ "darkStatusIcon": true, "textColor": "#3E3D3B", "textSize": 16, - "letterSpacing": 1, + "letterSpacing": 0, "lineSpacingExtra": 15, "lineSpacingMultiplier": 3, "paddingLeft": 16, @@ -33,7 +33,7 @@ "darkStatusIcon": true, "textColor": "#3E3D3B", "textSize": 16, - "letterSpacing": 1, + "letterSpacing": 0, "lineSpacingExtra": 15, "lineSpacingMultiplier": 3, "paddingLeft": 16, @@ -47,7 +47,7 @@ "darkStatusIcon": false, "textColor": "#3E3D3B", "textSize": 16, - "letterSpacing": 1, + "letterSpacing": 0, "lineSpacingExtra": 15, "lineSpacingMultiplier": 3, "paddingLeft": 16, @@ -61,7 +61,7 @@ "darkStatusIcon": false, "textColor": "#3E3D3B", "textSize": 16, - "letterSpacing": 1, + "letterSpacing": 0, "lineSpacingExtra": 15, "lineSpacingMultiplier": 3, "paddingLeft": 16, From e056b071c59948c040c873d476356d0d5d5809de Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 21 Aug 2019 11:46:16 +0800 Subject: [PATCH 0849/1997] up --- app/src/main/java/io/legado/app/help/ReadBookConfig.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index c54c0b6a7..252d635a5 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -84,6 +84,7 @@ object ReadBookConfig { list.add(Config()) list.add(Config()) list.add(Config()) + list.add(Config()) return list } From 14e93a181acf938f1fd91c7241a50f6ea17ea261 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 21 Aug 2019 12:30:15 +0800 Subject: [PATCH 0850/1997] up --- .../app/ui/widget/image/CircleImageView.kt | 387 ++++++++++++++++++ .../main/res/layout/pop_read_book_style.xml | 7 + app/src/main/res/values/attrs.xml | 7 + 3 files changed, 401 insertions(+) create mode 100644 app/src/main/java/io/legado/app/ui/widget/image/CircleImageView.kt create mode 100644 app/src/main/res/layout/pop_read_book_style.xml diff --git a/app/src/main/java/io/legado/app/ui/widget/image/CircleImageView.kt b/app/src/main/java/io/legado/app/ui/widget/image/CircleImageView.kt new file mode 100644 index 000000000..fd737e162 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/image/CircleImageView.kt @@ -0,0 +1,387 @@ +package io.legado.app.ui.widget.image + +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.* +import android.graphics.drawable.BitmapDrawable +import android.graphics.drawable.ColorDrawable +import android.graphics.drawable.Drawable +import android.net.Uri +import android.os.Build +import android.util.AttributeSet +import android.view.MotionEvent +import android.view.View +import android.view.ViewOutlineProvider +import androidx.annotation.ColorInt +import androidx.annotation.ColorRes +import androidx.annotation.DrawableRes +import androidx.annotation.RequiresApi +import androidx.appcompat.widget.AppCompatImageView +import io.legado.app.R +import kotlin.math.min +import kotlin.math.pow + +class CircleImageView : AppCompatImageView { + + private val mDrawableRect = RectF() + private val mBorderRect = RectF() + + private val mShaderMatrix = Matrix() + private val mBitmapPaint = Paint() + private val mBorderPaint = Paint() + private val mCircleBackgroundPaint = Paint() + + private var mBorderColor = DEFAULT_BORDER_COLOR + private var mBorderWidth = DEFAULT_BORDER_WIDTH + private var mCircleBackgroundColor = DEFAULT_CIRCLE_BACKGROUND_COLOR + + private var mBitmap: Bitmap? = null + private var mBitmapShader: BitmapShader? = null + private var mBitmapWidth: Int = 0 + private var mBitmapHeight: Int = 0 + + private var mDrawableRadius: Float = 0.toFloat() + private var mBorderRadius: Float = 0.toFloat() + + private var mColorFilter: ColorFilter? = null + + private var mReady: Boolean = false + private var mSetupPending: Boolean = false + private var mBorderOverlay: Boolean = false + var isDisableCircularTransformation: Boolean = false + set(disableCircularTransformation) { + if (isDisableCircularTransformation == disableCircularTransformation) { + return + } + + field = disableCircularTransformation + initializeBitmap() + } + + var borderColor: Int + get() = mBorderColor + set(@ColorInt borderColor) { + if (borderColor == mBorderColor) { + return + } + + mBorderColor = borderColor + mBorderPaint.color = mBorderColor + invalidate() + } + + var circleBackgroundColor: Int + get() = mCircleBackgroundColor + set(@ColorInt circleBackgroundColor) { + if (circleBackgroundColor == mCircleBackgroundColor) { + return + } + + mCircleBackgroundColor = circleBackgroundColor + mCircleBackgroundPaint.color = circleBackgroundColor + invalidate() + } + + var borderWidth: Int + get() = mBorderWidth + set(borderWidth) { + if (borderWidth == mBorderWidth) { + return + } + + mBorderWidth = borderWidth + setup() + } + + var isBorderOverlay: Boolean + get() = mBorderOverlay + set(borderOverlay) { + if (borderOverlay == mBorderOverlay) { + return + } + + mBorderOverlay = borderOverlay + setup() + } + + constructor(context: Context) : super(context) { + + init() + } + + @JvmOverloads + constructor(context: Context, attrs: AttributeSet, defStyle: Int = 0) : super(context, attrs, defStyle) { + + val a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyle, 0) + + mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_civ_border_width, DEFAULT_BORDER_WIDTH) + mBorderColor = a.getColor(R.styleable.CircleImageView_civ_border_color, DEFAULT_BORDER_COLOR) + mBorderOverlay = a.getBoolean(R.styleable.CircleImageView_civ_border_overlay, DEFAULT_BORDER_OVERLAY) + mCircleBackgroundColor = + a.getColor(R.styleable.CircleImageView_civ_circle_background_color, DEFAULT_CIRCLE_BACKGROUND_COLOR) + + a.recycle() + + init() + } + + private fun init() { + super.setScaleType(SCALE_TYPE) + mReady = true + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + outlineProvider = OutlineProvider() + } + + if (mSetupPending) { + setup() + mSetupPending = false + } + } + + override fun getScaleType(): ScaleType { + return SCALE_TYPE + } + + override fun setScaleType(scaleType: ScaleType) { + if (scaleType != SCALE_TYPE) { + throw IllegalArgumentException(String.format("ScaleType %s not supported.", scaleType)) + } + } + + override fun setAdjustViewBounds(adjustViewBounds: Boolean) { + if (adjustViewBounds) { + throw IllegalArgumentException("adjustViewBounds not supported.") + } + } + + override fun onDraw(canvas: Canvas) { + if (isDisableCircularTransformation) { + super.onDraw(canvas) + return + } + + if (mBitmap == null) { + return + } + + if (mCircleBackgroundColor != Color.TRANSPARENT) { + canvas.drawCircle(mDrawableRect.centerX(), mDrawableRect.centerY(), mDrawableRadius, mCircleBackgroundPaint) + } + canvas.drawCircle(mDrawableRect.centerX(), mDrawableRect.centerY(), mDrawableRadius, mBitmapPaint) + if (mBorderWidth > 0) { + canvas.drawCircle(mBorderRect.centerX(), mBorderRect.centerY(), mBorderRadius, mBorderPaint) + } + } + + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + super.onSizeChanged(w, h, oldw, oldh) + setup() + } + + override fun setPadding(left: Int, top: Int, right: Int, bottom: Int) { + super.setPadding(left, top, right, bottom) + setup() + } + + override fun setPaddingRelative(start: Int, top: Int, end: Int, bottom: Int) { + super.setPaddingRelative(start, top, end, bottom) + setup() + } + + fun setCircleBackgroundColorResource(@ColorRes circleBackgroundRes: Int) { + circleBackgroundColor = context.resources.getColor(circleBackgroundRes) + } + + override fun setImageBitmap(bm: Bitmap) { + super.setImageBitmap(bm) + initializeBitmap() + } + + override fun setImageDrawable(drawable: Drawable?) { + super.setImageDrawable(drawable) + initializeBitmap() + } + + override fun setImageResource(@DrawableRes resId: Int) { + super.setImageResource(resId) + initializeBitmap() + } + + override fun setImageURI(uri: Uri?) { + super.setImageURI(uri) + initializeBitmap() + } + + override fun setColorFilter(cf: ColorFilter) { + if (cf === mColorFilter) { + return + } + + mColorFilter = cf + applyColorFilter() + invalidate() + } + + override fun getColorFilter(): ColorFilter? { + return mColorFilter + } + + private fun applyColorFilter() { + mBitmapPaint.colorFilter = mColorFilter + } + + private fun getBitmapFromDrawable(drawable: Drawable?): Bitmap? { + if (drawable == null) { + return null + } + + if (drawable is BitmapDrawable) { + return drawable.bitmap + } + + try { + val bitmap: Bitmap + + if (drawable is ColorDrawable) { + bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG) + } else { + bitmap = Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, BITMAP_CONFIG) + } + + val canvas = Canvas(bitmap) + drawable.setBounds(0, 0, canvas.width, canvas.height) + drawable.draw(canvas) + return bitmap + } catch (e: Exception) { + e.printStackTrace() + return null + } + + } + + private fun initializeBitmap() { + if (isDisableCircularTransformation) { + mBitmap = null + } else { + mBitmap = getBitmapFromDrawable(drawable) + } + setup() + } + + private fun setup() { + if (!mReady) { + mSetupPending = true + return + } + + if (width == 0 && height == 0) { + return + } + + if (mBitmap == null) { + invalidate() + return + } + + mBitmapShader = BitmapShader(mBitmap!!, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP) + + mBitmapPaint.isAntiAlias = true + mBitmapPaint.shader = mBitmapShader + + mBorderPaint.style = Paint.Style.STROKE + mBorderPaint.isAntiAlias = true + mBorderPaint.color = mBorderColor + mBorderPaint.strokeWidth = mBorderWidth.toFloat() + + mCircleBackgroundPaint.style = Paint.Style.FILL + mCircleBackgroundPaint.isAntiAlias = true + mCircleBackgroundPaint.color = mCircleBackgroundColor + + mBitmapHeight = mBitmap!!.height + mBitmapWidth = mBitmap!!.width + + mBorderRect.set(calculateBounds()) + mBorderRadius = + min((mBorderRect.height() - mBorderWidth) / 2.0f, (mBorderRect.width() - mBorderWidth) / 2.0f) + + mDrawableRect.set(mBorderRect) + if (!mBorderOverlay && mBorderWidth > 0) { + mDrawableRect.inset(mBorderWidth - 1.0f, mBorderWidth - 1.0f) + } + mDrawableRadius = min(mDrawableRect.height() / 2.0f, mDrawableRect.width() / 2.0f) + + applyColorFilter() + updateShaderMatrix() + invalidate() + } + + private fun calculateBounds(): RectF { + val availableWidth = width - paddingLeft - paddingRight + val availableHeight = height - paddingTop - paddingBottom + + val sideLength = min(availableWidth, availableHeight) + + val left = paddingLeft + (availableWidth - sideLength) / 2f + val top = paddingTop + (availableHeight - sideLength) / 2f + + return RectF(left, top, left + sideLength, top + sideLength) + } + + private fun updateShaderMatrix() { + val scale: Float + var dx = 0f + var dy = 0f + + mShaderMatrix.set(null) + + if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) { + scale = mDrawableRect.height() / mBitmapHeight.toFloat() + dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f + } else { + scale = mDrawableRect.width() / mBitmapWidth.toFloat() + dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f + } + + mShaderMatrix.setScale(scale, scale) + mShaderMatrix.postTranslate((dx + 0.5f).toInt() + mDrawableRect.left, (dy + 0.5f).toInt() + mDrawableRect.top) + + mBitmapShader!!.setLocalMatrix(mShaderMatrix) + } + + @SuppressLint("ClickableViewAccessibility") + override fun onTouchEvent(event: MotionEvent): Boolean { + return inTouchableArea(event.x, event.y) && super.onTouchEvent(event) + } + + private fun inTouchableArea(x: Float, y: Float): Boolean { + return (x - mBorderRect.centerX()).toDouble() + .pow(2.0) + (y - mBorderRect.centerY()).toDouble() + .pow(2.0) <= mBorderRadius.toDouble().pow(2.0) + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + private inner class OutlineProvider : ViewOutlineProvider() { + + override fun getOutline(view: View, outline: Outline) { + val bounds = Rect() + mBorderRect.roundOut(bounds) + outline.setRoundRect(bounds, bounds.width() / 2.0f) + } + + } + + companion object { + + private val SCALE_TYPE = ScaleType.CENTER_CROP + + private val BITMAP_CONFIG = Bitmap.Config.ARGB_8888 + private const val COLORDRAWABLE_DIMENSION = 2 + + private const val DEFAULT_BORDER_WIDTH = 0 + private const val DEFAULT_BORDER_COLOR = Color.BLACK + private const val DEFAULT_CIRCLE_BACKGROUND_COLOR = Color.TRANSPARENT + private const val DEFAULT_BORDER_OVERLAY = false + } + +} \ No newline at end of file diff --git a/app/src/main/res/layout/pop_read_book_style.xml b/app/src/main/res/layout/pop_read_book_style.xml new file mode 100644 index 000000000..d829e291c --- /dev/null +++ b/app/src/main/res/layout/pop_read_book_style.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index 67c52d7c9..dbac9f574 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -114,4 +114,11 @@ + + + + + + + \ No newline at end of file From 21c02f08d2aebb50d0082a8a422f53ea04ce6f41 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 21 Aug 2019 13:32:11 +0800 Subject: [PATCH 0851/1997] up --- .../legado/app/ui/widget/image/CircleImageView.kt | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/image/CircleImageView.kt b/app/src/main/java/io/legado/app/ui/widget/image/CircleImageView.kt index fd737e162..965236486 100644 --- a/app/src/main/java/io/legado/app/ui/widget/image/CircleImageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/image/CircleImageView.kt @@ -240,22 +240,20 @@ class CircleImageView : AppCompatImageView { return drawable.bitmap } - try { - val bitmap: Bitmap - - if (drawable is ColorDrawable) { - bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG) + return try { + val bitmap: Bitmap = if (drawable is ColorDrawable) { + Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG) } else { - bitmap = Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, BITMAP_CONFIG) + Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, BITMAP_CONFIG) } val canvas = Canvas(bitmap) drawable.setBounds(0, 0, canvas.width, canvas.height) drawable.draw(canvas) - return bitmap + bitmap } catch (e: Exception) { e.printStackTrace() - return null + null } } From 539e2ed2b04be2ba618f80ab3e8bd7ce8fca64c8 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 21 Aug 2019 13:54:12 +0800 Subject: [PATCH 0852/1997] up --- app/src/main/java/io/legado/app/help/ReadBookConfig.kt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index 252d635a5..45097ff16 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -46,7 +46,15 @@ object ReadBookConfig { when (bgType) { 0 -> bg = ColorDrawable(Color.parseColor(bgStr)) 1 -> bg = Drawable.createFromStream(App.INSTANCE.assets.open("bg" + File.separator + bgStr), "bg") - 2 -> bg = Drawable.createFromPath(bgStr) + else -> { + try { + bg = Drawable.createFromPath(bgStr) + } finally { + bg ?: let { + bg = ColorDrawable(Color.parseColor("#015A86")) + } + } + } } } } From 40fc6da347cc09b76337ab7e72daed5a0c718f2c Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 21 Aug 2019 14:30:21 +0800 Subject: [PATCH 0853/1997] up --- .../main/res/layout/pop_read_book_style.xml | 102 +++++++++++++++++- 1 file changed, 99 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/layout/pop_read_book_style.xml b/app/src/main/res/layout/pop_read_book_style.xml index d829e291c..5fdd25a09 100644 --- a/app/src/main/res/layout/pop_read_book_style.xml +++ b/app/src/main/res/layout/pop_read_book_style.xml @@ -1,7 +1,103 @@ - + android:layout_height="wrap_content"> - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 80ee1a837bb9e83dc96d4afb6e61b3740449257b Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 21 Aug 2019 15:04:10 +0800 Subject: [PATCH 0854/1997] up --- .../main/java/io/legado/app/constant/Bus.kt | 1 + .../java/io/legado/app/help/ReadBookConfig.kt | 2 +- .../app/ui/readbook/ReadBookActivity.kt | 9 +++ .../app/ui/readbook/config/ReadStylePopup.kt | 76 +++++++++++++++++++ 4 files changed, 87 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/constant/Bus.kt b/app/src/main/java/io/legado/app/constant/Bus.kt index 12e72949d..03b4d7078 100644 --- a/app/src/main/java/io/legado/app/constant/Bus.kt +++ b/app/src/main/java/io/legado/app/constant/Bus.kt @@ -9,4 +9,5 @@ object Bus { const val BATTERY_CHANGED = "batteryChanged" const val TIME_CHANGED = "timeChanged" const val READ_ALOUD = "readAloud" + const val UP_CONFIG = "upConfig" } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index 45097ff16..cd6a77adf 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -32,7 +32,7 @@ object ReadBookConfig { list } - private var styleSelect + var styleSelect get() = App.INSTANCE.getPrefInt("readStyleSelect") set(value) = App.INSTANCE.putPrefInt("readStyleSelect", value) var bg: Drawable? = null diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 191e93f2c..2cb79f9de 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -327,5 +327,14 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea observeEvent(Bus.TIME_CHANGED) { page_view.upTime() } observeEvent(Bus.BATTERY_CHANGED) { page_view.upBattery(it) } observeEventSticky(Bus.READ_ALOUD) { onClickReadAloud() } + observeEventSticky(Bus.UP_CONFIG) { + when (it) { + 0 -> { + upBg() + upStyle() + } + 1 -> upStyle() + } + } } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStylePopup.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStylePopup.kt index b0a533d3a..5a3931388 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStylePopup.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStylePopup.kt @@ -1,12 +1,88 @@ package io.legado.app.ui.readbook.config +import android.annotation.SuppressLint import android.content.Context +import android.view.LayoutInflater import android.widget.PopupWindow +import io.legado.app.R +import io.legado.app.constant.Bus +import io.legado.app.help.ReadBookConfig +import io.legado.app.lib.theme.accentColor +import io.legado.app.lib.theme.primaryTextColor +import io.legado.app.utils.postEvent +import kotlinx.android.synthetic.main.pop_read_book_style.view.* +import org.jetbrains.anko.sdk27.listeners.onClick class ReadStylePopup(context: Context?) : PopupWindow(context) { init { + @SuppressLint("InflateParams") + contentView = LayoutInflater.from(context).inflate(R.layout.pop_read_book_style, null) + initData() + initOnClick() } + private fun initData() = with(contentView) { + upBg() + } + + + private fun initOnClick() = with(contentView) { + bg0.onClick { + ReadBookConfig.styleSelect = 0 + ReadBookConfig.upBg() + upBg() + postEvent(Bus.UP_CONFIG, 0) + } + bg1.onClick { + ReadBookConfig.styleSelect = 1 + ReadBookConfig.upBg() + upBg() + postEvent(Bus.UP_CONFIG, 0) + } + bg2.onClick { + ReadBookConfig.styleSelect = 2 + ReadBookConfig.upBg() + upBg() + postEvent(Bus.UP_CONFIG, 0) + } + bg3.onClick { + ReadBookConfig.styleSelect = 3 + ReadBookConfig.upBg() + upBg() + postEvent(Bus.UP_CONFIG, 0) + } + bg4.onClick { + ReadBookConfig.styleSelect = 4 + ReadBookConfig.upBg() + upBg() + postEvent(Bus.UP_CONFIG, 0) + } + } + + private fun upBg() = with(contentView) { + bg0.borderColor = context.primaryTextColor + bg1.borderColor = context.primaryTextColor + bg2.borderColor = context.primaryTextColor + bg3.borderColor = context.primaryTextColor + bg4.borderColor = context.primaryTextColor + when (ReadBookConfig.styleSelect) { + 1 -> { + bg1.borderColor = context.accentColor + } + 2 -> { + bg2.borderColor = context.accentColor + } + 3 -> { + bg3.borderColor = context.accentColor + } + 4 -> { + bg4.borderColor = context.accentColor + } + else -> { + bg0.borderColor = context.accentColor + } + } + } } \ No newline at end of file From 79c31680947883fac604a0a2654a6c2249b49cf1 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 21 Aug 2019 15:05:49 +0800 Subject: [PATCH 0855/1997] up --- .../java/io/legado/app/ui/readbook/ReadBookActivity.kt | 4 ++-- .../main/java/io/legado/app/ui/readbook/ReadBottomMenu.kt | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 2cb79f9de..993f20c2b 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -159,11 +159,11 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } - override fun openReadInterface() { + override fun showReadStyle() { } - override fun openMoreSetting() { + override fun showMoreSetting() { } diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBottomMenu.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBottomMenu.kt index 82461268c..df655a94c 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBottomMenu.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBottomMenu.kt @@ -98,10 +98,10 @@ class ReadBottomMenu : FrameLayout { ll_adjust.onClick { callback?.openAdjust() } //界面 - ll_font.onClick { callback?.openReadInterface() } + ll_font.onClick { callback?.showReadStyle() } //设置 - ll_setting.onClick { callback?.openMoreSetting() } + ll_setting.onClick { callback?.showMoreSetting() } tv_read_aloud_timer.onClick { } } @@ -171,9 +171,9 @@ class ReadBottomMenu : FrameLayout { fun openAdjust() - fun openReadInterface() + fun showReadStyle() - fun openMoreSetting() + fun showMoreSetting() fun toast(id: Int) From 44030aedfbb4da267e6af450024f9332c0e28315 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 21 Aug 2019 15:27:39 +0800 Subject: [PATCH 0856/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 3 +- .../{ReadStylePopup.kt => ReadStyleDialog.kt} | 55 ++++++++++--------- .../legado/app/ui/widget/KeyboardToolPop.kt | 2 +- ...k_style.xml => dialog_read_book_style.xml} | 0 ...board_tool.xml => popup_keyboard_tool.xml} | 0 5 files changed, 32 insertions(+), 28 deletions(-) rename app/src/main/java/io/legado/app/ui/readbook/config/{ReadStylePopup.kt => ReadStyleDialog.kt} (50%) rename app/src/main/res/layout/{pop_read_book_style.xml => dialog_read_book_style.xml} (100%) rename app/src/main/res/layout/{pop_keyboard_tool.xml => popup_keyboard_tool.xml} (100%) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 993f20c2b..07b5b3002 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -19,6 +19,7 @@ import io.legado.app.receiver.TimeElectricityReceiver import io.legado.app.service.ReadAloudService import io.legado.app.ui.changesource.ChangeSourceDialog import io.legado.app.ui.chapterlist.ChapterListActivity +import io.legado.app.ui.readbook.config.ReadStyleDialog import io.legado.app.ui.replacerule.ReplaceRuleActivity import io.legado.app.ui.widget.page.ChapterProvider import io.legado.app.ui.widget.page.PageView @@ -160,7 +161,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } override fun showReadStyle() { - + ReadStyleDialog().show(supportFragmentManager, "readStyle") } override fun showMoreSetting() { diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStylePopup.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt similarity index 50% rename from app/src/main/java/io/legado/app/ui/readbook/config/ReadStylePopup.kt rename to app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt index 5a3931388..3c3b40633 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStylePopup.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt @@ -1,59 +1,62 @@ package io.legado.app.ui.readbook.config -import android.annotation.SuppressLint -import android.content.Context +import android.os.Bundle import android.view.LayoutInflater -import android.widget.PopupWindow +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.DialogFragment import io.legado.app.R import io.legado.app.constant.Bus import io.legado.app.help.ReadBookConfig import io.legado.app.lib.theme.accentColor import io.legado.app.lib.theme.primaryTextColor import io.legado.app.utils.postEvent -import kotlinx.android.synthetic.main.pop_read_book_style.view.* +import kotlinx.android.synthetic.main.dialog_read_book_style.* import org.jetbrains.anko.sdk27.listeners.onClick -class ReadStylePopup(context: Context?) : PopupWindow(context) { +class ReadStyleDialog : DialogFragment() { - init { - @SuppressLint("InflateParams") - contentView = LayoutInflater.from(context).inflate(R.layout.pop_read_book_style, null) + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + return inflater.inflate(R.layout.dialog_read_book_style, container) + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) initData() initOnClick() } - private fun initData() = with(contentView) { + private fun initData() { upBg() } - private fun initOnClick() = with(contentView) { - bg0.onClick { + private fun initOnClick() { + tv_bg0.onClick { ReadBookConfig.styleSelect = 0 ReadBookConfig.upBg() upBg() postEvent(Bus.UP_CONFIG, 0) } - bg1.onClick { + tv_bg1.onClick { ReadBookConfig.styleSelect = 1 ReadBookConfig.upBg() upBg() postEvent(Bus.UP_CONFIG, 0) } - bg2.onClick { + tv_bg2.onClick { ReadBookConfig.styleSelect = 2 ReadBookConfig.upBg() upBg() postEvent(Bus.UP_CONFIG, 0) } - bg3.onClick { + tv_bg3.onClick { ReadBookConfig.styleSelect = 3 ReadBookConfig.upBg() upBg() postEvent(Bus.UP_CONFIG, 0) } - bg4.onClick { + tv_bg4.onClick { ReadBookConfig.styleSelect = 4 ReadBookConfig.upBg() upBg() @@ -61,27 +64,27 @@ class ReadStylePopup(context: Context?) : PopupWindow(context) { } } - private fun upBg() = with(contentView) { - bg0.borderColor = context.primaryTextColor - bg1.borderColor = context.primaryTextColor - bg2.borderColor = context.primaryTextColor - bg3.borderColor = context.primaryTextColor - bg4.borderColor = context.primaryTextColor + private fun upBg() { + bg0.borderColor = requireContext().primaryTextColor + bg1.borderColor = requireContext().primaryTextColor + bg2.borderColor = requireContext().primaryTextColor + bg3.borderColor = requireContext().primaryTextColor + bg4.borderColor = requireContext().primaryTextColor when (ReadBookConfig.styleSelect) { 1 -> { - bg1.borderColor = context.accentColor + bg1.borderColor = requireContext().accentColor } 2 -> { - bg2.borderColor = context.accentColor + bg2.borderColor = requireContext().accentColor } 3 -> { - bg3.borderColor = context.accentColor + bg3.borderColor = requireContext().accentColor } 4 -> { - bg4.borderColor = context.accentColor + bg4.borderColor = requireContext().accentColor } else -> { - bg0.borderColor = context.accentColor + bg0.borderColor = requireContext().accentColor } } } diff --git a/app/src/main/java/io/legado/app/ui/widget/KeyboardToolPop.kt b/app/src/main/java/io/legado/app/ui/widget/KeyboardToolPop.kt index f75e01a1b..b97e32e97 100644 --- a/app/src/main/java/io/legado/app/ui/widget/KeyboardToolPop.kt +++ b/app/src/main/java/io/legado/app/ui/widget/KeyboardToolPop.kt @@ -14,7 +14,7 @@ class KeyboardToolPop(context: Context, onClickListener: OnClickListener?) : Pop init { @SuppressLint("InflateParams") - val view = LayoutInflater.from(context).inflate(R.layout.pop_keyboard_tool, null) + val view = LayoutInflater.from(context).inflate(R.layout.popup_keyboard_tool, null) this.contentView = view isTouchable = true diff --git a/app/src/main/res/layout/pop_read_book_style.xml b/app/src/main/res/layout/dialog_read_book_style.xml similarity index 100% rename from app/src/main/res/layout/pop_read_book_style.xml rename to app/src/main/res/layout/dialog_read_book_style.xml diff --git a/app/src/main/res/layout/pop_keyboard_tool.xml b/app/src/main/res/layout/popup_keyboard_tool.xml similarity index 100% rename from app/src/main/res/layout/pop_keyboard_tool.xml rename to app/src/main/res/layout/popup_keyboard_tool.xml From 1d3232a3ac1d9ce9dbee8fbfa5fe8c22912ab2c4 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 21 Aug 2019 15:50:25 +0800 Subject: [PATCH 0857/1997] up --- .../java/io/legado/app/help/ReadBookConfig.kt | 10 +++-- .../app/ui/readbook/ReadBookActivity.kt | 1 + .../app/ui/readbook/config/ReadStyleDialog.kt | 18 +++++++++ .../legado/app/ui/widget/page/ContentView.kt | 2 +- .../res/layout/dialog_read_book_style.xml | 40 +++++++++---------- 5 files changed, 47 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index cd6a77adf..588889e40 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -37,8 +37,8 @@ object ReadBookConfig { set(value) = App.INSTANCE.putPrefInt("readStyleSelect", value) var bg: Drawable? = null - fun getConfig(): Config { - return configList[styleSelect] + fun getConfig(index: Int = styleSelect): Config { + return configList[index] } fun upBg() { @@ -109,5 +109,9 @@ object ReadBookConfig { var paddingTop: Int = 0, var textColor: String = "#3E3D3B", var textSize: Int = 15 - ) + ) { + fun textColor(): Int { + return Color.parseColor(textColor) + } + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 07b5b3002..319755c21 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -161,6 +161,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } override fun showReadStyle() { + runMenuOut() ReadStyleDialog().show(supportFragmentManager, "readStyle") } diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt index 3c3b40633..efa6d7c14 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt @@ -1,6 +1,7 @@ package io.legado.app.ui.readbook.config import android.os.Bundle +import android.util.DisplayMetrics import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -26,7 +27,15 @@ class ReadStyleDialog : DialogFragment() { initOnClick() } + override fun onStart() { + super.onStart() + val dm = DisplayMetrics() + activity?.windowManager?.defaultDisplay?.getMetrics(dm) + dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), ViewGroup.LayoutParams.WRAP_CONTENT) + } + private fun initData() { + setBg() upBg() } @@ -64,6 +73,15 @@ class ReadStyleDialog : DialogFragment() { } } + private fun setBg() { + tv_bg0.setTextColor(ReadBookConfig.getConfig(0).textColor()) + tv_bg1.setTextColor(ReadBookConfig.getConfig(1).textColor()) + tv_bg2.setTextColor(ReadBookConfig.getConfig(2).textColor()) + tv_bg3.setTextColor(ReadBookConfig.getConfig(3).textColor()) + tv_bg4.setTextColor(ReadBookConfig.getConfig(4).textColor()) + + } + private fun upBg() { bg0.borderColor = requireContext().primaryTextColor bg1.borderColor = requireContext().primaryTextColor diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index 38833feaf..208a1de3f 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -41,8 +41,8 @@ class ContentView : FrameLayout { fun setBg(bg: Drawable?) { if (bg is ColorDrawable) { + bgImage.setImageDrawable(null) bgImage.background = bg - bgImage } else { ImageLoader.load(context, bg) .centerCrop() diff --git a/app/src/main/res/layout/dialog_read_book_style.xml b/app/src/main/res/layout/dialog_read_book_style.xml index 5fdd25a09..99e9e6946 100644 --- a/app/src/main/res/layout/dialog_read_book_style.xml +++ b/app/src/main/res/layout/dialog_read_book_style.xml @@ -7,8 +7,8 @@ Date: Wed, 21 Aug 2019 15:57:13 +0800 Subject: [PATCH 0858/1997] up --- app/src/main/assets/readConfig.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/assets/readConfig.json b/app/src/main/assets/readConfig.json index 74abbc986..587944d9a 100644 --- a/app/src/main/assets/readConfig.json +++ b/app/src/main/assets/readConfig.json @@ -17,7 +17,7 @@ "bgStr": "#C6BAA1", "bgType": 0, "darkStatusIcon": true, - "textColor": "#3E3D3B", + "textColor": "#5E432E", "textSize": 16, "letterSpacing": 0, "lineSpacingExtra": 15, @@ -31,7 +31,7 @@ "bgStr": "#E1F1DA", "bgType": 0, "darkStatusIcon": true, - "textColor": "#3E3D3B", + "textColor": "#22482C", "textSize": 16, "letterSpacing": 0, "lineSpacingExtra": 15, @@ -45,7 +45,7 @@ "bgStr": "#015A86", "bgType": 0, "darkStatusIcon": false, - "textColor": "#3E3D3B", + "textColor": "#FFFFFF", "textSize": 16, "letterSpacing": 0, "lineSpacingExtra": 15, @@ -56,10 +56,10 @@ "paddingBottom": 0 }, { - "bgStr": "#808080", + "bgStr": "#000000", "bgType": 0, "darkStatusIcon": false, - "textColor": "#3E3D3B", + "textColor": "#808080", "textSize": 16, "letterSpacing": 0, "lineSpacingExtra": 15, From 8aaf5bf36aee90b865cedf2c68b35fde5cc162a8 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 21 Aug 2019 16:06:38 +0800 Subject: [PATCH 0859/1997] up --- app/src/main/assets/readConfig.json | 2 +- app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/assets/readConfig.json b/app/src/main/assets/readConfig.json index 587944d9a..fdd8894b5 100644 --- a/app/src/main/assets/readConfig.json +++ b/app/src/main/assets/readConfig.json @@ -59,7 +59,7 @@ "bgStr": "#000000", "bgType": 0, "darkStatusIcon": false, - "textColor": "#808080", + "textColor": "#adadad", "textSize": 16, "letterSpacing": 0, "lineSpacingExtra": 15, diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index 208a1de3f..27d794bd9 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -36,6 +36,7 @@ class ContentView : FrameLayout { content_text_view.textSize = textSize.toFloat() content_text_view.setLineSpacing(lineSpacingExtra, lineSpacingMultiplier) content_text_view.letterSpacing = letterSpacing + content_text_view.setTextColor(textColor()) } } From 116a64f90c99994cdc759133e0c894636370ace5 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 21 Aug 2019 16:40:50 +0800 Subject: [PATCH 0860/1997] up --- .../java/io/legado/app/help/ReadBookConfig.kt | 29 +++++++++---------- .../app/ui/readbook/config/ReadStyleDialog.kt | 21 +++++++++++++- 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index 588889e40..cea83752d 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -42,21 +42,7 @@ object ReadBookConfig { } fun upBg() { - getConfig().apply { - when (bgType) { - 0 -> bg = ColorDrawable(Color.parseColor(bgStr)) - 1 -> bg = Drawable.createFromStream(App.INSTANCE.assets.open("bg" + File.separator + bgStr), "bg") - else -> { - try { - bg = Drawable.createFromPath(bgStr) - } finally { - bg ?: let { - bg = ColorDrawable(Color.parseColor("#015A86")) - } - } - } - } - } + bg = getConfig().bgDrawable() } fun save() { @@ -113,5 +99,18 @@ object ReadBookConfig { fun textColor(): Int { return Color.parseColor(textColor) } + + fun bgDrawable(): Drawable { + var bgDrawable: Drawable? = null + when (bgType) { + 0 -> bgDrawable = ColorDrawable(Color.parseColor(bgStr)) + 1 -> bgDrawable = + Drawable.createFromStream(App.INSTANCE.assets.open("bg" + File.separator + bgStr), "bg") + else -> runCatching { + bgDrawable = Drawable.createFromPath(bgStr) + } + } + return bgDrawable ?: ColorDrawable(Color.parseColor("#015A86")) + } } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt index efa6d7c14..080e6ff54 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt @@ -8,6 +8,7 @@ import android.view.ViewGroup import androidx.fragment.app.DialogFragment import io.legado.app.R import io.legado.app.constant.Bus +import io.legado.app.help.ImageLoader import io.legado.app.help.ReadBookConfig import io.legado.app.lib.theme.accentColor import io.legado.app.lib.theme.primaryTextColor @@ -79,7 +80,25 @@ class ReadStyleDialog : DialogFragment() { tv_bg2.setTextColor(ReadBookConfig.getConfig(2).textColor()) tv_bg3.setTextColor(ReadBookConfig.getConfig(3).textColor()) tv_bg4.setTextColor(ReadBookConfig.getConfig(4).textColor()) - + for (i in 0..4) { + val iv = when (i) { + 1 -> bg1 + 2 -> bg2 + 3 -> bg3 + 4 -> bg4 + else -> bg0 + } + ReadBookConfig.getConfig(i).apply { + when (bgType) { + 2 -> { + ImageLoader.load(requireContext(), bgStr) + .centerCrop() + .setAsFile(iv) + } + else -> iv.setImageDrawable(bgDrawable()) + } + } + } } private fun upBg() { From 2c4720d1dfbb297a489ae7847e7b56ddeb4586ca Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 21 Aug 2019 16:44:20 +0800 Subject: [PATCH 0861/1997] up --- app/src/main/res/layout/dialog_read_book_style.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/layout/dialog_read_book_style.xml b/app/src/main/res/layout/dialog_read_book_style.xml index 99e9e6946..8e22adc05 100644 --- a/app/src/main/res/layout/dialog_read_book_style.xml +++ b/app/src/main/res/layout/dialog_read_book_style.xml @@ -3,7 +3,8 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:orientation="vertical" android:layout_width="match_parent" - android:layout_height="wrap_content"> + android:layout_height="wrap_content" + android:padding="10dp"> Date: Wed, 21 Aug 2019 16:46:01 +0800 Subject: [PATCH 0862/1997] up --- app/src/main/res/layout/dialog_read_book_style.xml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/app/src/main/res/layout/dialog_read_book_style.xml b/app/src/main/res/layout/dialog_read_book_style.xml index 8e22adc05..98f85f295 100644 --- a/app/src/main/res/layout/dialog_read_book_style.xml +++ b/app/src/main/res/layout/dialog_read_book_style.xml @@ -33,7 +33,8 @@ app:civ_border_width="1dp" app:layout_constraintLeft_toRightOf="@+id/bg0" app:layout_constraintRight_toLeftOf="@+id/bg2" - app:layout_constraintBottom_toBottomOf="parent" /> + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintTop_toTopOf="@+id/bg0" /> + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintTop_toTopOf="@+id/bg0" /> + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintTop_toTopOf="@+id/bg0" /> + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintTop_toTopOf="@+id/bg0" /> Date: Wed, 21 Aug 2019 17:22:04 +0800 Subject: [PATCH 0863/1997] up --- .../io/legado/app/ui/readbook/config/ReadStyleDialog.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt index 080e6ff54..bd49296ab 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt @@ -32,7 +32,12 @@ class ReadStyleDialog : DialogFragment() { super.onStart() val dm = DisplayMetrics() activity?.windowManager?.defaultDisplay?.getMetrics(dm) - dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), ViewGroup.LayoutParams.WRAP_CONTENT) + dialog?.window?.let { + val attr = it.attributes + attr.dimAmount = 0.0f + it.attributes = attr + it.setLayout((dm.widthPixels * 0.9).toInt(), ViewGroup.LayoutParams.WRAP_CONTENT) + } } private fun initData() { From da6369f87becea1fb73cf0dc5f670c907aa7128c Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 21 Aug 2019 18:04:58 +0800 Subject: [PATCH 0864/1997] up --- .../res/layout/dialog_read_book_style.xml | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/layout/dialog_read_book_style.xml b/app/src/main/res/layout/dialog_read_book_style.xml index 98f85f295..f14268b6e 100644 --- a/app/src/main/res/layout/dialog_read_book_style.xml +++ b/app/src/main/res/layout/dialog_read_book_style.xml @@ -6,6 +6,22 @@ android:layout_height="wrap_content" android:padding="10dp"> + + + + + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintTop_toBottomOf="@+id/tv_bg_ts" /> Date: Wed, 21 Aug 2019 19:19:31 +0800 Subject: [PATCH 0865/1997] up --- .../io/legado/app/ui/readbook/config/ReadStyleDialog.kt | 6 +++++- app/src/main/res/layout/dialog_read_book_style.xml | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt index bd49296ab..ef10c357c 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt @@ -2,6 +2,7 @@ package io.legado.app.ui.readbook.config import android.os.Bundle import android.util.DisplayMetrics +import android.view.Gravity import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -33,10 +34,13 @@ class ReadStyleDialog : DialogFragment() { val dm = DisplayMetrics() activity?.windowManager?.defaultDisplay?.getMetrics(dm) dialog?.window?.let { + it.setBackgroundDrawableResource(R.color.transparent) + it.decorView.setPadding(0, 0, 0, 0) val attr = it.attributes attr.dimAmount = 0.0f + attr.gravity = Gravity.BOTTOM it.attributes = attr - it.setLayout((dm.widthPixels * 0.9).toInt(), ViewGroup.LayoutParams.WRAP_CONTENT) + it.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) } } diff --git a/app/src/main/res/layout/dialog_read_book_style.xml b/app/src/main/res/layout/dialog_read_book_style.xml index f14268b6e..83fc3f585 100644 --- a/app/src/main/res/layout/dialog_read_book_style.xml +++ b/app/src/main/res/layout/dialog_read_book_style.xml @@ -4,6 +4,7 @@ android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content" + android:background="@color/background" android:padding="10dp"> Date: Wed, 21 Aug 2019 19:22:45 +0800 Subject: [PATCH 0866/1997] up --- .../legado/app/ui/readbook/config/ReadStyleDialog.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt index ef10c357c..6f6611f93 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt @@ -12,7 +12,7 @@ import io.legado.app.constant.Bus import io.legado.app.help.ImageLoader import io.legado.app.help.ReadBookConfig import io.legado.app.lib.theme.accentColor -import io.legado.app.lib.theme.primaryTextColor +import io.legado.app.lib.theme.primaryColor import io.legado.app.utils.postEvent import kotlinx.android.synthetic.main.dialog_read_book_style.* import org.jetbrains.anko.sdk27.listeners.onClick @@ -111,11 +111,11 @@ class ReadStyleDialog : DialogFragment() { } private fun upBg() { - bg0.borderColor = requireContext().primaryTextColor - bg1.borderColor = requireContext().primaryTextColor - bg2.borderColor = requireContext().primaryTextColor - bg3.borderColor = requireContext().primaryTextColor - bg4.borderColor = requireContext().primaryTextColor + bg0.borderColor = requireContext().primaryColor + bg1.borderColor = requireContext().primaryColor + bg2.borderColor = requireContext().primaryColor + bg3.borderColor = requireContext().primaryColor + bg4.borderColor = requireContext().primaryColor when (ReadBookConfig.styleSelect) { 1 -> { bg1.borderColor = requireContext().accentColor From 4d19aaedb324c651c4d4d048a30a624ee32ac684 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 21 Aug 2019 19:45:18 +0800 Subject: [PATCH 0867/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 36 ++++++++++--------- .../app/ui/readbook/ReadBookViewModel.kt | 20 +++++++---- .../legado/app/ui/widget/page/DataSource.kt | 2 +- .../io/legado/app/ui/widget/page/PageView.kt | 22 ++++++++---- 4 files changed, 49 insertions(+), 31 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 319755c21..c0f1e9411 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -53,7 +53,6 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea initAnimation() initView() viewModel.callBack = this - viewModel.chapterMaxIndex.observe(this, Observer { bookLoadFinish() }) viewModel.bookData.observe(this, Observer { title_bar.title = it.name }) viewModel.initData(intent) savedInstanceState?.let { @@ -235,7 +234,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } - private fun bookLoadFinish() { + override fun bookLoadFinish() { viewModel.bookData.value?.let { viewModel.loadContent(it, viewModel.durChapterIndex) viewModel.loadContent(it, viewModel.durChapterIndex + 1) @@ -243,7 +242,13 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } - override fun onLoadFinish(bookChapter: BookChapter, content: String) { + override fun loadChapter(index: Int) { + viewModel.bookData.value?.let { + viewModel.loadContent(it, index) + } + } + + override fun contentLoadFinish(bookChapter: BookChapter, content: String) { launch { when (bookChapter.index) { viewModel.durChapterIndex -> { @@ -268,12 +273,16 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } + override fun chapterSize(): Int { + return viewModel.chapterSize + } + override fun oldBook(): Book? { return viewModel.bookData.value } override fun changeTo(book: Book) { - + viewModel.changeTo(book) } override fun durChapterIndex(): Int { @@ -296,15 +305,6 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } - fun upStyle() { - content_view.upStyle() - page_view.upStyle() - } - - fun upBg() { - page_view.upBg() - } - private fun onClickReadAloud() { if (!ReadAloudService.isRun) { readAloudStatus = Status.STOP @@ -332,10 +332,14 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea observeEventSticky(Bus.UP_CONFIG) { when (it) { 0 -> { - upBg() - upStyle() + page_view.upBg() + content_view.upStyle() + page_view.upStyle() + } + 1 -> { + content_view.upStyle() + page_view.upStyle() } - 1 -> upStyle() } } } diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index 380c70988..d44c15b03 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -2,7 +2,6 @@ package io.legado.app.ui.readbook import android.app.Application import android.content.Intent -import androidx.lifecycle.MediatorLiveData import androidx.lifecycle.MutableLiveData import io.legado.app.App import io.legado.app.R @@ -20,7 +19,7 @@ import kotlinx.coroutines.Dispatchers.IO class ReadBookViewModel(application: Application) : BaseViewModel(application) { var bookData = MutableLiveData() - var chapterMaxIndex = MediatorLiveData() + var chapterSize = 0 var bookSource: BookSource? = null var webBook: WebBook? = null var callBack: CallBack? = null @@ -52,7 +51,8 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { ?.onSuccess(IO) { cList -> if (!cList.isNullOrEmpty()) { App.db.bookChapterDao().insert(*cList.toTypedArray()) - chapterMaxIndex.postValue(cList.size) + chapterSize = cList.size + callBack?.bookLoadFinish() } else { toast(R.string.error_load_toc) } @@ -63,7 +63,8 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { if (durChapterIndex > count - 1) { durChapterIndex = count - 1 } - chapterMaxIndex.postValue(count) + chapterSize = count + callBack?.bookLoadFinish() } } @@ -80,7 +81,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { execute { App.db.bookChapterDao().getChapter(book.bookUrl, index)?.let { chapter -> BookHelp.getContent(book, chapter)?.let { - callBack?.onLoadFinish(chapter, it) + callBack?.contentLoadFinish(chapter, it) synchronized(loadingLock) { loadingChapters.remove(index) } @@ -118,7 +119,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { ?.onSuccess(IO) { content -> content?.let { BookHelp.saveContent(book, chapter, it) - callBack?.onLoadFinish(chapter, it) + callBack?.contentLoadFinish(chapter, it) synchronized(loadingLock) { loadingChapters.remove(chapter.index) } @@ -130,6 +131,10 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } } + fun changeTo(book: Book) { + + } + private fun autoChangeSource() { } @@ -140,6 +145,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } interface CallBack { - fun onLoadFinish(bookChapter: BookChapter, content: String) + fun bookLoadFinish() + fun contentLoadFinish(bookChapter: BookChapter, content: String) } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt b/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt index 76c11a532..2101ed952 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt @@ -6,7 +6,7 @@ interface DataSource { fun isPrepared(): Boolean - fun getChapterPosition() + fun getChapterPosition(): Int fun getChapter(position: Int): TextChapter? diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 640d1578a..c98785fcd 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -37,8 +37,8 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } - override fun getChapterPosition() { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + override fun getChapterPosition(): Int { + return callback?.durChapterIndex() ?: 0 } override fun getChapter(position: Int): TextChapter? { @@ -46,23 +46,29 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att } override fun getCurrentChapter(): TextChapter? { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + return callback?.textChapter(0) } override fun getNextChapter(): TextChapter? { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + return callback?.textChapter(1) } override fun getPreviousChapter(): TextChapter? { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + return callback?.textChapter(-1) } override fun hasNextChapter(): Boolean { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + callback?.let { + return it.durChapterIndex() < it.chapterSize() - 1 + } + return false } override fun hasPrevChapter(): Boolean { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + callback?.let { + return it.durChapterIndex() > 0 + } + return false } })) } @@ -190,8 +196,10 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att } interface CallBack { + fun chapterSize(): Int fun durChapterIndex(): Int fun durChapterPos(pageSize: Int): Int fun textChapter(chapterOnDur: Int = 0): TextChapter? + fun loadChapter(index: Int) } } From bfcdd574591cc00ee138a5dcdf9b0435e0159855 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 21 Aug 2019 19:56:39 +0800 Subject: [PATCH 0868/1997] up --- .../main/java/io/legado/app/ui/widget/page/TextPageFactory.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt index 790981026..9f3497a5e 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt @@ -43,7 +43,7 @@ class TextPageFactory private constructor(dataSource: DataSource) : PageFactory< } override fun currentPage(): TextPage? { - return TextPage(index, "index:$index") + return dataSource.getCurrentChapter()?.page(index) } override fun nextPage(): TextPage? { From c11105d84ac7c729d1fb9d2c233d535ba6f00a6d Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 21 Aug 2019 20:50:20 +0800 Subject: [PATCH 0869/1997] up --- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 4dfd23870..c6798862d 100644 --- a/build.gradle +++ b/build.gradle @@ -8,7 +8,7 @@ buildscript { maven { url 'https://maven.fabric.io/public' } } dependencies { - classpath 'com.android.tools.build:gradle:3.4.2' + classpath 'com.android.tools.build:gradle:3.5.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1aa595a87..7002c3786 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Wed May 22 11:28:32 CST 2019 +#Wed Aug 21 20:30:49 CST 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip From 273ddf83b186e3e206a0765db699d3358179f009 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 22 Aug 2019 08:08:50 +0800 Subject: [PATCH 0870/1997] up --- .../main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt | 5 ++++- .../main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index c2a8de623..88db8e75b 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -155,7 +155,10 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo viewModel.bookData.value?.let { if (!viewModel.inBookshelf) { viewModel.saveBook { - startActivity(Pair("bookUrl", it.bookUrl)) + startActivity( + Pair("bookUrl", it.bookUrl), + Pair("inBookshelf", false) + ) } } else { startActivity(Pair("bookUrl", it.bookUrl)) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index d44c15b03..8527ada13 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -17,7 +17,7 @@ import io.legado.app.ui.widget.page.TextChapter import kotlinx.coroutines.Dispatchers.IO class ReadBookViewModel(application: Application) : BaseViewModel(application) { - + var inBookshelf = false var bookData = MutableLiveData() var chapterSize = 0 var bookSource: BookSource? = null @@ -33,6 +33,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { private val loadingLock = "loadingLock" fun initData(intent: Intent) { + inBookshelf = intent.getBooleanExtra("inBookshelf", true) val bookUrl = intent.getStringExtra("bookUrl") if (!bookUrl.isNullOrEmpty()) { execute { From 54c8c55b50fbf48971caf028a3e6a51ed781157a Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 22 Aug 2019 08:28:44 +0800 Subject: [PATCH 0871/1997] up --- .../io/legado/app/ui/bookinfo/BookInfoActivity.kt | 10 ++++++++-- .../io/legado/app/ui/bookinfo/BookInfoViewModel.kt | 11 +++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index 88db8e75b..a6ff40a57 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -166,8 +166,14 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo } } tv_shelf.onClick { - viewModel.saveBook { - tv_shelf.text = getString(R.string.remove_from_bookshelf) + if (viewModel.inBookshelf) { + viewModel.delBook { + tv_shelf.text = getString(R.string.add_to_shelf) + } + } else { + viewModel.saveBook { + tv_shelf.text = getString(R.string.remove_from_bookshelf) + } } } tv_loading.onClick { } diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt index a4f7a1b53..fdc13bb8c 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt @@ -106,6 +106,17 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { chapterListData.value?.let { App.db.bookChapterDao().insert(*it.toTypedArray()) } + inBookshelf = true + }.onSuccess { + success?.invoke() + } + } + + fun delBook(success: (() -> Unit)?) { + execute { + bookData.value?.let { + App.db.bookDao().delete(it.bookUrl) + } }.onSuccess { success?.invoke() } From 4281f5d870b67ef9ce260ee4fe4f253d6677d2f2 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 22 Aug 2019 09:06:30 +0800 Subject: [PATCH 0872/1997] up --- .../app/ui/readbook/ReadBookViewModel.kt | 55 ++++++++++++++----- 1 file changed, 42 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index 8527ada13..c1c6dc7a5 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -48,18 +48,11 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } val count = App.db.bookChapterDao().getChapterCount(bookUrl) if (count == 0) { - webBook?.getChapterList(book, this) - ?.onSuccess(IO) { cList -> - if (!cList.isNullOrEmpty()) { - App.db.bookChapterDao().insert(*cList.toTypedArray()) - chapterSize = cList.size - callBack?.bookLoadFinish() - } else { - toast(R.string.error_load_toc) - } - }?.onError { - toast(R.string.error_load_toc) - } ?: autoChangeSource() + if (book.tocUrl.isEmpty()) { + loadBookInfo(book) + } else { + loadChapterList(book) + } } else { if (durChapterIndex > count - 1) { durChapterIndex = count - 1 @@ -73,6 +66,31 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } } + private fun loadBookInfo(book: Book) { + execute { + webBook?.getBookInfo(book, this) + ?.onSuccess { + loadChapterList(book) + } + } + } + + private fun loadChapterList(book: Book) { + execute { + webBook?.getChapterList(book, this) + ?.onSuccess(IO) { cList -> + if (!cList.isNullOrEmpty()) { + App.db.bookChapterDao().insert(*cList.toTypedArray()) + chapterSize = cList.size + callBack?.bookLoadFinish() + } else { + toast(R.string.error_load_toc) + } + }?.onError { + toast(R.string.error_load_toc) + } ?: autoChangeSource() + } + } fun loadContent(book: Book, index: Int) { synchronized(loadingLock) { @@ -133,7 +151,18 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } fun changeTo(book: Book) { - + execute { + bookData.value?.let { + App.db.bookDao().delete(it.bookUrl) + } + bookData.postValue(book) + bookSource = App.db.bookSourceDao().getBookSource(book.origin) + if (book.tocUrl.isEmpty()) { + loadBookInfo(book) + } else { + loadChapterList(book) + } + } } private fun autoChangeSource() { From 75cc605764f0bf3f72b5c95b14bfbc3a591462e9 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 22 Aug 2019 09:11:43 +0800 Subject: [PATCH 0873/1997] up --- app/src/main/java/io/legado/app/help/BlurTransformation.kt | 3 +++ app/src/main/java/io/legado/app/help/ReadBookConfig.kt | 3 +++ 2 files changed, 6 insertions(+) diff --git a/app/src/main/java/io/legado/app/help/BlurTransformation.kt b/app/src/main/java/io/legado/app/help/BlurTransformation.kt index 7cf8de88b..9d60a9047 100644 --- a/app/src/main/java/io/legado/app/help/BlurTransformation.kt +++ b/app/src/main/java/io/legado/app/help/BlurTransformation.kt @@ -14,6 +14,9 @@ import com.bumptech.glide.load.resource.bitmap.BitmapTransformation import java.security.MessageDigest +/** + * 模糊 + */ class BlurTransformation(context: Context, private val radius: Int) : BitmapTransformation() { private val rs: RenderScript = RenderScript.create(context) diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index cea83752d..d26f67bbd 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -13,6 +13,9 @@ import java.io.File import java.io.FileWriter import java.io.IOException +/** + * 阅读界面配置 + */ object ReadBookConfig { private val configList: ArrayList by lazy { val list: ArrayList = arrayListOf() From 44e1c465d5b3a55253633cceb95a27ad5d4e615e Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 22 Aug 2019 09:16:26 +0800 Subject: [PATCH 0874/1997] up --- app/src/main/java/io/legado/app/help/PendingIntentHelp.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/help/PendingIntentHelp.kt b/app/src/main/java/io/legado/app/help/PendingIntentHelp.kt index 5684390f2..e0725cb27 100644 --- a/app/src/main/java/io/legado/app/help/PendingIntentHelp.kt +++ b/app/src/main/java/io/legado/app/help/PendingIntentHelp.kt @@ -3,6 +3,7 @@ package io.legado.app.help import android.app.PendingIntent import android.content.Context import android.content.Intent +import io.legado.app.service.ReadAloudService import io.legado.app.ui.readbook.ReadBookActivity object PendingIntentHelp { @@ -14,7 +15,7 @@ object PendingIntentHelp { } fun aloudServicePendingIntent(context: Context, actionStr: String): PendingIntent { - val intent = Intent(context, this.javaClass) + val intent = Intent(context, ReadAloudService::class.java) intent.action = actionStr return PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) } From a7cc477e69478126248771d31b8844b5b2ba431a Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 22 Aug 2019 10:38:09 +0800 Subject: [PATCH 0875/1997] up --- .../app/ui/readbook/config/ReadAloudDialog.kt | 24 +++++++++++++++++++ .../app/ui/readbook/config/ReadAloudPopup.kt | 8 ------- app/src/main/res/layout/dialog_read_aloud.xml | 7 ++++++ 3 files changed, 31 insertions(+), 8 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt delete mode 100644 app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudPopup.kt create mode 100644 app/src/main/res/layout/dialog_read_aloud.xml diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt new file mode 100644 index 000000000..58ab4a6a8 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt @@ -0,0 +1,24 @@ +package io.legado.app.ui.readbook.config + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.DialogFragment +import io.legado.app.R + +class ReadAloudDialog : DialogFragment() { + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + return inflater.inflate(R.layout.dialog_read_aloud, container) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + } + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudPopup.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudPopup.kt deleted file mode 100644 index 3c2863478..000000000 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudPopup.kt +++ /dev/null @@ -1,8 +0,0 @@ -package io.legado.app.ui.readbook.config - -import android.content.Context -import android.widget.PopupWindow - -class ReadAloudPopup(context: Context?) : PopupWindow(context) { - -} \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_read_aloud.xml b/app/src/main/res/layout/dialog_read_aloud.xml new file mode 100644 index 000000000..d829e291c --- /dev/null +++ b/app/src/main/res/layout/dialog_read_aloud.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file From de103d2f5deedf920d48ec9019e18f8f9669b8d7 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 22 Aug 2019 12:18:38 +0800 Subject: [PATCH 0876/1997] up --- .../app/lib/theme/MaterialValueHelper.kt | 7 ++++ .../app/ui/chapterlist/BookmarkFragment.kt | 8 +++++ .../app/ui/chapterlist/ChapterListAdapter.kt | 16 ++++++--- .../app/ui/chapterlist/ChapterListFragment.kt | 33 ++++++++++++++++--- 4 files changed, 56 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/theme/MaterialValueHelper.kt b/app/src/main/java/io/legado/app/lib/theme/MaterialValueHelper.kt index ea37c7b00..e611ac728 100644 --- a/app/src/main/java/io/legado/app/lib/theme/MaterialValueHelper.kt +++ b/app/src/main/java/io/legado/app/lib/theme/MaterialValueHelper.kt @@ -123,6 +123,13 @@ val Fragment.primaryDisabledTextColor: Int val Fragment.secondaryDisabledTextColor: Int get() = getSecondaryDisabledTextColor(isDarkTheme) +val Context.buttonDisabledColor: Int + get() = if (isDarkTheme) { + ContextCompat.getColor(this, R.color.ate_button_disabled_dark) + } else { + ContextCompat.getColor(this, R.color.ate_button_disabled_light) + } + val Context.isDarkTheme: Boolean get() = ColorUtils.isColorLight(ThemeStore.primaryColor(this)) diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/BookmarkFragment.kt b/app/src/main/java/io/legado/app/ui/chapterlist/BookmarkFragment.kt index 43c583e7f..0d42b5600 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/BookmarkFragment.kt +++ b/app/src/main/java/io/legado/app/ui/chapterlist/BookmarkFragment.kt @@ -2,10 +2,12 @@ package io.legado.app.ui.chapterlist import android.os.Bundle import android.view.View +import android.widget.LinearLayout import androidx.lifecycle.LiveData import androidx.lifecycle.Observer import androidx.paging.LivePagedListBuilder import androidx.paging.PagedList +import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.App import io.legado.app.R @@ -32,6 +34,12 @@ class BookmarkFragment : VMBaseFragment(R.layout.fragment_ ATH.applyEdgeEffectColor(recycler_view) adapter = BookmarkAdapter() recycler_view.layoutManager = LinearLayoutManager(requireContext()) + recycler_view.addItemDecoration( + DividerItemDecoration( + requireContext(), + LinearLayout.VERTICAL + ) + ) recycler_view.adapter = adapter } diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListAdapter.kt b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListAdapter.kt index 5dc8d27f2..581bf3c01 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListAdapter.kt @@ -8,10 +8,13 @@ import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import io.legado.app.R import io.legado.app.data.entities.BookChapter +import io.legado.app.lib.theme.accentColor +import io.legado.app.utils.getCompatColor import kotlinx.android.synthetic.main.item_bookmark.view.* import org.jetbrains.anko.sdk27.listeners.onClick -class ChapterListAdapter : PagedListAdapter(DIFF_CALLBACK) { +class ChapterListAdapter(val callback: Callback) : + PagedListAdapter(DIFF_CALLBACK) { companion object { @@ -26,8 +29,6 @@ class ChapterListAdapter : PagedListAdapter(R.layout.fragment_chapter_list) { +class ChapterListFragment : VMBaseFragment(R.layout.fragment_chapter_list), + ChapterListAdapter.Callback { override val viewModel: ChapterListViewModel get() = getViewModelOfActivity(ChapterListViewModel::class.java) lateinit var adapter: ChapterListAdapter private var liveData: LiveData>? = null + private var durChapterIndex = 0 override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -30,8 +35,14 @@ class ChapterListFragment : VMBaseFragment(R.layout.fragme } private fun initRecyclerView() { - adapter = ChapterListAdapter() + adapter = ChapterListAdapter(this) recycler_view.layoutManager = LinearLayoutManager(requireContext()) + recycler_view.addItemDecoration( + DividerItemDecoration( + requireContext(), + LinearLayout.VERTICAL + ) + ) recycler_view.adapter = adapter } @@ -43,9 +54,9 @@ class ChapterListFragment : VMBaseFragment(R.layout.fragme private fun initView() { viewModel.bookDate.value?.let { - tv_current_chapter_info.text = it.durChapterTitle + loadBookFinish(it) } ?: viewModel.bookDate.observe(viewLifecycleOwner, Observer { - tv_current_chapter_info.text = it.durChapterTitle + loadBookFinish(it) }) iv_chapter_top.onClick { recycler_view.scrollToPosition(0) } iv_chapter_bottom.onClick { @@ -59,4 +70,18 @@ class ChapterListFragment : VMBaseFragment(R.layout.fragme } } } + + private fun loadBookFinish(book: Book) { + durChapterIndex = book.durChapterIndex + tv_current_chapter_info.text = book.durChapterTitle + recycler_view.scrollToPosition(durChapterIndex) + } + + override fun durChapterIndex(): Int { + return durChapterIndex + } + + override fun openChapter() { + + } } \ No newline at end of file From b3a9c875ce89b0493eac5cbb398c04ebf3aa68ee Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 22 Aug 2019 12:24:44 +0800 Subject: [PATCH 0877/1997] up --- app/src/main/java/io/legado/app/constant/Bus.kt | 1 + .../io/legado/app/ui/chapterlist/ChapterListAdapter.kt | 4 ++-- .../io/legado/app/ui/chapterlist/ChapterListFragment.kt | 7 +++++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/constant/Bus.kt b/app/src/main/java/io/legado/app/constant/Bus.kt index 03b4d7078..2d7608626 100644 --- a/app/src/main/java/io/legado/app/constant/Bus.kt +++ b/app/src/main/java/io/legado/app/constant/Bus.kt @@ -10,4 +10,5 @@ object Bus { const val TIME_CHANGED = "timeChanged" const val READ_ALOUD = "readAloud" const val UP_CONFIG = "upConfig" + const val OPEN_CHAPTER = "openChapter" } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListAdapter.kt b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListAdapter.kt index 581bf3c01..44f690f52 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListAdapter.kt @@ -51,13 +51,13 @@ class ChapterListAdapter(val callback: Callback) : } } itemView.onClick { - callback?.openChapter() + callback?.openChapter(bookChapter) } } } interface Callback { - fun openChapter() + fun openChapter(bookChapter: BookChapter) fun durChapterIndex(): Int } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt index 97eee3cd8..390de1a0c 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt +++ b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt @@ -12,9 +12,11 @@ import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.App import io.legado.app.R import io.legado.app.base.VMBaseFragment +import io.legado.app.constant.Bus import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter import io.legado.app.utils.getViewModelOfActivity +import io.legado.app.utils.postEvent import kotlinx.android.synthetic.main.fragment_chapter_list.* import org.jetbrains.anko.sdk27.listeners.onClick @@ -81,7 +83,8 @@ class ChapterListFragment : VMBaseFragment(R.layout.fragme return durChapterIndex } - override fun openChapter() { - + override fun openChapter(bookChapter: BookChapter) { + postEvent(Bus.OPEN_CHAPTER, bookChapter) + activity?.finish() } } \ No newline at end of file From d4fca01df102d6c52b03d616415c812f58ab2fd9 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 22 Aug 2019 12:33:24 +0800 Subject: [PATCH 0878/1997] up --- .../io/legado/app/ui/bookinfo/BookInfoActivity.kt | 9 ++++++++- .../io/legado/app/ui/bookinfo/BookInfoViewModel.kt | 3 +++ .../io/legado/app/ui/bookinfo/ChapterListAdapter.kt | 12 ++++++++++-- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index a6ff40a57..94863261a 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -9,6 +9,7 @@ import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.R import io.legado.app.base.VMBaseActivity +import io.legado.app.constant.Bus import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter import io.legado.app.help.ImageLoader @@ -19,6 +20,7 @@ import io.legado.app.ui.readbook.ReadBookActivity import io.legado.app.ui.sourceedit.SourceEditActivity import io.legado.app.utils.getViewModel import io.legado.app.utils.gone +import io.legado.app.utils.postEvent import io.legado.app.utils.visible import kotlinx.android.synthetic.main.activity_book_info.* import kotlinx.android.synthetic.main.view_title_bar.* @@ -127,6 +129,7 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo } adapter.clearItems() adapter.addItems(chapterList) + rv_chapter_list.scrollToPosition(viewModel.durChapterIndex) } private fun upLoading(isLoading: Boolean) { @@ -206,7 +209,11 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo viewModel.changeTo(book) } - override fun skipToChapter(index: Int) { + override fun openChapter(chapter: BookChapter) { + postEvent(Bus.OPEN_CHAPTER, chapter) + } + override fun durChapterIndex(): Int { + return viewModel.durChapterIndex } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt index fdc13bb8c..8bdbf18a4 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt @@ -16,6 +16,7 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { val bookData = MutableLiveData() val chapterListData = MutableLiveData>() val isLoadingData = MutableLiveData() + var durChapterIndex = 0 var inBookshelf = false fun loadBook(intent: Intent) { @@ -23,6 +24,7 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { intent.getStringExtra("bookUrl")?.let { App.db.bookDao().getBook(it)?.let { book -> inBookshelf = true + durChapterIndex = book.durChapterIndex bookData.postValue(book) val chapterList = App.db.bookChapterDao().getChapterList(it) if (chapterList.isNotEmpty()) { @@ -34,6 +36,7 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { } } ?: intent.getStringExtra("searchBookUrl")?.let { App.db.searchBookDao().getSearchBook(it)?.toBook()?.let { book -> + durChapterIndex = book.durChapterIndex bookData.postValue(book) if (book.tocUrl.isEmpty()) { loadBookInfo(book) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/ChapterListAdapter.kt b/app/src/main/java/io/legado/app/ui/bookinfo/ChapterListAdapter.kt index cd5a759db..31468c980 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/ChapterListAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/ChapterListAdapter.kt @@ -5,8 +5,10 @@ import io.legado.app.R import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.data.entities.BookChapter +import io.legado.app.lib.theme.accentColor import kotlinx.android.synthetic.main.item_chapter_list.view.* import org.jetbrains.anko.sdk27.listeners.onClick +import org.jetbrains.anko.textColorResource class ChapterListAdapter(context: Context, var callBack: CallBack) : SimpleRecyclerAdapter(context, R.layout.item_chapter_list) { @@ -14,13 +16,19 @@ class ChapterListAdapter(context: Context, var callBack: CallBack) : override fun convert(holder: ItemViewHolder, item: BookChapter, payloads: MutableList) { holder.itemView.apply { tv_chapter_name.text = item.title + if (item.index == callBack.durChapterIndex()) { + tv_chapter_name.setTextColor(context.accentColor) + } else { + tv_chapter_name.textColorResource = R.color.tv_text_default + } this.onClick { - callBack.skipToChapter(item.index) + callBack.openChapter(item) } } } interface CallBack { - fun skipToChapter(index: Int) + fun openChapter(chapter: BookChapter) + fun durChapterIndex(): Int } } \ No newline at end of file From f572c0574b0f6d3ce6e24970826ddb6e5f4f9173 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 22 Aug 2019 12:37:14 +0800 Subject: [PATCH 0879/1997] up --- .../java/io/legado/app/ui/bookinfo/BookInfoActivity.kt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index 94863261a..a387b1e0f 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -199,6 +199,14 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo rv_chapter_list.scrollToPosition(it.durChapterIndex) } } + iv_chapter_top.onClick { + rv_chapter_list.scrollToPosition(0) + } + iv_chapter_bottom.onClick { + viewModel.chapterListData.value?.let { + rv_chapter_list.scrollToPosition(it.size - 1) + } + } } override fun oldBook(): Book? { From 720ced5291b48ba6e65d20156ca1d199ee8545d1 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 22 Aug 2019 14:32:43 +0800 Subject: [PATCH 0880/1997] up --- .../app/ui/bookinfo/BookInfoActivity.kt | 40 ++++++++++++------- .../app/ui/bookinfo/BookInfoViewModel.kt | 21 ++++++++++ 2 files changed, 47 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index a387b1e0f..b618f29d6 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -9,7 +9,6 @@ import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.R import io.legado.app.base.VMBaseActivity -import io.legado.app.constant.Bus import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter import io.legado.app.help.ImageLoader @@ -20,7 +19,6 @@ import io.legado.app.ui.readbook.ReadBookActivity import io.legado.app.ui.sourceedit.SourceEditActivity import io.legado.app.utils.getViewModel import io.legado.app.utils.gone -import io.legado.app.utils.postEvent import io.legado.app.utils.visible import kotlinx.android.synthetic.main.activity_book_info.* import kotlinx.android.synthetic.main.view_title_bar.* @@ -156,16 +154,7 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo private fun initOnClick() { tv_read.onClick { viewModel.bookData.value?.let { - if (!viewModel.inBookshelf) { - viewModel.saveBook { - startActivity( - Pair("bookUrl", it.bookUrl), - Pair("inBookshelf", false) - ) - } - } else { - startActivity(Pair("bookUrl", it.bookUrl)) - } + readBook(it) } } tv_shelf.onClick { @@ -174,7 +163,7 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo tv_shelf.text = getString(R.string.add_to_shelf) } } else { - viewModel.saveBook { + viewModel.addToBookshelf { tv_shelf.text = getString(R.string.remove_from_bookshelf) } } @@ -209,6 +198,23 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo } } + private fun readBook(book: Book) { + if (!viewModel.inBookshelf) { + viewModel.saveBook { + viewModel.saveChapterList { + startActivity( + Pair("bookUrl", book.bookUrl), + Pair("inBookshelf", false) + ) + } + } + } else { + viewModel.saveBook { + startActivity(Pair("bookUrl", book.bookUrl)) + } + } + } + override fun oldBook(): Book? { return viewModel.bookData.value } @@ -218,7 +224,13 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo } override fun openChapter(chapter: BookChapter) { - postEvent(Bus.OPEN_CHAPTER, chapter) + if (chapter.index != viewModel.durChapterIndex) { + viewModel.bookData.value?.let { + it.durChapterIndex = chapter.index + it.durChapterPos = 0 + readBook(it) + } + } } override fun durChapterIndex(): Int { diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt index 8bdbf18a4..7b6c093bd 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt @@ -102,6 +102,26 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { } fun saveBook(success: (() -> Unit)?) { + execute { + bookData.value?.let { book -> + App.db.bookDao().insert(book) + } + }.onSuccess { + success?.invoke() + } + } + + fun saveChapterList(success: (() -> Unit)?) { + execute { + chapterListData.value?.let { + App.db.bookChapterDao().insert(*it.toTypedArray()) + } + }.onSuccess { + success?.invoke() + } + } + + fun addToBookshelf(success: (() -> Unit)?) { execute { bookData.value?.let { book -> App.db.bookDao().insert(book) @@ -120,6 +140,7 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { bookData.value?.let { App.db.bookDao().delete(it.bookUrl) } + inBookshelf = false }.onSuccess { success?.invoke() } From 86b954ea947f6ba9ae7e931e8c82b32f6b7f0178 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 22 Aug 2019 15:05:08 +0800 Subject: [PATCH 0881/1997] up --- .../legado/app/ui/readbook/ReadBookActivity.kt | 1 + .../legado/app/ui/readbook/ReadBookViewModel.kt | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index c0f1e9411..b5a851298 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -328,6 +328,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea observeEvent(Bus.TTS_RANGE_START) {} observeEvent(Bus.TIME_CHANGED) { page_view.upTime() } observeEvent(Bus.BATTERY_CHANGED) { page_view.upBattery(it) } + observeEvent(Bus.OPEN_CHAPTER) { viewModel.openChapter(it) } observeEventSticky(Bus.READ_ALOUD) { onClickReadAloud() } observeEventSticky(Bus.UP_CONFIG) { when (it) { diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index c1c6dc7a5..818f50810 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -169,6 +169,23 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } + fun openChapter(chapter: BookChapter) { + if (chapter.index != durChapterIndex) { + durChapterIndex = chapter.index + durPageIndex = 0 + } + callBack?.bookLoadFinish() + } + + fun saveRead() { + execute { + bookData.value?.let { book -> + book.durChapterIndex = durChapterIndex + book.durChapterPos = durPageIndex + } + } + } + override fun onCleared() { super.onCleared() ReadAloudService.stop(context) From 35128f2a654e5fc81159c572123ede6dc990f28b Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 22 Aug 2019 15:05:49 +0800 Subject: [PATCH 0882/1997] up --- app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index 818f50810..c478aa1b2 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -182,6 +182,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { bookData.value?.let { book -> book.durChapterIndex = durChapterIndex book.durChapterPos = durPageIndex + App.db.bookDao().update(book) } } } From 74a5bccfcd1d82239ab75efd861083f29f5511fd Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 22 Aug 2019 15:09:15 +0800 Subject: [PATCH 0883/1997] up --- app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index c478aa1b2..8c0c0c3cc 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -174,6 +174,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { durChapterIndex = chapter.index durPageIndex = 0 } + saveRead() callBack?.bookLoadFinish() } From 3b72ddd3b96f064da86ff3119274adf1358936b8 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 22 Aug 2019 15:16:50 +0800 Subject: [PATCH 0884/1997] up --- .../app/ui/readbook/config/MoreConfigDialog.kt | 15 +++++++++++++++ app/src/main/res/xml/pref_config_read.xml | 4 ++++ 2 files changed, 19 insertions(+) create mode 100644 app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt create mode 100644 app/src/main/res/xml/pref_config_read.xml diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt new file mode 100644 index 000000000..9cbbe6270 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt @@ -0,0 +1,15 @@ +package io.legado.app.ui.readbook.config + +import android.os.Bundle +import androidx.preference.PreferenceFragmentCompat +import io.legado.app.R + +class MoreConfigDialog : PreferenceFragmentCompat() { + + + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + addPreferencesFromResource(R.xml.pref_config_read) + } + + +} \ No newline at end of file diff --git a/app/src/main/res/xml/pref_config_read.xml b/app/src/main/res/xml/pref_config_read.xml new file mode 100644 index 000000000..65a47daa7 --- /dev/null +++ b/app/src/main/res/xml/pref_config_read.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file From fc318d2579813d34fc8be08f6761481d256b0bff Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 22 Aug 2019 15:52:47 +0800 Subject: [PATCH 0885/1997] up --- app/src/main/res/xml/pref_config.xml | 17 ++++++++++++++++- app/src/main/res/xml/pref_config_read.xml | 12 ++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/xml/pref_config.xml b/app/src/main/res/xml/pref_config.xml index 3a3478f41..b6656a907 100644 --- a/app/src/main/res/xml/pref_config.xml +++ b/app/src/main/res/xml/pref_config.xml @@ -1,5 +1,20 @@ - + + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/pref_config_read.xml b/app/src/main/res/xml/pref_config_read.xml index 65a47daa7..9b52e4753 100644 --- a/app/src/main/res/xml/pref_config_read.xml +++ b/app/src/main/res/xml/pref_config_read.xml @@ -1,4 +1,12 @@ - + - \ No newline at end of file + + + + \ No newline at end of file From ed5492536d82085619b197eafdbcc89136501277 Mon Sep 17 00:00:00 2001 From: Administrator <1760316362@qq.com> Date: Thu, 22 Aug 2019 15:57:45 +0800 Subject: [PATCH 0886/1997] update SlidePageDelegate --- .../java/io/legado/app/help/ImageLoader.kt | 16 ++++--- .../io/legado/app/ui/main/MainActivity.kt | 5 +-- .../legado/app/ui/widget/page/ContentView.kt | 13 ++---- .../legado/app/ui/widget/page/PageFactory.kt | 2 + .../io/legado/app/ui/widget/page/PageView.kt | 4 +- .../app/ui/widget/page/TextPageFactory.kt | 7 ++- .../widget/page/delegate/CoverPageDelegate.kt | 16 +++---- .../ui/widget/page/delegate/PageDelegate.kt | 30 ++++++------- .../widget/page/delegate/SlidePageDelegate.kt | 43 +++++++++++++++++++ 9 files changed, 89 insertions(+), 47 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/ImageLoader.kt b/app/src/main/java/io/legado/app/help/ImageLoader.kt index 370be11cc..10a9a8a50 100644 --- a/app/src/main/java/io/legado/app/help/ImageLoader.kt +++ b/app/src/main/java/io/legado/app/help/ImageLoader.kt @@ -10,7 +10,9 @@ import com.bumptech.glide.Glide import com.bumptech.glide.RequestBuilder import com.bumptech.glide.RequestManager import com.bumptech.glide.load.engine.DiskCacheStrategy -import com.bumptech.glide.load.resource.bitmap.* +import com.bumptech.glide.load.resource.bitmap.BitmapTransitionOptions +import com.bumptech.glide.load.resource.bitmap.CenterCrop +import com.bumptech.glide.load.resource.bitmap.RoundedCorners import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions import com.bumptech.glide.load.resource.gif.GifDrawable import com.bumptech.glide.request.RequestOptions @@ -74,27 +76,27 @@ object ImageLoader { } fun toCropRound(corner: Int): ImageLoadBuilder { - requestOptions = requestOptions.transforms(CenterCrop(), RoundedCorners(corner)) + requestOptions = requestOptions.transform(CenterCrop(), RoundedCorners(corner)) return this } fun toCircle(): ImageLoadBuilder { - requestOptions = requestOptions.transform(CircleCrop()) + requestOptions = requestOptions.circleCrop() return this } fun centerInside(): ImageLoadBuilder { - requestOptions = requestOptions.transform(CenterInside()) + requestOptions = requestOptions.centerInside() return this } fun fitCenter(): ImageLoadBuilder { - requestOptions = requestOptions.transform(FitCenter()) + requestOptions = requestOptions.fitCenter() return this } fun centerCrop(): ImageLoadBuilder { - requestOptions = requestOptions.transform(CenterCrop()) + requestOptions = requestOptions.centerCrop() return this } @@ -213,7 +215,7 @@ object ImageLoader { } private fun ensureOptions(builder: RequestBuilder): RequestBuilder { - return builder.apply(requestOptions.diskCacheStrategy(if (noCache) DiskCacheStrategy.NONE else DiskCacheStrategy.RESOURCE)) + return builder.apply(requestOptions.diskCacheStrategy(if (noCache) DiskCacheStrategy.NONE else DiskCacheStrategy.AUTOMATIC)) } private inner class Target constructor(private val target: ImageViewTarget) : diff --git a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt index af8765812..db04c42f2 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt @@ -18,10 +18,7 @@ import io.legado.app.ui.main.bookshelf.BookshelfFragment import io.legado.app.ui.main.findbook.FindBookFragment import io.legado.app.ui.main.my.MyFragment import io.legado.app.ui.main.rss.RssFragment -import io.legado.app.utils.getPrefInt -import io.legado.app.utils.getViewModel -import io.legado.app.utils.observeEvent -import io.legado.app.utils.putPrefInt +import io.legado.app.utils.* import kotlinx.android.synthetic.main.activity_main.* import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.launch diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index 27d794bd9..e2c15ee03 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -1,7 +1,6 @@ package io.legado.app.ui.widget.page import android.content.Context -import android.graphics.drawable.ColorDrawable import android.graphics.drawable.Drawable import android.util.AttributeSet import android.widget.FrameLayout @@ -41,14 +40,10 @@ class ContentView : FrameLayout { } fun setBg(bg: Drawable?) { - if (bg is ColorDrawable) { - bgImage.setImageDrawable(null) - bgImage.background = bg - } else { - ImageLoader.load(context, bg) - .centerCrop() - .setAsDrawable(bgImage) - } + //all supported + ImageLoader.load(context, bg) + .centerCrop() + .setAsDrawable(bgImage) } fun upTime() { diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageFactory.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageFactory.kt index a0e0f32cd..f9b9ca4cb 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageFactory.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageFactory.kt @@ -6,6 +6,8 @@ abstract class PageFactory(protected val dataSource: DataSource) { abstract fun moveToFirst() + abstract fun moveToLast() + abstract fun moveToNext():Boolean abstract fun moveToPrevious(): Boolean diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index c98785fcd..1269c6387 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -7,8 +7,8 @@ import android.util.AttributeSet import android.view.MotionEvent import android.widget.FrameLayout import io.legado.app.help.ReadBookConfig -import io.legado.app.ui.widget.page.delegate.CoverPageDelegate import io.legado.app.ui.widget.page.delegate.PageDelegate +import io.legado.app.ui.widget.page.delegate.SlidePageDelegate class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, attrs), PageDelegate.PageInterface { @@ -30,7 +30,7 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att upBg() setWillNotDraw(false) - pageDelegate = CoverPageDelegate(this) + pageDelegate = SlidePageDelegate(this) setPageFactory(TextPageFactory.create(object : DataSource { override fun isPrepared(): Boolean { diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt index 9f3497a5e..31fb586b2 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt @@ -26,6 +26,10 @@ class TextPageFactory private constructor(dataSource: DataSource) : PageFactory< index = 0 } + override fun moveToLast() { + + } + override fun moveToNext(): Boolean { return if(hasNext()){ index = index.plus(1) @@ -43,7 +47,8 @@ class TextPageFactory private constructor(dataSource: DataSource) : PageFactory< } override fun currentPage(): TextPage? { - return dataSource.getCurrentChapter()?.page(index) +// return dataSource.getCurrentChapter()?.page(index) + return TextPage(index, "index:$index") } override fun nextPage(): TextPage? { diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/CoverPageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/CoverPageDelegate.kt index 69130b5f8..a0a5bde9e 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/CoverPageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/CoverPageDelegate.kt @@ -69,15 +69,13 @@ class CoverPageDelegate(pageView: PageView) : PageDelegate(pageView) { } } - private fun addShadow(left: Int, canvas: Canvas?) { - canvas?.let { - if (left < 0) { - shadowDrawableR.setBounds(left + viewWidth, 0, left + viewWidth + 30, viewHeight) - shadowDrawableR.draw(it) - } else { - shadowDrawableL.setBounds(left - 30, 0, left, viewHeight) - shadowDrawableL.draw(it) - } + private fun addShadow(left: Int, canvas: Canvas) { + if (left < 0) { + shadowDrawableR.setBounds(left + viewWidth, 0, left + viewWidth + 30, viewHeight) + shadowDrawableR.draw(canvas) + } else { + shadowDrawableL.setBounds(left - 30, 0, left, viewHeight) + shadowDrawableL.draw(canvas) } } } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt index 5ce6345b7..ea32785c7 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt @@ -67,36 +67,41 @@ abstract class PageDelegate(protected val pageView: PageView) { onScroll() } - fun setViewSize(width: Int, height: Int) { - viewWidth = width - viewHeight = height - invalidate() - } - - fun invalidate() { + protected fun invalidate() { pageView.invalidate() } - fun start() { + protected fun start() { isRunning = true isStarted = true invalidate() } - fun stop() { + protected fun stop() { isRunning = false isStarted = false bitmap = null invalidate() } + protected fun getDuration(distance: Float): Int { + val duration = 300 * abs(distance) / viewWidth + return duration.toInt() + } + + fun setViewSize(width: Int, height: Int) { + viewWidth = width + viewHeight = height + invalidate() + } + fun scroll() { if (scroller.computeScrollOffset()) { setTouchPoint(scroller.currX.toFloat(), scroller.currY.toFloat()) } else if (isStarted) { setTouchPoint(scroller.finalX.toFloat(), scroller.finalY.toFloat(), false) - stop() onScrollStop() + stop() } } @@ -150,11 +155,6 @@ abstract class PageDelegate(protected val pageView: PageView) { return detector.onTouchEvent(event) } - fun getDuration(distance: Float): Int { - val duration = 300 * abs(distance) / viewWidth - return duration.toInt() - } - abstract fun onScrollStart()//scroller start abstract fun onDraw(canvas: Canvas)//绘制 diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/SlidePageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/SlidePageDelegate.kt index d78eb9698..434c45de1 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/SlidePageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/SlidePageDelegate.kt @@ -1,22 +1,65 @@ package io.legado.app.ui.widget.page.delegate import android.graphics.Canvas +import android.graphics.Matrix import io.legado.app.ui.widget.page.PageView class SlidePageDelegate(pageView: PageView) : PageDelegate(pageView) { + private val bitmapMatrix = Matrix() + override fun onScrollStart() { + val distanceX: Float + when (direction) { + Direction.NEXT -> if (isCancel) { + var dis = viewWidth - startX + touchX + if (dis > viewWidth) { + dis = viewWidth.toFloat() + } + distanceX = viewWidth - dis + } else { + distanceX = -(touchX + (viewWidth - startX)) + } + else -> distanceX = if (isCancel) { + -(touchX - startX) + } else { + viewWidth - (touchX - startX) + } + } + scroller.startScroll(touchX.toInt(), 0, distanceX.toInt(), 0, getDuration(distanceX)) + start() } override fun onDraw(canvas: Canvas) { + val offsetX = touchX - startX + + if ((direction == Direction.NEXT && offsetX > 0) + || (direction == Direction.PREV && offsetX < 0) + ) return + + val distanceX = if (offsetX > 0) offsetX - viewWidth else offsetX + viewWidth + bitmap?.let { + bitmapMatrix.setTranslate(distanceX, 0.toFloat()) + canvas.drawBitmap(it, bitmapMatrix, null) + } } override fun onScroll() { + val offsetX = touchX - startX + + if ((direction == Direction.NEXT && offsetX > 0) + || (direction == Direction.PREV && offsetX < 0) + ) return + curPage?.translationX = offsetX } override fun onScrollStop() { + curPage?.x = 0.toFloat() + if (!isCancel) { + pageView.fillPage(direction) + } } } \ No newline at end of file From 3f13a65d7f1e59f82e5ae58de85a5dcb2d5a892d Mon Sep 17 00:00:00 2001 From: Administrator <1760316362@qq.com> Date: Thu, 22 Aug 2019 16:09:18 +0800 Subject: [PATCH 0887/1997] update SlidePageDelegate --- .../widget/page/delegate/CoverPageDelegate.kt | 3 +-- .../ui/widget/page/delegate/PageDelegate.kt | 24 +++++++------------ .../page/delegate/SimulationPageDelegate.kt | 15 ++++++++++++ .../widget/page/delegate/SlidePageDelegate.kt | 3 +-- 4 files changed, 25 insertions(+), 20 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/CoverPageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/CoverPageDelegate.kt index a0a5bde9e..ccab1295f 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/CoverPageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/CoverPageDelegate.kt @@ -43,8 +43,7 @@ class CoverPageDelegate(pageView: PageView) : PageDelegate(pageView) { } } - scroller.startScroll(touchX.toInt(), 0, distanceX.toInt(), 0, getDuration(distanceX)) - start() + startScroll(touchX.toInt(), 0, distanceX.toInt(), 0) } override fun onScrollStop() { diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt index ea32785c7..9261a0e06 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt @@ -6,6 +6,7 @@ import android.view.GestureDetector import android.view.MotionEvent import android.widget.Scroller import androidx.interpolator.view.animation.FastOutLinearInInterpolator +import io.legado.app.service.ReadAloudService.Companion.stop import io.legado.app.ui.widget.page.ContentView import io.legado.app.ui.widget.page.PageView import io.legado.app.utils.screenshot @@ -34,7 +35,7 @@ abstract class PageDelegate(protected val pageView: PageView) { protected var viewWidth: Int = pageView.width protected var viewHeight: Int = pageView.height - protected val scroller: Scroller by lazy { Scroller(pageView.context, FastOutLinearInInterpolator()) } + private val scroller: Scroller by lazy { Scroller(pageView.context, FastOutLinearInInterpolator()) } private val detector: GestureDetector by lazy { GestureDetector(pageView.context, GestureListener()) } @@ -71,13 +72,14 @@ abstract class PageDelegate(protected val pageView: PageView) { pageView.invalidate() } - protected fun start() { + protected fun startScroll(startX: Int, startY: Int, dx: Int, dy: Int) { + scroller.startScroll(startX, startY, dx, dy, getDuration((if(dx !=0) dx else dy).toFloat())) isRunning = true isStarted = true invalidate() } - protected fun stop() { + protected fun stopScroll() { isRunning = false isStarted = false bitmap = null @@ -101,7 +103,7 @@ abstract class PageDelegate(protected val pageView: PageView) { } else if (isStarted) { setTouchPoint(scroller.finalX.toFloat(), scroller.finalY.toFloat(), false) onScrollStop() - stop() + stopScroll() } } @@ -162,14 +164,14 @@ abstract class PageDelegate(protected val pageView: PageView) { abstract fun onScrollStop()//scroller finish open fun onScroll() {//移动contentView, slidePage - } enum class Direction { NONE, PREV, NEXT } - private inner class GestureListener : GestureDetector.OnGestureListener { + + private inner class GestureListener : GestureDetector.SimpleOnGestureListener() { override fun onDown(e: MotionEvent): Boolean { // abort() @@ -188,8 +190,6 @@ abstract class PageDelegate(protected val pageView: PageView) { return true } - override fun onShowPress(e: MotionEvent) {} - override fun onSingleTapUp(e: MotionEvent): Boolean { val x = e.x val y = e.y @@ -253,14 +253,6 @@ abstract class PageDelegate(protected val pageView: PageView) { } return isMoved } - - override fun onLongPress(e: MotionEvent) { - - } - - override fun onFling(e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean { - return false - } } interface PageInterface { diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt new file mode 100644 index 000000000..2020e3a60 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt @@ -0,0 +1,15 @@ +package io.legado.app.ui.widget.page.delegate + +import android.graphics.Canvas +import io.legado.app.ui.widget.page.PageView + +class SimulationPageDelegate(pageView: PageView) : PageDelegate(pageView) { + override fun onScrollStart() { + } + + override fun onDraw(canvas: Canvas) { + } + + override fun onScrollStop() { + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/SlidePageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/SlidePageDelegate.kt index 434c45de1..584a4aa2e 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/SlidePageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/SlidePageDelegate.kt @@ -27,8 +27,7 @@ class SlidePageDelegate(pageView: PageView) : PageDelegate(pageView) { } } - scroller.startScroll(touchX.toInt(), 0, distanceX.toInt(), 0, getDuration(distanceX)) - start() + startScroll(touchX.toInt(), 0, distanceX.toInt(), 0) } override fun onDraw(canvas: Canvas) { From 4d4a4e0a7903da1792675661bda1573e448130c1 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 22 Aug 2019 16:15:25 +0800 Subject: [PATCH 0888/1997] up --- .../app/lib/theme/prefs/IconListPreference.kt | 96 ------------------- app/src/main/res/xml/pref_config.xml | 7 ++ app/src/main/res/xml/pref_config_read.xml | 5 + 3 files changed, 12 insertions(+), 96 deletions(-) delete mode 100644 app/src/main/java/io/legado/app/lib/theme/prefs/IconListPreference.kt diff --git a/app/src/main/java/io/legado/app/lib/theme/prefs/IconListPreference.kt b/app/src/main/java/io/legado/app/lib/theme/prefs/IconListPreference.kt deleted file mode 100644 index d78849b3e..000000000 --- a/app/src/main/java/io/legado/app/lib/theme/prefs/IconListPreference.kt +++ /dev/null @@ -1,96 +0,0 @@ -package io.legado.app.lib.theme.prefs - -import android.annotation.SuppressLint -import android.app.Activity -import android.app.AlertDialog.Builder -import android.content.Context -import android.graphics.drawable.Drawable -import android.preference.ListPreference -import android.util.AttributeSet -import android.view.View -import android.view.ViewGroup -import android.widget.ArrayAdapter -import android.widget.CheckedTextView -import android.widget.ImageView -import android.widget.ListAdapter -import io.legado.app.R -import java.util.* - - -class IconListPreference(context: Context, attrs: AttributeSet) : ListPreference(context, attrs) { - - private val mEntryDrawables = ArrayList() - - init { - - val a = context.theme.obtainStyledAttributes(attrs, R.styleable.IconListPreference, 0, 0) - - val drawables: Array - - try { - drawables = a.getTextArray(R.styleable.IconListPreference_icons) - } finally { - a.recycle() - } - - for (drawable in drawables) { - val resId = context.resources.getIdentifier(drawable.toString(), "mipmap", context.packageName) - - @Suppress("DEPRECATION") - val d = context.resources.getDrawable(resId) - - mEntryDrawables.add(d) - } - - widgetLayoutResource = R.layout.view_icon - } - - protected fun createListAdapter(): ListAdapter { - val selectedValue = value - val selectedIndex = findIndexOfValue(selectedValue) - return AppArrayAdapter(context, R.layout.item_icon_preference, entries, mEntryDrawables, selectedIndex) - } - - override fun onBindView(view: View) { - super.onBindView(view) - - val selectedValue = value - val selectedIndex = findIndexOfValue(selectedValue) - - val drawable = mEntryDrawables[selectedIndex] - - (view.findViewById(R.id.preview) as ImageView).setImageDrawable(drawable) - } - - override fun onPrepareDialogBuilder(builder: Builder) { - builder.setAdapter(createListAdapter(), this) - super.onPrepareDialogBuilder(builder) - } - - inner class AppArrayAdapter( - context: Context, textViewResourceId: Int, - objects: Array, imageDrawables: List, - selectedIndex: Int - ) : ArrayAdapter(context, textViewResourceId, objects) { - private var mImageDrawables: List? = null - private var mSelectedIndex = 0 - - init { - mSelectedIndex = selectedIndex - mImageDrawables = imageDrawables - } - - @SuppressLint("ViewHolder") - override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { - val inflater = (context as Activity).layoutInflater - val view = inflater.inflate(R.layout.item_icon_preference, parent, false) - val textView = view.findViewById(R.id.label) as CheckedTextView - textView.text = getItem(position) - textView.isChecked = position == mSelectedIndex - - val imageView = view.findViewById(R.id.icon) as ImageView - imageView.setImageDrawable(mImageDrawables!![position]) - return view - } - } -} diff --git a/app/src/main/res/xml/pref_config.xml b/app/src/main/res/xml/pref_config.xml index b6656a907..043eb7cbc 100644 --- a/app/src/main/res/xml/pref_config.xml +++ b/app/src/main/res/xml/pref_config.xml @@ -17,4 +17,11 @@ app:iconSpaceReserved="false" /> + + \ No newline at end of file diff --git a/app/src/main/res/xml/pref_config_read.xml b/app/src/main/res/xml/pref_config_read.xml index 9b52e4753..06ddce418 100644 --- a/app/src/main/res/xml/pref_config_read.xml +++ b/app/src/main/res/xml/pref_config_read.xml @@ -8,5 +8,10 @@ android:key="hideStatusBar" app:iconSpaceReserved="false" /> + \ No newline at end of file From 2949d7200a46a6298e0be37d00ba9add359aff1d Mon Sep 17 00:00:00 2001 From: Administrator <1760316362@qq.com> Date: Thu, 22 Aug 2019 16:28:48 +0800 Subject: [PATCH 0889/1997] update SlidePageDelegate --- .../legado/app/ui/widget/page/ContentView.kt | 6 +++-- .../io/legado/app/ui/widget/page/PageView.kt | 22 +++++++++---------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index e2c15ee03..732a85b49 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -54,7 +54,9 @@ class ContentView : FrameLayout { } - fun setContent(text: CharSequence?) { - content_text_view.text = text + fun setContent(page: TextPage?) { + content_text_view.text = page?.text + + //bottom_status_bar draw index } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 1269c6387..6dc20664b 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -99,26 +99,26 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att when (chapterOnDur) { 0 -> { cb.textChapter()?.let { - curPage?.setContent(it.page(cb.durChapterPos(it.pageSize()))?.text) + curPage?.setContent(it.page(cb.durChapterPos(it.pageSize()))) if (cb.durChapterPos(it.pageSize()) > 0) { - prevPage?.setContent(it.page(cb.durChapterPos(it.pageSize()) - 1)?.text) + prevPage?.setContent(it.page(cb.durChapterPos(it.pageSize()) - 1)) } if (cb.durChapterPos(it.pageSize()) < it.pageSize() - 1) { - nextPage?.setContent(it.page(cb.durChapterPos(it.pageSize()) + 1)?.text) + nextPage?.setContent(it.page(cb.durChapterPos(it.pageSize()) + 1)) } } } 1 -> { cb.textChapter()?.let { if (cb.durChapterPos(it.pageSize()) == it.pageSize() - 1) { - nextPage?.setContent(cb.textChapter(1)?.page(0)?.text) + nextPage?.setContent(cb.textChapter(1)?.page(0)) } } } -1 -> { cb.textChapter()?.let { if (cb.durChapterPos(it.pageSize()) == 0) { - prevPage?.setContent(cb.textChapter(-1)?.lastPage()?.text) + prevPage?.setContent(cb.textChapter(-1)?.lastPage()) } } } @@ -143,9 +143,9 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att } } - prevPage?.setContent(it.previousPage()?.text) - curPage?.setContent(it.currentPage()?.text) - nextPage?.setContent(it.nextPage()?.text) + prevPage?.setContent(it.previousPage()) + curPage?.setContent(it.currentPage()) + nextPage?.setContent(it.nextPage()) } } @@ -154,9 +154,9 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att //可做成异步回调 pageFactory?.let { - prevPage?.setContent(it.previousPage()?.text) - curPage?.setContent(it.currentPage()?.text) - nextPage?.setContent(it.nextPage()?.text) + prevPage?.setContent(it.previousPage()) + curPage?.setContent(it.currentPage()) + nextPage?.setContent(it.nextPage()) } } From fb7664736243661a1816cc2705204fa1b4d91c17 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 22 Aug 2019 17:25:47 +0800 Subject: [PATCH 0890/1997] up --- .../legado/app/ui/readbook/ReadBottomMenu.kt | 77 ++++--------------- .../main/res/layout/view_read_bottom_menu.xml | 44 +---------- 2 files changed, 16 insertions(+), 105 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBottomMenu.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBottomMenu.kt index df655a94c..b507675e7 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBottomMenu.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBottomMenu.kt @@ -6,8 +6,7 @@ import android.widget.FrameLayout import android.widget.SeekBar import io.legado.app.R import io.legado.app.service.ReadAloudService -import io.legado.app.utils.gone -import io.legado.app.utils.visible +import io.legado.app.utils.isNightTheme import kotlinx.android.synthetic.main.view_read_bottom_menu.view.* import org.jetbrains.anko.sdk27.listeners.onClick import org.jetbrains.anko.sdk27.listeners.onLongClick @@ -16,42 +15,37 @@ class ReadBottomMenu : FrameLayout { private var callback: Callback? = null - val readProgress: SeekBar - get() = hpb_read_progress + constructor(context: Context) : super(context) - constructor(context: Context) : super(context) { - init(context) - } - - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { - init(context) - } + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { - init(context) - } + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) - private fun init(context: Context) { + init { inflate(context, R.layout.view_read_bottom_menu, this) + if (context.isNightTheme) { + fabNightTheme.setImageResource(R.drawable.ic_daytime) + } else { + fabNightTheme.setImageResource(R.drawable.ic_brightness) + } vw_bg.onClick { } vwNavigationBar.onClick { } } - fun setNavigationBarHeight(height: Int) { - vwNavigationBar.layoutParams.height = height - } - fun setListener(callback: Callback) { this.callback = callback bindEvent() } private fun bindEvent() { - ll_read_aloud_timer.onClick { callback?.dismiss() } ll_floating_button.onClick { callback?.dismiss() } //阅读进度 - hpb_read_progress.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { + seek_bar_read_page.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { override fun onProgressChanged(seekBar: SeekBar, i: Int, b: Boolean) { } @@ -65,9 +59,6 @@ class ReadBottomMenu : FrameLayout { } }) - //朗读定时 - fab_read_aloud_timer.onClick { } - //朗读 fab_read_aloud.onClick { callback?.clickReadAloud() } //长按停止朗读 @@ -102,36 +93,6 @@ class ReadBottomMenu : FrameLayout { //设置 ll_setting.onClick { callback?.showMoreSetting() } - - tv_read_aloud_timer.onClick { } - } - - fun setFabReadAloudImage(id: Int) { - fab_read_aloud.setImageResource(id) - } - - fun setReadAloudTimer(visibility: Boolean) { - if (visibility) { - ll_read_aloud_timer.visible() - } else { - ll_read_aloud_timer.gone() - } - } - - fun setReadAloudTimer(text: String) { - tv_read_aloud_timer.text = text - } - - fun setFabReadAloudText(text: String) { - fab_read_aloud.contentDescription = text - } - - fun setTvPre(enable: Boolean) { - tv_pre.isEnabled = enable - } - - fun setTvNext(enable: Boolean) { - tv_next.isEnabled = enable } fun setAutoPage(autoPage: Boolean) { @@ -144,14 +105,6 @@ class ReadBottomMenu : FrameLayout { } } - fun setFabNightTheme(isNightTheme: Boolean) { - if (isNightTheme) { - fabNightTheme.setImageResource(R.drawable.ic_daytime) - } else { - fabNightTheme.setImageResource(R.drawable.ic_brightness) - } - } - interface Callback { fun skipToPage(page: Int) diff --git a/app/src/main/res/layout/view_read_bottom_menu.xml b/app/src/main/res/layout/view_read_bottom_menu.xml index 7dc266d02..1e6a091bb 100644 --- a/app/src/main/res/layout/view_read_bottom_menu.xml +++ b/app/src/main/res/layout/view_read_bottom_menu.xml @@ -6,48 +6,6 @@ android:layout_height="wrap_content" android:orientation="vertical"> - - - - - - - - - - - Date: Thu, 22 Aug 2019 17:31:10 +0800 Subject: [PATCH 0891/1997] up --- .../java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt index af66e4031..2957d9953 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt @@ -1,7 +1,6 @@ package io.legado.app.ui.replacerule import android.os.Bundle -import android.util.Log import androidx.core.content.ContextCompat import androidx.lifecycle.LiveData import androidx.lifecycle.Observer @@ -14,7 +13,6 @@ import androidx.recyclerview.widget.RecyclerView import io.legado.app.App import io.legado.app.R import io.legado.app.base.VMBaseActivity -import io.legado.app.constant.AppConst.APP_TAG import io.legado.app.data.entities.ReplaceRule import io.legado.app.lib.theme.ATH import io.legado.app.utils.getViewModel @@ -68,7 +66,6 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi rv_replace_rule.addItemDecoration( DividerItemDecoration(this, DividerItemDecoration.VERTICAL).apply { ContextCompat.getDrawable(baseContext, R.drawable.ic_divider)?.let { - Log.e(APP_TAG, it.toString()) this.setDrawable(it) } }) From 565e2a86e42dc97ca72b4650173e3c1cc4d3fe6f Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 22 Aug 2019 17:55:24 +0800 Subject: [PATCH 0892/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 4 +- .../{ReadBottomMenu.kt => ReadMenu.kt} | 6 +- .../main/res/layout/activity_read_book.xml | 47 +-- .../main/res/layout/view_read_bottom_menu.xml | 326 --------------- app/src/main/res/layout/view_read_menu.xml | 370 ++++++++++++++++++ 5 files changed, 379 insertions(+), 374 deletions(-) rename app/src/main/java/io/legado/app/ui/readbook/{ReadBottomMenu.kt => ReadMenu.kt} (95%) delete mode 100644 app/src/main/res/layout/view_read_bottom_menu.xml create mode 100644 app/src/main/res/layout/view_read_menu.xml diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index b5a851298..760b285c4 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -27,6 +27,7 @@ import io.legado.app.ui.widget.page.TextChapter import io.legado.app.utils.* import kotlinx.android.synthetic.main.activity_read_book.* import kotlinx.android.synthetic.main.view_book_page.* +import kotlinx.android.synthetic.main.view_read_menu.* import kotlinx.android.synthetic.main.view_title_bar.* import kotlinx.coroutines.launch import org.jetbrains.anko.sdk27.listeners.onClick @@ -119,7 +120,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea tv_chapter_url.onClick { } - bottom_menu.setListener(object : ReadBottomMenu.Callback { + fl_menu.setListener(object : ReadMenu.Callback { override fun skipToPage(page: Int) { } @@ -260,6 +261,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } viewModel.curTextChapter = ChapterProvider.getTextChapter(content_text_view, bookChapter, content) page_view.chapterLoadFinish() + } viewModel.durChapterIndex - 1 -> { viewModel.prevTextChapter = ChapterProvider.getTextChapter(content_text_view, bookChapter, content) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBottomMenu.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt similarity index 95% rename from app/src/main/java/io/legado/app/ui/readbook/ReadBottomMenu.kt rename to app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt index b507675e7..ef58c8445 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBottomMenu.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt @@ -7,11 +7,11 @@ import android.widget.SeekBar import io.legado.app.R import io.legado.app.service.ReadAloudService import io.legado.app.utils.isNightTheme -import kotlinx.android.synthetic.main.view_read_bottom_menu.view.* +import kotlinx.android.synthetic.main.view_read_menu.view.* import org.jetbrains.anko.sdk27.listeners.onClick import org.jetbrains.anko.sdk27.listeners.onLongClick -class ReadBottomMenu : FrameLayout { +class ReadMenu : FrameLayout { private var callback: Callback? = null @@ -26,7 +26,7 @@ class ReadBottomMenu : FrameLayout { ) init { - inflate(context, R.layout.view_read_bottom_menu, this) + inflate(context, R.layout.view_read_menu, this) if (context.isNightTheme) { fabNightTheme.setImageResource(R.drawable.ic_daytime) } else { diff --git a/app/src/main/res/layout/activity_read_book.xml b/app/src/main/res/layout/activity_read_book.xml index 7e72bc822..723bc9a00 100644 --- a/app/src/main/res/layout/activity_read_book.xml +++ b/app/src/main/res/layout/activity_read_book.xml @@ -15,52 +15,11 @@ android:layout_width="match_parent" android:layout_height="match_parent" /> - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/view_read_bottom_menu.xml b/app/src/main/res/layout/view_read_bottom_menu.xml deleted file mode 100644 index 1e6a091bb..000000000 --- a/app/src/main/res/layout/view_read_bottom_menu.xml +++ /dev/null @@ -1,326 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/view_read_menu.xml b/app/src/main/res/layout/view_read_menu.xml new file mode 100644 index 000000000..27bdc85fc --- /dev/null +++ b/app/src/main/res/layout/view_read_menu.xml @@ -0,0 +1,370 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 1887ce05cb4eeb5aa786a9d213c9c1c5ba48b9fd Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 22 Aug 2019 18:02:49 +0800 Subject: [PATCH 0893/1997] up --- app/src/main/res/layout/view_read_menu.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/layout/view_read_menu.xml b/app/src/main/res/layout/view_read_menu.xml index 27bdc85fc..06a747850 100644 --- a/app/src/main/res/layout/view_read_menu.xml +++ b/app/src/main/res/layout/view_read_menu.xml @@ -9,7 +9,9 @@ + android:layout_height="match_parent" + tools:layout_editor_absoluteX="0dp" + tools:layout_editor_absoluteY="0dp" /> Date: Thu, 22 Aug 2019 20:15:08 +0800 Subject: [PATCH 0894/1997] up --- .../java/io/legado/app/ui/readbook/ReadBookActivity.kt | 3 ++- .../java/io/legado/app/ui/readbook/ReadBookViewModel.kt | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 760b285c4..5b33ef5b6 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -55,6 +55,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea initView() viewModel.callBack = this viewModel.bookData.observe(this, Observer { title_bar.title = it.name }) + viewModel.chapterListFinish.observe(this, Observer { bookLoadFinish() }) viewModel.initData(intent) savedInstanceState?.let { changeSourceDialog = supportFragmentManager.findFragmentByTag(ChangeSourceDialog.tag) as? ChangeSourceDialog @@ -235,7 +236,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } - override fun bookLoadFinish() { + fun bookLoadFinish() { viewModel.bookData.value?.let { viewModel.loadContent(it, viewModel.durChapterIndex) viewModel.loadContent(it, viewModel.durChapterIndex + 1) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index 8c0c0c3cc..b3105599f 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -19,6 +19,7 @@ import kotlinx.coroutines.Dispatchers.IO class ReadBookViewModel(application: Application) : BaseViewModel(application) { var inBookshelf = false var bookData = MutableLiveData() + val chapterListFinish = MutableLiveData() var chapterSize = 0 var bookSource: BookSource? = null var webBook: WebBook? = null @@ -58,7 +59,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { durChapterIndex = count - 1 } chapterSize = count - callBack?.bookLoadFinish() + chapterListFinish.postValue(true) } } @@ -82,7 +83,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { if (!cList.isNullOrEmpty()) { App.db.bookChapterDao().insert(*cList.toTypedArray()) chapterSize = cList.size - callBack?.bookLoadFinish() + chapterListFinish.postValue(true) } else { toast(R.string.error_load_toc) } @@ -175,7 +176,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { durPageIndex = 0 } saveRead() - callBack?.bookLoadFinish() + chapterListFinish.postValue(true) } fun saveRead() { @@ -194,7 +195,6 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } interface CallBack { - fun bookLoadFinish() fun contentLoadFinish(bookChapter: BookChapter, content: String) } } \ No newline at end of file From e26532ec7f97df5984f9d172fc9c7195c7aadc04 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 22 Aug 2019 20:28:07 +0800 Subject: [PATCH 0895/1997] up --- .../legado/app/ui/chapterlist/ChapterListAdapter.kt | 12 +++++++++--- .../legado/app/ui/chapterlist/ChapterListFragment.kt | 4 ++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListAdapter.kt b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListAdapter.kt index 44f690f52..aff557711 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListAdapter.kt @@ -7,7 +7,9 @@ import androidx.paging.PagedListAdapter import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import io.legado.app.R +import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter +import io.legado.app.help.BookHelp import io.legado.app.lib.theme.accentColor import io.legado.app.utils.getCompatColor import kotlinx.android.synthetic.main.item_bookmark.view.* @@ -41,9 +43,9 @@ class ChapterListAdapter(val callback: Callback) : class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { - fun bind(bookChapter: BookChapter, callback: Callback?) = with(itemView) { + fun bind(bookChapter: BookChapter, callback: Callback) = with(itemView) { tv_chapter_name.text = bookChapter.title - callback?.let { + callback.let { if (it.durChapterIndex() == bookChapter.index) { tv_chapter_name.setTextColor(context.accentColor) } else { @@ -51,12 +53,16 @@ class ChapterListAdapter(val callback: Callback) : } } itemView.onClick { - callback?.openChapter(bookChapter) + callback.openChapter(bookChapter) + } + callback.book()?.let { + tv_chapter_name.paint.isFakeBoldText = BookHelp.hasContent(it, bookChapter) } } } interface Callback { + fun book(): Book? fun openChapter(bookChapter: BookChapter) fun durChapterIndex(): Int } diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt index 390de1a0c..dacc8a851 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt +++ b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt @@ -87,4 +87,8 @@ class ChapterListFragment : VMBaseFragment(R.layout.fragme postEvent(Bus.OPEN_CHAPTER, bookChapter) activity?.finish() } + + override fun book(): Book? { + return viewModel.bookDate.value + } } \ No newline at end of file From 930e4ae6fb637c2fa59636812bafa1967752586b Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 22 Aug 2019 20:52:33 +0800 Subject: [PATCH 0896/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 1 + .../legado/app/ui/widget/page/ContentView.kt | 2 +- .../app/ui/widget/page/TextPageFactory.kt | 10 ++-- app/src/main/res/layout/view_book_page.xml | 49 +++++++++++++------ 4 files changed, 42 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 5b33ef5b6..7322806bb 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -53,6 +53,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea setSupportActionBar(toolbar) initAnimation() initView() + page_view.callback = this viewModel.callBack = this viewModel.bookData.observe(this, Observer { title_bar.title = it.name }) viewModel.chapterListFinish.observe(this, Observer { bookLoadFinish() }) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index 732a85b49..fbd02d20b 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -57,6 +57,6 @@ class ContentView : FrameLayout { fun setContent(page: TextPage?) { content_text_view.text = page?.text - //bottom_status_bar draw index + tv_bottom_right.text = page?.index?.toString() } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt index 31fb586b2..fdc94f27a 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt @@ -47,16 +47,18 @@ class TextPageFactory private constructor(dataSource: DataSource) : PageFactory< } override fun currentPage(): TextPage? { -// return dataSource.getCurrentChapter()?.page(index) - return TextPage(index, "index:$index") + return dataSource.getCurrentChapter()?.page(index) +// return TextPage(index, "index:$index") } override fun nextPage(): TextPage? { - return TextPage(index + 1, "index:${index + 1}") + return dataSource.getCurrentChapter()?.page(index + 1) +// return TextPage(index + 1, "index:${index + 1}") } override fun previousPage(): TextPage? { - return TextPage(index - 1, "index:${index - 1}") + return dataSource.getCurrentChapter()?.page(index - 1) +// return TextPage(index - 1, "index:${index - 1}") } diff --git a/app/src/main/res/layout/view_book_page.xml b/app/src/main/res/layout/view_book_page.xml index db1dd5bf9..3ffff8da2 100644 --- a/app/src/main/res/layout/view_book_page.xml +++ b/app/src/main/res/layout/view_book_page.xml @@ -8,27 +8,46 @@ app:divider="@drawable/ic_divider" app:showDividers="middle"> - + android:layout_height="wrap_content" + android:orientation="horizontal"> - + + + + + + + android:layout_weight="1" /> - + - + - + + + \ No newline at end of file From fbdc44ec1750bc4dfa425827fac390ba098649b3 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 22 Aug 2019 21:08:00 +0800 Subject: [PATCH 0897/1997] up --- .../java/io/legado/app/ui/widget/page/ContentView.kt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index fbd02d20b..a5868195a 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -9,6 +9,8 @@ import io.legado.app.R import io.legado.app.help.ImageLoader import io.legado.app.help.ReadBookConfig import io.legado.app.utils.dp +import io.legado.app.utils.getPrefBoolean +import io.legado.app.utils.getStatusBarHeight import kotlinx.android.synthetic.main.view_book_page.view.* import org.jetbrains.anko.matchParent @@ -31,7 +33,12 @@ class ContentView : FrameLayout { fun upStyle() { ReadBookConfig.getConfig().apply { - page_panel.setPadding(paddingLeft.dp, paddingTop.dp, paddingRight.dp, paddingBottom.dp) + val pt = if (context.getPrefBoolean("hideStatusBar", false)) { + paddingTop.dp + } else { + paddingTop.dp + context.getStatusBarHeight() + } + page_panel.setPadding(paddingLeft.dp, pt, paddingRight.dp, paddingBottom.dp) content_text_view.textSize = textSize.toFloat() content_text_view.setLineSpacing(lineSpacingExtra, lineSpacingMultiplier) content_text_view.letterSpacing = letterSpacing From 47e0b60317f81ad071b37abd83f37011d02baddd Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 22 Aug 2019 21:45:10 +0800 Subject: [PATCH 0898/1997] up --- .../legado/app/ui/widget/page/TextPageFactory.kt | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt index fdc94f27a..6421b788a 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt @@ -47,18 +47,21 @@ class TextPageFactory private constructor(dataSource: DataSource) : PageFactory< } override fun currentPage(): TextPage? { - return dataSource.getCurrentChapter()?.page(index) -// return TextPage(index, "index:$index") + return dataSource.getCurrentChapter()?.page(index) ?: TextPage(index, "index:$index") } override fun nextPage(): TextPage? { - return dataSource.getCurrentChapter()?.page(index + 1) -// return TextPage(index + 1, "index:${index + 1}") + return dataSource.getCurrentChapter()?.page(index + 1) ?: TextPage( + index + 1, + "index:${index + 1}" + ) } override fun previousPage(): TextPage? { - return dataSource.getCurrentChapter()?.page(index - 1) -// return TextPage(index - 1, "index:${index - 1}") + return dataSource.getCurrentChapter()?.page(index - 1) ?: TextPage( + index - 1, + "index:${index - 1}" + ) } From e610f9fd34f75383c235a4e1ade810bcf7cd5524 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 22 Aug 2019 21:46:08 +0800 Subject: [PATCH 0899/1997] up --- .../legado/app/ui/widget/page/TextPageFactory.kt | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt index 6421b788a..16b06e23b 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt @@ -47,21 +47,18 @@ class TextPageFactory private constructor(dataSource: DataSource) : PageFactory< } override fun currentPage(): TextPage? { - return dataSource.getCurrentChapter()?.page(index) ?: TextPage(index, "index:$index") + return dataSource.getCurrentChapter()?.page(index) + ?: TextPage(index, "index:$index") } override fun nextPage(): TextPage? { - return dataSource.getCurrentChapter()?.page(index + 1) ?: TextPage( - index + 1, - "index:${index + 1}" - ) + return dataSource.getCurrentChapter()?.page(index + 1) + ?: TextPage(index + 1, "index:${index + 1}") } override fun previousPage(): TextPage? { - return dataSource.getCurrentChapter()?.page(index - 1) ?: TextPage( - index - 1, - "index:${index - 1}" - ) + return dataSource.getCurrentChapter()?.page(index - 1) + ?: TextPage(index - 1, "index:${index - 1}") } From ed7e94aee7b3f0db9ce1417dd3f1e840acd657b4 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 22 Aug 2019 22:10:01 +0800 Subject: [PATCH 0900/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 2 +- .../app/ui/readbook/ReadBookViewModel.kt | 2 +- .../app/ui/widget/page/TextPageFactory.kt | 25 ++++++++++++------- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 7322806bb..6616805de 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -237,7 +237,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } - fun bookLoadFinish() { + private fun bookLoadFinish() { viewModel.bookData.value?.let { viewModel.loadContent(it, viewModel.durChapterIndex) viewModel.loadContent(it, viewModel.durChapterIndex + 1) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index b3105599f..ba3c9b845 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -39,10 +39,10 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { if (!bookUrl.isNullOrEmpty()) { execute { App.db.bookDao().getBook(bookUrl)?.let { book -> - bookData.postValue(book) durChapterIndex = book.durChapterIndex durPageIndex = book.durChapterPos isLocalBook = book.origin == BookType.local + bookData.postValue(book) bookSource = App.db.bookSourceDao().getBookSource(book.origin) bookSource?.let { webBook = WebBook(it) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt index 16b06e23b..7fe165942 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt @@ -1,14 +1,15 @@ package io.legado.app.ui.widget.page -class TextPageFactory private constructor(dataSource: DataSource) : PageFactory(dataSource) { +class TextPageFactory private constructor(dataSource: DataSource) : + PageFactory(dataSource) { - companion object{ - fun create(dataSource: DataSource): TextPageFactory{ + companion object { + fun create(dataSource: DataSource): TextPageFactory { return TextPageFactory(dataSource) } } - private var index: Int = 0 + var index: Int = 0 override fun hasPrev(): Boolean { return true @@ -27,22 +28,28 @@ class TextPageFactory private constructor(dataSource: DataSource) : PageFactory< } override fun moveToLast() { - + index = dataSource.getCurrentChapter()?.let { + if (it.pageSize() == 0) { + 0 + } else { + it.pageSize() - 1 + } + } ?: 0 } override fun moveToNext(): Boolean { - return if(hasNext()){ + return if (hasNext()) { index = index.plus(1) true - }else + } else false } override fun moveToPrevious(): Boolean { - return if(hasPrev()){ + return if (hasPrev()) { index = index.minus(1) true - }else + } else false } From 5891a8c40b491ecf0772fe141a1db77522afc6e1 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 22 Aug 2019 22:42:47 +0800 Subject: [PATCH 0901/1997] up --- .../java/io/legado/app/constant/AppConst.kt | 19 ++++++++++++++----- .../legado/app/ui/widget/page/ContentView.kt | 14 ++++++++++---- app/src/main/res/layout/view_book_page.xml | 2 ++ app/src/main/res/values/strings.xml | 2 +- 4 files changed, 27 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/io/legado/app/constant/AppConst.kt b/app/src/main/java/io/legado/app/constant/AppConst.kt index b414786c6..3d86a738b 100644 --- a/app/src/main/java/io/legado/app/constant/AppConst.kt +++ b/app/src/main/java/io/legado/app/constant/AppConst.kt @@ -1,12 +1,15 @@ package io.legado.app.constant +import android.annotation.SuppressLint import com.google.gson.Gson import com.google.gson.GsonBuilder import io.legado.app.App import io.legado.app.R +import java.text.SimpleDateFormat import javax.script.ScriptEngine import javax.script.ScriptEngineManager +@SuppressLint("SimpleDateFormat") object AppConst { const val channelIdDownload = "channel_download" const val channelIdReadAloud = "channel_read_aloud" @@ -21,9 +24,15 @@ object AppConst { val NOT_AVAILABLE = App.INSTANCE.getString(R.string.not_available) - val GSON_CONVERTER: Gson = GsonBuilder() - .disableHtmlEscaping() - .setPrettyPrinting() - .setDateFormat("yyyy-MM-dd HH:mm:ssZ") - .create() + val TIME_FORMAT: SimpleDateFormat by lazy { + SimpleDateFormat("HH:mm") + } + + val GSON_CONVERTER: Gson by lazy { + GsonBuilder() + .disableHtmlEscaping() + .setPrettyPrinting() + .setDateFormat("yyyy-MM-dd HH:mm:ssZ") + .create() + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index a5868195a..63bc0a8c9 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -6,13 +6,13 @@ import android.util.AttributeSet import android.widget.FrameLayout import androidx.appcompat.widget.AppCompatImageView import io.legado.app.R +import io.legado.app.constant.AppConst.TIME_FORMAT import io.legado.app.help.ImageLoader import io.legado.app.help.ReadBookConfig -import io.legado.app.utils.dp -import io.legado.app.utils.getPrefBoolean -import io.legado.app.utils.getStatusBarHeight +import io.legado.app.utils.* import kotlinx.android.synthetic.main.view_book_page.view.* import org.jetbrains.anko.matchParent +import java.util.* class ContentView : FrameLayout { @@ -34,8 +34,10 @@ class ContentView : FrameLayout { fun upStyle() { ReadBookConfig.getConfig().apply { val pt = if (context.getPrefBoolean("hideStatusBar", false)) { + top_bar.visible() paddingTop.dp } else { + top_bar.gone() paddingTop.dp + context.getStatusBarHeight() } page_panel.setPadding(paddingLeft.dp, pt, paddingRight.dp, paddingBottom.dp) @@ -54,11 +56,15 @@ class ContentView : FrameLayout { } fun upTime() { - + tv_top_left.text = TIME_FORMAT.format(Date(System.currentTimeMillis())) } fun upBattery(battery: Int) { + tv_top_right.text = context.getString(R.string.battery_show, battery) + } + fun setChapterTile(tile: String) { + tv_bottom_left.text = tile } fun setContent(page: TextPage?) { diff --git a/app/src/main/res/layout/view_book_page.xml b/app/src/main/res/layout/view_book_page.xml index 3ffff8da2..c764d4884 100644 --- a/app/src/main/res/layout/view_book_page.xml +++ b/app/src/main/res/layout/view_book_page.xml @@ -9,6 +9,7 @@ app:showDividers="middle"> @@ -33,6 +34,7 @@ android:layout_weight="1" /> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8a70911dd..02f36623c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -481,6 +481,6 @@ ]]> 阅读 - + %d%% From 73a4842748782e54faf4abb29cce3bd39833edd3 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 23 Aug 2019 09:03:16 +0800 Subject: [PATCH 0902/1997] up --- .../main/java/io/legado/app/ui/widget/page/ContentView.kt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index 63bc0a8c9..c7b1480ce 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -44,7 +44,13 @@ class ContentView : FrameLayout { content_text_view.textSize = textSize.toFloat() content_text_view.setLineSpacing(lineSpacingExtra, lineSpacingMultiplier) content_text_view.letterSpacing = letterSpacing - content_text_view.setTextColor(textColor()) + textColor().let { + content_text_view.setTextColor(it) + tv_top_left.setTextColor(it) + tv_top_right.setTextColor(it) + tv_bottom_left.setTextColor(it) + tv_bottom_right.setTextColor(it) + } } } From a6f923a09a0bf398cc964148358f97ce86b0b34a Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 23 Aug 2019 09:31:26 +0800 Subject: [PATCH 0903/1997] up --- app/src/main/assets/readConfig.json | 34 ++++++++++++++--------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/app/src/main/assets/readConfig.json b/app/src/main/assets/readConfig.json index fdd8894b5..b09b971cc 100644 --- a/app/src/main/assets/readConfig.json +++ b/app/src/main/assets/readConfig.json @@ -3,14 +3,14 @@ "bgStr": "bg1.jpg", "bgType": 1, "darkStatusIcon": true, - "textColor": "#3E3D3B", - "textSize": 16, + "textColor": "#5E432E", + "textSize": 20, "letterSpacing": 0, - "lineSpacingExtra": 15, - "lineSpacingMultiplier": 3, + "lineSpacingExtra": 10, + "lineSpacingMultiplier": 1, "paddingLeft": 16, "paddingRight": 16, - "paddingTop": 0, + "paddingTop": 10, "paddingBottom": 0 }, { @@ -18,10 +18,10 @@ "bgType": 0, "darkStatusIcon": true, "textColor": "#5E432E", - "textSize": 16, + "textSize": 20, "letterSpacing": 0, - "lineSpacingExtra": 15, - "lineSpacingMultiplier": 3, + "lineSpacingExtra": 10, + "lineSpacingMultiplier": 1, "paddingLeft": 16, "paddingRight": 16, "paddingTop": 0, @@ -32,10 +32,10 @@ "bgType": 0, "darkStatusIcon": true, "textColor": "#22482C", - "textSize": 16, + "textSize": 20, "letterSpacing": 0, - "lineSpacingExtra": 15, - "lineSpacingMultiplier": 3, + "lineSpacingExtra": 10, + "lineSpacingMultiplier": 1, "paddingLeft": 16, "paddingRight": 16, "paddingTop": 0, @@ -46,10 +46,10 @@ "bgType": 0, "darkStatusIcon": false, "textColor": "#FFFFFF", - "textSize": 16, + "textSize": 20, "letterSpacing": 0, - "lineSpacingExtra": 15, - "lineSpacingMultiplier": 3, + "lineSpacingExtra": 10, + "lineSpacingMultiplier": 1, "paddingLeft": 16, "paddingRight": 16, "paddingTop": 0, @@ -60,10 +60,10 @@ "bgType": 0, "darkStatusIcon": false, "textColor": "#adadad", - "textSize": 16, + "textSize": 20, "letterSpacing": 0, - "lineSpacingExtra": 15, - "lineSpacingMultiplier": 3, + "lineSpacingExtra": 10, + "lineSpacingMultiplier": 1, "paddingLeft": 16, "paddingRight": 16, "paddingTop": 0, From a9a8d720e60e41b0a2910496b9f7f928b5470b88 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 23 Aug 2019 11:36:56 +0800 Subject: [PATCH 0904/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 4 ++- .../ui/readbook/config/MoreConfigDialog.kt | 34 ++++++++++++++++--- .../readbook/config/ReadPreferenceFragment.kt | 14 ++++++++ 3 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/readbook/config/ReadPreferenceFragment.kt diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 6616805de..6c11b007a 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -19,6 +19,7 @@ import io.legado.app.receiver.TimeElectricityReceiver import io.legado.app.service.ReadAloudService import io.legado.app.ui.changesource.ChangeSourceDialog import io.legado.app.ui.chapterlist.ChapterListActivity +import io.legado.app.ui.readbook.config.MoreConfigDialog import io.legado.app.ui.readbook.config.ReadStyleDialog import io.legado.app.ui.replacerule.ReplaceRuleActivity import io.legado.app.ui.widget.page.ChapterProvider @@ -168,7 +169,8 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } override fun showMoreSetting() { - + runMenuOut() + MoreConfigDialog().show(supportFragmentManager, "moreConfig") } override fun toast(id: Int) { diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt index 9cbbe6270..8f52d65ef 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt @@ -1,15 +1,41 @@ package io.legado.app.ui.readbook.config import android.os.Bundle -import androidx.preference.PreferenceFragmentCompat +import android.util.DisplayMetrics +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.LinearLayout +import androidx.fragment.app.DialogFragment import io.legado.app.R -class MoreConfigDialog : PreferenceFragmentCompat() { +class MoreConfigDialog : DialogFragment() { + private val readPreferTag = "readPreferenceFragment" - override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - addPreferencesFromResource(R.xml.pref_config_read) + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + val view = LinearLayout(context) + view.id = R.id.tag1 + container?.addView(view) + return view } + override fun onStart() { + super.onStart() + val dm = DisplayMetrics() + activity?.windowManager?.defaultDisplay?.getMetrics(dm) + dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.9).toInt()) + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + var preferenceFragment = childFragmentManager.findFragmentByTag(readPreferTag) + if (preferenceFragment == null) preferenceFragment = ReadPreferenceFragment() + childFragmentManager.beginTransaction().replace(view.id, preferenceFragment, readPreferTag) + .commit() + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadPreferenceFragment.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadPreferenceFragment.kt new file mode 100644 index 000000000..d26bbf65a --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadPreferenceFragment.kt @@ -0,0 +1,14 @@ +package io.legado.app.ui.readbook.config + +import android.os.Bundle +import androidx.preference.PreferenceFragmentCompat +import io.legado.app.R + +class ReadPreferenceFragment : PreferenceFragmentCompat() { + + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + addPreferencesFromResource(R.xml.pref_config_read) + } + + +} \ No newline at end of file From b27902fee707f0b13c0ea29d37c4121c8432ef69 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 23 Aug 2019 11:38:42 +0800 Subject: [PATCH 0905/1997] up --- .../java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt index 8f52d65ef..479ce5969 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt @@ -35,7 +35,8 @@ class MoreConfigDialog : DialogFragment() { super.onViewCreated(view, savedInstanceState) var preferenceFragment = childFragmentManager.findFragmentByTag(readPreferTag) if (preferenceFragment == null) preferenceFragment = ReadPreferenceFragment() - childFragmentManager.beginTransaction().replace(view.id, preferenceFragment, readPreferTag) + childFragmentManager.beginTransaction() + .replace(view.id, preferenceFragment, readPreferTag) .commit() } } \ No newline at end of file From 3b0d9ed5ad31a7864ac88478531fec32aad5d013 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 23 Aug 2019 12:14:11 +0800 Subject: [PATCH 0906/1997] up --- .../io/legado/app/ui/readbook/ReadMenu.kt | 7 -- app/src/main/res/layout/dialog_read_aloud.xml | 91 ++++++++++++++++++- 2 files changed, 90 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt index ef58c8445..5e8320c78 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt @@ -5,11 +5,9 @@ import android.util.AttributeSet import android.widget.FrameLayout import android.widget.SeekBar import io.legado.app.R -import io.legado.app.service.ReadAloudService import io.legado.app.utils.isNightTheme import kotlinx.android.synthetic.main.view_read_menu.view.* import org.jetbrains.anko.sdk27.listeners.onClick -import org.jetbrains.anko.sdk27.listeners.onLongClick class ReadMenu : FrameLayout { @@ -61,11 +59,6 @@ class ReadMenu : FrameLayout { //朗读 fab_read_aloud.onClick { callback?.clickReadAloud() } - //长按停止朗读 - fab_read_aloud.onLongClick { - ReadAloudService.stop(context) - true - } //自动翻页 fabAutoPage.onClick { callback?.autoPage() } diff --git a/app/src/main/res/layout/dialog_read_aloud.xml b/app/src/main/res/layout/dialog_read_aloud.xml index d829e291c..866119a66 100644 --- a/app/src/main/res/layout/dialog_read_aloud.xml +++ b/app/src/main/res/layout/dialog_read_aloud.xml @@ -2,6 +2,95 @@ + android:layout_height="match_parent" + android:padding="10dp"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From e2d7351a406c455ac49807556423ab69bd40ebd3 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 23 Aug 2019 12:29:37 +0800 Subject: [PATCH 0907/1997] up --- .../app/receiver/MediaButtonReceiver.kt | 2 +- .../app/ui/readbook/ReadBookActivity.kt | 80 ++----------------- .../io/legado/app/ui/readbook/ReadMenu.kt | 75 ++++++++++++++++- 3 files changed, 81 insertions(+), 76 deletions(-) diff --git a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt index 587471648..cec51bea0 100644 --- a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt +++ b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt @@ -51,7 +51,7 @@ class MediaButtonReceiver : BroadcastReceiver() { context.startActivity() } } - postEvent(Bus.READ_ALOUD, "") + postEvent(Bus.READ_ALOUD, true) } } diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 6c11b007a..8067ef255 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -4,9 +4,6 @@ import android.os.Bundle import android.view.KeyEvent import android.view.Menu import android.view.MenuItem -import android.view.animation.Animation -import android.view.animation.AnimationUtils -import androidx.core.view.isVisible import androidx.lifecycle.Observer import io.legado.app.App import io.legado.app.R @@ -43,16 +40,10 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea private var changeSourceDialog: ChangeSourceDialog? = null private var timeElectricityReceiver: TimeElectricityReceiver? = null - private var menuBarShow: Boolean = false - private lateinit var menuTopIn: Animation - private lateinit var menuTopOut: Animation - private lateinit var menuBottomIn: Animation - private lateinit var menuBottomOut: Animation private var readAloudStatus = Status.STOP override fun onActivityCreated(savedInstanceState: Bundle?) { setSupportActionBar(toolbar) - initAnimation() initView() page_view.callback = this viewModel.callBack = this @@ -78,43 +69,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } - private fun initAnimation() { - menuTopIn = AnimationUtils.loadAnimation(this, R.anim.anim_readbook_top_in) - menuBottomIn = AnimationUtils.loadAnimation(this, R.anim.anim_readbook_bottom_in) - menuBottomIn.setAnimationListener(object : Animation.AnimationListener { - override fun onAnimationStart(animation: Animation) { - } - - override fun onAnimationEnd(animation: Animation) { - vw_menu_bg.onClick { runMenuOut() } - } - - override fun onAnimationRepeat(animation: Animation) { - - } - }) - - //隐藏菜单 - menuTopOut = AnimationUtils.loadAnimation(this, R.anim.anim_readbook_top_out) - menuBottomOut = AnimationUtils.loadAnimation(this, R.anim.anim_readbook_bottom_out) - menuBottomOut.setAnimationListener(object : Animation.AnimationListener { - override fun onAnimationStart(animation: Animation) { - vw_menu_bg.setOnClickListener(null) - } - - override fun onAnimationEnd(animation: Animation) { - fl_menu.invisible() - title_bar.invisible() - bottom_menu.invisible() - menuBarShow = false - } - - override fun onAnimationRepeat(animation: Animation) { - - } - }) - } private fun initView() { tv_chapter_name.onClick { @@ -128,10 +83,6 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } - override fun clickReadAloud() { - onClickReadAloud() - } - override fun autoPage() { } @@ -164,12 +115,12 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } override fun showReadStyle() { - runMenuOut() + fl_menu.runMenuOut() ReadStyleDialog().show(supportFragmentManager, "readStyle") } override fun showMoreSetting() { - runMenuOut() + fl_menu.runMenuOut() MoreConfigDialog().show(supportFragmentManager, "moreConfig") } @@ -178,7 +129,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } override fun dismiss() { - runMenuOut() + fl_menu.runMenuOut() } }) @@ -210,34 +161,19 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea val isDown = action == 0 if (keyCode == KeyEvent.KEYCODE_MENU) { - if (isDown && !menuBarShow) { - runMenuIn() + if (isDown && !fl_menu.menuBarShow) { + fl_menu.runMenuIn() return true } - if (!isDown && !menuBarShow) { - menuBarShow = true + if (!isDown && !fl_menu.menuBarShow) { + fl_menu.menuBarShow = true return true } } return super.dispatchKeyEvent(event) } - private fun runMenuIn() { - fl_menu.visible() - title_bar.visible() - bottom_menu.visible() - title_bar.startAnimation(menuTopIn) - bottom_menu.startAnimation(menuBottomIn) - } - private fun runMenuOut() { - if (fl_menu.isVisible) { - if (bottom_menu.isVisible) { - title_bar.startAnimation(menuTopOut) - bottom_menu.startAnimation(menuBottomOut) - } - } - } private fun bookLoadFinish() { viewModel.bookData.value?.let { @@ -335,7 +271,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea observeEvent(Bus.TIME_CHANGED) { page_view.upTime() } observeEvent(Bus.BATTERY_CHANGED) { page_view.upBattery(it) } observeEvent(Bus.OPEN_CHAPTER) { viewModel.openChapter(it) } - observeEventSticky(Bus.READ_ALOUD) { onClickReadAloud() } + observeEventSticky(Bus.READ_ALOUD) { onClickReadAloud() } observeEventSticky(Bus.UP_CONFIG) { when (it) { 0 -> { diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt index 5e8320c78..960101dfb 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt @@ -2,16 +2,28 @@ package io.legado.app.ui.readbook import android.content.Context import android.util.AttributeSet +import android.view.animation.Animation +import android.view.animation.AnimationUtils import android.widget.FrameLayout import android.widget.SeekBar +import androidx.core.view.isVisible import io.legado.app.R +import io.legado.app.constant.Bus +import io.legado.app.utils.invisible import io.legado.app.utils.isNightTheme +import io.legado.app.utils.postEvent +import io.legado.app.utils.visible import kotlinx.android.synthetic.main.view_read_menu.view.* import org.jetbrains.anko.sdk27.listeners.onClick class ReadMenu : FrameLayout { private var callback: Callback? = null + var menuBarShow: Boolean = false + private lateinit var menuTopIn: Animation + private lateinit var menuTopOut: Animation + private lateinit var menuBottomIn: Animation + private lateinit var menuBottomOut: Animation constructor(context: Context) : super(context) @@ -30,6 +42,7 @@ class ReadMenu : FrameLayout { } else { fabNightTheme.setImageResource(R.drawable.ic_brightness) } + initAnimation() vw_bg.onClick { } vwNavigationBar.onClick { } } @@ -39,6 +52,61 @@ class ReadMenu : FrameLayout { bindEvent() } + private fun initAnimation() { + menuTopIn = AnimationUtils.loadAnimation(context, R.anim.anim_readbook_top_in) + menuBottomIn = AnimationUtils.loadAnimation(context, R.anim.anim_readbook_bottom_in) + menuBottomIn.setAnimationListener(object : Animation.AnimationListener { + override fun onAnimationStart(animation: Animation) { + + } + + override fun onAnimationEnd(animation: Animation) { + vw_menu_bg.onClick { runMenuOut() } + } + + override fun onAnimationRepeat(animation: Animation) { + + } + }) + + //隐藏菜单 + menuTopOut = AnimationUtils.loadAnimation(context, R.anim.anim_readbook_top_out) + menuBottomOut = AnimationUtils.loadAnimation(context, R.anim.anim_readbook_bottom_out) + menuBottomOut.setAnimationListener(object : Animation.AnimationListener { + override fun onAnimationStart(animation: Animation) { + vw_menu_bg.setOnClickListener(null) + } + + override fun onAnimationEnd(animation: Animation) { + this@ReadMenu.invisible() + title_bar.invisible() + bottom_menu.invisible() + menuBarShow = false + } + + override fun onAnimationRepeat(animation: Animation) { + + } + }) + } + + fun runMenuIn() { + this.visible() + title_bar.visible() + bottom_menu.visible() + title_bar.startAnimation(menuTopIn) + bottom_menu.startAnimation(menuBottomIn) + } + + fun runMenuOut() { + if (this.isVisible) { + if (bottom_menu.isVisible) { + title_bar.startAnimation(menuTopOut) + bottom_menu.startAnimation(menuBottomOut) + } + } + } + private fun bindEvent() { ll_floating_button.onClick { callback?.dismiss() } @@ -58,7 +126,10 @@ class ReadMenu : FrameLayout { }) //朗读 - fab_read_aloud.onClick { callback?.clickReadAloud() } + fab_read_aloud.onClick { + postEvent(Bus.READ_ALOUD, true) + callback?.dismiss() + } //自动翻页 fabAutoPage.onClick { callback?.autoPage() } @@ -101,8 +172,6 @@ class ReadMenu : FrameLayout { interface Callback { fun skipToPage(page: Int) - fun clickReadAloud() - fun autoPage() fun setNightTheme() From ebe970344580bd169efc524f6e6314bb17f78698 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 23 Aug 2019 12:31:42 +0800 Subject: [PATCH 0908/1997] up --- .../io/legado/app/ui/readbook/ReadBookActivity.kt | 8 -------- .../main/java/io/legado/app/ui/readbook/ReadMenu.kt | 13 ++++++------- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 8067ef255..1e4ace654 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -5,7 +5,6 @@ import android.view.KeyEvent import android.view.Menu import android.view.MenuItem import androidx.lifecycle.Observer -import io.legado.app.App import io.legado.app.R import io.legado.app.base.VMBaseActivity import io.legado.app.constant.Bus @@ -69,8 +68,6 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } - - private fun initView() { tv_chapter_name.onClick { @@ -87,11 +84,6 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } - override fun setNightTheme() { - putPrefBoolean("isNightTheme", !isNightTheme) - App.INSTANCE.applyDayNight() - } - override fun skipPreChapter() { } diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt index 960101dfb..aaba5fda2 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt @@ -7,12 +7,10 @@ import android.view.animation.AnimationUtils import android.widget.FrameLayout import android.widget.SeekBar import androidx.core.view.isVisible +import io.legado.app.App import io.legado.app.R import io.legado.app.constant.Bus -import io.legado.app.utils.invisible -import io.legado.app.utils.isNightTheme -import io.legado.app.utils.postEvent -import io.legado.app.utils.visible +import io.legado.app.utils.* import kotlinx.android.synthetic.main.view_read_menu.view.* import org.jetbrains.anko.sdk27.listeners.onClick @@ -138,7 +136,10 @@ class ReadMenu : FrameLayout { fabReplaceRule.onClick { callback?.openReplaceRule() } //夜间模式 - fabNightTheme.onClick { callback?.setNightTheme() } + fabNightTheme.onClick { + context.putPrefBoolean("isNightTheme", !context.isNightTheme) + App.INSTANCE.applyDayNight() + } //上一章 tv_pre.onClick { callback?.skipPreChapter() } @@ -174,8 +175,6 @@ class ReadMenu : FrameLayout { fun autoPage() - fun setNightTheme() - fun skipPreChapter() fun skipNextChapter() From 9b27244fee38847211aae8bbccbc83857fc6a954 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 23 Aug 2019 12:35:00 +0800 Subject: [PATCH 0909/1997] up --- .../java/io/legado/app/ui/readbook/ReadBookActivity.kt | 9 --------- app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt | 8 ++------ 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 1e4ace654..9da05ab78 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -115,15 +115,6 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea fl_menu.runMenuOut() MoreConfigDialog().show(supportFragmentManager, "moreConfig") } - - override fun toast(id: Int) { - this@ReadBookActivity.toast(id) - } - - override fun dismiss() { - fl_menu.runMenuOut() - } - }) } diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt index aaba5fda2..c48fbb159 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt @@ -106,7 +106,7 @@ class ReadMenu : FrameLayout { } private fun bindEvent() { - ll_floating_button.onClick { callback?.dismiss() } + ll_floating_button.onClick { runMenuOut() } //阅读进度 seek_bar_read_page.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { @@ -126,7 +126,7 @@ class ReadMenu : FrameLayout { //朗读 fab_read_aloud.onClick { postEvent(Bus.READ_ALOUD, true) - callback?.dismiss() + runMenuOut() } //自动翻页 @@ -188,10 +188,6 @@ class ReadMenu : FrameLayout { fun showReadStyle() fun showMoreSetting() - - fun toast(id: Int) - - fun dismiss() } } From 370301ed640898d2fc6773ac5a5e0508390a1af5 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 23 Aug 2019 13:29:54 +0800 Subject: [PATCH 0910/1997] up --- .../legado/app/ui/readbook/ReadBookActivity.kt | 2 -- .../java/io/legado/app/ui/readbook/ReadMenu.kt | 17 ++++++++++++++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 9da05ab78..8d88c3baf 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -107,12 +107,10 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } override fun showReadStyle() { - fl_menu.runMenuOut() ReadStyleDialog().show(supportFragmentManager, "readStyle") } override fun showMoreSetting() { - fl_menu.runMenuOut() MoreConfigDialog().show(supportFragmentManager, "moreConfig") } }) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt index c48fbb159..7ee55318c 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt @@ -22,6 +22,7 @@ class ReadMenu : FrameLayout { private lateinit var menuTopOut: Animation private lateinit var menuBottomIn: Animation private lateinit var menuBottomOut: Animation + private var onMenuOutEnd: (() -> Unit)? = null constructor(context: Context) : super(context) @@ -80,6 +81,7 @@ class ReadMenu : FrameLayout { title_bar.invisible() bottom_menu.invisible() menuBarShow = false + onMenuOutEnd?.invoke() } override fun onAnimationRepeat(animation: Animation) { @@ -96,7 +98,8 @@ class ReadMenu : FrameLayout { bottom_menu.startAnimation(menuBottomIn) } - fun runMenuOut() { + fun runMenuOut(onMenuOutEnd: (() -> Unit)? = null) { + this.onMenuOutEnd = onMenuOutEnd if (this.isVisible) { if (bottom_menu.isVisible) { title_bar.startAnimation(menuTopOut) @@ -154,10 +157,18 @@ class ReadMenu : FrameLayout { ll_adjust.onClick { callback?.openAdjust() } //界面 - ll_font.onClick { callback?.showReadStyle() } + ll_font.onClick { + runMenuOut { + callback?.showReadStyle() + } + } //设置 - ll_setting.onClick { callback?.showMoreSetting() } + ll_setting.onClick { + runMenuOut { + callback?.showMoreSetting() + } + } } fun setAutoPage(autoPage: Boolean) { From 76a912f5e98c3a0dfe93f854e9e0cb02956a2609 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 23 Aug 2019 13:43:15 +0800 Subject: [PATCH 0911/1997] up --- app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt index 7ee55318c..2c2835074 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt @@ -151,7 +151,11 @@ class ReadMenu : FrameLayout { tv_next.onClick { callback?.skipNextChapter() } //目录 - ll_catalog.onClick { callback?.openChapterList() } + ll_catalog.onClick { + runMenuOut { + callback?.openChapterList() + } + } //调节 ll_adjust.onClick { callback?.openAdjust() } From faf62dba1f504e33340881c70262cc3f0bca0b29 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 23 Aug 2019 17:20:49 +0800 Subject: [PATCH 0912/1997] up --- .../app/ui/readbook/config/ReadAloudDialog.kt | 7 +++++ app/src/main/res/layout/dialog_read_aloud.xml | 30 +++++++++++++++++-- app/src/main/res/values/strings.xml | 1 + 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt index 58ab4a6a8..945ccc251 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt @@ -6,6 +6,7 @@ import android.view.View import android.view.ViewGroup import androidx.fragment.app.DialogFragment import io.legado.app.R +import kotlinx.android.synthetic.main.dialog_read_aloud.* class ReadAloudDialog : DialogFragment() { @@ -19,6 +20,12 @@ class ReadAloudDialog : DialogFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + initData() + } + + private fun initData() { + + seek_tts_SpeechRate.setProgress(0) } } \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_read_aloud.xml b/app/src/main/res/layout/dialog_read_aloud.xml index 866119a66..505344bfa 100644 --- a/app/src/main/res/layout/dialog_read_aloud.xml +++ b/app/src/main/res/layout/dialog_read_aloud.xml @@ -5,34 +5,58 @@ android:layout_height="match_parent" android:padding="10dp"> + + + + + + + + + android:text="@string/timer_m" /> @@ -84,7 +108,7 @@ ]]> 阅读 %d%% + %d分钟 From 213df1e0e2c6efad380c0b538441662f97e682fa Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 23 Aug 2019 17:40:28 +0800 Subject: [PATCH 0913/1997] up --- .../app/ui/readbook/config/MoreConfigDialog.kt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt index 479ce5969..4e9676a1a 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt @@ -2,6 +2,7 @@ package io.legado.app.ui.readbook.config import android.os.Bundle import android.util.DisplayMetrics +import android.view.Gravity import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -19,6 +20,7 @@ class MoreConfigDialog : DialogFragment() { savedInstanceState: Bundle? ): View? { val view = LinearLayout(context) + view.setBackgroundResource(R.color.background) view.id = R.id.tag1 container?.addView(view) return view @@ -28,7 +30,15 @@ class MoreConfigDialog : DialogFragment() { super.onStart() val dm = DisplayMetrics() activity?.windowManager?.defaultDisplay?.getMetrics(dm) - dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.9).toInt()) + dialog?.window?.let { + it.setBackgroundDrawableResource(R.color.transparent) + it.decorView.setPadding(0, 0, 0, 0) + val attr = it.attributes + attr.dimAmount = 0.0f + attr.gravity = Gravity.BOTTOM + it.attributes = attr + it.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) + } } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { From 326bba230324227d15c16197e50bc53388aa115c Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 23 Aug 2019 18:01:58 +0800 Subject: [PATCH 0914/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 22 ++++++------- .../io/legado/app/ui/readbook/ReadMenu.kt | 22 ++++++------- .../main/res/layout/activity_read_book.xml | 2 +- app/src/main/res/layout/view_read_menu.xml | 32 ++++--------------- 4 files changed, 28 insertions(+), 50 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 8d88c3baf..8e16368ac 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -75,7 +75,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea tv_chapter_url.onClick { } - fl_menu.setListener(object : ReadMenu.Callback { + read_menu.setListener(object : ReadMenu.Callback { override fun skipToPage(page: Int) { } @@ -102,10 +102,6 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } - override fun openAdjust() { - - } - override fun showReadStyle() { ReadStyleDialog().show(supportFragmentManager, "readStyle") } @@ -142,12 +138,12 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea val isDown = action == 0 if (keyCode == KeyEvent.KEYCODE_MENU) { - if (isDown && !fl_menu.menuBarShow) { - fl_menu.runMenuIn() + if (isDown && !read_menu.menuBarShow) { + read_menu.runMenuIn() return true } - if (!isDown && !fl_menu.menuBarShow) { - fl_menu.menuBarShow = true + if (!isDown && !read_menu.menuBarShow) { + read_menu.menuBarShow = true return true } } @@ -180,9 +176,11 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea tv_chapter_url.text = bookChapter.url tv_chapter_url.visible() } - viewModel.curTextChapter = ChapterProvider.getTextChapter(content_text_view, bookChapter, content) - page_view.chapterLoadFinish() - + ChapterProvider.getTextChapter(content_text_view, bookChapter, content).let { + viewModel.curTextChapter = it + page_view.chapterLoadFinish() + read_menu.upReadProgress(it.pageSize(), viewModel.durPageIndex) + } } viewModel.durChapterIndex - 1 -> { viewModel.prevTextChapter = ChapterProvider.getTextChapter(content_text_view, bookChapter, content) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt index 2c2835074..90c228841 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt @@ -108,11 +108,16 @@ class ReadMenu : FrameLayout { } } + fun upReadProgress(max: Int, dur: Int) { + seek_read_page.max = max + seek_read_page.progress = dur + } + private fun bindEvent() { ll_floating_button.onClick { runMenuOut() } //阅读进度 - seek_bar_read_page.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { + seek_read_page.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { override fun onProgressChanged(seekBar: SeekBar, i: Int, b: Boolean) { } @@ -126,12 +131,6 @@ class ReadMenu : FrameLayout { } }) - //朗读 - fab_read_aloud.onClick { - postEvent(Bus.READ_ALOUD, true) - runMenuOut() - } - //自动翻页 fabAutoPage.onClick { callback?.autoPage() } @@ -157,8 +156,11 @@ class ReadMenu : FrameLayout { } } - //调节 - ll_adjust.onClick { callback?.openAdjust() } + //朗读 + ll_read_aloud.onClick { + postEvent(Bus.READ_ALOUD, true) + runMenuOut() + } //界面 ll_font.onClick { @@ -198,8 +200,6 @@ class ReadMenu : FrameLayout { fun openChapterList() - fun openAdjust() - fun showReadStyle() fun showMoreSetting() diff --git a/app/src/main/res/layout/activity_read_book.xml b/app/src/main/res/layout/activity_read_book.xml index 723bc9a00..6fb639eb6 100644 --- a/app/src/main/res/layout/activity_read_book.xml +++ b/app/src/main/res/layout/activity_read_book.xml @@ -17,7 +17,7 @@ diff --git a/app/src/main/res/layout/view_read_menu.xml b/app/src/main/res/layout/view_read_menu.xml index 06a747850..ba84bece8 100644 --- a/app/src/main/res/layout/view_read_menu.xml +++ b/app/src/main/res/layout/view_read_menu.xml @@ -57,26 +57,6 @@ android:paddingStart="32dp" android:paddingEnd="32dp"> - - - - @@ -264,8 +244,8 @@ android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" - android:contentDescription="@string/adjust" - android:src="@drawable/ic_tune" + android:contentDescription="@string/read_aloud" + android:src="@drawable/ic_read_aloud" app:tint="@color/tv_text_default" tools:ignore="NestedWeights" /> @@ -274,7 +254,7 @@ android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="3dp" - android:text="@string/adjust" + android:text="@string/read_aloud" android:textColor="@color/tv_text_default" android:textSize="12sp" /> From ad5fd8fb28c3ebeb6dbdd55c6d629d772e198ddf Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 23 Aug 2019 18:18:01 +0800 Subject: [PATCH 0915/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 35 ++++++++++++++++--- .../io/legado/app/ui/readbook/ReadMenu.kt | 3 +- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 8e16368ac..94b4cb37e 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -1,5 +1,8 @@ package io.legado.app.ui.readbook +import android.app.Activity +import android.content.Intent +import android.net.Uri import android.os.Bundle import android.view.KeyEvent import android.view.Menu @@ -18,6 +21,7 @@ import io.legado.app.ui.chapterlist.ChapterListActivity import io.legado.app.ui.readbook.config.MoreConfigDialog import io.legado.app.ui.readbook.config.ReadStyleDialog import io.legado.app.ui.replacerule.ReplaceRuleActivity +import io.legado.app.ui.sourceedit.SourceEditActivity import io.legado.app.ui.widget.page.ChapterProvider import io.legado.app.ui.widget.page.PageView import io.legado.app.ui.widget.page.TextChapter @@ -29,6 +33,7 @@ import kotlinx.android.synthetic.main.view_title_bar.* import kotlinx.coroutines.launch import org.jetbrains.anko.sdk27.listeners.onClick import org.jetbrains.anko.startActivity +import org.jetbrains.anko.startActivityForResult class ReadBookActivity : VMBaseActivity(R.layout.activity_read_book), PageView.CallBack, @@ -37,6 +42,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea override val viewModel: ReadBookViewModel get() = getViewModel(ReadBookViewModel::class.java) + private val requestCodeEditSource = 111 private var changeSourceDialog: ChangeSourceDialog? = null private var timeElectricityReceiver: TimeElectricityReceiver? = null private var readAloudStatus = Status.STOP @@ -70,18 +76,28 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea private fun initView() { tv_chapter_name.onClick { - + viewModel.bookSource?.let { + startActivityForResult( + requestCodeEditSource, + Pair("data", it.bookSourceUrl) + ) + } } tv_chapter_url.onClick { - + runCatching { + val url = tv_chapter_url.text.toString() + val intent = Intent(Intent.ACTION_VIEW) + intent.data = Uri.parse(url) + startActivity(intent) + } } read_menu.setListener(object : ReadMenu.Callback { - override fun skipToPage(page: Int) { + override fun autoPage() { } - override fun autoPage() { - + override fun skipToPage(page: Int) { + viewModel.durPageIndex = page } override fun skipPreChapter() { @@ -265,4 +281,13 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (resultCode == Activity.RESULT_OK) { + when (requestCode) { + + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt index 90c228841..6fde199ab 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt @@ -188,10 +188,11 @@ class ReadMenu : FrameLayout { } interface Callback { - fun skipToPage(page: Int) fun autoPage() + fun skipToPage(page: Int) + fun skipPreChapter() fun skipNextChapter() From f98262629161c778c507cc0383d29d147686a50d Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 23 Aug 2019 21:15:51 +0800 Subject: [PATCH 0916/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 16 +- .../io/legado/app/ui/readbook/ReadMenu.kt | 124 +++--- .../app/ui/widget/seekbar/VerticalSeekBar.kt | 363 ++++++++++++++++++ .../widget/seekbar/VerticalSeekBarWrapper.kt | 184 +++++++++ .../main/res/drawable/ic_brightness_auto.xml | 11 + app/src/main/res/layout/view_read_menu.xml | 27 ++ app/src/main/res/values/attrs.xml | 9 + app/src/main/res/values/strings.xml | 1 + 8 files changed, 686 insertions(+), 49 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/widget/seekbar/VerticalSeekBar.kt create mode 100644 app/src/main/java/io/legado/app/ui/widget/seekbar/VerticalSeekBarWrapper.kt create mode 100644 app/src/main/res/drawable/ic_brightness_auto.xml diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 94b4cb37e..dbdb11b1e 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -7,6 +7,7 @@ import android.os.Bundle import android.view.KeyEvent import android.view.Menu import android.view.MenuItem +import android.view.WindowManager import androidx.lifecycle.Observer import io.legado.app.R import io.legado.app.base.VMBaseActivity @@ -92,6 +93,18 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } read_menu.setListener(object : ReadMenu.Callback { + override fun setScreenBrightness(value: Int) { + var brightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE + if (this@ReadBookActivity.getPrefBoolean("brightnessAuto").not()) { + brightness = value.toFloat() + if (brightness < 1f) brightness = 1f + brightness = brightness * 1.0f / 255f + } + val params = window.attributes + params.screenBrightness = brightness + window.attributes = params + } + override fun autoPage() { } @@ -286,7 +299,8 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea super.onActivityResult(requestCode, resultCode, data) if (resultCode == Activity.RESULT_OK) { when (requestCode) { - + requestCodeEditSource -> { + } } } } diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt index 6fde199ab..94db4efc8 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt @@ -10,6 +10,8 @@ import androidx.core.view.isVisible import io.legado.app.App import io.legado.app.R import io.legado.app.constant.Bus +import io.legado.app.lib.theme.accentColor +import io.legado.app.lib.theme.buttonDisabledColor import io.legado.app.utils.* import kotlinx.android.synthetic.main.view_read_menu.view.* import org.jetbrains.anko.sdk27.listeners.onClick @@ -44,6 +46,19 @@ class ReadMenu : FrameLayout { initAnimation() vw_bg.onClick { } vwNavigationBar.onClick { } + seek_brightness.progress = context.getPrefInt("brightness", 100) + upBrightness() + } + + private fun upBrightness() { + if (context.getPrefBoolean("brightnessAuto", true)) { + iv_brightness_auto.setColorFilter(context.accentColor) + seek_brightness.isEnabled = false + } else { + iv_brightness_auto.setColorFilter(context.buttonDisabledColor) + seek_brightness.isEnabled = true + } + callback?.setScreenBrightness(context.getPrefInt("brightness", 100)) } fun setListener(callback: Callback) { @@ -51,45 +66,6 @@ class ReadMenu : FrameLayout { bindEvent() } - private fun initAnimation() { - menuTopIn = AnimationUtils.loadAnimation(context, R.anim.anim_readbook_top_in) - menuBottomIn = AnimationUtils.loadAnimation(context, R.anim.anim_readbook_bottom_in) - menuBottomIn.setAnimationListener(object : Animation.AnimationListener { - override fun onAnimationStart(animation: Animation) { - - } - - override fun onAnimationEnd(animation: Animation) { - vw_menu_bg.onClick { runMenuOut() } - } - - override fun onAnimationRepeat(animation: Animation) { - - } - }) - - //隐藏菜单 - menuTopOut = AnimationUtils.loadAnimation(context, R.anim.anim_readbook_top_out) - menuBottomOut = AnimationUtils.loadAnimation(context, R.anim.anim_readbook_bottom_out) - menuBottomOut.setAnimationListener(object : Animation.AnimationListener { - override fun onAnimationStart(animation: Animation) { - vw_menu_bg.setOnClickListener(null) - } - - override fun onAnimationEnd(animation: Animation) { - this@ReadMenu.invisible() - title_bar.invisible() - bottom_menu.invisible() - menuBarShow = false - onMenuOutEnd?.invoke() - } - - override fun onAnimationRepeat(animation: Animation) { - - } - }) - } - fun runMenuIn() { this.visible() title_bar.visible() @@ -114,7 +90,27 @@ class ReadMenu : FrameLayout { } private fun bindEvent() { - ll_floating_button.onClick { runMenuOut() } + iv_brightness_auto.onClick { + context.putPrefBoolean( + "brightnessAuto", + !context.getPrefBoolean("brightnessAuto", true) + ) + upBrightness() + } + seek_brightness.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { + override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { + callback?.setScreenBrightness(progress) + } + + override fun onStartTrackingTouch(seekBar: SeekBar?) { + + } + + override fun onStopTrackingTouch(seekBar: SeekBar?) { + context.putPrefInt("brightness", seek_brightness.progress) + } + + }) //阅读进度 seek_read_page.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { @@ -177,6 +173,45 @@ class ReadMenu : FrameLayout { } } + private fun initAnimation() { + menuTopIn = AnimationUtils.loadAnimation(context, R.anim.anim_readbook_top_in) + menuBottomIn = AnimationUtils.loadAnimation(context, R.anim.anim_readbook_bottom_in) + menuBottomIn.setAnimationListener(object : Animation.AnimationListener { + override fun onAnimationStart(animation: Animation) { + + } + + override fun onAnimationEnd(animation: Animation) { + vw_menu_bg.onClick { runMenuOut() } + } + + override fun onAnimationRepeat(animation: Animation) { + + } + }) + + //隐藏菜单 + menuTopOut = AnimationUtils.loadAnimation(context, R.anim.anim_readbook_top_out) + menuBottomOut = AnimationUtils.loadAnimation(context, R.anim.anim_readbook_bottom_out) + menuBottomOut.setAnimationListener(object : Animation.AnimationListener { + override fun onAnimationStart(animation: Animation) { + vw_menu_bg.setOnClickListener(null) + } + + override fun onAnimationEnd(animation: Animation) { + this@ReadMenu.invisible() + title_bar.invisible() + bottom_menu.invisible() + menuBarShow = false + onMenuOutEnd?.invoke() + } + + override fun onAnimationRepeat(animation: Animation) { + + } + }) + } + fun setAutoPage(autoPage: Boolean) { if (autoPage) { fabAutoPage.setImageResource(R.drawable.ic_auto_page_stop) @@ -188,21 +223,14 @@ class ReadMenu : FrameLayout { } interface Callback { - + fun setScreenBrightness(value: Int) fun autoPage() - fun skipToPage(page: Int) - fun skipPreChapter() - fun skipNextChapter() - fun openReplaceRule() - fun openChapterList() - fun showReadStyle() - fun showMoreSetting() } diff --git a/app/src/main/java/io/legado/app/ui/widget/seekbar/VerticalSeekBar.kt b/app/src/main/java/io/legado/app/ui/widget/seekbar/VerticalSeekBar.kt new file mode 100644 index 000000000..f08e2b3c6 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/seekbar/VerticalSeekBar.kt @@ -0,0 +1,363 @@ +package io.legado.app.ui.widget.seekbar + +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.Canvas +import android.graphics.drawable.Drawable +import android.util.AttributeSet +import android.view.KeyEvent +import android.view.MotionEvent +import android.widget.ProgressBar +import androidx.appcompat.widget.AppCompatSeekBar +import androidx.core.view.ViewCompat +import io.legado.app.R +import io.legado.app.lib.theme.ATH +import io.legado.app.lib.theme.ThemeStore +import java.lang.reflect.InvocationTargetException +import java.lang.reflect.Method + +class VerticalSeekBar : AppCompatSeekBar { + + private var mIsDragging: Boolean = false + private var mThumb: Drawable? = null + private var mMethodSetProgressFromUser: Method? = null + private var mRotationAngle = ROTATION_ANGLE_CW_90 + + var rotationAngle: Int + get() = mRotationAngle + set(angle) { + require(isValidRotationAngle(angle)) { "Invalid angle specified :$angle" } + + if (mRotationAngle == angle) { + return + } + + mRotationAngle = angle + + if (useViewRotation()) { + val wrapper = wrapper + wrapper?.applyViewRotation() + } else { + requestLayout() + } + } + + private val wrapper: VerticalSeekBarWrapper? + get() { + val parent = parent + + return if (parent is VerticalSeekBarWrapper) { + parent + } else { + null + } + } + + constructor(context: Context) : super(context) { + initialize(context, null, 0, 0) + } + + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { + initialize(context, attrs, 0, 0) + } + + constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super( + context, + attrs, + defStyle + ) { + initialize(context, attrs, defStyle, 0) + } + + private fun initialize( + context: Context, + attrs: AttributeSet?, + defStyleAttr: Int, + defStyleRes: Int + ) { + ATH.setTint(this, ThemeStore.accentColor(context)) + ViewCompat.setLayoutDirection(this, ViewCompat.LAYOUT_DIRECTION_LTR) + + if (attrs != null) { + val a = context.obtainStyledAttributes( + attrs, + R.styleable.VerticalSeekBar, + defStyleAttr, + defStyleRes + ) + val rotationAngle = a.getInteger(R.styleable.VerticalSeekBar_seekBarRotation, 0) + if (isValidRotationAngle(rotationAngle)) { + mRotationAngle = rotationAngle + } + a.recycle() + } + } + + override fun setThumb(thumb: Drawable) { + mThumb = thumb + super.setThumb(thumb) + } + + @SuppressLint("ClickableViewAccessibility") + override fun onTouchEvent(event: MotionEvent): Boolean { + return if (useViewRotation()) { + onTouchEventUseViewRotation(event) + } else { + onTouchEventTraditionalRotation(event) + } + } + + private fun onTouchEventTraditionalRotation(event: MotionEvent): Boolean { + if (!isEnabled) { + return false + } + + when (event.action) { + MotionEvent.ACTION_DOWN -> { + isPressed = true + onStartTrackingTouch() + trackTouchEvent(event) + attemptClaimDrag(true) + invalidate() + } + + MotionEvent.ACTION_MOVE -> if (mIsDragging) { + trackTouchEvent(event) + } + + MotionEvent.ACTION_UP -> { + if (mIsDragging) { + trackTouchEvent(event) + onStopTrackingTouch() + isPressed = false + } else { + // Touch up when we never crossed the touch slop threshold + // should + // be interpreted as a tap-seek to that location. + onStartTrackingTouch() + trackTouchEvent(event) + onStopTrackingTouch() + attemptClaimDrag(false) + } + // ProgressBar doesn't know to repaint the thumb drawable + // in its inactive state when the touch stops (because the + // value has not apparently changed) + invalidate() + } + + MotionEvent.ACTION_CANCEL -> { + if (mIsDragging) { + onStopTrackingTouch() + isPressed = false + } + invalidate() // see above explanation + } + } + return true + } + + private fun onTouchEventUseViewRotation(event: MotionEvent): Boolean { + val handled = super.onTouchEvent(event) + + if (handled) { + when (event.action) { + MotionEvent.ACTION_DOWN -> attemptClaimDrag(true) + + MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> attemptClaimDrag(false) + } + } + + return handled + } + + private fun trackTouchEvent(event: MotionEvent) { + val paddingLeft = super.getPaddingLeft() + val paddingRight = super.getPaddingRight() + val height = height + + val available = height - paddingLeft - paddingRight + val y = event.y.toInt() + + val scale: Float + var value = 0f + + when (mRotationAngle) { + ROTATION_ANGLE_CW_90 -> value = (y - paddingLeft).toFloat() + ROTATION_ANGLE_CW_270 -> value = (height - paddingLeft - y).toFloat() + } + + scale = if (value < 0 || available == 0) { + 0.0f + } else if (value > available) { + 1.0f + } else { + value / available.toFloat() + } + + val max = max + val progress = scale * max + + setProgressFromUser(progress.toInt(), true) + } + + /** + * Tries to claim the user's drag motion, and requests disallowing any + * ancestors from stealing events in the drag. + */ + private fun attemptClaimDrag(active: Boolean) { + val parent = parent + parent?.requestDisallowInterceptTouchEvent(active) + } + + /** + * This is called when the user has started touching this widget. + */ + private fun onStartTrackingTouch() { + mIsDragging = true + } + + /** + * This is called when the user either releases his touch or the touch is + * canceled. + */ + private fun onStopTrackingTouch() { + mIsDragging = false + } + + override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean { + if (isEnabled) { + val handled: Boolean + var direction = 0 + + when (keyCode) { + KeyEvent.KEYCODE_DPAD_DOWN -> { + direction = if (mRotationAngle == ROTATION_ANGLE_CW_90) 1 else -1 + handled = true + } + KeyEvent.KEYCODE_DPAD_UP -> { + direction = if (mRotationAngle == ROTATION_ANGLE_CW_270) 1 else -1 + handled = true + } + KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT -> + // move view focus to previous/next view + return false + else -> handled = false + } + + if (handled) { + val keyProgressIncrement = keyProgressIncrement + var progress = progress + + progress += direction * keyProgressIncrement + + if (progress in 0..max) { + setProgressFromUser(progress, true) + } + + return true + } + } + + return super.onKeyDown(keyCode, event) + } + + @Synchronized + override fun setProgress(progress: Int) { + super.setProgress(progress) + if (!useViewRotation()) { + refreshThumb() + } + } + + @Synchronized + private fun setProgressFromUser(progress: Int, fromUser: Boolean) { + if (mMethodSetProgressFromUser == null) { + try { + val m: Method = ProgressBar::class.java.getDeclaredMethod( + "setProgress", + Int::class.javaPrimitiveType, + Boolean::class.javaPrimitiveType + ) + m.isAccessible = true + mMethodSetProgressFromUser = m + } catch (e: NoSuchMethodException) { + } + + } + + if (mMethodSetProgressFromUser != null) { + try { + mMethodSetProgressFromUser!!.invoke(this, progress, fromUser) + } catch (e: IllegalArgumentException) { + } catch (e: IllegalAccessException) { + } catch (e: InvocationTargetException) { + } + + } else { + super.setProgress(progress) + } + refreshThumb() + } + + @Synchronized + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + if (useViewRotation()) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + } else { + super.onMeasure(heightMeasureSpec, widthMeasureSpec) + + val lp = layoutParams + + if (isInEditMode && lp != null && lp.height >= 0) { + setMeasuredDimension(super.getMeasuredHeight(), lp.height) + } else { + setMeasuredDimension(super.getMeasuredHeight(), super.getMeasuredWidth()) + } + } + } + + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + if (useViewRotation()) { + super.onSizeChanged(w, h, oldw, oldh) + } else { + super.onSizeChanged(h, w, oldh, oldw) + } + } + + @Synchronized + override fun onDraw(canvas: Canvas) { + if (!useViewRotation()) { + when (mRotationAngle) { + ROTATION_ANGLE_CW_90 -> { + canvas.rotate(90f) + canvas.translate(0f, (-super.getWidth()).toFloat()) + } + ROTATION_ANGLE_CW_270 -> { + canvas.rotate(-90f) + canvas.translate((-super.getHeight()).toFloat(), 0f) + } + } + } + + super.onDraw(canvas) + } + + // refresh thumb position + private fun refreshThumb() { + onSizeChanged(super.getWidth(), super.getHeight(), 0, 0) + } + + /*package*/ + internal fun useViewRotation(): Boolean { + return !isInEditMode + } + + companion object { + const val ROTATION_ANGLE_CW_90 = 90 + const val ROTATION_ANGLE_CW_270 = 270 + + private fun isValidRotationAngle(angle: Int): Boolean { + return angle == ROTATION_ANGLE_CW_90 || angle == ROTATION_ANGLE_CW_270 + } + } +} diff --git a/app/src/main/java/io/legado/app/ui/widget/seekbar/VerticalSeekBarWrapper.kt b/app/src/main/java/io/legado/app/ui/widget/seekbar/VerticalSeekBarWrapper.kt new file mode 100644 index 000000000..da69c33ab --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/seekbar/VerticalSeekBarWrapper.kt @@ -0,0 +1,184 @@ +package io.legado.app.ui.widget.seekbar + +import android.annotation.SuppressLint +import android.content.Context +import android.util.AttributeSet +import android.view.Gravity +import android.view.View +import android.view.ViewGroup +import android.widget.FrameLayout + +import androidx.core.view.ViewCompat +import kotlin.math.max + +class VerticalSeekBarWrapper @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : FrameLayout(context, attrs, defStyleAttr) { + + private val childSeekBar: VerticalSeekBar? + get() { + val child = if (childCount > 0) getChildAt(0) else null + return if (child is VerticalSeekBar) child else null + } + + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + if (useViewRotation()) { + onSizeChangedUseViewRotation(w, h, oldw, oldh) + } else { + onSizeChangedTraditionalRotation(w, h, oldw, oldh) + } + } + + @SuppressLint("RtlHardcoded") + private fun onSizeChangedTraditionalRotation(w: Int, h: Int, oldw: Int, oldh: Int) { + val seekBar = childSeekBar + + if (seekBar != null) { + val hPadding = paddingLeft + paddingRight + val vPadding = paddingTop + paddingBottom + val lp = seekBar.layoutParams as LayoutParams + + lp.width = ViewGroup.LayoutParams.WRAP_CONTENT + lp.height = max(0, h - vPadding) + seekBar.layoutParams = lp + + seekBar.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED) + + val seekBarMeasuredWidth = seekBar.measuredWidth + seekBar.measure( + MeasureSpec.makeMeasureSpec( + max(0, w - hPadding), + MeasureSpec.AT_MOST + ), + MeasureSpec.makeMeasureSpec( + max(0, h - vPadding), + MeasureSpec.EXACTLY + ) + ) + + lp.gravity = Gravity.TOP or Gravity.LEFT + lp.leftMargin = (max(0, w - hPadding) - seekBarMeasuredWidth) / 2 + seekBar.layoutParams = lp + } + + super.onSizeChanged(w, h, oldw, oldh) + } + + private fun onSizeChangedUseViewRotation(w: Int, h: Int, oldw: Int, oldh: Int) { + val seekBar = childSeekBar + + if (seekBar != null) { + val hPadding = paddingLeft + paddingRight + val vPadding = paddingTop + paddingBottom + seekBar.measure( + MeasureSpec.makeMeasureSpec( + max(0, h - vPadding), + MeasureSpec.EXACTLY + ), + MeasureSpec.makeMeasureSpec( + max(0, w - hPadding), + MeasureSpec.AT_MOST + ) + ) + } + + applyViewRotation(w, h) + super.onSizeChanged(w, h, oldw, oldh) + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + val seekBar = childSeekBar + val widthMode = MeasureSpec.getMode(widthMeasureSpec) + val heightMode = MeasureSpec.getMode(heightMeasureSpec) + val widthSize = MeasureSpec.getSize(widthMeasureSpec) + val heightSize = MeasureSpec.getSize(heightMeasureSpec) + + if (seekBar != null && widthMode != MeasureSpec.EXACTLY) { + val seekBarWidth: Int + val seekBarHeight: Int + val hPadding = paddingLeft + paddingRight + val vPadding = paddingTop + paddingBottom + val innerContentWidthMeasureSpec = + MeasureSpec.makeMeasureSpec(max(0, widthSize - hPadding), widthMode) + val innerContentHeightMeasureSpec = + MeasureSpec.makeMeasureSpec(max(0, heightSize - vPadding), heightMode) + + if (useViewRotation()) { + seekBar.measure(innerContentHeightMeasureSpec, innerContentWidthMeasureSpec) + seekBarWidth = seekBar.measuredHeight + seekBarHeight = seekBar.measuredWidth + } else { + seekBar.measure(innerContentWidthMeasureSpec, innerContentHeightMeasureSpec) + seekBarWidth = seekBar.measuredWidth + seekBarHeight = seekBar.measuredHeight + } + + val measuredWidth = + View.resolveSizeAndState(seekBarWidth + hPadding, widthMeasureSpec, 0) + val measuredHeight = + View.resolveSizeAndState(seekBarHeight + vPadding, heightMeasureSpec, 0) + + setMeasuredDimension(measuredWidth, measuredHeight) + } else { + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + } + } + + /*package*/ + internal fun applyViewRotation() { + applyViewRotation(width, height) + } + + private fun applyViewRotation(w: Int, h: Int) { + val seekBar = childSeekBar + + if (seekBar != null) { + val isLTR = ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_LTR + val rotationAngle = seekBar.rotationAngle + val seekBarMeasuredWidth = seekBar.measuredWidth + val seekBarMeasuredHeight = seekBar.measuredHeight + val hPadding = paddingLeft + paddingRight + val vPadding = paddingTop + paddingBottom + val hOffset = (max(0, w - hPadding) - seekBarMeasuredHeight) * 0.5f + val lp = seekBar.layoutParams + + lp.width = max(0, h - vPadding) + lp.height = ViewGroup.LayoutParams.WRAP_CONTENT + + seekBar.layoutParams = lp + + seekBar.pivotX = (if (isLTR) 0 else max(0, h - vPadding)).toFloat() + seekBar.pivotY = 0f + + when (rotationAngle) { + VerticalSeekBar.ROTATION_ANGLE_CW_90 -> { + seekBar.rotation = 90f + if (isLTR) { + seekBar.translationX = seekBarMeasuredHeight + hOffset + seekBar.translationY = 0f + } else { + seekBar.translationX = -hOffset + seekBar.translationY = seekBarMeasuredWidth.toFloat() + } + } + VerticalSeekBar.ROTATION_ANGLE_CW_270 -> { + seekBar.rotation = 270f + if (isLTR) { + seekBar.translationX = hOffset + seekBar.translationY = seekBarMeasuredWidth.toFloat() + } else { + seekBar.translationX = -(seekBarMeasuredHeight + hOffset) + seekBar.translationY = 0f + } + } + } + } + } + + private fun useViewRotation(): Boolean { + val seekBar = childSeekBar + return seekBar?.useViewRotation() ?: false + } +} diff --git a/app/src/main/res/drawable/ic_brightness_auto.xml b/app/src/main/res/drawable/ic_brightness_auto.xml new file mode 100644 index 000000000..6ea7b953e --- /dev/null +++ b/app/src/main/res/drawable/ic_brightness_auto.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_read_menu.xml b/app/src/main/res/layout/view_read_menu.xml index ba84bece8..b1f3ea57b 100644 --- a/app/src/main/res/layout/view_read_menu.xml +++ b/app/src/main/res/layout/view_read_menu.xml @@ -42,6 +42,33 @@ + + + + + + + + + + + + + + + + + \ 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 43793d206..0c7c90e4a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -483,5 +483,6 @@ 阅读 %d%% %d分钟 + 自动亮度%s From a6d99214ea547c3027b2140c79f43564e8a456ff Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 23 Aug 2019 21:26:05 +0800 Subject: [PATCH 0917/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 22 +++++++++++-------- app/src/main/res/xml/pref_config_read.xml | 6 +++++ 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index dbdb11b1e..3346df73e 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -94,15 +94,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } read_menu.setListener(object : ReadMenu.Callback { override fun setScreenBrightness(value: Int) { - var brightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE - if (this@ReadBookActivity.getPrefBoolean("brightnessAuto").not()) { - brightness = value.toFloat() - if (brightness < 1f) brightness = 1f - brightness = brightness * 1.0f / 255f - } - val params = window.attributes - params.screenBrightness = brightness - window.attributes = params + this@ReadBookActivity.setScreenBrightness(value) } override fun autoPage() { @@ -295,6 +287,18 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } + fun setScreenBrightness(value: Int) { + var brightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE + if (this.getPrefBoolean("brightnessAuto").not()) { + brightness = value.toFloat() + if (brightness < 1f) brightness = 1f + brightness = brightness * 1.0f / 255f + } + val params = window.attributes + params.screenBrightness = brightness + window.attributes = params + } + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (resultCode == Activity.RESULT_OK) { diff --git a/app/src/main/res/xml/pref_config_read.xml b/app/src/main/res/xml/pref_config_read.xml index 06ddce418..d5cec54d1 100644 --- a/app/src/main/res/xml/pref_config_read.xml +++ b/app/src/main/res/xml/pref_config_read.xml @@ -14,4 +14,10 @@ android:key="hideNavigationBar" app:iconSpaceReserved="false" /> + + \ No newline at end of file From cd400578a54a4341ef22eaac7716b72a8478578c Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 23 Aug 2019 21:27:25 +0800 Subject: [PATCH 0918/1997] up --- app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 3346df73e..a15d23c01 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -60,6 +60,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea changeSourceDialog = supportFragmentManager.findFragmentByTag(ChangeSourceDialog.tag) as? ChangeSourceDialog changeSourceDialog?.callBack = this } + setScreenBrightness(getPrefInt("brightness", 100)) } override fun onResume() { From 0d92197b0b45139f08c0e5b28c872535a9791790 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 23 Aug 2019 21:28:06 +0800 Subject: [PATCH 0919/1997] up --- app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index a15d23c01..1701f36c6 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -288,7 +288,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } - fun setScreenBrightness(value: Int) { + private fun setScreenBrightness(value: Int) { var brightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE if (this.getPrefBoolean("brightnessAuto").not()) { brightness = value.toFloat() From d1114b846feded721e0d8c3fc2744301e591b8b8 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 23 Aug 2019 21:35:20 +0800 Subject: [PATCH 0920/1997] up --- app/src/main/res/values/strings.xml | 4 ++-- app/src/main/res/xml/pref_config_read.xml | 10 ++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0c7c90e4a..40b0ddca9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -166,7 +166,7 @@ 替换为 封面 - 音量键翻页 + 音量键翻页 点击翻页 点击总是翻下一页 翻页动画 @@ -292,7 +292,7 @@ 系统文件选择器 新版本 下载更新 - 朗读时音量键翻页 + 朗读时音量键翻页 Tip边距跟随边距调整 禁止更新 允许更新 diff --git a/app/src/main/res/xml/pref_config_read.xml b/app/src/main/res/xml/pref_config_read.xml index d5cec54d1..7c3a38460 100644 --- a/app/src/main/res/xml/pref_config_read.xml +++ b/app/src/main/res/xml/pref_config_read.xml @@ -14,10 +14,16 @@ android:key="hideNavigationBar" app:iconSpaceReserved="false" /> + + \ No newline at end of file From 1ccab90db4cddfafe0cf068197a4eeb875968e8c Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 23 Aug 2019 21:37:40 +0800 Subject: [PATCH 0921/1997] up --- .../io/legado/app/ui/widget/page/ChapterProvider.kt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt index 2c6afd592..29a82318a 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt @@ -8,6 +8,8 @@ import io.legado.app.data.entities.BookChapter object ChapterProvider { + private val titleSpan = RelativeSizeSpan(1.3f) + @Synchronized fun getTextChapter(textView: ContentTextView, bookChapter: BookChapter, content: String): TextChapter { val textPages = arrayListOf() @@ -17,8 +19,12 @@ object ChapterProvider { while (surplusText.isNotEmpty()) { val spannableStringBuilder = SpannableStringBuilder(surplusText) if (pageIndex == 0) { - val span = RelativeSizeSpan(1.5f) - spannableStringBuilder.setSpan(span, 0, surplusText.indexOf("\n"), Spannable.SPAN_INCLUSIVE_EXCLUSIVE) + spannableStringBuilder.setSpan( + titleSpan, + 0, + surplusText.indexOf("\n"), + Spannable.SPAN_INCLUSIVE_EXCLUSIVE + ) } textView.text = spannableStringBuilder pageLengths.add(textView.getCharNum()) From 2ebdf5e1e63f844f1d15b45eecba8a15d7ce4678 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 23 Aug 2019 22:34:30 +0800 Subject: [PATCH 0922/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 47 ++++++++++--------- .../app/ui/readbook/ReadBookViewModel.kt | 8 ++++ .../readbook/config/ReadPreferenceFragment.kt | 27 ++++++++++- 3 files changed, 60 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 1701f36c6..351d38967 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -65,6 +65,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea override fun onResume() { super.onResume() + upBar() timeElectricityReceiver = TimeElectricityReceiver.register(this) } @@ -74,6 +75,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea unregisterReceiver(it) timeElectricityReceiver = null } + upBar() } private fun initView() { @@ -264,6 +266,30 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } + private fun setScreenBrightness(value: Int) { + var brightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE + if (this.getPrefBoolean("brightnessAuto").not()) { + brightness = value.toFloat() + if (brightness < 1f) brightness = 1f + brightness = brightness * 1.0f / 255f + } + val params = window.attributes + params.screenBrightness = brightness + window.attributes = params + } + + private fun upBar() { + + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (resultCode == Activity.RESULT_OK) { + when (requestCode) { + requestCodeEditSource -> viewModel.upBookSource() + } + } + } override fun observeLiveBus() { super.observeLiveBus() observeEvent(Bus.ALOUD_STATE) { readAloudStatus = it } @@ -288,25 +314,4 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } - private fun setScreenBrightness(value: Int) { - var brightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE - if (this.getPrefBoolean("brightnessAuto").not()) { - brightness = value.toFloat() - if (brightness < 1f) brightness = 1f - brightness = brightness * 1.0f / 255f - } - val params = window.attributes - params.screenBrightness = brightness - window.attributes = params - } - - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - if (resultCode == Activity.RESULT_OK) { - when (requestCode) { - requestCodeEditSource -> { - } - } - } - } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index ba3c9b845..b69f3c3d8 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -189,6 +189,14 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } } + fun upBookSource() { + execute { + bookData.value?.let { + bookSource = App.db.bookSourceDao().getBookSource(it.origin) + } + } + } + override fun onCleared() { super.onCleared() ReadAloudService.stop(context) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadPreferenceFragment.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadPreferenceFragment.kt index d26bbf65a..f66d7e222 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadPreferenceFragment.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadPreferenceFragment.kt @@ -1,14 +1,39 @@ package io.legado.app.ui.readbook.config +import android.content.SharedPreferences import android.os.Bundle +import android.view.View import androidx.preference.PreferenceFragmentCompat import io.legado.app.R +import io.legado.app.lib.theme.ATH -class ReadPreferenceFragment : PreferenceFragmentCompat() { +class ReadPreferenceFragment : PreferenceFragmentCompat(), + SharedPreferences.OnSharedPreferenceChangeListener { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { addPreferencesFromResource(R.xml.pref_config_read) } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + ATH.applyEdgeEffectColor(listView) + } + + override fun onResume() { + super.onResume() + preferenceManager.sharedPreferences.registerOnSharedPreferenceChangeListener(this) + } + + override fun onPause() { + preferenceManager.sharedPreferences.unregisterOnSharedPreferenceChangeListener(this) + super.onPause() + } + + override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { + when (key) { + "hideStatusBar" -> { + } + } + } } \ No newline at end of file From c406f5592ef5d34b535c1d98e7f834434e256407 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 24 Aug 2019 07:03:57 +0800 Subject: [PATCH 0923/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 351d38967..65dfd1481 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -4,10 +4,7 @@ import android.app.Activity import android.content.Intent import android.net.Uri import android.os.Bundle -import android.view.KeyEvent -import android.view.Menu -import android.view.MenuItem -import android.view.WindowManager +import android.view.* import androidx.lifecycle.Observer import io.legado.app.R import io.legado.app.base.VMBaseActivity @@ -279,7 +276,19 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } private fun upBar() { - + var flag = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + if (getPrefBoolean("hideNavigationBar")) { + flag = flag or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + } + if (!read_menu.menuBarShow) { + if (getPrefBoolean("hideStatusBar")) { + flag = flag or View.SYSTEM_UI_FLAG_FULLSCREEN + } + if (getPrefBoolean("hideNavigationBar")) { + flag = flag or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + } + } + window.decorView.systemUiVisibility = flag } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { From e42dc586564b52788e6b7a58a61c518d10cd013c Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 24 Aug 2019 08:04:44 +0800 Subject: [PATCH 0924/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 28 ++++++++++--------- .../io/legado/app/ui/readbook/ReadMenu.kt | 20 ++++++++----- .../readbook/config/ReadPreferenceFragment.kt | 6 ++-- .../app/ui/readbook/config/ReadStyleDialog.kt | 10 +++---- app/src/main/res/layout/view_read_menu.xml | 1 - 5 files changed, 37 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 65dfd1481..a0582c6ea 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -5,6 +5,7 @@ import android.content.Intent import android.net.Uri import android.os.Bundle import android.view.* +import androidx.core.view.isVisible import androidx.lifecycle.Observer import io.legado.app.R import io.legado.app.base.VMBaseActivity @@ -130,6 +131,14 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea override fun showMoreSetting() { MoreConfigDialog().show(supportFragmentManager, "moreConfig") } + + override fun menuShow() { + upBar() + } + + override fun menuHide() { + upBar() + } }) } @@ -280,7 +289,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea if (getPrefBoolean("hideNavigationBar")) { flag = flag or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION } - if (!read_menu.menuBarShow) { + if (!read_menu.isVisible) { if (getPrefBoolean("hideStatusBar")) { flag = flag or View.SYSTEM_UI_FLAG_FULLSCREEN } @@ -308,18 +317,11 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea observeEvent(Bus.BATTERY_CHANGED) { page_view.upBattery(it) } observeEvent(Bus.OPEN_CHAPTER) { viewModel.openChapter(it) } observeEventSticky(Bus.READ_ALOUD) { onClickReadAloud() } - observeEventSticky(Bus.UP_CONFIG) { - when (it) { - 0 -> { - page_view.upBg() - content_view.upStyle() - page_view.upStyle() - } - 1 -> { - content_view.upStyle() - page_view.upStyle() - } - } + observeEvent(Bus.UP_CONFIG) { + upBar() + page_view.upBg() + content_view.upStyle() + page_view.upStyle() } } diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt index 94db4efc8..da1ce7511 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt @@ -77,10 +77,8 @@ class ReadMenu : FrameLayout { fun runMenuOut(onMenuOutEnd: (() -> Unit)? = null) { this.onMenuOutEnd = onMenuOutEnd if (this.isVisible) { - if (bottom_menu.isVisible) { - title_bar.startAnimation(menuTopOut) - bottom_menu.startAnimation(menuBottomOut) - } + title_bar.startAnimation(menuTopOut) + bottom_menu.startAnimation(menuBottomOut) } } @@ -176,13 +174,18 @@ class ReadMenu : FrameLayout { private fun initAnimation() { menuTopIn = AnimationUtils.loadAnimation(context, R.anim.anim_readbook_top_in) menuBottomIn = AnimationUtils.loadAnimation(context, R.anim.anim_readbook_bottom_in) - menuBottomIn.setAnimationListener(object : Animation.AnimationListener { + menuTopIn.setAnimationListener(object : Animation.AnimationListener { override fun onAnimationStart(animation: Animation) { - + callback?.menuShow() } override fun onAnimationEnd(animation: Animation) { vw_menu_bg.onClick { runMenuOut() } + if (context.getPrefBoolean("hideNavigationBar")) { + vwNavigationBar.layoutParams.height = context.getNavigationBarHeight() + } else { + vwNavigationBar.layoutParams.height = 0 + } } override fun onAnimationRepeat(animation: Animation) { @@ -193,7 +196,7 @@ class ReadMenu : FrameLayout { //隐藏菜单 menuTopOut = AnimationUtils.loadAnimation(context, R.anim.anim_readbook_top_out) menuBottomOut = AnimationUtils.loadAnimation(context, R.anim.anim_readbook_bottom_out) - menuBottomOut.setAnimationListener(object : Animation.AnimationListener { + menuTopOut.setAnimationListener(object : Animation.AnimationListener { override fun onAnimationStart(animation: Animation) { vw_menu_bg.setOnClickListener(null) } @@ -204,6 +207,7 @@ class ReadMenu : FrameLayout { bottom_menu.invisible() menuBarShow = false onMenuOutEnd?.invoke() + callback?.menuHide() } override fun onAnimationRepeat(animation: Animation) { @@ -232,6 +236,8 @@ class ReadMenu : FrameLayout { fun openChapterList() fun showReadStyle() fun showMoreSetting() + fun menuShow() + fun menuHide() } } diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadPreferenceFragment.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadPreferenceFragment.kt index f66d7e222..47b27bf33 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadPreferenceFragment.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadPreferenceFragment.kt @@ -5,7 +5,9 @@ import android.os.Bundle import android.view.View import androidx.preference.PreferenceFragmentCompat import io.legado.app.R +import io.legado.app.constant.Bus import io.legado.app.lib.theme.ATH +import io.legado.app.utils.postEvent class ReadPreferenceFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedPreferenceChangeListener { @@ -31,8 +33,8 @@ class ReadPreferenceFragment : PreferenceFragmentCompat(), override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { when (key) { - "hideStatusBar" -> { - } + "hideStatusBar" -> postEvent(Bus.UP_CONFIG, true) + "hideNavigationBar" -> postEvent(Bus.UP_CONFIG, true) } } diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt index 6f6611f93..530fa4a8a 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt @@ -55,31 +55,31 @@ class ReadStyleDialog : DialogFragment() { ReadBookConfig.styleSelect = 0 ReadBookConfig.upBg() upBg() - postEvent(Bus.UP_CONFIG, 0) + postEvent(Bus.UP_CONFIG, true) } tv_bg1.onClick { ReadBookConfig.styleSelect = 1 ReadBookConfig.upBg() upBg() - postEvent(Bus.UP_CONFIG, 0) + postEvent(Bus.UP_CONFIG, true) } tv_bg2.onClick { ReadBookConfig.styleSelect = 2 ReadBookConfig.upBg() upBg() - postEvent(Bus.UP_CONFIG, 0) + postEvent(Bus.UP_CONFIG, true) } tv_bg3.onClick { ReadBookConfig.styleSelect = 3 ReadBookConfig.upBg() upBg() - postEvent(Bus.UP_CONFIG, 0) + postEvent(Bus.UP_CONFIG, true) } tv_bg4.onClick { ReadBookConfig.styleSelect = 4 ReadBookConfig.upBg() upBg() - postEvent(Bus.UP_CONFIG, 0) + postEvent(Bus.UP_CONFIG, true) } } diff --git a/app/src/main/res/layout/view_read_menu.xml b/app/src/main/res/layout/view_read_menu.xml index b1f3ea57b..515353389 100644 --- a/app/src/main/res/layout/view_read_menu.xml +++ b/app/src/main/res/layout/view_read_menu.xml @@ -154,7 +154,6 @@ android:layout_height="match_parent" /> Date: Sat, 24 Aug 2019 08:10:35 +0800 Subject: [PATCH 0925/1997] up --- .../main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index a0582c6ea..941b6ec3f 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -287,7 +287,8 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea private fun upBar() { var flag = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN if (getPrefBoolean("hideNavigationBar")) { - flag = flag or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + flag = + flag or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_IMMERSIVE } if (!read_menu.isVisible) { if (getPrefBoolean("hideStatusBar")) { From 589b4a91fbd9c3f3539783916bc271a31fd08432 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 24 Aug 2019 08:20:30 +0800 Subject: [PATCH 0926/1997] up --- app/src/main/AndroidManifest.xml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index bd15cad0a..0984f2a72 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -35,9 +35,10 @@ - - - + @@ -47,6 +48,9 @@ android:configChanges="locale|keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize|stateHidden" /> + + + @@ -54,7 +58,6 @@ - From 6acd9bd02570d92bb89e77cef4e1c2b659e9f74d Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 24 Aug 2019 08:38:22 +0800 Subject: [PATCH 0927/1997] up --- .../main/java/io/legado/app/ui/widget/page/ContentView.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index c7b1480ce..dfa912836 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -4,6 +4,7 @@ import android.content.Context import android.graphics.drawable.Drawable import android.util.AttributeSet import android.widget.FrameLayout +import android.widget.ImageView import androidx.appcompat.widget.AppCompatImageView import io.legado.app.R import io.legado.app.constant.AppConst.TIME_FORMAT @@ -17,7 +18,11 @@ import java.util.* class ContentView : FrameLayout { - private val bgImage: AppCompatImageView = AppCompatImageView(context) + private val bgImage: AppCompatImageView by lazy { + val iv = AppCompatImageView(context) + iv.scaleType = ImageView.ScaleType.CENTER_CROP + iv + } constructor(context: Context) : super(context) From 77433fc65e24743f95774b94ab156693761cbcde Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 24 Aug 2019 09:42:35 +0800 Subject: [PATCH 0928/1997] up --- .../main/java/io/legado/app/ui/about/AboutActivity.kt | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/about/AboutActivity.kt b/app/src/main/java/io/legado/app/ui/about/AboutActivity.kt index 303e9de4b..4648bb02d 100644 --- a/app/src/main/java/io/legado/app/ui/about/AboutActivity.kt +++ b/app/src/main/java/io/legado/app/ui/about/AboutActivity.kt @@ -5,11 +5,8 @@ import android.net.Uri import android.os.Bundle import android.view.Menu import android.view.MenuItem -import androidx.lifecycle.AndroidViewModel import io.legado.app.R import io.legado.app.base.BaseActivity -import io.legado.app.base.VMBaseActivity -import io.legado.app.utils.getViewModel import org.jetbrains.anko.toast class AboutActivity : BaseActivity(R.layout.activity_about) { @@ -31,15 +28,15 @@ class AboutActivity : BaseActivity(R.layout.activity_about) { override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { R.id.menu_scoring -> { - openIntent(Intent.ACTION_VIEW, "market://details?id=$packageName") + openIntent("market://details?id=$packageName") } } return super.onCompatOptionsItemSelected(item) } - private fun openIntent(intentName: String, address: String) { + private fun openIntent(address: String) { try { - val intent = Intent(intentName) + val intent = Intent(Intent.ACTION_VIEW) intent.data = Uri.parse(address) startActivity(intent) } catch (e: Exception) { From 11eaa35d86b43403eccecb5035e6aec564ce58b1 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 24 Aug 2019 09:48:08 +0800 Subject: [PATCH 0929/1997] up --- app/src/main/java/io/legado/app/help/ReadBookConfig.kt | 1 + app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt | 1 + 2 files changed, 2 insertions(+) diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index d26f67bbd..0dc5e2f18 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -96,6 +96,7 @@ object ReadBookConfig { var paddingLeft: Int = 16, var paddingRight: Int = 16, var paddingTop: Int = 0, + var textBold: Boolean = false, var textColor: String = "#3E3D3B", var textSize: Int = 15 ) { diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index dfa912836..bd80e8136 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -49,6 +49,7 @@ class ContentView : FrameLayout { content_text_view.textSize = textSize.toFloat() content_text_view.setLineSpacing(lineSpacingExtra, lineSpacingMultiplier) content_text_view.letterSpacing = letterSpacing + content_text_view.paint.isFakeBoldText = textBold textColor().let { content_text_view.setTextColor(it) tv_top_left.setTextColor(it) From 8762cd3696e6849eca5242d7106f55140a898343 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 24 Aug 2019 10:15:12 +0800 Subject: [PATCH 0930/1997] up --- .../io/legado/app/ui/widget/page/ContentView.kt | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index bd80e8136..e0804359b 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -18,17 +18,20 @@ import java.util.* class ContentView : FrameLayout { - private val bgImage: AppCompatImageView by lazy { - val iv = AppCompatImageView(context) - iv.scaleType = ImageView.ScaleType.CENTER_CROP - iv - } + private val bgImage: AppCompatImageView = AppCompatImageView(context) + .apply { + scaleType = ImageView.ScaleType.CENTER_CROP + } constructor(context: Context) : super(context) constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) - constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) init { addView(bgImage, LayoutParams(matchParent, matchParent)) From 7acdacb27464f232e1e9769e86b950f3b58af23c Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 24 Aug 2019 10:31:55 +0800 Subject: [PATCH 0931/1997] up --- app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index e0804359b..24d06331d 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -37,6 +37,7 @@ class ContentView : FrameLayout { addView(bgImage, LayoutParams(matchParent, matchParent)) inflate(context, R.layout.view_book_page, this) upStyle() + upTime() } fun upStyle() { From 15f12da6c4928195002c0bff772927dfd64a1d19 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 24 Aug 2019 10:40:18 +0800 Subject: [PATCH 0932/1997] up --- .../java/io/legado/app/ui/widget/page/ChapterProvider.kt | 6 +++++- .../main/java/io/legado/app/ui/widget/page/ContentView.kt | 6 +----- app/src/main/java/io/legado/app/ui/widget/page/TextPage.kt | 3 ++- .../java/io/legado/app/ui/widget/page/TextPageFactory.kt | 6 +++--- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt index 29a82318a..6666d4a07 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt @@ -31,7 +31,11 @@ object ChapterProvider { textPages.add( TextPage( pageIndex, - spannableStringBuilder.delete(pageLengths[pageIndex], spannableStringBuilder.length) + spannableStringBuilder.delete( + pageLengths[pageIndex], + spannableStringBuilder.length + ), + bookChapter.title ) ) surplusText = surplusText.substring(pageLengths[pageIndex]) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index 24d06331d..c2fc3abd2 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -79,13 +79,9 @@ class ContentView : FrameLayout { tv_top_right.text = context.getString(R.string.battery_show, battery) } - fun setChapterTile(tile: String) { - tv_bottom_left.text = tile - } - fun setContent(page: TextPage?) { content_text_view.text = page?.text - + tv_bottom_left.text = page?.title tv_bottom_right.text = page?.index?.toString() } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextPage.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextPage.kt index 202529ca8..ea261ff2b 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextPage.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextPage.kt @@ -2,5 +2,6 @@ package io.legado.app.ui.widget.page data class TextPage( val index: Int, - val text: CharSequence + val text: CharSequence, + val title: String ) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt index 7fe165942..4d66ed307 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt @@ -55,17 +55,17 @@ class TextPageFactory private constructor(dataSource: DataSource) : override fun currentPage(): TextPage? { return dataSource.getCurrentChapter()?.page(index) - ?: TextPage(index, "index:$index") + ?: TextPage(index, "index:$index", "index:$index") } override fun nextPage(): TextPage? { return dataSource.getCurrentChapter()?.page(index + 1) - ?: TextPage(index + 1, "index:${index + 1}") + ?: TextPage(index + 1, "index:${index + 1}", "index:${index + 1}") } override fun previousPage(): TextPage? { return dataSource.getCurrentChapter()?.page(index - 1) - ?: TextPage(index - 1, "index:${index - 1}") + ?: TextPage(index - 1, "index:${index - 1}", "index:${index - 1}") } From cff8b28a515eb93c1e96a7e81f867a0ae0d0a01f Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 24 Aug 2019 12:50:33 +0800 Subject: [PATCH 0933/1997] up --- .../io/legado/app/ui/widget/page/PageView.kt | 2 +- app/src/main/res/values/arrays.xml | 92 +++++++++++++++++++ 2 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 app/src/main/res/values/arrays.xml diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 6dc20664b..2850b32e3 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -149,7 +149,7 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att } } - fun setPageFactory(factory: TextPageFactory) { + private fun setPageFactory(factory: TextPageFactory) { this.pageFactory = factory //可做成异步回调 diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml new file mode 100644 index 000000000..01d25293d --- /dev/null +++ b/app/src/main/res/values/arrays.xml @@ -0,0 +1,92 @@ + + + + @string/indent_0 + @string/indent_1 + @string/indent_2 + @string/indent_3 + @string/indent_4 + + + + @string/all_book + @string/pursue_more_book + @string/fattening_book + @string/finish_book + @string/local_book + + + + .txt + .json + .xml + + + + @string/jf_convert_o + @string/jf_convert_j + @string/jf_convert_f + + + + 自动 + 黑色 + 白色 + 跟随背景 + + + + 默认 + 1分钟 + 2分钟 + 3分钟 + 常亮 + + + + 0 + 60 + 120 + 180 + -1 + + + + @string/screen_unspecified + @string/screen_portrait + @string/screen_landscape + @string/screen_sensor + + + + @string/bookshelf_px_0 + @string/bookshelf_px_1 + @string/bookshelf_px_2 + + + + 0 + 1 + 2 + + + + + + + + + + + + + icon1 + icon2 + + + + @string/icon_main + @string/icon_book + + + \ No newline at end of file From 7d516587b3d282552dccba636accb1c96cb3634e Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 24 Aug 2019 13:45:15 +0800 Subject: [PATCH 0934/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 8 +++++ .../app/ui/readbook/ReadBookViewModel.kt | 18 ++++++++++++ .../legado/app/ui/widget/page/DataSource.kt | 4 +++ .../io/legado/app/ui/widget/page/PageView.kt | 10 +++++++ .../legado/app/ui/widget/page/TextChapter.kt | 8 +++++ .../app/ui/widget/page/TextPageFactory.kt | 29 ++++++++++++++++--- 6 files changed, 73 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 941b6ec3f..1a1b5c885 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -256,6 +256,14 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } + override fun moveToNextChapter() { + viewModel.moveToNextChapter() + } + + override fun moveToPrevChapter() { + viewModel.moveToPrevChapter() + } + private fun onClickReadAloud() { if (!ReadAloudService.isRun) { readAloudStatus = Status.STOP diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index b69f3c3d8..dedb9b702 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -197,6 +197,24 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } } + fun moveToNextChapter() { + durChapterIndex++ + prevTextChapter = curTextChapter + curTextChapter = nextTextChapter + bookData.value?.let { + loadContent(it, durChapterIndex.plus(1)) + } + } + + fun moveToPrevChapter() { + durChapterIndex-- + nextTextChapter = curTextChapter + curTextChapter = prevTextChapter + bookData.value?.let { + loadContent(it, durChapterIndex.minus(1)) + } + } + override fun onCleared() { super.onCleared() ReadAloudService.stop(context) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt b/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt index 2101ed952..ce3974b01 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt @@ -20,6 +20,10 @@ interface DataSource { fun hasPrevChapter(): Boolean + fun moveToNextChapter() + + fun moveToPrevChapter() + interface CallBack { fun onLoadFinish(bookChapter: BookChapter, content: String) } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 2850b32e3..2a78d0cdd 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -70,6 +70,14 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att } return false } + + override fun moveToNextChapter() { + callback?.moveToNextChapter() + } + + override fun moveToPrevChapter() { + callback?.moveToPrevChapter() + } })) } @@ -201,5 +209,7 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att fun durChapterPos(pageSize: Int): Int fun textChapter(chapterOnDur: Int = 0): TextChapter? fun loadChapter(index: Int) + fun moveToNextChapter() + fun moveToPrevChapter() } } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt index 8f913d92c..54295f149 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt @@ -20,6 +20,14 @@ data class TextChapter( return null } + fun lastIndex(): Int { + return pages.size - 1 + } + + fun isLastIndex(index: Int): Boolean { + return index == pages.size - 1 + } + fun pageSize(): Int { return pages.size } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt index 4d66ed307..e19cd2487 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt @@ -39,7 +39,12 @@ class TextPageFactory private constructor(dataSource: DataSource) : override fun moveToNext(): Boolean { return if (hasNext()) { - index = index.plus(1) + index = if (dataSource.getCurrentChapter()?.isLastIndex(index) == true) { + dataSource.moveToNextChapter() + 0 + } else { + index.plus(1) + } true } else false @@ -47,7 +52,12 @@ class TextPageFactory private constructor(dataSource: DataSource) : override fun moveToPrevious(): Boolean { return if (hasPrev()) { - index = index.minus(1) + index = if (index > 0) { + index.minus(1) + } else { + dataSource.moveToPrevChapter() + dataSource.getPreviousChapter()?.lastIndex() ?: 0 + } true } else false @@ -59,12 +69,23 @@ class TextPageFactory private constructor(dataSource: DataSource) : } override fun nextPage(): TextPage? { - return dataSource.getCurrentChapter()?.page(index + 1) + dataSource.getCurrentChapter()?.let { + if (index < it.pageSize() - 1) { + return dataSource.getCurrentChapter()?.page(index + 1) + ?: TextPage(index + 1, "index:${index + 1}", "index:${index + 1}") + } + } + return dataSource.getNextChapter()?.page(0) ?: TextPage(index + 1, "index:${index + 1}", "index:${index + 1}") } override fun previousPage(): TextPage? { - return dataSource.getCurrentChapter()?.page(index - 1) + if (index > 0) { + return dataSource.getCurrentChapter()?.page(index - 1) + ?: TextPage(index - 1, "index:${index - 1}", "index:${index - 1}") + } + + return dataSource.getPreviousChapter()?.lastPage() ?: TextPage(index - 1, "index:${index - 1}", "index:${index - 1}") } From d4c6a9d335bac528adebc28ef521c8e26d84825f Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 24 Aug 2019 13:59:19 +0800 Subject: [PATCH 0935/1997] up --- .../main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 1a1b5c885..25979afc6 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -104,14 +104,16 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea override fun skipToPage(page: Int) { viewModel.durPageIndex = page + page_view.chapterLoadFinish() } override fun skipPreChapter() { - + viewModel.durPageIndex = 0 + moveToPrevChapter() } override fun skipNextChapter() { - + moveToNextChapter() } override fun openReplaceRule() { From 74994e3e4c1f4bb0d5c3e24a85738d7771ac3616 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 24 Aug 2019 16:42:47 +0800 Subject: [PATCH 0936/1997] up --- app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index c2fc3abd2..f566e672f 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -82,6 +82,6 @@ class ContentView : FrameLayout { fun setContent(page: TextPage?) { content_text_view.text = page?.text tv_bottom_left.text = page?.title - tv_bottom_right.text = page?.index?.toString() + tv_bottom_right.text = page?.index?.plus(1)?.toString() } } \ No newline at end of file From 973066795ccc4698e743617078e924801a606f73 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 24 Aug 2019 17:02:29 +0800 Subject: [PATCH 0937/1997] up --- .../java/io/legado/app/ui/readbook/ReadBookActivity.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 25979afc6..10b8e2ac1 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -295,10 +295,13 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } private fun upBar() { - var flag = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + var flag = (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + or View.SYSTEM_UI_FLAG_LAYOUT_STABLE + or View.SYSTEM_UI_FLAG_IMMERSIVE + or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) if (getPrefBoolean("hideNavigationBar")) { flag = - flag or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_IMMERSIVE + flag or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION } if (!read_menu.isVisible) { if (getPrefBoolean("hideStatusBar")) { From e426e8775358675efe33468b983e8f5cae97b0b8 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 24 Aug 2019 17:20:07 +0800 Subject: [PATCH 0938/1997] up --- app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt index da1ce7511..7ed2418b2 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt @@ -181,11 +181,10 @@ class ReadMenu : FrameLayout { override fun onAnimationEnd(animation: Animation) { vw_menu_bg.onClick { runMenuOut() } - if (context.getPrefBoolean("hideNavigationBar")) { - vwNavigationBar.layoutParams.height = context.getNavigationBarHeight() - } else { - vwNavigationBar.layoutParams.height = 0 - } + val lp = vwNavigationBar.layoutParams + lp.height = if (context.getPrefBoolean("hideNavigationBar")) + context.getNavigationBarHeight() else 0 + vwNavigationBar.layoutParams = lp } override fun onAnimationRepeat(animation: Animation) { From 630ceb613ffba48c8020da4e676bdad1788a624f Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 24 Aug 2019 17:52:30 +0800 Subject: [PATCH 0939/1997] up --- .../java/io/legado/app/ui/readbook/Help.kt | 31 ++++++++++++++ .../app/ui/readbook/ReadBookActivity.kt | 41 +++++++------------ .../ui/readbook/config/MoreConfigDialog.kt | 2 + .../app/ui/readbook/config/ReadAloudDialog.kt | 19 +++++++++ .../app/ui/readbook/config/ReadStyleDialog.kt | 2 + 5 files changed, 69 insertions(+), 26 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/readbook/Help.kt diff --git a/app/src/main/java/io/legado/app/ui/readbook/Help.kt b/app/src/main/java/io/legado/app/ui/readbook/Help.kt new file mode 100644 index 000000000..3f5a4cd2f --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/readbook/Help.kt @@ -0,0 +1,31 @@ +package io.legado.app.ui.readbook + +import android.view.View +import android.view.Window +import io.legado.app.App +import io.legado.app.utils.getPrefBoolean + +object Help { + + fun upSystemUiVisibility(window: Window, hide: Boolean = true) { + var flag = (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + or View.SYSTEM_UI_FLAG_LAYOUT_STABLE + or View.SYSTEM_UI_FLAG_IMMERSIVE + or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) + val hideNavigationBar = App.INSTANCE.getPrefBoolean("hideNavigationBar") + if (hideNavigationBar) { + flag = + flag or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + } + if (hide) { + if (App.INSTANCE.getPrefBoolean("hideStatusBar")) { + flag = flag or View.SYSTEM_UI_FLAG_FULLSCREEN + } + if (hideNavigationBar) { + flag = flag or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + } + } + window.decorView.systemUiVisibility = flag + } + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 10b8e2ac1..18dde4e00 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -4,7 +4,10 @@ import android.app.Activity import android.content.Intent import android.net.Uri import android.os.Bundle -import android.view.* +import android.view.KeyEvent +import android.view.Menu +import android.view.MenuItem +import android.view.WindowManager import androidx.core.view.isVisible import androidx.lifecycle.Observer import io.legado.app.R @@ -61,9 +64,14 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea setScreenBrightness(getPrefInt("brightness", 100)) } + override fun onWindowFocusChanged(hasFocus: Boolean) { + super.onWindowFocusChanged(hasFocus) + Help.upSystemUiVisibility(window, !read_menu.isVisible) + } + override fun onResume() { super.onResume() - upBar() + Help.upSystemUiVisibility(window, !read_menu.isVisible) timeElectricityReceiver = TimeElectricityReceiver.register(this) } @@ -73,7 +81,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea unregisterReceiver(it) timeElectricityReceiver = null } - upBar() + Help.upSystemUiVisibility(window, !read_menu.isVisible) } private fun initView() { @@ -135,11 +143,11 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } override fun menuShow() { - upBar() + Help.upSystemUiVisibility(window, !read_menu.isVisible) } override fun menuHide() { - upBar() + Help.upSystemUiVisibility(window, !read_menu.isVisible) } }) } @@ -294,26 +302,6 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea window.attributes = params } - private fun upBar() { - var flag = (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - or View.SYSTEM_UI_FLAG_LAYOUT_STABLE - or View.SYSTEM_UI_FLAG_IMMERSIVE - or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) - if (getPrefBoolean("hideNavigationBar")) { - flag = - flag or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - } - if (!read_menu.isVisible) { - if (getPrefBoolean("hideStatusBar")) { - flag = flag or View.SYSTEM_UI_FLAG_FULLSCREEN - } - if (getPrefBoolean("hideNavigationBar")) { - flag = flag or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION - } - } - window.decorView.systemUiVisibility = flag - } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (resultCode == Activity.RESULT_OK) { @@ -322,6 +310,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } } + override fun observeLiveBus() { super.observeLiveBus() observeEvent(Bus.ALOUD_STATE) { readAloudStatus = it } @@ -332,7 +321,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea observeEvent(Bus.OPEN_CHAPTER) { viewModel.openChapter(it) } observeEventSticky(Bus.READ_ALOUD) { onClickReadAloud() } observeEvent(Bus.UP_CONFIG) { - upBar() + Help.upSystemUiVisibility(window, !read_menu.isVisible) page_view.upBg() content_view.upStyle() page_view.upStyle() diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt index 4e9676a1a..02dff931e 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt @@ -9,6 +9,7 @@ import android.view.ViewGroup import android.widget.LinearLayout import androidx.fragment.app.DialogFragment import io.legado.app.R +import io.legado.app.ui.readbook.Help class MoreConfigDialog : DialogFragment() { @@ -38,6 +39,7 @@ class MoreConfigDialog : DialogFragment() { attr.gravity = Gravity.BOTTOM it.attributes = attr it.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) + Help.upSystemUiVisibility(it) } } diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt index 945ccc251..dde061329 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt @@ -1,11 +1,14 @@ package io.legado.app.ui.readbook.config import android.os.Bundle +import android.util.DisplayMetrics +import android.view.Gravity import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.DialogFragment import io.legado.app.R +import io.legado.app.ui.readbook.Help import kotlinx.android.synthetic.main.dialog_read_aloud.* class ReadAloudDialog : DialogFragment() { @@ -23,6 +26,22 @@ class ReadAloudDialog : DialogFragment() { initData() } + override fun onStart() { + super.onStart() + val dm = DisplayMetrics() + activity?.windowManager?.defaultDisplay?.getMetrics(dm) + dialog?.window?.let { + it.setBackgroundDrawableResource(R.color.transparent) + it.decorView.setPadding(0, 0, 0, 0) + val attr = it.attributes + attr.dimAmount = 0.0f + attr.gravity = Gravity.BOTTOM + it.attributes = attr + it.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) + Help.upSystemUiVisibility(it) + } + } + private fun initData() { seek_tts_SpeechRate.setProgress(0) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt index 530fa4a8a..f3f81f433 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt @@ -13,6 +13,7 @@ import io.legado.app.help.ImageLoader import io.legado.app.help.ReadBookConfig import io.legado.app.lib.theme.accentColor import io.legado.app.lib.theme.primaryColor +import io.legado.app.ui.readbook.Help import io.legado.app.utils.postEvent import kotlinx.android.synthetic.main.dialog_read_book_style.* import org.jetbrains.anko.sdk27.listeners.onClick @@ -41,6 +42,7 @@ class ReadStyleDialog : DialogFragment() { attr.gravity = Gravity.BOTTOM it.attributes = attr it.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) + Help.upSystemUiVisibility(it) } } From dd5d5e15d06248945522f2acfa2f13f1b61eb078 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 24 Aug 2019 18:33:49 +0800 Subject: [PATCH 0940/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 22 +++++++++++++++++++ .../app/ui/readbook/ReadBookViewModel.kt | 10 +++++++++ 2 files changed, 32 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 18dde4e00..235ef4d2e 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -33,6 +33,7 @@ import kotlinx.android.synthetic.main.view_book_page.* import kotlinx.android.synthetic.main.view_read_menu.* import kotlinx.android.synthetic.main.view_title_bar.* import kotlinx.coroutines.launch +import org.jetbrains.anko.alert import org.jetbrains.anko.sdk27.listeners.onClick import org.jetbrains.anko.startActivity import org.jetbrains.anko.startActivityForResult @@ -311,6 +312,27 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } + override fun finish() { + viewModel.bookData.value?.let { + if (!viewModel.inBookshelf) { + alert { + title = getString(R.string.add_to_shelf) + message = getString(R.string.check_add_bookshelf, it.name) + positiveButton(R.string.yes) { + viewModel.inBookshelf = true + } + negativeButton(R.string.no) { + viewModel.removeFromBookshelf { + super.finish() + } + } + }.show() + } else { + super.finish() + } + } ?: super.finish() + } + override fun observeLiveBus() { super.observeLiveBus() observeEvent(Bus.ALOUD_STATE) { readAloudStatus = it } diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index dedb9b702..45fd04c68 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -189,6 +189,16 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } } + fun removeFromBookshelf(success: (() -> Unit)?) { + execute { + bookData.value?.let { + App.db.bookDao().delete(it.bookUrl) + } + }.onSuccess { + success?.invoke() + } + } + fun upBookSource() { execute { bookData.value?.let { From e4784e620088ff659e185f93a73a6df7a6587815 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 24 Aug 2019 18:40:07 +0800 Subject: [PATCH 0941/1997] up --- .../java/io/legado/app/ui/readbook/ReadBookActivity.kt | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 235ef4d2e..dfbe83e85 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -33,10 +33,8 @@ import kotlinx.android.synthetic.main.view_book_page.* import kotlinx.android.synthetic.main.view_read_menu.* import kotlinx.android.synthetic.main.view_title_bar.* import kotlinx.coroutines.launch -import org.jetbrains.anko.alert +import org.jetbrains.anko.* import org.jetbrains.anko.sdk27.listeners.onClick -import org.jetbrains.anko.startActivity -import org.jetbrains.anko.startActivityForResult class ReadBookActivity : VMBaseActivity(R.layout.activity_read_book), PageView.CallBack, @@ -318,10 +316,10 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea alert { title = getString(R.string.add_to_shelf) message = getString(R.string.check_add_bookshelf, it.name) - positiveButton(R.string.yes) { + okButton { viewModel.inBookshelf = true } - negativeButton(R.string.no) { + noButton { viewModel.removeFromBookshelf { super.finish() } From ab2072fcf99d57c6d86e33d5142c3e34c1908d42 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 24 Aug 2019 20:36:21 +0800 Subject: [PATCH 0942/1997] up --- .../java/io/legado/app/help/ReadBookConfig.kt | 43 +++++++++++-------- .../java/io/legado/app/ui/readbook/Help.kt | 26 +++++++++++ .../io/legado/app/ui/readbook/ReadMenu.kt | 6 ++- .../res/layout/dialog_read_book_style.xml | 18 +++++++- app/src/main/res/values/strings.xml | 2 +- 5 files changed, 75 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index 0dc5e2f18..d3f6c69a3 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -17,31 +17,37 @@ import java.io.IOException * 阅读界面配置 */ object ReadBookConfig { - private val configList: ArrayList by lazy { - val list: ArrayList = arrayListOf() - val configFile = File(App.INSTANCE.filesDir.absolutePath + File.separator + "config") + const val fileName = "readConfig.json" + private val configList: ArrayList = arrayListOf() + .apply { + upConfig(this) + } + + var styleSelect + get() = App.INSTANCE.getPrefInt("readStyleSelect") + set(value) = App.INSTANCE.putPrefInt("readStyleSelect", value) + var bg: Drawable? = null + + fun getConfig(index: Int = styleSelect): Config { + return configList[index] + } + + fun upConfig(list: ArrayList = configList) { + val configFile = File(App.INSTANCE.filesDir.absolutePath + File.separator + fileName) val json = if (configFile.exists()) { String(configFile.readBytes()) } else { - String(App.INSTANCE.assets.open("readConfig.json").readBytes()) + String(App.INSTANCE.assets.open(fileName).readBytes()) } try { GSON.fromJsonArray(json)?.let { + list.clear() list.addAll(it) } } catch (e: Exception) { + list.clear() list.addAll(getOnError()) } - list - } - - var styleSelect - get() = App.INSTANCE.getPrefInt("readStyleSelect") - set(value) = App.INSTANCE.putPrefInt("readStyleSelect", value) - var bg: Drawable? = null - - fun getConfig(index: Int = styleSelect): Config { - return configList[index] } fun upBg() { @@ -50,7 +56,7 @@ object ReadBookConfig { fun save() { val json = GSON.toJson(configList) - val configFile = File(App.INSTANCE.filesDir.absolutePath + File.separator + "config") + val configFile = File(App.INSTANCE.filesDir.absolutePath + File.separator + fileName) //获取流并存储 try { BufferedWriter(FileWriter(configFile)).use { writer -> @@ -64,7 +70,7 @@ object ReadBookConfig { fun reset() { try { - val json = String(App.INSTANCE.assets.open("readConfig.json").readBytes()) + val json = String(App.INSTANCE.assets.open(fileName).readBytes()) GSON.fromJsonArray(json)?.let { configList.clear() configList.addAll(it) @@ -109,7 +115,10 @@ object ReadBookConfig { when (bgType) { 0 -> bgDrawable = ColorDrawable(Color.parseColor(bgStr)) 1 -> bgDrawable = - Drawable.createFromStream(App.INSTANCE.assets.open("bg" + File.separator + bgStr), "bg") + Drawable.createFromStream( + App.INSTANCE.assets.open("bg" + File.separator + bgStr), + "bg" + ) else -> runCatching { bgDrawable = Drawable.createFromPath(bgStr) } diff --git a/app/src/main/java/io/legado/app/ui/readbook/Help.kt b/app/src/main/java/io/legado/app/ui/readbook/Help.kt index 3f5a4cd2f..13bdebf50 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/Help.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/Help.kt @@ -1,12 +1,18 @@ package io.legado.app.ui.readbook +import android.app.Activity import android.view.View +import android.view.View.NO_ID +import android.view.ViewGroup import android.view.Window import io.legado.app.App import io.legado.app.utils.getPrefBoolean + object Help { + private const val NAVIGATION = "navigationBarBackground" + fun upSystemUiVisibility(window: Window, hide: Boolean = true) { var flag = (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_STABLE @@ -28,4 +34,24 @@ object Help { window.decorView.systemUiVisibility = flag } + // 该方法需要在View完全被绘制出来之后调用,否则判断不了 + //在比如 onWindowFocusChanged()方法中可以得到正确的结果 + fun isNavigationBarExist(activity: Activity?): Boolean { + activity?.let { + val vp = it.window.decorView as? ViewGroup + if (vp != null) { + for (i in 0 until vp.childCount) { + vp.getChildAt(i).context.packageName + if (vp.getChildAt(i).id != NO_ID && NAVIGATION == activity.resources.getResourceEntryName( + vp.getChildAt(i).id + ) + ) { + return true + } + } + } + } + return false + } + } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt index 7ed2418b2..81bdb2616 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt @@ -182,7 +182,11 @@ class ReadMenu : FrameLayout { override fun onAnimationEnd(animation: Animation) { vw_menu_bg.onClick { runMenuOut() } val lp = vwNavigationBar.layoutParams - lp.height = if (context.getPrefBoolean("hideNavigationBar")) + lp.height = + if (context.getPrefBoolean("hideNavigationBar") and Help.isNavigationBarExist( + activity + ) + ) context.getNavigationBarHeight() else 0 vwNavigationBar.layoutParams = lp } diff --git a/app/src/main/res/layout/dialog_read_book_style.xml b/app/src/main/res/layout/dialog_read_book_style.xml index 83fc3f585..76b32aa5b 100644 --- a/app/src/main/res/layout/dialog_read_book_style.xml +++ b/app/src/main/res/layout/dialog_read_book_style.xml @@ -14,6 +14,22 @@ android:background="@color/btn_bg_press" app:layout_constraintTop_toTopOf="parent" /> + + + + + app:layout_constraintTop_toBottomOf="@+id/vw_bg_fg1" /> 音量键翻页 点击翻页 点击总是翻下一页 - 翻页动画 + 翻页动画 屏幕超时 返回 菜单 From e98795c53e694a8953013dabdaa7de5594c2c718 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 24 Aug 2019 21:07:55 +0800 Subject: [PATCH 0943/1997] up --- .../res/layout/dialog_read_book_style.xml | 38 ++++++++++++++++++- app/src/main/res/values/strings.xml | 10 ++--- 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/app/src/main/res/layout/dialog_read_book_style.xml b/app/src/main/res/layout/dialog_read_book_style.xml index 76b32aa5b..c2fdc5d39 100644 --- a/app/src/main/res/layout/dialog_read_book_style.xml +++ b/app/src/main/res/layout/dialog_read_book_style.xml @@ -15,7 +15,7 @@ app:layout_constraintTop_toTopOf="parent" /> + + + + + + + + + app:layout_constraintTop_toBottomOf="@+id/rg_page_anim" /> 放入书架 继续阅读 封面地址 - 覆盖 - 仿真 - 滑动 - 滚动 - 无动画 + 覆盖 + 滑动 + 仿真 + 滚动 + 无动画 此书源使用了高级功能,请到捐赠里点击支付宝红包搜索码领取红包开启。 后台更新换源最新章节 开启则会在软件打开1分钟后开始更新 From dcaac551f4f27e487084632526dc58e4a2292808 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 24 Aug 2019 21:09:45 +0800 Subject: [PATCH 0944/1997] up --- app/src/main/java/io/legado/app/help/ReadBookConfig.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index d3f6c69a3..dad8c76d3 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -17,7 +17,7 @@ import java.io.IOException * 阅读界面配置 */ object ReadBookConfig { - const val fileName = "readConfig.json" + private const val fileName = "readConfig.json" private val configList: ArrayList = arrayListOf() .apply { upConfig(this) From f06bdf0fe557e7d86aae9ca23c1f8d2747da84c3 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 24 Aug 2019 21:43:37 +0800 Subject: [PATCH 0945/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 16 ++++++--- .../legado/app/ui/widget/page/DataSource.kt | 4 +++ .../io/legado/app/ui/widget/page/PageView.kt | 25 +++++++++----- .../app/ui/widget/page/TextPageFactory.kt | 34 +++++++++---------- 4 files changed, 49 insertions(+), 30 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index dfbe83e85..75d622e8d 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -249,11 +249,19 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea return viewModel.durChapterIndex } - override fun durChapterPos(pageSize: Int): Int { - if (viewModel.durPageIndex < pageSize) { - return viewModel.durPageIndex + override fun durChapterPos(): Int { + viewModel.curTextChapter?.let { + if (viewModel.durPageIndex < it.pageSize()) { + return viewModel.durPageIndex + } + return it.pageSize() - 1 } - return pageSize - 1 + return viewModel.durPageIndex + } + + override fun setPageIndex(pageIndex: Int) { + viewModel.durPageIndex = pageIndex + viewModel.saveRead() } override fun textChapter(chapterOnDur: Int): TextChapter? { diff --git a/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt b/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt index ce3974b01..8ba58b6ba 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt @@ -4,6 +4,10 @@ import io.legado.app.data.entities.BookChapter interface DataSource { + fun pageIndex(): Int + + fun setPageIndex(pageIndex: Int) + fun isPrepared(): Boolean fun getChapterPosition(): Int diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 2a78d0cdd..1744020d8 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -33,6 +33,14 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att pageDelegate = SlidePageDelegate(this) setPageFactory(TextPageFactory.create(object : DataSource { + override fun pageIndex(): Int { + return callback?.durChapterPos() ?: 0 + } + + override fun setPageIndex(pageIndex: Int) { + callback?.setPageIndex(pageIndex) + } + override fun isPrepared(): Boolean { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } @@ -107,25 +115,25 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att when (chapterOnDur) { 0 -> { cb.textChapter()?.let { - curPage?.setContent(it.page(cb.durChapterPos(it.pageSize()))) - if (cb.durChapterPos(it.pageSize()) > 0) { - prevPage?.setContent(it.page(cb.durChapterPos(it.pageSize()) - 1)) + curPage?.setContent(it.page(cb.durChapterPos())) + if (cb.durChapterPos() > 0) { + prevPage?.setContent(it.page(cb.durChapterPos().minus(1))) } - if (cb.durChapterPos(it.pageSize()) < it.pageSize() - 1) { - nextPage?.setContent(it.page(cb.durChapterPos(it.pageSize()) + 1)) + if (cb.durChapterPos() < it.pageSize().minus(1)) { + nextPage?.setContent(it.page(cb.durChapterPos().plus(1))) } } } 1 -> { cb.textChapter()?.let { - if (cb.durChapterPos(it.pageSize()) == it.pageSize() - 1) { + if (cb.durChapterPos() == it.pageSize().minus(1)) { nextPage?.setContent(cb.textChapter(1)?.page(0)) } } } -1 -> { cb.textChapter()?.let { - if (cb.durChapterPos(it.pageSize()) == 0) { + if (cb.durChapterPos() == 0) { prevPage?.setContent(cb.textChapter(-1)?.lastPage()) } } @@ -206,10 +214,11 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att interface CallBack { fun chapterSize(): Int fun durChapterIndex(): Int - fun durChapterPos(pageSize: Int): Int + fun durChapterPos(): Int fun textChapter(chapterOnDur: Int = 0): TextChapter? fun loadChapter(index: Int) fun moveToNextChapter() fun moveToPrevChapter() + fun setPageIndex(pageIndex: Int) } } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt index e19cd2487..0cc47789e 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt @@ -9,8 +9,6 @@ class TextPageFactory private constructor(dataSource: DataSource) : } } - var index: Int = 0 - override fun hasPrev(): Boolean { return true } @@ -24,51 +22,51 @@ class TextPageFactory private constructor(dataSource: DataSource) : } override fun moveToFirst() { - index = 0 + dataSource.setPageIndex(0) } override fun moveToLast() { - index = dataSource.getCurrentChapter()?.let { + dataSource.getCurrentChapter()?.let { if (it.pageSize() == 0) { - 0 + dataSource.setPageIndex(0) } else { - it.pageSize() - 1 + dataSource.setPageIndex(it.pageSize().minus(1)) } - } ?: 0 + } ?: dataSource.setPageIndex(0) } - override fun moveToNext(): Boolean { + override fun moveToNext(): Boolean = dataSource.pageIndex().let { index -> return if (hasNext()) { - index = if (dataSource.getCurrentChapter()?.isLastIndex(index) == true) { + if (dataSource.getCurrentChapter()?.isLastIndex(index) == true) { dataSource.moveToNextChapter() - 0 + dataSource.setPageIndex(0) } else { - index.plus(1) + dataSource.setPageIndex(index.plus(1)) } true } else false } - override fun moveToPrevious(): Boolean { + override fun moveToPrevious(): Boolean = dataSource.pageIndex().let { index -> return if (hasPrev()) { - index = if (index > 0) { - index.minus(1) + if (index > 0) { + dataSource.setPageIndex(index.minus(1)) } else { dataSource.moveToPrevChapter() - dataSource.getPreviousChapter()?.lastIndex() ?: 0 + dataSource.setPageIndex(dataSource.getPreviousChapter()?.lastIndex() ?: 0) } true } else false } - override fun currentPage(): TextPage? { + override fun currentPage(): TextPage? = dataSource.pageIndex().let { index -> return dataSource.getCurrentChapter()?.page(index) ?: TextPage(index, "index:$index", "index:$index") } - override fun nextPage(): TextPage? { + override fun nextPage(): TextPage? = dataSource.pageIndex().let { index -> dataSource.getCurrentChapter()?.let { if (index < it.pageSize() - 1) { return dataSource.getCurrentChapter()?.page(index + 1) @@ -79,7 +77,7 @@ class TextPageFactory private constructor(dataSource: DataSource) : ?: TextPage(index + 1, "index:${index + 1}", "index:${index + 1}") } - override fun previousPage(): TextPage? { + override fun previousPage(): TextPage? = dataSource.pageIndex().let { index -> if (index > 0) { return dataSource.getCurrentChapter()?.page(index - 1) ?: TextPage(index - 1, "index:${index - 1}", "index:${index - 1}") From 0d8b9be12d723a2da3837f22bfbaaa48e8422a7a Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 25 Aug 2019 08:49:07 +0800 Subject: [PATCH 0946/1997] up --- .../io/legado/app/service/ReadAloudService.kt | 2 +- .../app/ui/readbook/ReadBookActivity.kt | 19 ++++++++++++++----- .../legado/app/ui/widget/page/TextChapter.kt | 18 ++++++++++++++++++ 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index ebb4513da..ed47cb88f 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -28,7 +28,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage val tag: String = ReadAloudService::class.java.simpleName var isRun = false - fun paly(context: Context, title: String, subtitle: String, body: String) { + fun play(context: Context, title: String, subtitle: String, body: String) { val readAloudIntent = Intent(context, ReadAloudService::class.java) readAloudIntent.action = "play" readAloudIntent.putExtra("title", title) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 75d622e8d..bf91ba595 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -287,16 +287,25 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea SystemUtils.ignoreBatteryOptimization(this) } when (readAloudStatus) { - Status.STOP -> { - viewModel.bookData.value?.let { - ReadAloudService.paly(this, it.name, "", "") - } - } + Status.STOP -> readAloud() Status.PLAY -> ReadAloudService.pause(this) Status.PAUSE -> ReadAloudService.resume(this) } } + private fun readAloud() { + val book = viewModel.bookData.value + val textChapter = viewModel.curTextChapter + if (book != null && textChapter != null) { + ReadAloudService.play( + this, + book.name, + textChapter.title, + "" + ) + } + } + private fun setScreenBrightness(value: Int) { var brightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE if (this.getPrefBoolean("brightnessAuto").not()) { diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt index 54295f149..5903f9876 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt @@ -31,5 +31,23 @@ data class TextChapter( fun pageSize(): Int { return pages.size } + + fun getReadLength(pageIndex: Int): Int { + var length = 0 + for (index in 0 until pageIndex) { + length += pageLengths[index] + } + return length + } + + fun getUnRead(pageIndex: Int): String { + val stringBuilder = StringBuilder() + if (pageIndex < pages.size) { + for (index in pageIndex..lastIndex()) { + stringBuilder.append(pages[index].text) + } + } + return stringBuilder.toString() + } } From 381cf86bf08a2f0d3ddae871bae1016f088466c4 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 25 Aug 2019 09:21:43 +0800 Subject: [PATCH 0947/1997] up --- .../io/legado/app/ui/main/rss/RssAdapter.kt | 37 ++++++++++++++++++- .../io/legado/app/ui/main/rss/RssFragment.kt | 2 +- app/src/main/res/layout/item_rss.xml | 7 ++++ 3 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 app/src/main/res/layout/item_rss.xml diff --git a/app/src/main/java/io/legado/app/ui/main/rss/RssAdapter.kt b/app/src/main/java/io/legado/app/ui/main/rss/RssAdapter.kt index cbce98ce0..882e4f738 100644 --- a/app/src/main/java/io/legado/app/ui/main/rss/RssAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/rss/RssAdapter.kt @@ -1,13 +1,48 @@ package io.legado.app.ui.main.rss +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup +import androidx.paging.PagedListAdapter +import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView +import io.legado.app.R +import io.legado.app.data.entities.RssSource -class RssAdapter { +class RssAdapter : PagedListAdapter(DIFF_CALLBACK) { + companion object { + @JvmField + val DIFF_CALLBACK = object : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: RssSource, newItem: RssSource): Boolean = + oldItem.sourceUrl == newItem.sourceUrl + + override fun areContentsTheSame(oldItem: RssSource, newItem: RssSource): Boolean = + oldItem.sourceName == newItem.sourceName + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { + return MyViewHolder( + LayoutInflater.from(parent.context).inflate( + R.layout.item_rss, + parent, + false + ) + ) + } + + override fun onBindViewHolder(holder: MyViewHolder, position: Int) { + getItem(position)?.let { + holder.onBind(it) + } + } class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { + fun onBind(rssSource: RssSource) { + + } } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt b/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt index e00c9d00e..7603f03ea 100644 --- a/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt @@ -28,7 +28,7 @@ class RssFragment : BaseFragment(R.layout.fragment_rss) { ATH.applyEdgeEffectColor(recycler_view) adapter = RssAdapter() recycler_view.layoutManager = GridLayoutManager(requireContext(), 4) - + recycler_view.adapter = adapter } private fun initData() { diff --git a/app/src/main/res/layout/item_rss.xml b/app/src/main/res/layout/item_rss.xml new file mode 100644 index 000000000..d829e291c --- /dev/null +++ b/app/src/main/res/layout/item_rss.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file From 548414170754589365aa2e381a0922ece3e76899 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 25 Aug 2019 09:22:31 +0800 Subject: [PATCH 0948/1997] up --- app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt b/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt index 7603f03ea..fba701142 100644 --- a/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt @@ -34,6 +34,6 @@ class RssFragment : BaseFragment(R.layout.fragment_rss) { private fun initData() { rssLiveData?.removeObservers(viewLifecycleOwner) rssLiveData = LivePagedListBuilder(App.db.rssSourceDao().observeEnabled(), 50).build() - rssLiveData?.observe(viewLifecycleOwner, Observer { }) + rssLiveData?.observe(viewLifecycleOwner, Observer { adapter.submitList(it) }) } } \ No newline at end of file From 12b16317173a7b16e0d5e10793995de33be80af6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 25 Aug 2019 09:47:07 +0800 Subject: [PATCH 0949/1997] up --- .../java/io/legado/app/ui/widget/page/ChapterProvider.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt index 6666d4a07..8aa4fffde 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt @@ -2,12 +2,15 @@ package io.legado.app.ui.widget.page import android.text.Spannable import android.text.SpannableStringBuilder +import android.text.style.ForegroundColorSpan import android.text.style.RelativeSizeSpan +import io.legado.app.App import io.legado.app.data.entities.BookChapter +import io.legado.app.lib.theme.accentColor object ChapterProvider { - + val readAloudSpan = ForegroundColorSpan(App.INSTANCE.accentColor) private val titleSpan = RelativeSizeSpan(1.3f) @Synchronized From aeb210bf4bb93b313cb3a3a9132c632a364cb5f4 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 25 Aug 2019 09:54:15 +0800 Subject: [PATCH 0950/1997] up --- app/src/main/java/io/legado/app/service/ReadAloudService.kt | 6 ++++-- .../main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index ed47cb88f..a1e7ffd4e 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -28,11 +28,12 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage val tag: String = ReadAloudService::class.java.simpleName var isRun = false - fun play(context: Context, title: String, subtitle: String, body: String) { + fun play(context: Context, title: String, subtitle: String, readLength: Int, body: String) { val readAloudIntent = Intent(context, ReadAloudService::class.java) readAloudIntent.action = "play" readAloudIntent.putExtra("title", title) readAloudIntent.putExtra("subtitle", subtitle) + readAloudIntent.putExtra("readLength", readLength) readAloudIntent.putExtra("body", body) context.startService(readAloudIntent) } @@ -74,8 +75,8 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage var pause = false var title: String = "" var subtitle: String = "" - private var readAloudNumber: Int = 0 var timeMinute: Int = 0 + private var readAloudNumber: Int = 0 override fun onCreate() { super.onCreate() @@ -103,6 +104,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage "play" -> { title = intent.getStringExtra("title") ?: "" subtitle = intent.getStringExtra("subtitle") ?: "" + readAloudNumber = intent.getIntExtra("readLength", 0) newReadAloud(intent.getStringExtra("body")) } "pause" -> { diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index bf91ba595..e25694c50 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -301,7 +301,8 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea this, book.name, textChapter.title, - "" + textChapter.getReadLength(viewModel.durPageIndex), + textChapter.getUnRead(viewModel.durPageIndex) ) } } From e274d2c3e4832b8a524b1a8e9ea7dde311f538f2 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 25 Aug 2019 11:50:15 +0800 Subject: [PATCH 0951/1997] up --- .../java/io/legado/app/help/IntentDataHelp.kt | 16 +++++ .../io/legado/app/service/ReadAloudService.kt | 59 +++++++++++-------- .../io/legado/app/utils/GsonExtensions.kt | 4 +- 3 files changed, 51 insertions(+), 28 deletions(-) create mode 100644 app/src/main/java/io/legado/app/help/IntentDataHelp.kt diff --git a/app/src/main/java/io/legado/app/help/IntentDataHelp.kt b/app/src/main/java/io/legado/app/help/IntentDataHelp.kt new file mode 100644 index 000000000..4c1ca38d5 --- /dev/null +++ b/app/src/main/java/io/legado/app/help/IntentDataHelp.kt @@ -0,0 +1,16 @@ +package io.legado.app.help + +object IntentDataHelp { + + private val bigData: MutableMap = mutableMapOf() + + fun putData(key: String, data: Any) { + bigData[key] = data + } + + fun getData(key: String): Any? { + val data = bigData[key] + bigData.remove(key) + return data + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index a1e7ffd4e..5c757d3f0 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -13,10 +13,12 @@ import io.legado.app.R import io.legado.app.base.BaseService import io.legado.app.constant.Bus import io.legado.app.constant.Status +import io.legado.app.help.IntentDataHelp import io.legado.app.help.IntentHelp import io.legado.app.help.MediaHelp import io.legado.app.receiver.MediaButtonReceiver import io.legado.app.service.notification.ReadAloudNotification +import io.legado.app.ui.widget.page.TextChapter import io.legado.app.utils.postEvent import io.legado.app.utils.toast import kotlinx.coroutines.launch @@ -28,13 +30,19 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage val tag: String = ReadAloudService::class.java.simpleName var isRun = false - fun play(context: Context, title: String, subtitle: String, readLength: Int, body: String) { + fun play( + context: Context, + title: String, + subtitle: String, + pageIndex: Int, + dataKey: String + ) { val readAloudIntent = Intent(context, ReadAloudService::class.java) readAloudIntent.action = "play" readAloudIntent.putExtra("title", title) readAloudIntent.putExtra("subtitle", subtitle) - readAloudIntent.putExtra("readLength", readLength) - readAloudIntent.putExtra("body", body) + readAloudIntent.putExtra("pageIndex", pageIndex) + readAloudIntent.putExtra("dataKey", dataKey) context.startService(readAloudIntent) } @@ -67,16 +75,18 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage private var ttsIsSuccess: Boolean = false private lateinit var audioManager: AudioManager private lateinit var mFocusRequest: AudioFocusRequest - var mediaSessionCompat: MediaSessionCompat? = null private var broadcastReceiver: BroadcastReceiver? = null private var speak: Boolean = true private var nowSpeak: Int = 0 private val contentList = arrayListOf() + private var readAloudNumber: Int = 0 + private var textChapter: TextChapter? = null + private var pageIndex = 0 + var mediaSessionCompat: MediaSessionCompat? = null var pause = false var title: String = "" var subtitle: String = "" var timeMinute: Int = 0 - private var readAloudNumber: Int = 0 override fun onCreate() { super.onCreate() @@ -104,18 +114,12 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage "play" -> { title = intent.getStringExtra("title") ?: "" subtitle = intent.getStringExtra("subtitle") ?: "" - readAloudNumber = intent.getIntExtra("readLength", 0) - newReadAloud(intent.getStringExtra("body")) - } - "pause" -> { - pauseReadAloud(true) - } - "resume" -> { - resumeReadAloud() - } - "stop" -> { - stopSelf() + pageIndex = intent.getIntExtra("pageIndex", 0) + newReadAloud(intent.getStringExtra("dataKey")) } + "pause" -> pauseReadAloud(true) + "resume" -> resumeReadAloud() + "stop" -> stopSelf() } } return super.onStartCommand(intent, flags, startId) @@ -139,15 +143,16 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage } } - private fun newReadAloud(body: String?) { - if (body.isNullOrEmpty()) { - stopSelf() - } else { - nowSpeak = 0 - readAloudNumber = 0 - contentList.clear() - contentList.addAll(body.split("\n")) - } + private fun newReadAloud(dataKey: String?) { + dataKey?.let { + textChapter = IntentDataHelp.getData(dataKey) as? TextChapter + textChapter?.let { + nowSpeak = 0 + readAloudNumber = it.getReadLength(pageIndex) + contentList.clear() + contentList.addAll(it.getUnRead(pageIndex).split("\n")) + } ?: stopSelf() + } ?: stopSelf() } @Suppress("DEPRECATION") @@ -288,7 +293,9 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage } override fun onError(s: String) { - + launch { + toast(s) + } } } diff --git a/app/src/main/java/io/legado/app/utils/GsonExtensions.kt b/app/src/main/java/io/legado/app/utils/GsonExtensions.kt index 1f3627873..d81ef7ac6 100644 --- a/app/src/main/java/io/legado/app/utils/GsonExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/GsonExtensions.kt @@ -30,10 +30,10 @@ inline fun Gson.fromJsonArray(json: String?): List? { }.value } -class ParameterizedTypeImpl(val clz: Class<*>) : ParameterizedType { +class ParameterizedTypeImpl(private val clazz: Class<*>) : ParameterizedType { override fun getRawType(): Type = List::class.java override fun getOwnerType(): Type? = null - override fun getActualTypeArguments(): Array = arrayOf(clz) + override fun getActualTypeArguments(): Array = arrayOf(clazz) } From 820c3b18cd52b56e93b1e80c17d62d238f8102f2 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 25 Aug 2019 12:04:50 +0800 Subject: [PATCH 0952/1997] up --- app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index e25694c50..e06c287f2 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -302,7 +302,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea book.name, textChapter.title, textChapter.getReadLength(viewModel.durPageIndex), - textChapter.getUnRead(viewModel.durPageIndex) + System.currentTimeMillis().toString() ) } } From 1cee44e72d4e8d438e18ec74d8022fea6fc7fd86 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 25 Aug 2019 12:45:16 +0800 Subject: [PATCH 0953/1997] up --- .../legado/app/lib/theme/view/ATESeekBar.kt | 22 +++++++++---------- .../app/ui/readbook/ReadBookActivity.kt | 14 +++++++++++- .../io/legado/app/ui/readbook/ReadMenu.kt | 13 ++++++----- .../app/ui/readbook/config/ReadStyleDialog.kt | 6 ++++- 4 files changed, 36 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATESeekBar.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATESeekBar.kt index 4a49b34f3..e6725c42a 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATESeekBar.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATESeekBar.kt @@ -4,26 +4,24 @@ import android.content.Context import android.util.AttributeSet import androidx.appcompat.widget.AppCompatSeekBar import io.legado.app.lib.theme.ATH -import io.legado.app.lib.theme.ThemeStore +import io.legado.app.lib.theme.accentColor /** * @author Aidan Follestad (afollestad) */ class ATESeekBar : AppCompatSeekBar { - constructor(context: Context) : super(context) { - init(context, null) - } + constructor(context: Context) : super(context) - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { - init(context, attrs) - } + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { - init(context, attrs) - } + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) - private fun init(context: Context, attrs: AttributeSet?) { - ATH.setTint(this, ThemeStore.accentColor(context)) + init { + ATH.setTint(this, context.accentColor) } } diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index e06c287f2..9c4c7c505 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -16,11 +16,13 @@ import io.legado.app.constant.Bus import io.legado.app.constant.Status import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter +import io.legado.app.help.IntentDataHelp import io.legado.app.receiver.TimeElectricityReceiver import io.legado.app.service.ReadAloudService import io.legado.app.ui.changesource.ChangeSourceDialog import io.legado.app.ui.chapterlist.ChapterListActivity import io.legado.app.ui.readbook.config.MoreConfigDialog +import io.legado.app.ui.readbook.config.ReadAloudDialog import io.legado.app.ui.readbook.config.ReadStyleDialog import io.legado.app.ui.replacerule.ReplaceRuleActivity import io.legado.app.ui.sourceedit.SourceEditActivity @@ -141,6 +143,14 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea MoreConfigDialog().show(supportFragmentManager, "moreConfig") } + override fun showReadAloud(): Boolean { + if (readAloudStatus == Status.STOP) { + return false + } + ReadAloudDialog().show(supportFragmentManager, "readAloud") + return true + } + override fun menuShow() { Help.upSystemUiVisibility(window, !read_menu.isVisible) } @@ -297,12 +307,14 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea val book = viewModel.bookData.value val textChapter = viewModel.curTextChapter if (book != null && textChapter != null) { + val key = System.currentTimeMillis().toString() + IntentDataHelp.putData(key, textChapter) ReadAloudService.play( this, book.name, textChapter.title, textChapter.getReadLength(viewModel.durPageIndex), - System.currentTimeMillis().toString() + key ) } } diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt index 81bdb2616..4b09ceb25 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt @@ -67,11 +67,13 @@ class ReadMenu : FrameLayout { } fun runMenuIn() { - this.visible() - title_bar.visible() - bottom_menu.visible() - title_bar.startAnimation(menuTopIn) - bottom_menu.startAnimation(menuBottomIn) + if (callback?.showReadAloud() != true) { + this.visible() + title_bar.visible() + bottom_menu.visible() + title_bar.startAnimation(menuTopIn) + bottom_menu.startAnimation(menuBottomIn) + } } fun runMenuOut(onMenuOutEnd: (() -> Unit)? = null) { @@ -239,6 +241,7 @@ class ReadMenu : FrameLayout { fun openChapterList() fun showReadStyle() fun showMoreSetting() + fun showReadAloud(): Boolean fun menuShow() fun menuHide() } diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt index f3f81f433..6579fbf65 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt @@ -20,7 +20,11 @@ import org.jetbrains.anko.sdk27.listeners.onClick class ReadStyleDialog : DialogFragment() { - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { return inflater.inflate(R.layout.dialog_read_book_style, container) } From 5251f7bcc6e14a5ba130a62cfe3ef8711cec560b Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 25 Aug 2019 12:47:23 +0800 Subject: [PATCH 0954/1997] up --- .../app/ui/readbook/config/ReadAloudDialog.kt | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt index dde061329..6a9100096 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt @@ -9,7 +9,6 @@ import android.view.ViewGroup import androidx.fragment.app.DialogFragment import io.legado.app.R import io.legado.app.ui.readbook.Help -import kotlinx.android.synthetic.main.dialog_read_aloud.* class ReadAloudDialog : DialogFragment() { @@ -21,11 +20,6 @@ class ReadAloudDialog : DialogFragment() { return inflater.inflate(R.layout.dialog_read_aloud, container) } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - initData() - } - override fun onStart() { super.onStart() val dm = DisplayMetrics() @@ -42,9 +36,14 @@ class ReadAloudDialog : DialogFragment() { } } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + initData() + } + private fun initData() { - seek_tts_SpeechRate.setProgress(0) + } } \ No newline at end of file From e7d33bb570dfd4b51e0e9d94b9670e436d551c6e Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 25 Aug 2019 13:02:00 +0800 Subject: [PATCH 0955/1997] up --- app/src/main/java/io/legado/app/lib/theme/ATHUtils.kt | 6 ++++-- app/src/main/res/layout/dialog_read_aloud.xml | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/theme/ATHUtils.kt b/app/src/main/java/io/legado/app/lib/theme/ATHUtils.kt index ed6dfb734..24d0a923a 100644 --- a/app/src/main/java/io/legado/app/lib/theme/ATHUtils.kt +++ b/app/src/main/java/io/legado/app/lib/theme/ATHUtils.kt @@ -15,8 +15,10 @@ object ATHUtils { @JvmOverloads fun resolveColor(context: Context, @AttrRes attr: Int, fallback: Int = 0): Int { val a = context.theme.obtainStyledAttributes(intArrayOf(attr)) - try { - return a.getColor(0, fallback) + return try { + a.getColor(0, fallback) + } catch (e: Exception) { + fallback } finally { a.recycle() } diff --git a/app/src/main/res/layout/dialog_read_aloud.xml b/app/src/main/res/layout/dialog_read_aloud.xml index 505344bfa..114a3eebf 100644 --- a/app/src/main/res/layout/dialog_read_aloud.xml +++ b/app/src/main/res/layout/dialog_read_aloud.xml @@ -3,6 +3,7 @@ android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" + android:background="@color/background_menu" android:padding="10dp"> @@ -68,7 +69,6 @@ Date: Sun, 25 Aug 2019 13:09:30 +0800 Subject: [PATCH 0956/1997] up --- .../io/legado/app/ui/readbook/ReadBookActivity.kt | 9 --------- .../main/java/io/legado/app/ui/readbook/ReadMenu.kt | 13 +++++-------- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 9c4c7c505..db6810886 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -22,7 +22,6 @@ import io.legado.app.service.ReadAloudService import io.legado.app.ui.changesource.ChangeSourceDialog import io.legado.app.ui.chapterlist.ChapterListActivity import io.legado.app.ui.readbook.config.MoreConfigDialog -import io.legado.app.ui.readbook.config.ReadAloudDialog import io.legado.app.ui.readbook.config.ReadStyleDialog import io.legado.app.ui.replacerule.ReplaceRuleActivity import io.legado.app.ui.sourceedit.SourceEditActivity @@ -143,14 +142,6 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea MoreConfigDialog().show(supportFragmentManager, "moreConfig") } - override fun showReadAloud(): Boolean { - if (readAloudStatus == Status.STOP) { - return false - } - ReadAloudDialog().show(supportFragmentManager, "readAloud") - return true - } - override fun menuShow() { Help.upSystemUiVisibility(window, !read_menu.isVisible) } diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt index 4b09ceb25..81bdb2616 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt @@ -67,13 +67,11 @@ class ReadMenu : FrameLayout { } fun runMenuIn() { - if (callback?.showReadAloud() != true) { - this.visible() - title_bar.visible() - bottom_menu.visible() - title_bar.startAnimation(menuTopIn) - bottom_menu.startAnimation(menuBottomIn) - } + this.visible() + title_bar.visible() + bottom_menu.visible() + title_bar.startAnimation(menuTopIn) + bottom_menu.startAnimation(menuBottomIn) } fun runMenuOut(onMenuOutEnd: (() -> Unit)? = null) { @@ -241,7 +239,6 @@ class ReadMenu : FrameLayout { fun openChapterList() fun showReadStyle() fun showMoreSetting() - fun showReadAloud(): Boolean fun menuShow() fun menuHide() } From 1c13a624386964a8899e08a56c9566c9237e4e46 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 25 Aug 2019 14:48:28 +0800 Subject: [PATCH 0957/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 9 ++++ .../io/legado/app/ui/widget/page/PageView.kt | 5 ++ .../ui/widget/page/delegate/PageDelegate.kt | 48 +++++++++++-------- 3 files changed, 43 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index db6810886..980055745 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -22,6 +22,7 @@ import io.legado.app.service.ReadAloudService import io.legado.app.ui.changesource.ChangeSourceDialog import io.legado.app.ui.chapterlist.ChapterListActivity import io.legado.app.ui.readbook.config.MoreConfigDialog +import io.legado.app.ui.readbook.config.ReadAloudDialog import io.legado.app.ui.readbook.config.ReadStyleDialog import io.legado.app.ui.replacerule.ReplaceRuleActivity import io.legado.app.ui.sourceedit.SourceEditActivity @@ -282,6 +283,14 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea viewModel.moveToPrevChapter() } + override fun clickCenter() { + if (readAloudStatus != Status.STOP) { + ReadAloudDialog().show(supportFragmentManager, "readAloud") + } else { + read_menu.runMenuIn() + } + } + private fun onClickReadAloud() { if (!ReadAloudService.isRun) { readAloudStatus = Status.STOP diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 1744020d8..e29f5e83d 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -211,6 +211,10 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att nextPage?.upBattery(battery) } + override fun clickCenter() { + callback?.clickCenter() + } + interface CallBack { fun chapterSize(): Int fun durChapterIndex(): Int @@ -220,5 +224,6 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att fun moveToNextChapter() fun moveToPrevChapter() fun setPageIndex(pageIndex: Int) + fun clickCenter() } } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt index 9261a0e06..f1d730469 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt @@ -2,18 +2,18 @@ package io.legado.app.ui.widget.page.delegate import android.graphics.Bitmap import android.graphics.Canvas +import android.graphics.RectF import android.view.GestureDetector import android.view.MotionEvent import android.widget.Scroller import androidx.interpolator.view.animation.FastOutLinearInInterpolator -import io.legado.app.service.ReadAloudService.Companion.stop import io.legado.app.ui.widget.page.ContentView import io.legado.app.ui.widget.page.PageView import io.legado.app.utils.screenshot import kotlin.math.abs abstract class PageDelegate(protected val pageView: PageView) { - + val centerRectF = RectF() //起始点 protected var startX: Float = 0.toFloat() protected var startY: Float = 0.toFloat() @@ -95,6 +95,10 @@ abstract class PageDelegate(protected val pageView: PageView) { viewWidth = width viewHeight = height invalidate() + centerRectF.set( + width / 3f, height / 3f, + width * 2f / 3, height * 2f / 3 + ) } fun scroll() { @@ -193,26 +197,31 @@ abstract class PageDelegate(protected val pageView: PageView) { override fun onSingleTapUp(e: MotionEvent): Boolean { val x = e.x val y = e.y - direction = if (x > viewWidth / 2) Direction.NEXT else Direction.PREV - if (direction == Direction.NEXT) { - //判断是否下一页存在 - val hasNext = pageView.hasNext() - //设置动画方向 - if (!hasNext) { - return true - } - //下一页截图 - bitmap = nextPage?.screenshot() + if (centerRectF.contains(x, y)) { + pageView.clickCenter() + setTouchPoint(x, y) } else { - val hasPrev = pageView.hasPrev() - if (!hasPrev) { - return true + direction = if (x > viewWidth / 2) Direction.NEXT else Direction.PREV + if (direction == Direction.NEXT) { + //判断是否下一页存在 + val hasNext = pageView.hasNext() + //设置动画方向 + if (!hasNext) { + return true + } + //下一页截图 + bitmap = nextPage?.screenshot() + } else { + val hasPrev = pageView.hasPrev() + if (!hasPrev) { + return true + } + //上一页截图 + bitmap = prevPage?.screenshot() } - //上一页截图 - bitmap = prevPage?.screenshot() + setTouchPoint(x, y) + onScrollStart() } - setTouchPoint(x, y) - onScrollStart() return true } @@ -258,5 +267,6 @@ abstract class PageDelegate(protected val pageView: PageView) { interface PageInterface { fun hasNext(): Boolean fun hasPrev(): Boolean + fun clickCenter() } } \ No newline at end of file From 8bc59eede9eb37c514115e6246f84c81b2e649c9 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 25 Aug 2019 16:02:31 +0800 Subject: [PATCH 0958/1997] up --- app/src/main/java/io/legado/app/service/ReadAloudService.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index 5c757d3f0..6bc20b35c 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -103,9 +103,10 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage } override fun onDestroy() { - super.onDestroy() + textToSpeech?.stop() isRun = false unregisterReceiver(broadcastReceiver) + super.onDestroy() } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { @@ -120,6 +121,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage "pause" -> pauseReadAloud(true) "resume" -> resumeReadAloud() "stop" -> stopSelf() + else -> stopSelf() } } return super.onStartCommand(intent, flags, startId) @@ -132,6 +134,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) { toast(R.string.tts_fix) IntentHelp.toTTSSetting(this@ReadAloudService) + stopSelf() } else { textToSpeech?.setOnUtteranceProgressListener(TTSUtteranceListener()) ttsIsSuccess = true From 3a9bca8fdf88440533ea2e3ad21aa7faf0715a2b Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 25 Aug 2019 16:05:26 +0800 Subject: [PATCH 0959/1997] up --- app/src/main/java/io/legado/app/service/ReadAloudService.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index 6bc20b35c..a496a2816 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -106,6 +106,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage textToSpeech?.stop() isRun = false unregisterReceiver(broadcastReceiver) + postEvent(Bus.ALOUD_STATE, Status.STOP) super.onDestroy() } From e562fa3fcb28aeec5e9d3f3eb38e8a9422c5ea61 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 25 Aug 2019 16:08:52 +0800 Subject: [PATCH 0960/1997] up --- app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt index 81bdb2616..ab45663f6 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt @@ -152,8 +152,9 @@ class ReadMenu : FrameLayout { //朗读 ll_read_aloud.onClick { - postEvent(Bus.READ_ALOUD, true) - runMenuOut() + runMenuOut { + postEvent(Bus.READ_ALOUD, true) + } } //界面 From bbdf66fbd138378847c573da3e45a7721de349ea Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 25 Aug 2019 16:14:33 +0800 Subject: [PATCH 0961/1997] up --- .../legado/app/ui/readbook/config/ReadAloudDialog.kt | 10 ++++++++++ app/src/main/res/layout/dialog_read_aloud.xml | 2 ++ 2 files changed, 12 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt index 6a9100096..4bc3e6335 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt @@ -8,7 +8,12 @@ import android.view.View import android.view.ViewGroup import androidx.fragment.app.DialogFragment import io.legado.app.R +import io.legado.app.constant.Bus +import io.legado.app.service.ReadAloudService import io.legado.app.ui.readbook.Help +import io.legado.app.utils.observeEvent +import kotlinx.android.synthetic.main.dialog_read_aloud.* +import org.jetbrains.anko.sdk27.listeners.onClick class ReadAloudDialog : DialogFragment() { @@ -39,11 +44,16 @@ class ReadAloudDialog : DialogFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) initData() + initOnClick() } private fun initData() { + observeEvent(Bus.ALOUD_STATE) {} + } + private fun initOnClick() { + iv_stop.onClick { ReadAloudService.stop(requireContext()) } } } \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_read_aloud.xml b/app/src/main/res/layout/dialog_read_aloud.xml index 114a3eebf..7ad7dc815 100644 --- a/app/src/main/res/layout/dialog_read_aloud.xml +++ b/app/src/main/res/layout/dialog_read_aloud.xml @@ -15,6 +15,7 @@ android:padding="8dp"> Date: Sun, 25 Aug 2019 16:20:31 +0800 Subject: [PATCH 0962/1997] up --- app/src/main/java/io/legado/app/service/ReadAloudService.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index a496a2816..bcb6cd6ee 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -104,6 +104,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage override fun onDestroy() { textToSpeech?.stop() + textToSpeech?.shutdown() isRun = false unregisterReceiver(broadcastReceiver) postEvent(Bus.ALOUD_STATE, Status.STOP) @@ -214,6 +215,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage private fun pauseReadAloud(pause: Boolean) { this.pause = pause textToSpeech?.stop() + ReadAloudNotification.upNotification(this) } private fun resumeReadAloud() { From 37a039e7945dbb8718e50289f4dd75048fd10467 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 25 Aug 2019 18:45:16 +0800 Subject: [PATCH 0963/1997] up --- .../main/java/io/legado/app/constant/Bus.kt | 2 +- .../io/legado/app/service/ReadAloudService.kt | 11 +++-- .../app/ui/readbook/ReadBookActivity.kt | 46 +++++++++++++++---- .../io/legado/app/ui/readbook/ReadMenu.kt | 4 +- .../io/legado/app/ui/widget/page/PageView.kt | 2 +- 5 files changed, 50 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/io/legado/app/constant/Bus.kt b/app/src/main/java/io/legado/app/constant/Bus.kt index 2d7608626..e84d4b8c3 100644 --- a/app/src/main/java/io/legado/app/constant/Bus.kt +++ b/app/src/main/java/io/legado/app/constant/Bus.kt @@ -5,7 +5,7 @@ object Bus { const val UP_BOOK = "sourceDebugLog" const val ALOUD_STATE = "aloud_state" const val TTS_START = "ttsStart" - const val TTS_RANGE_START = "readAloudNumber" + const val TTS_NEXT = "ttsNextPage" const val BATTERY_CHANGED = "batteryChanged" const val TIME_CHANGED = "timeChanged" const val READ_ALOUD = "readAloud" diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index bcb6cd6ee..cb300d6e3 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -282,20 +282,25 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage override fun onStart(s: String) { postEvent(Bus.TTS_START, readAloudNumber + 1) - postEvent(Bus.TTS_RANGE_START, readAloudNumber + 1) } override fun onDone(s: String) { readAloudNumber += contentList[nowSpeak].length + 1 nowSpeak += 1 if (nowSpeak >= contentList.size) { - postEvent(Bus.ALOUD_STATE, Status.NEXT) + postEvent(Bus.TTS_NEXT, true) } } override fun onRangeStart(utteranceId: String?, start: Int, end: Int, frame: Int) { super.onRangeStart(utteranceId, start, end, frame) - postEvent(Bus.TTS_RANGE_START, readAloudNumber + start) + textChapter?.let { + if (readAloudNumber + start > it.getReadLength(pageIndex + 1)) { + pageIndex++ + postEvent(Bus.TTS_NEXT, false) + postEvent(Bus.TTS_START, readAloudNumber + start) + } + } } override fun onError(s: String) { diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 980055745..ff6e49e2d 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -158,6 +158,9 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea return super.onCompatCreateOptionsMenu(menu) } + /** + * 菜单 + */ override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { R.id.menu_change_source -> { @@ -173,26 +176,30 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea return super.onCompatOptionsItemSelected(item) } + /** + * 按键拦截,显示菜单 + */ override fun dispatchKeyEvent(event: KeyEvent?): Boolean { val keyCode = event?.keyCode val action = event?.action val isDown = action == 0 if (keyCode == KeyEvent.KEYCODE_MENU) { - if (isDown && !read_menu.menuBarShow) { + if (isDown && !read_menu.cnaShowMenu) { read_menu.runMenuIn() return true } - if (!isDown && !read_menu.menuBarShow) { - read_menu.menuBarShow = true + if (!isDown && !read_menu.cnaShowMenu) { + read_menu.cnaShowMenu = true return true } } return super.dispatchKeyEvent(event) } - - + /** + * 书籍加载完成,开始加载章节内容 + */ private fun bookLoadFinish() { viewModel.bookData.value?.let { viewModel.loadContent(it, viewModel.durChapterIndex) @@ -201,12 +208,18 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } - override fun loadChapter(index: Int) { + /** + * 加载章节内容 + */ + override fun loadContent(index: Int) { viewModel.bookData.value?.let { viewModel.loadContent(it, index) } } + /** + * 内容加载完成 + */ override fun contentLoadFinish(bookChapter: BookChapter, content: String) { launch { when (bookChapter.index) { @@ -291,6 +304,9 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } + /** + * 朗读按钮 + */ private fun onClickReadAloud() { if (!ReadAloudService.isRun) { readAloudStatus = Status.STOP @@ -303,6 +319,9 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } + /** + * 朗读 + */ private fun readAloud() { val book = viewModel.bookData.value val textChapter = viewModel.curTextChapter @@ -319,6 +338,9 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } + /** + * 设置屏幕亮度 + */ private fun setScreenBrightness(value: Int) { var brightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE if (this.getPrefBoolean("brightnessAuto").not()) { @@ -364,8 +386,6 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea override fun observeLiveBus() { super.observeLiveBus() observeEvent(Bus.ALOUD_STATE) { readAloudStatus = it } - observeEvent(Bus.TTS_START) {} - observeEvent(Bus.TTS_RANGE_START) {} observeEvent(Bus.TIME_CHANGED) { page_view.upTime() } observeEvent(Bus.BATTERY_CHANGED) { page_view.upBattery(it) } observeEvent(Bus.OPEN_CHAPTER) { viewModel.openChapter(it) } @@ -376,6 +396,16 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea content_view.upStyle() page_view.upStyle() } + observeEvent(Bus.TTS_START) { + + } + observeEvent(Bus.TTS_NEXT) { + if (it) { + + } else { + + } + } } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt index ab45663f6..256e02cb3 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt @@ -19,7 +19,7 @@ import org.jetbrains.anko.sdk27.listeners.onClick class ReadMenu : FrameLayout { private var callback: Callback? = null - var menuBarShow: Boolean = false + var cnaShowMenu: Boolean = false private lateinit var menuTopIn: Animation private lateinit var menuTopOut: Animation private lateinit var menuBottomIn: Animation @@ -209,7 +209,7 @@ class ReadMenu : FrameLayout { this@ReadMenu.invisible() title_bar.invisible() bottom_menu.invisible() - menuBarShow = false + cnaShowMenu = false onMenuOutEnd?.invoke() callback?.menuHide() } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index e29f5e83d..c1bbc54d4 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -220,7 +220,7 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att fun durChapterIndex(): Int fun durChapterPos(): Int fun textChapter(chapterOnDur: Int = 0): TextChapter? - fun loadChapter(index: Int) + fun loadContent(index: Int) fun moveToNextChapter() fun moveToPrevChapter() fun setPageIndex(pageIndex: Int) From 5a3c039d3e4657bed748325a289ba1ee3cdbaedc Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 25 Aug 2019 19:06:24 +0800 Subject: [PATCH 0964/1997] up --- .../java/io/legado/app/ui/readbook/ReadBookActivity.kt | 8 ++++++-- .../main/java/io/legado/app/ui/widget/page/PageView.kt | 8 ++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index ff6e49e2d..84e90e8f9 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -397,13 +397,17 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea page_view.upStyle() } observeEvent(Bus.TTS_START) { + viewModel.curTextChapter?.let { + } } observeEvent(Bus.TTS_NEXT) { if (it) { - + moveToNextChapter() } else { - + viewModel.durPageIndex += viewModel.durPageIndex + 1 + page_view.upContent() + viewModel.saveRead() } } } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index c1bbc54d4..d598d5626 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -184,6 +184,14 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att return true } + fun upContent() { + callback?.let { + it.textChapter()?.let { textChapter -> + curPage?.setContent(textChapter.page(it.durChapterIndex())) + } + } + } + fun upStyle() { curPage?.upStyle() prevPage?.upStyle() From 9bfffd33bd28233e649b9e6e7a8e2db5c12439bc Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 25 Aug 2019 19:12:43 +0800 Subject: [PATCH 0965/1997] up --- .../main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 84e90e8f9..e9caf141d 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -277,6 +277,9 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea override fun setPageIndex(pageIndex: Int) { viewModel.durPageIndex = pageIndex viewModel.saveRead() + if (readAloudStatus == Status.PLAY) { + readAloud() + } } override fun textChapter(chapterOnDur: Int): TextChapter? { From f47765d1c6ad8daa9b3076efb39ba1962e256ac1 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 25 Aug 2019 19:18:41 +0800 Subject: [PATCH 0966/1997] up --- app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index e9caf141d..00cc39274 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -335,7 +335,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea this, book.name, textChapter.title, - textChapter.getReadLength(viewModel.durPageIndex), + viewModel.durPageIndex, key ) } From 2f3093c2a9d446eb658fccdb95e46bee34a37e19 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 25 Aug 2019 19:40:26 +0800 Subject: [PATCH 0967/1997] up --- app/src/main/java/io/legado/app/App.kt | 3 +- .../java/io/legado/app/help/CrashHandler.kt | 150 ++++++++++++++++++ 2 files changed, 152 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/io/legado/app/help/CrashHandler.kt diff --git a/app/src/main/java/io/legado/app/App.kt b/app/src/main/java/io/legado/app/App.kt index 7994ac212..c72c5133c 100644 --- a/app/src/main/java/io/legado/app/App.kt +++ b/app/src/main/java/io/legado/app/App.kt @@ -15,6 +15,7 @@ import io.legado.app.constant.AppConst.channelIdReadAloud import io.legado.app.constant.AppConst.channelIdWeb import io.legado.app.data.AppDatabase import io.legado.app.help.ActivityHelp +import io.legado.app.help.CrashHandler import io.legado.app.lib.theme.ThemeStore import io.legado.app.utils.getCompatColor import io.legado.app.utils.getPrefInt @@ -39,7 +40,7 @@ class App : Application() { override fun onCreate() { super.onCreate() INSTANCE = this - + CrashHandler().init(this) db = AppDatabase.createDatabase(INSTANCE) packageManager.getPackageInfo(packageName, 0)?.let { versionCode = it.versionCode diff --git a/app/src/main/java/io/legado/app/help/CrashHandler.kt b/app/src/main/java/io/legado/app/help/CrashHandler.kt new file mode 100644 index 000000000..59623a96d --- /dev/null +++ b/app/src/main/java/io/legado/app/help/CrashHandler.kt @@ -0,0 +1,150 @@ +package io.legado.app.help + +import android.annotation.SuppressLint +import android.content.Context +import android.content.pm.PackageManager +import android.os.Build +import android.os.Handler +import android.os.Looper +import android.util.Log +import android.widget.Toast +import java.io.File +import java.io.FileOutputStream +import java.io.PrintWriter +import java.io.StringWriter +import java.text.SimpleDateFormat +import java.util.* + +/** + * 异常管理类 + */ +class CrashHandler : Thread.UncaughtExceptionHandler { + private val tag = this.javaClass.simpleName + /** + * 系统默认UncaughtExceptionHandler + */ + private var mDefaultHandler: Thread.UncaughtExceptionHandler? = null + + /** + * context + */ + private var mContext: Context? = null + + /** + * 存储异常和参数信息 + */ + private val paramsMap = HashMap() + + /** + * 格式化时间 + */ + @SuppressLint("SimpleDateFormat") + private val format = SimpleDateFormat("yyyy-MM-dd-HH-mm-ss") + + fun init(context: Context) { + mContext = context + mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler() + //设置该CrashHandler为系统默认的 + Thread.setDefaultUncaughtExceptionHandler(this) + } + + /** + * uncaughtException 回调函数 + */ + override fun uncaughtException(thread: Thread, ex: Throwable) { + handleException(ex) + mDefaultHandler?.uncaughtException(thread, ex) + } + + /** + * 处理该异常 + */ + private fun handleException(ex: Throwable?) { + if (ex == null) return + //收集设备参数信息 + collectDeviceInfo(mContext!!) + //添加自定义信息 + addCustomInfo() + kotlin.runCatching { + //使用Toast来显示异常信息 + Handler(Looper.getMainLooper()).post { + Toast.makeText( + mContext, + ex.message, + Toast.LENGTH_LONG + ).show() + } + } + //保存日志文件 + saveCrashInfo2File(ex) + } + + /** + * 收集设备参数信息 + */ + private fun collectDeviceInfo(ctx: Context) { + //获取versionName,versionCode + kotlin.runCatching { + val pm = ctx.packageManager + val pi = pm.getPackageInfo(ctx.packageName, PackageManager.GET_ACTIVITIES) + if (pi != null) { + val versionName = if (pi.versionName == null) "null" else pi.versionName + val versionCode = pi.versionCode.toString() + "" + paramsMap["versionName"] = versionName + paramsMap["versionCode"] = versionCode + } + } + + //获取所有系统信息 + val fields = Build::class.java.declaredFields + kotlin.runCatching { + for (field in fields) { + field.isAccessible = true + paramsMap[field.name] = field.get(null).toString() + } + } + } + + /** + * 添加自定义参数 + */ + private fun addCustomInfo() { + Log.i(tag, "addCustomInfo: 程序出错了...") + } + + /** + * 保存错误信息到文件中 + */ + private fun saveCrashInfo2File(ex: Throwable) { + kotlin.runCatching { + val sb = StringBuilder() + for ((key, value) in paramsMap) { + sb.append(key).append("=").append(value).append("\n") + } + + val writer = StringWriter() + val printWriter = PrintWriter(writer) + ex.printStackTrace(printWriter) + var cause: Throwable? = ex.cause + while (cause != null) { + cause.printStackTrace(printWriter) + cause = cause.cause + } + printWriter.close() + val result = writer.toString() + sb.append(result) + val timestamp = System.currentTimeMillis() + val time = format.format(Date()) + val fileName = "crash-$time-$timestamp.log" + val path = mContext?.externalCacheDir?.toString() + "/crash/" + val dir = File(path) + if (!dir.exists()) { + dir.mkdirs() + } + val fos = FileOutputStream(path + fileName) + fos.write(sb.toString().toByteArray()) + fos.close() + } + } + +} From 1e72cd46db8618cdcd4e3af1d2ae478d53eceb42 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 25 Aug 2019 19:41:58 +0800 Subject: [PATCH 0968/1997] up --- app/src/main/java/io/legado/app/help/CrashHandler.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/help/CrashHandler.kt b/app/src/main/java/io/legado/app/help/CrashHandler.kt index 59623a96d..98e50fa21 100644 --- a/app/src/main/java/io/legado/app/help/CrashHandler.kt +++ b/app/src/main/java/io/legado/app/help/CrashHandler.kt @@ -18,6 +18,7 @@ import java.util.* /** * 异常管理类 */ +@Suppress("DEPRECATION") class CrashHandler : Thread.UncaughtExceptionHandler { private val tag = this.javaClass.simpleName /** From 759d6028853bfa0e1074fdf292f7eb81c63ac26a Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 25 Aug 2019 19:52:24 +0800 Subject: [PATCH 0969/1997] up --- .../main/java/io/legado/app/help/CrashHandler.kt | 2 ++ .../io/legado/app/service/ReadAloudService.kt | 15 ++++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/CrashHandler.kt b/app/src/main/java/io/legado/app/help/CrashHandler.kt index 98e50fa21..35c29304c 100644 --- a/app/src/main/java/io/legado/app/help/CrashHandler.kt +++ b/app/src/main/java/io/legado/app/help/CrashHandler.kt @@ -8,6 +8,7 @@ import android.os.Handler import android.os.Looper import android.util.Log import android.widget.Toast +import io.legado.app.service.ReadAloudService import java.io.File import java.io.FileOutputStream import java.io.PrintWriter @@ -53,6 +54,7 @@ class CrashHandler : Thread.UncaughtExceptionHandler { * uncaughtException 回调函数 */ override fun uncaughtException(thread: Thread, ex: Throwable) { + ReadAloudService.clearTTS() handleException(ex) mDefaultHandler?.uncaughtException(thread, ex) } diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index cb300d6e3..574641b6a 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -29,6 +29,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage companion object { val tag: String = ReadAloudService::class.java.simpleName var isRun = false + var textToSpeech: TextToSpeech? = null fun play( context: Context, @@ -69,9 +70,14 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage context.startService(intent) } } + + fun clearTTS() { + textToSpeech?.stop() + textToSpeech?.shutdown() + textToSpeech = null + } } - private var textToSpeech: TextToSpeech? = null private var ttsIsSuccess: Boolean = false private lateinit var audioManager: AudioManager private lateinit var mFocusRequest: AudioFocusRequest @@ -103,12 +109,11 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage } override fun onDestroy() { - textToSpeech?.stop() - textToSpeech?.shutdown() - isRun = false + super.onDestroy() + clearTTS() unregisterReceiver(broadcastReceiver) postEvent(Bus.ALOUD_STATE, Status.STOP) - super.onDestroy() + isRun = false } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { From b3ea9f420b1f1ce61d61e1db60cf7f8209edf292 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 25 Aug 2019 19:57:44 +0800 Subject: [PATCH 0970/1997] up --- app/src/main/java/io/legado/app/service/ReadAloudService.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index 574641b6a..d45da9558 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -161,6 +161,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage readAloudNumber = it.getReadLength(pageIndex) contentList.clear() contentList.addAll(it.getUnRead(pageIndex).split("\n")) + playTTS() } ?: stopSelf() } ?: stopSelf() } From 8975e23e198b4880dfef0d60c3b3ac20f6daee4e Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 25 Aug 2019 21:07:43 +0800 Subject: [PATCH 0971/1997] up --- app/src/main/java/io/legado/app/help/MediaHelp.kt | 7 ++----- .../java/io/legado/app/ui/widget/page/PageView.kt | 14 +++++--------- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/MediaHelp.kt b/app/src/main/java/io/legado/app/help/MediaHelp.kt index a7235a342..b59a88e88 100644 --- a/app/src/main/java/io/legado/app/help/MediaHelp.kt +++ b/app/src/main/java/io/legado/app/help/MediaHelp.kt @@ -19,7 +19,6 @@ object MediaHelp { or PlaybackStateCompat.ACTION_STOP or PlaybackStateCompat.ACTION_SEEK_TO) - @RequiresApi(Build.VERSION_CODES.O) fun getFocusRequest(audioFocusChangeListener: AudioManager.OnAudioFocusChangeListener): AudioFocusRequest { val mPlaybackAttributes = AudioAttributes.Builder() @@ -34,13 +33,11 @@ object MediaHelp { } fun playSilentSound(mContext: Context) { - try { + kotlin.runCatching { // Stupid Android 8 "Oreo" hack to make media buttons work val mMediaPlayer = MediaPlayer.create(mContext, R.raw.silent_sound) - mMediaPlayer.setOnCompletionListener { it.release() } + mMediaPlayer.setOnCompletionListener { mMediaPlayer.release() } mMediaPlayer.start() - } catch (ignored: Exception) { } - } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index d598d5626..6d665ceef 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -169,11 +169,7 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att this.pageFactory = factory //可做成异步回调 - pageFactory?.let { - prevPage?.setContent(it.previousPage()) - curPage?.setContent(it.currentPage()) - nextPage?.setContent(it.nextPage()) - } + upContent() } override fun hasNext(): Boolean { @@ -185,10 +181,10 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att } fun upContent() { - callback?.let { - it.textChapter()?.let { textChapter -> - curPage?.setContent(textChapter.page(it.durChapterIndex())) - } + pageFactory?.let { + prevPage?.setContent(it.previousPage()) + curPage?.setContent(it.currentPage()) + nextPage?.setContent(it.nextPage()) } } From a79d45b00b9c9d980fadf3bf9850bcce92ad0b18 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 25 Aug 2019 21:15:02 +0800 Subject: [PATCH 0972/1997] up --- app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 00cc39274..783d79a97 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -408,7 +408,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea if (it) { moveToNextChapter() } else { - viewModel.durPageIndex += viewModel.durPageIndex + 1 + viewModel.durPageIndex = viewModel.durPageIndex + 1 page_view.upContent() viewModel.saveRead() } From 2a2ed2d3f9c456aa5cb8d5c975c2e897db5ad477 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 25 Aug 2019 21:19:10 +0800 Subject: [PATCH 0973/1997] up --- app/src/main/java/io/legado/app/service/ReadAloudService.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index d45da9558..aad32d9d6 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -225,6 +225,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage } private fun resumeReadAloud() { + pause = false playTTS() } From 993f7fb7f09a565c5f5b4dbee00f2ae8af0a26f7 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 25 Aug 2019 21:25:18 +0800 Subject: [PATCH 0974/1997] up --- .../main/java/io/legado/app/receiver/MediaButtonReceiver.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt index cec51bea0..ec23e0265 100644 --- a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt +++ b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt @@ -8,7 +8,6 @@ import io.legado.app.constant.Bus import io.legado.app.help.ActivityHelp import io.legado.app.ui.readbook.ReadBookActivity import io.legado.app.utils.postEvent -import org.jetbrains.anko.startActivity /** @@ -48,7 +47,9 @@ class MediaButtonReceiver : BroadcastReceiver() { private fun readAloud(context: Context) { ActivityHelp.isExist(ReadBookActivity::class.java).let { if (!it) { - context.startActivity() + val intent = Intent(context, ReadBookActivity::class.java) + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + context.startActivity(intent) } } postEvent(Bus.READ_ALOUD, true) From 9a5758634c2953fa05871e5b604700d4b97be241 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 25 Aug 2019 21:29:46 +0800 Subject: [PATCH 0975/1997] up --- .../java/io/legado/app/receiver/MediaButtonReceiver.kt | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt index ec23e0265..f1cbfb52c 100644 --- a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt +++ b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt @@ -45,12 +45,10 @@ class MediaButtonReceiver : BroadcastReceiver() { } private fun readAloud(context: Context) { - ActivityHelp.isExist(ReadBookActivity::class.java).let { - if (!it) { - val intent = Intent(context, ReadBookActivity::class.java) - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - context.startActivity(intent) - } + if (!ActivityHelp.isExist(ReadBookActivity::class.java)) { + val intent = Intent(context, ReadBookActivity::class.java) + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + context.startActivity(intent) } postEvent(Bus.READ_ALOUD, true) } From 75fce76f62225432b48cf79c4b21c6475623d1ce Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 25 Aug 2019 21:36:44 +0800 Subject: [PATCH 0976/1997] up --- app/src/main/java/io/legado/app/App.kt | 3 ++- app/src/main/java/io/legado/app/service/ReadAloudService.kt | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/App.kt b/app/src/main/java/io/legado/app/App.kt index c72c5133c..f1da4ab01 100644 --- a/app/src/main/java/io/legado/app/App.kt +++ b/app/src/main/java/io/legado/app/App.kt @@ -144,13 +144,13 @@ class App : Application() { private fun registerActivityLife(){ registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks{ override fun onActivityPaused(activity: Activity) { - ActivityHelp.add(activity) } override fun onActivityResumed(activity: Activity) { } override fun onActivityStarted(activity: Activity) { + } override fun onActivityDestroyed(activity: Activity) { @@ -164,6 +164,7 @@ class App : Application() { } override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) { + ActivityHelp.add(activity) } }) diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index aad32d9d6..7ae517880 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -219,6 +219,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage } private fun pauseReadAloud(pause: Boolean) { + if (pause) postEvent(Bus.ALOUD_STATE, Status.PAUSE) this.pause = pause textToSpeech?.stop() ReadAloudNotification.upNotification(this) From 6db709df6a3241109389e3882cb0c58bc0a3a9f8 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 25 Aug 2019 21:42:23 +0800 Subject: [PATCH 0977/1997] up --- app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt index 5903f9876..d63c7b526 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt @@ -42,7 +42,7 @@ data class TextChapter( fun getUnRead(pageIndex: Int): String { val stringBuilder = StringBuilder() - if (pageIndex < pages.size) { + if (pageIndex < pages.size && pages.isNotEmpty()) { for (index in pageIndex..lastIndex()) { stringBuilder.append(pages[index].text) } From 37666eea94700f0f249060d0fab30df8ea2eb38e Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 25 Aug 2019 22:09:51 +0800 Subject: [PATCH 0978/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 8 +-- .../io/legado/app/ui/widget/page/PageView.kt | 50 +++---------------- 2 files changed, 12 insertions(+), 46 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 783d79a97..c7c913e52 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -113,7 +113,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea override fun skipToPage(page: Int) { viewModel.durPageIndex = page - page_view.chapterLoadFinish() + page_view.upContent() } override fun skipPreChapter() { @@ -232,17 +232,17 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } ChapterProvider.getTextChapter(content_text_view, bookChapter, content).let { viewModel.curTextChapter = it - page_view.chapterLoadFinish() + page_view.upContent() read_menu.upReadProgress(it.pageSize(), viewModel.durPageIndex) } } viewModel.durChapterIndex - 1 -> { viewModel.prevTextChapter = ChapterProvider.getTextChapter(content_text_view, bookChapter, content) - page_view.chapterLoadFinish(-1) + page_view.upContent() } viewModel.durChapterIndex + 1 -> { viewModel.nextTextChapter = ChapterProvider.getTextChapter(content_text_view, bookChapter, content) - page_view.chapterLoadFinish(1) + page_view.upContent() } } } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 6d665ceef..0626f0d14 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -110,40 +110,6 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att return pageDelegate?.onTouch(event) ?: super.onTouchEvent(event) } - fun chapterLoadFinish(chapterOnDur: Int = 0) { - callback?.let { cb -> - when (chapterOnDur) { - 0 -> { - cb.textChapter()?.let { - curPage?.setContent(it.page(cb.durChapterPos())) - if (cb.durChapterPos() > 0) { - prevPage?.setContent(it.page(cb.durChapterPos().minus(1))) - } - if (cb.durChapterPos() < it.pageSize().minus(1)) { - nextPage?.setContent(it.page(cb.durChapterPos().plus(1))) - } - } - } - 1 -> { - cb.textChapter()?.let { - if (cb.durChapterPos() == it.pageSize().minus(1)) { - nextPage?.setContent(cb.textChapter(1)?.page(0)) - } - } - } - -1 -> { - cb.textChapter()?.let { - if (cb.durChapterPos() == 0) { - prevPage?.setContent(cb.textChapter(-1)?.lastPage()) - } - } - } - else -> { - } - } - } - } - fun fillPage(direction: PageDelegate.Direction) { pageFactory?.let { when (direction) { @@ -172,14 +138,6 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att upContent() } - override fun hasNext(): Boolean { - return true - } - - override fun hasPrev(): Boolean { - return true - } - fun upContent() { pageFactory?.let { prevPage?.setContent(it.previousPage()) @@ -188,6 +146,14 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att } } + override fun hasNext(): Boolean { + return true + } + + override fun hasPrev(): Boolean { + return true + } + fun upStyle() { curPage?.upStyle() prevPage?.upStyle() From 5970604607bf466fbee7f90eaae8dfb6fe9a26d6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 25 Aug 2019 22:15:01 +0800 Subject: [PATCH 0979/1997] up --- .../app/ui/widget/page/TextPageFactory.kt | 30 +++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt index 0cc47789e..d681f2b58 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt @@ -1,5 +1,8 @@ package io.legado.app.ui.widget.page +import io.legado.app.App +import io.legado.app.R + class TextPageFactory private constructor(dataSource: DataSource) : PageFactory(dataSource) { @@ -63,28 +66,43 @@ class TextPageFactory private constructor(dataSource: DataSource) : override fun currentPage(): TextPage? = dataSource.pageIndex().let { index -> return dataSource.getCurrentChapter()?.page(index) - ?: TextPage(index, "index:$index", "index:$index") + ?: TextPage(index, App.INSTANCE.getString(R.string.data_loading), "index:$index") } override fun nextPage(): TextPage? = dataSource.pageIndex().let { index -> dataSource.getCurrentChapter()?.let { if (index < it.pageSize() - 1) { return dataSource.getCurrentChapter()?.page(index + 1) - ?: TextPage(index + 1, "index:${index + 1}", "index:${index + 1}") + ?: TextPage( + index + 1, + App.INSTANCE.getString(R.string.data_loading), + "index:${index + 1}" + ) } } return dataSource.getNextChapter()?.page(0) - ?: TextPage(index + 1, "index:${index + 1}", "index:${index + 1}") + ?: TextPage( + index + 1, + App.INSTANCE.getString(R.string.data_loading), + "index:${index + 1}" + ) } override fun previousPage(): TextPage? = dataSource.pageIndex().let { index -> if (index > 0) { return dataSource.getCurrentChapter()?.page(index - 1) - ?: TextPage(index - 1, "index:${index - 1}", "index:${index - 1}") + ?: TextPage( + index - 1, + App.INSTANCE.getString(R.string.data_loading), + "index:${index - 1}" + ) } - return dataSource.getPreviousChapter()?.lastPage() - ?: TextPage(index - 1, "index:${index - 1}", "index:${index - 1}") + ?: TextPage( + index - 1, + App.INSTANCE.getString(R.string.data_loading), + "index:${index - 1}" + ) } From df30bcafd00ae28b4adac22e0bd4da08f45de5b3 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 25 Aug 2019 22:32:28 +0800 Subject: [PATCH 0980/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 29 ++++++++++++------- .../app/ui/widget/page/ChapterProvider.kt | 9 ++++-- .../legado/app/ui/widget/page/TextChapter.kt | 1 + 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index c7c913e52..ea59fb2e5 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -224,17 +224,10 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea launch { when (bookChapter.index) { viewModel.durChapterIndex -> { - tv_chapter_name.text = bookChapter.title - tv_chapter_name.visible() - if (!viewModel.isLocalBook) { - tv_chapter_url.text = bookChapter.url - tv_chapter_url.visible() - } - ChapterProvider.getTextChapter(content_text_view, bookChapter, content).let { - viewModel.curTextChapter = it - page_view.upContent() - read_menu.upReadProgress(it.pageSize(), viewModel.durPageIndex) - } + viewModel.curTextChapter = + ChapterProvider.getTextChapter(content_text_view, bookChapter, content) + page_view.upContent() + curChapterChange() } viewModel.durChapterIndex - 1 -> { viewModel.prevTextChapter = ChapterProvider.getTextChapter(content_text_view, bookChapter, content) @@ -248,6 +241,18 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } + private fun curChapterChange() { + viewModel.curTextChapter?.let { + tv_chapter_name.text = it.title + tv_chapter_name.visible() + if (!viewModel.isLocalBook) { + tv_chapter_url.text = it.url + tv_chapter_url.visible() + } + read_menu.upReadProgress(it.pageSize(), viewModel.durPageIndex) + } + } + override fun chapterSize(): Int { return viewModel.chapterSize } @@ -293,10 +298,12 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea override fun moveToNextChapter() { viewModel.moveToNextChapter() + curChapterChange() } override fun moveToPrevChapter() { viewModel.moveToPrevChapter() + curChapterChange() } override fun clickCenter() { diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt index 8aa4fffde..d24e411d2 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt @@ -45,8 +45,13 @@ object ChapterProvider { pageIndex++ } - return TextChapter(bookChapter.index, bookChapter.title, textPages, pageLengths) + return TextChapter( + bookChapter.index, + bookChapter.title, + bookChapter.url, + textPages, + pageLengths + ) } - } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt index d63c7b526..60df9a04a 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt @@ -3,6 +3,7 @@ package io.legado.app.ui.widget.page data class TextChapter( val position: Int, val title: String, + val url: String, val pages: List, val pageLengths: List ) { From 100f002edfcb74963afe9d8b6e82ee7967f63461 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 25 Aug 2019 22:38:40 +0800 Subject: [PATCH 0981/1997] up --- .../legado/app/ui/readbook/ReadBookActivity.kt | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index ea59fb2e5..8ed5a17d2 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -59,7 +59,8 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea viewModel.chapterListFinish.observe(this, Observer { bookLoadFinish() }) viewModel.initData(intent) savedInstanceState?.let { - changeSourceDialog = supportFragmentManager.findFragmentByTag(ChangeSourceDialog.tag) as? ChangeSourceDialog + changeSourceDialog = + supportFragmentManager.findFragmentByTag(ChangeSourceDialog.tag) as? ChangeSourceDialog changeSourceDialog?.callBack = this } setScreenBrightness(getPrefInt("brightness", 100)) @@ -114,6 +115,9 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea override fun skipToPage(page: Int) { viewModel.durPageIndex = page page_view.upContent() + if (readAloudStatus == Status.PLAY) { + readAloud() + } } override fun skipPreChapter() { @@ -230,12 +234,12 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea curChapterChange() } viewModel.durChapterIndex - 1 -> { - viewModel.prevTextChapter = ChapterProvider.getTextChapter(content_text_view, bookChapter, content) - page_view.upContent() + viewModel.prevTextChapter = + ChapterProvider.getTextChapter(content_text_view, bookChapter, content) } viewModel.durChapterIndex + 1 -> { - viewModel.nextTextChapter = ChapterProvider.getTextChapter(content_text_view, bookChapter, content) - page_view.upContent() + viewModel.nextTextChapter = + ChapterProvider.getTextChapter(content_text_view, bookChapter, content) } } } @@ -250,6 +254,9 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea tv_chapter_url.visible() } read_menu.upReadProgress(it.pageSize(), viewModel.durPageIndex) + if (readAloudStatus == Status.PLAY) { + readAloud() + } } } From da5e2f9c47c3874762d069964eed56cb3c8df48b Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 25 Aug 2019 22:51:34 +0800 Subject: [PATCH 0982/1997] up --- app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 2 ++ .../main/java/io/legado/app/ui/widget/page/TextPageFactory.kt | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 8ed5a17d2..762a02ac0 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -304,11 +304,13 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } override fun moveToNextChapter() { + viewModel.durPageIndex = 0 viewModel.moveToNextChapter() curChapterChange() } override fun moveToPrevChapter() { + viewModel.durPageIndex = viewModel.prevTextChapter?.lastIndex() ?: 0 viewModel.moveToPrevChapter() curChapterChange() } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt index d681f2b58..ba5ce5153 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt @@ -42,7 +42,6 @@ class TextPageFactory private constructor(dataSource: DataSource) : return if (hasNext()) { if (dataSource.getCurrentChapter()?.isLastIndex(index) == true) { dataSource.moveToNextChapter() - dataSource.setPageIndex(0) } else { dataSource.setPageIndex(index.plus(1)) } @@ -57,7 +56,6 @@ class TextPageFactory private constructor(dataSource: DataSource) : dataSource.setPageIndex(index.minus(1)) } else { dataSource.moveToPrevChapter() - dataSource.setPageIndex(dataSource.getPreviousChapter()?.lastIndex() ?: 0) } true } else From 0ab8ea716243380cc1206a622c9c5e815e9bc4c4 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 26 Aug 2019 07:07:22 +0800 Subject: [PATCH 0983/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 30 ++++++++++-- .../app/ui/widget/page/TextPageFactory.kt | 48 ++++++++++++------- 2 files changed, 58 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 762a02ac0..248400518 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -4,6 +4,8 @@ import android.app.Activity import android.content.Intent import android.net.Uri import android.os.Bundle +import android.text.Spannable +import android.text.SpannableStringBuilder import android.view.KeyEvent import android.view.Menu import android.view.MenuItem @@ -34,7 +36,10 @@ import kotlinx.android.synthetic.main.activity_read_book.* import kotlinx.android.synthetic.main.view_book_page.* import kotlinx.android.synthetic.main.view_read_menu.* import kotlinx.android.synthetic.main.view_title_bar.* +import kotlinx.coroutines.Dispatchers.IO +import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import org.jetbrains.anko.* import org.jetbrains.anko.sdk27.listeners.onClick @@ -415,9 +420,28 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea content_view.upStyle() page_view.upStyle() } - observeEvent(Bus.TTS_START) { - viewModel.curTextChapter?.let { - + observeEvent(Bus.TTS_START) { chapterStart -> + launch(IO) { + viewModel.curTextChapter?.let { + val pageStart = chapterStart - it.getReadLength(viewModel.durPageIndex) + val page = it.page(viewModel.durPageIndex) + if (page != null && page.text is SpannableStringBuilder) { + page.text.removeSpan(ChapterProvider.readAloudSpan) + var end = page.text.indexOf("\n", pageStart) + if (end == -1) end = page.text.length - 1 + var start = page.text.lastIndexOf("\n", pageStart) + if (start == -1) start = 0 + page.text.setSpan( + ChapterProvider.readAloudSpan, + start, + end, + Spannable.SPAN_INCLUSIVE_EXCLUSIVE + ) + withContext(Main) { + page_view.upContent() + } + } + } } } observeEvent(Bus.TTS_NEXT) { diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt index ba5ce5153..d5d3414e1 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt @@ -1,7 +1,9 @@ package io.legado.app.ui.widget.page +import android.text.SpannableStringBuilder import io.legado.app.App import io.legado.app.R +import io.legado.app.ui.widget.page.ChapterProvider.readAloudSpan class TextPageFactory private constructor(dataSource: DataSource) : PageFactory(dataSource) { @@ -70,16 +72,22 @@ class TextPageFactory private constructor(dataSource: DataSource) : override fun nextPage(): TextPage? = dataSource.pageIndex().let { index -> dataSource.getCurrentChapter()?.let { if (index < it.pageSize() - 1) { - return dataSource.getCurrentChapter()?.page(index + 1) - ?: TextPage( - index + 1, - App.INSTANCE.getString(R.string.data_loading), - "index:${index + 1}" - ) + return dataSource.getCurrentChapter()?.page(index + 1)?.apply { + if (text is SpannableStringBuilder) { + text.removeSpan(readAloudSpan) + } + } ?: TextPage( + index + 1, + App.INSTANCE.getString(R.string.data_loading), + "index:${index + 1}" + ) } } - return dataSource.getNextChapter()?.page(0) - ?: TextPage( + return dataSource.getNextChapter()?.page(0)?.apply { + if (text is SpannableStringBuilder) { + text.removeSpan(readAloudSpan) + } + } ?: TextPage( index + 1, App.INSTANCE.getString(R.string.data_loading), "index:${index + 1}" @@ -88,19 +96,25 @@ class TextPageFactory private constructor(dataSource: DataSource) : override fun previousPage(): TextPage? = dataSource.pageIndex().let { index -> if (index > 0) { - return dataSource.getCurrentChapter()?.page(index - 1) - ?: TextPage( - index - 1, - App.INSTANCE.getString(R.string.data_loading), - "index:${index - 1}" - ) - } - return dataSource.getPreviousChapter()?.lastPage() - ?: TextPage( + return dataSource.getCurrentChapter()?.page(index - 1)?.apply { + if (text is SpannableStringBuilder) { + text.removeSpan(readAloudSpan) + } + } ?: TextPage( index - 1, App.INSTANCE.getString(R.string.data_loading), "index:${index - 1}" ) + } + return dataSource.getPreviousChapter()?.lastPage()?.apply { + if (text is SpannableStringBuilder) { + text.removeSpan(readAloudSpan) + } + } ?: TextPage( + index - 1, + App.INSTANCE.getString(R.string.data_loading), + "index:${index - 1}" + ) } From 45994f363954be8e5edb9c20f583af163a825f16 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 26 Aug 2019 08:11:40 +0800 Subject: [PATCH 0984/1997] up --- .../java/io/legado/app/ui/readbook/ReadBookActivity.kt | 7 +++++-- .../java/io/legado/app/ui/readbook/ReadBookViewModel.kt | 3 +++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 248400518..2c2ff3def 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -412,7 +412,10 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea observeEvent(Bus.ALOUD_STATE) { readAloudStatus = it } observeEvent(Bus.TIME_CHANGED) { page_view.upTime() } observeEvent(Bus.BATTERY_CHANGED) { page_view.upBattery(it) } - observeEvent(Bus.OPEN_CHAPTER) { viewModel.openChapter(it) } + observeEvent(Bus.OPEN_CHAPTER) { + viewModel.openChapter(it) + page_view.upContent() + } observeEventSticky(Bus.READ_ALOUD) { onClickReadAloud() } observeEvent(Bus.UP_CONFIG) { Help.upSystemUiVisibility(window, !read_menu.isVisible) @@ -428,7 +431,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea if (page != null && page.text is SpannableStringBuilder) { page.text.removeSpan(ChapterProvider.readAloudSpan) var end = page.text.indexOf("\n", pageStart) - if (end == -1) end = page.text.length - 1 + if (end == -1) end = page.text.length var start = page.text.lastIndexOf("\n", pageStart) if (start == -1) start = 0 page.text.setSpan( diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index 45fd04c68..7dcd4254d 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -171,6 +171,9 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } fun openChapter(chapter: BookChapter) { + prevTextChapter = null + curTextChapter = null + nextTextChapter = null if (chapter.index != durChapterIndex) { durChapterIndex = chapter.index durPageIndex = 0 From f7e2d5fce2aacf98c26302d761ce8e4b9d6bd158 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 26 Aug 2019 08:24:10 +0800 Subject: [PATCH 0985/1997] up --- app/src/main/java/io/legado/app/ui/readbook/Help.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/Help.kt b/app/src/main/java/io/legado/app/ui/readbook/Help.kt index 13bdebf50..1eafb1902 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/Help.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/Help.kt @@ -34,7 +34,7 @@ object Help { window.decorView.systemUiVisibility = flag } - // 该方法需要在View完全被绘制出来之后调用,否则判断不了 + //该方法需要在View完全被绘制出来之后调用,否则判断不了 //在比如 onWindowFocusChanged()方法中可以得到正确的结果 fun isNavigationBarExist(activity: Activity?): Boolean { activity?.let { From 0376267e27aee5dbe157107347e3ad0daa9c37f9 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 26 Aug 2019 08:27:04 +0800 Subject: [PATCH 0986/1997] up --- app/src/main/java/io/legado/app/ui/readbook/Help.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/Help.kt b/app/src/main/java/io/legado/app/ui/readbook/Help.kt index 1eafb1902..c6226d3a8 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/Help.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/Help.kt @@ -34,8 +34,11 @@ object Help { window.decorView.systemUiVisibility = flag } - //该方法需要在View完全被绘制出来之后调用,否则判断不了 - //在比如 onWindowFocusChanged()方法中可以得到正确的结果 + /** + * 返回NavigationBar是否存在 + * 该方法需要在View完全被绘制出来之后调用,否则判断不了 + * 在比如 onWindowFocusChanged()方法中可以得到正确的结果 + */ fun isNavigationBarExist(activity: Activity?): Boolean { activity?.let { val vp = it.window.decorView as? ViewGroup From c3a7f4991f489ce1990c3b8f537326d9c63f688c Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 26 Aug 2019 08:47:33 +0800 Subject: [PATCH 0987/1997] up --- .../io/legado/app/service/ReadAloudService.kt | 13 +++++--- .../app/ui/readbook/ReadBookActivity.kt | 32 +++++++++++-------- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index 7ae517880..2dca6a24a 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -36,7 +36,8 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage title: String, subtitle: String, pageIndex: Int, - dataKey: String + dataKey: String, + play: Boolean = true ) { val readAloudIntent = Intent(context, ReadAloudService::class.java) readAloudIntent.action = "play" @@ -44,6 +45,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage readAloudIntent.putExtra("subtitle", subtitle) readAloudIntent.putExtra("pageIndex", pageIndex) readAloudIntent.putExtra("dataKey", dataKey) + readAloudIntent.putExtra("play", play) context.startService(readAloudIntent) } @@ -123,7 +125,10 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage title = intent.getStringExtra("title") ?: "" subtitle = intent.getStringExtra("subtitle") ?: "" pageIndex = intent.getIntExtra("pageIndex", 0) - newReadAloud(intent.getStringExtra("dataKey")) + newReadAloud( + intent.getStringExtra("dataKey"), + intent.getBooleanExtra("play", true) + ) } "pause" -> pauseReadAloud(true) "resume" -> resumeReadAloud() @@ -153,7 +158,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage } } - private fun newReadAloud(dataKey: String?) { + private fun newReadAloud(dataKey: String?, paly: Boolean) { dataKey?.let { textChapter = IntentDataHelp.getData(dataKey) as? TextChapter textChapter?.let { @@ -161,7 +166,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage readAloudNumber = it.getReadLength(pageIndex) contentList.clear() contentList.addAll(it.getUnRead(pageIndex).split("\n")) - playTTS() + if (paly) playTTS() } ?: stopSelf() } ?: stopSelf() } diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 2c2ff3def..424fec041 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -120,9 +120,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea override fun skipToPage(page: Int) { viewModel.durPageIndex = page page_view.upContent() - if (readAloudStatus == Status.PLAY) { - readAloud() - } + curPageChanged() } override fun skipPreChapter() { @@ -236,7 +234,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea viewModel.curTextChapter = ChapterProvider.getTextChapter(content_text_view, bookChapter, content) page_view.upContent() - curChapterChange() + curChapterChanged() } viewModel.durChapterIndex - 1 -> { viewModel.prevTextChapter = @@ -250,7 +248,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } - private fun curChapterChange() { + private fun curChapterChanged() { viewModel.curTextChapter?.let { tv_chapter_name.text = it.title tv_chapter_name.visible() @@ -259,8 +257,15 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea tv_chapter_url.visible() } read_menu.upReadProgress(it.pageSize(), viewModel.durPageIndex) - if (readAloudStatus == Status.PLAY) { - readAloud() + curPageChanged() + } + } + + private fun curPageChanged() { + when (readAloudStatus) { + Status.PLAY -> readAloud() + Status.PAUSE -> { + readAloud(false) } } } @@ -294,9 +299,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea override fun setPageIndex(pageIndex: Int) { viewModel.durPageIndex = pageIndex viewModel.saveRead() - if (readAloudStatus == Status.PLAY) { - readAloud() - } + curPageChanged() } override fun textChapter(chapterOnDur: Int): TextChapter? { @@ -311,13 +314,13 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea override fun moveToNextChapter() { viewModel.durPageIndex = 0 viewModel.moveToNextChapter() - curChapterChange() + curChapterChanged() } override fun moveToPrevChapter() { viewModel.durPageIndex = viewModel.prevTextChapter?.lastIndex() ?: 0 viewModel.moveToPrevChapter() - curChapterChange() + curChapterChanged() } override fun clickCenter() { @@ -346,7 +349,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea /** * 朗读 */ - private fun readAloud() { + private fun readAloud(play: Boolean = true) { val book = viewModel.bookData.value val textChapter = viewModel.curTextChapter if (book != null && textChapter != null) { @@ -357,7 +360,8 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea book.name, textChapter.title, viewModel.durPageIndex, - key + key, + play ) } } From dda07dcd7d54833bcaa39480a4b214f3e7674d3a Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 26 Aug 2019 09:01:10 +0800 Subject: [PATCH 0988/1997] up --- app/src/main/java/io/legado/app/service/ReadAloudService.kt | 2 +- app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index 2dca6a24a..cc2cf51e9 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -176,7 +176,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage if (contentList.size < 1 || !ttsIsSuccess) { return } - if (!pause && requestFocus()) { + if (requestFocus()) { postEvent(Bus.ALOUD_STATE, Status.PLAY) ReadAloudNotification.upNotification(this) for (i in nowSpeak until contentList.size) { diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 424fec041..0dd3790eb 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -420,7 +420,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea viewModel.openChapter(it) page_view.upContent() } - observeEventSticky(Bus.READ_ALOUD) { onClickReadAloud() } + observeEvent(Bus.READ_ALOUD) { onClickReadAloud() } observeEvent(Bus.UP_CONFIG) { Help.upSystemUiVisibility(window, !read_menu.isVisible) page_view.upBg() From ecd9d4feb8b234ec5b2804a0a7c955b350b86dca Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 26 Aug 2019 09:03:31 +0800 Subject: [PATCH 0989/1997] up --- app/src/main/java/io/legado/app/service/ReadAloudService.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index cc2cf51e9..e769f7991 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -158,7 +158,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage } } - private fun newReadAloud(dataKey: String?, paly: Boolean) { + private fun newReadAloud(dataKey: String?, play: Boolean) { dataKey?.let { textChapter = IntentDataHelp.getData(dataKey) as? TextChapter textChapter?.let { @@ -166,7 +166,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage readAloudNumber = it.getReadLength(pageIndex) contentList.clear() contentList.addAll(it.getUnRead(pageIndex).split("\n")) - if (paly) playTTS() + if (play) playTTS() } ?: stopSelf() } ?: stopSelf() } From 15804a4cf54a0a5503500d31fa2ea6e19b274c04 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 26 Aug 2019 09:47:28 +0800 Subject: [PATCH 0990/1997] up --- .../java/io/legado/app/help/ReadBookConfig.kt | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index dad8c76d3..5fb46551d 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -4,10 +4,7 @@ import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.graphics.drawable.Drawable import io.legado.app.App -import io.legado.app.utils.GSON -import io.legado.app.utils.fromJsonArray -import io.legado.app.utils.getPrefInt -import io.legado.app.utils.putPrefInt +import io.legado.app.utils.* import java.io.BufferedWriter import java.io.File import java.io.FileWriter @@ -24,8 +21,16 @@ object ReadBookConfig { } var styleSelect - get() = App.INSTANCE.getPrefInt("readStyleSelect") - set(value) = App.INSTANCE.putPrefInt("readStyleSelect", value) + get() = if (App.INSTANCE.isNightTheme) { + App.INSTANCE.getPrefInt("readStyleSelectNight", 4) + } else { + App.INSTANCE.getPrefInt("readStyleSelect") + } + set(value) = if (App.INSTANCE.isNightTheme) { + App.INSTANCE.putPrefInt("readStyleSelectNight", value) + } else { + App.INSTANCE.putPrefInt("readStyleSelect", value) + } var bg: Drawable? = null fun getConfig(index: Int = styleSelect): Config { From cfbc72cbd3d1dab1171fa16e8cec612e2f13e02e Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 26 Aug 2019 09:59:40 +0800 Subject: [PATCH 0991/1997] up --- .../main/java/io/legado/app/model/WebBook.kt | 44 ++++++++++++++++--- .../app/model/webbook/BookChapterList.kt | 41 ++++++++++++++--- .../legado/app/model/webbook/BookContent.kt | 15 +++++-- 3 files changed, 84 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/WebBook.kt b/app/src/main/java/io/legado/app/model/WebBook.kt index 972ec4b87..8ed3f812b 100644 --- a/app/src/main/java/io/legado/app/model/WebBook.kt +++ b/app/src/main/java/io/legado/app/model/WebBook.kt @@ -25,7 +25,13 @@ class WebBook(private val bookSource: BookSource) { ): Coroutine> { return Coroutine.async(scope) { bookSource.getSearchRule().searchUrl?.let { searchUrl -> - val analyzeUrl = AnalyzeUrl(searchUrl, key, page, baseUrl = sourceUrl) + val analyzeUrl = AnalyzeUrl( + ruleUrl = searchUrl, + key = key, + page = page, + baseUrl = sourceUrl, + headerMapF = bookSource.getHeaderMap() + ) val response = analyzeUrl.getResponseAsync().await() BookList.analyzeBookList(response, bookSource, analyzeUrl, isSearch) } ?: arrayListOf() @@ -34,16 +40,29 @@ class WebBook(private val bookSource: BookSource) { fun getBookInfo(book: Book, scope: CoroutineScope = Coroutine.DEFAULT): Coroutine { return Coroutine.async(scope) { - val analyzeUrl = AnalyzeUrl(book = book, ruleUrl = book.bookUrl, baseUrl = sourceUrl) + val analyzeUrl = AnalyzeUrl( + book = book, + ruleUrl = book.bookUrl, + baseUrl = sourceUrl, + headerMapF = bookSource.getHeaderMap() + ) val response = analyzeUrl.getResponseAsync().await() BookInfo.analyzeBookInfo(book, response.body(), bookSource, analyzeUrl) book } } - fun getChapterList(book: Book, scope: CoroutineScope = Coroutine.DEFAULT): Coroutine> { + fun getChapterList( + book: Book, + scope: CoroutineScope = Coroutine.DEFAULT + ): Coroutine> { return Coroutine.async(scope) { - val analyzeUrl = AnalyzeUrl(book = book, ruleUrl = book.tocUrl, baseUrl = book.bookUrl) + val analyzeUrl = AnalyzeUrl( + book = book, + ruleUrl = book.tocUrl, + baseUrl = book.bookUrl, + headerMapF = bookSource.getHeaderMap() + ) val response = analyzeUrl.getResponseAsync().await() BookChapterList.analyzeChapterList(this, book, response, bookSource, analyzeUrl) } @@ -56,9 +75,22 @@ class WebBook(private val bookSource: BookSource) { scope: CoroutineScope = Coroutine.DEFAULT ): Coroutine { return Coroutine.async(scope) { - val analyzeUrl = AnalyzeUrl(book = book, ruleUrl = bookChapter.url, baseUrl = book.tocUrl) + val analyzeUrl = + AnalyzeUrl( + book = book, + ruleUrl = bookChapter.url, + baseUrl = book.tocUrl, + headerMapF = bookSource.getHeaderMap() + ) val response = analyzeUrl.getResponseAsync().await() - BookContent.analyzeContent(this, response, book, bookChapter, bookSource, nextChapterUrl) + BookContent.analyzeContent( + this, + response, + book, + bookChapter, + bookSource, + nextChapterUrl + ) } } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt b/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt index 57c8635ba..56adb8278 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt @@ -44,7 +44,8 @@ object BookChapterList { if (listRule.startsWith("+")) { listRule = listRule.substring(1) } - var chapterData = analyzeChapterList(body, baseUrl, tocRule, listRule, book, bookSource, printLog = true) + var chapterData = + analyzeChapterList(body, baseUrl, tocRule, listRule, book, bookSource, printLog = true) chapterData.chapterList?.let { chapterList.addAll(it) } @@ -52,10 +53,22 @@ object BookChapterList { var nextUrl = chapterData.nextUrl[0] while (nextUrl.isNotEmpty() && !nextUrlList.contains(nextUrl)) { nextUrlList.add(nextUrl) - AnalyzeUrl(ruleUrl = nextUrl, book = book).getResponseAsync().await() + AnalyzeUrl( + ruleUrl = nextUrl, + book = book, + headerMapF = bookSource.getHeaderMap() + ).getResponseAsync().await() .body()?.let { nextBody -> - chapterData = analyzeChapterList(nextBody, nextUrl, tocRule, listRule, book, bookSource) - nextUrl = if (chapterData.nextUrl.isNotEmpty()) chapterData.nextUrl[0] else "" + chapterData = analyzeChapterList( + nextBody, + nextUrl, + tocRule, + listRule, + book, + bookSource + ) + nextUrl = + if (chapterData.nextUrl.isNotEmpty()) chapterData.nextUrl[0] else "" chapterData.chapterList?.let { chapterList.addAll(it) } @@ -69,7 +82,11 @@ object BookChapterList { } for (item in chapterDataList) { withContext(coroutineScope.coroutineContext) { - val nextResponse = AnalyzeUrl(ruleUrl = item.nextUrl, book = book).getResponseAsync().await() + val nextResponse = AnalyzeUrl( + ruleUrl = item.nextUrl, + book = book, + headerMapF = bookSource.getHeaderMap() + ).getResponseAsync().await() val nextChapterData = analyzeChapterList( nextResponse.body() ?: "", item.nextUrl, @@ -126,7 +143,12 @@ object BookChapterList { } } } - SourceDebug.printLog(bookSource.bookSourceUrl, 1, TextUtils.join(",", nextUrlList), printLog) + SourceDebug.printLog( + bookSource.bookSourceUrl, + 1, + TextUtils.join(",", nextUrlList), + printLog + ) } SourceDebug.printLog(bookSource.bookSourceUrl, 1, "解析目录列表", printLog) val elements = analyzeRule.getElements(listRule) @@ -146,7 +168,12 @@ object BookChapterList { chapterList.add(bookChapter) } } - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "${chapterList[0].title}${chapterList[0].url}", printLog) + SourceDebug.printLog( + bookSource.bookSourceUrl, + 1, + "${chapterList[0].title}${chapterList[0].url}", + printLog + ) } return ChapterData(chapterList, nextUrlList) } diff --git a/app/src/main/java/io/legado/app/model/webbook/BookContent.kt b/app/src/main/java/io/legado/app/model/webbook/BookContent.kt index 77fb14ebc..0f78b9d4a 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookContent.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookContent.kt @@ -51,10 +51,15 @@ object BookContent { == NetworkUtils.getAbsoluteURL(baseUrl, nextChapterUrl) ) break nextUrlList.add(nextUrl) - AnalyzeUrl(ruleUrl = nextUrl, book = book).getResponseAsync().await() + AnalyzeUrl( + ruleUrl = nextUrl, + book = book, + headerMapF = bookSource.getHeaderMap() + ).getResponseAsync().await() .body()?.let { nextBody -> contentData = analyzeContent(nextBody, contentRule, book, baseUrl) - nextUrl = if (contentData.nextUrl.isNotEmpty()) contentData.nextUrl[0] else "" + nextUrl = + if (contentData.nextUrl.isNotEmpty()) contentData.nextUrl[0] else "" content.append(contentData.content) } } @@ -66,7 +71,11 @@ object BookContent { } for (item in contentDataList) { withContext(coroutineScope.coroutineContext) { - val nextResponse = AnalyzeUrl(ruleUrl = item.nextUrl, book = book).getResponseAsync().await() + val nextResponse = AnalyzeUrl( + ruleUrl = item.nextUrl, + book = book, + headerMapF = bookSource.getHeaderMap() + ).getResponseAsync().await() val nextContentData = analyzeContent( nextResponse.body() ?: "", contentRule, From 3b62ce358f4cbc3a8e7042018023e46e08dc2cfe Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 26 Aug 2019 10:11:00 +0800 Subject: [PATCH 0992/1997] up --- app/src/main/java/io/legado/app/help/storage/OldRule.kt | 6 ++++++ app/src/main/java/io/legado/app/help/storage/Restore.kt | 1 + 2 files changed, 7 insertions(+) diff --git a/app/src/main/java/io/legado/app/help/storage/OldRule.kt b/app/src/main/java/io/legado/app/help/storage/OldRule.kt index 27738806c..361fd1402 100644 --- a/app/src/main/java/io/legado/app/help/storage/OldRule.kt +++ b/app/src/main/java/io/legado/app/help/storage/OldRule.kt @@ -45,4 +45,10 @@ object OldRule { } return url } + + fun uaToHeader(ua: String?): String? { + if (ua.isNullOrEmpty()) return null + val map = mapOf(Pair("user_agent", ua)) + return GSON.toJson(map) + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/help/storage/Restore.kt b/app/src/main/java/io/legado/app/help/storage/Restore.kt index 0e9b73dbf..82d256d88 100644 --- a/app/src/main/java/io/legado/app/help/storage/Restore.kt +++ b/app/src/main/java/io/legado/app/help/storage/Restore.kt @@ -109,6 +109,7 @@ object Restore { source.loginUrl = jsonItem.readString("loginUrl") source.bookUrlPattern = jsonItem.readString("ruleBookUrlPattern") source.customOrder = jsonItem.readInt("serialNumber") ?: 0 + source.header = OldRule.uaToHeader(jsonItem.readString("httpUserAgent")) val searchRule = SearchRule( searchUrl = OldRule.toNewUrl(jsonItem.readString("ruleSearchUrl")), bookList = jsonItem.readString("ruleSearchList"), From 1899374419c2ffa7402ca863f12bb5d6f7ee2a24 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 26 Aug 2019 10:38:43 +0800 Subject: [PATCH 0993/1997] up --- app/src/main/res/layout/dialog_read_aloud.xml | 52 ++++++++++++++----- app/src/main/res/values/strings.xml | 1 + 2 files changed, 40 insertions(+), 13 deletions(-) diff --git a/app/src/main/res/layout/dialog_read_aloud.xml b/app/src/main/res/layout/dialog_read_aloud.xml index 7ad7dc815..bf5e0ec86 100644 --- a/app/src/main/res/layout/dialog_read_aloud.xml +++ b/app/src/main/res/layout/dialog_read_aloud.xml @@ -1,12 +1,12 @@ - + + + + @@ -29,9 +45,24 @@ android:layout_height="30dp" android:layout_marginLeft="8dp" android:layout_marginRight="8dp" + android:background="?android:attr/selectableItemBackgroundBorderless" android:src="@drawable/ic_stop_black_24dp" android:tint="@color/tv_text_default" /> + + + + - - - + android:text="@string/flow_sys" + android:contentDescription="@string/flow_sys" + tools:ignore="RtlHardcoded" /> %d%% %d分钟 自动亮度%s + 按页 From db88e7ebec1ba6a494f605e95ecb0c3a030afdba Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 26 Aug 2019 10:55:25 +0800 Subject: [PATCH 0994/1997] up --- app/src/main/res/layout/dialog_read_aloud.xml | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/app/src/main/res/layout/dialog_read_aloud.xml b/app/src/main/res/layout/dialog_read_aloud.xml index bf5e0ec86..4d3849c6a 100644 --- a/app/src/main/res/layout/dialog_read_aloud.xml +++ b/app/src/main/res/layout/dialog_read_aloud.xml @@ -29,6 +29,16 @@ android:layout_height="1dp" android:layout_weight="1" /> + + + + Date: Mon, 26 Aug 2019 11:05:23 +0800 Subject: [PATCH 0995/1997] up --- .../io/legado/app/ui/readbook/config/ReadAloudDialog.kt | 9 +++++++++ app/src/main/res/layout/dialog_read_aloud.xml | 1 - 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt index 4bc3e6335..41015b5f2 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt @@ -11,7 +11,9 @@ import io.legado.app.R import io.legado.app.constant.Bus import io.legado.app.service.ReadAloudService import io.legado.app.ui.readbook.Help +import io.legado.app.ui.readbook.ReadBookActivity import io.legado.app.utils.observeEvent +import kotlinx.android.synthetic.main.activity_read_book.* import kotlinx.android.synthetic.main.dialog_read_aloud.* import org.jetbrains.anko.sdk27.listeners.onClick @@ -53,6 +55,13 @@ class ReadAloudDialog : DialogFragment() { } private fun initOnClick() { + iv_menu.onClick { + val activity = activity + if (activity is ReadBookActivity) { + activity.read_menu.runMenuIn() + dismiss() + } + } iv_stop.onClick { ReadAloudService.stop(requireContext()) } } diff --git a/app/src/main/res/layout/dialog_read_aloud.xml b/app/src/main/res/layout/dialog_read_aloud.xml index 4d3849c6a..1e7a2c25b 100644 --- a/app/src/main/res/layout/dialog_read_aloud.xml +++ b/app/src/main/res/layout/dialog_read_aloud.xml @@ -149,7 +149,6 @@ android:button="@null" android:drawableRight="?android:attr/listChoiceIndicatorMultiple" android:drawableEnd="?android:attr/listChoiceIndicatorMultiple" - android:clickable="false" android:text="@string/flow_sys" android:contentDescription="@string/flow_sys" tools:ignore="RtlHardcoded" /> From 6fd47432cf98dcbeb4144a7475f5d58f8a4b29ee Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 26 Aug 2019 11:42:01 +0800 Subject: [PATCH 0996/1997] up --- .../main/java/io/legado/app/constant/Bus.kt | 2 +- .../app/receiver/MediaButtonReceiver.kt | 2 +- .../app/ui/readbook/ReadBookActivity.kt | 4 +-- .../io/legado/app/ui/readbook/ReadMenu.kt | 2 +- .../app/ui/readbook/config/ReadAloudDialog.kt | 36 ++++++++++++++++++- app/src/main/res/layout/dialog_read_aloud.xml | 3 +- 6 files changed, 42 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/io/legado/app/constant/Bus.kt b/app/src/main/java/io/legado/app/constant/Bus.kt index e84d4b8c3..562da87ed 100644 --- a/app/src/main/java/io/legado/app/constant/Bus.kt +++ b/app/src/main/java/io/legado/app/constant/Bus.kt @@ -8,7 +8,7 @@ object Bus { const val TTS_NEXT = "ttsNextPage" const val BATTERY_CHANGED = "batteryChanged" const val TIME_CHANGED = "timeChanged" - const val READ_ALOUD = "readAloud" + const val READ_ALOUD_BUTTON = "readAloudButton" const val UP_CONFIG = "upConfig" const val OPEN_CHAPTER = "openChapter" } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt index f1cbfb52c..2e6d33712 100644 --- a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt +++ b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt @@ -50,7 +50,7 @@ class MediaButtonReceiver : BroadcastReceiver() { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) context.startActivity(intent) } - postEvent(Bus.READ_ALOUD, true) + postEvent(Bus.READ_ALOUD_BUTTON, true) } } diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 0dd3790eb..ae660a2a6 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -53,7 +53,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea private val requestCodeEditSource = 111 private var changeSourceDialog: ChangeSourceDialog? = null private var timeElectricityReceiver: TimeElectricityReceiver? = null - private var readAloudStatus = Status.STOP + var readAloudStatus = Status.STOP override fun onActivityCreated(savedInstanceState: Bundle?) { setSupportActionBar(toolbar) @@ -420,7 +420,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea viewModel.openChapter(it) page_view.upContent() } - observeEvent(Bus.READ_ALOUD) { onClickReadAloud() } + observeEvent(Bus.READ_ALOUD_BUTTON) { onClickReadAloud() } observeEvent(Bus.UP_CONFIG) { Help.upSystemUiVisibility(window, !read_menu.isVisible) page_view.upBg() diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt index 256e02cb3..630735701 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt @@ -153,7 +153,7 @@ class ReadMenu : FrameLayout { //朗读 ll_read_aloud.onClick { runMenuOut { - postEvent(Bus.READ_ALOUD, true) + postEvent(Bus.READ_ALOUD_BUTTON, true) } } diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt index 41015b5f2..02de1d2a1 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt @@ -9,10 +9,14 @@ import android.view.ViewGroup import androidx.fragment.app.DialogFragment import io.legado.app.R import io.legado.app.constant.Bus +import io.legado.app.constant.Status import io.legado.app.service.ReadAloudService import io.legado.app.ui.readbook.Help import io.legado.app.ui.readbook.ReadBookActivity +import io.legado.app.utils.getPrefBoolean import io.legado.app.utils.observeEvent +import io.legado.app.utils.postEvent +import io.legado.app.utils.putPrefBoolean import kotlinx.android.synthetic.main.activity_read_book.* import kotlinx.android.synthetic.main.dialog_read_aloud.* import org.jetbrains.anko.sdk27.listeners.onClick @@ -46,12 +50,33 @@ class ReadAloudDialog : DialogFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) initData() + initOnChange() initOnClick() } private fun initData() { - observeEvent(Bus.ALOUD_STATE) {} + observeEvent(Bus.ALOUD_STATE) { upPlayState(it) } + val activity = activity + if (activity is ReadBookActivity) { + upPlayState(activity.readAloudStatus) + } + cb_by_page.isChecked = requireContext().getPrefBoolean("readAloudByPage") + cb_tts_follow_sys.isChecked = requireContext().getPrefBoolean("ttsFollowSys", true) + seek_tts_SpeechRate.isEnabled = !cb_tts_follow_sys.isChecked + } + private fun initOnChange() { + cb_by_page.setOnCheckedChangeListener { buttonView, isChecked -> + if (buttonView.isPressed) { + requireContext().putPrefBoolean("readAloudByPage", isChecked) + } + } + cb_tts_follow_sys.setOnCheckedChangeListener { buttonView, isChecked -> + if (buttonView.isPressed) { + requireContext().putPrefBoolean("ttsFollowSys", isChecked) + seek_tts_SpeechRate.isEnabled = !isChecked + } + } } private fun initOnClick() { @@ -63,6 +88,15 @@ class ReadAloudDialog : DialogFragment() { } } iv_stop.onClick { ReadAloudService.stop(requireContext()) } + iv_play_pause.onClick { postEvent(Bus.READ_ALOUD_BUTTON, true) } + } + + private fun upPlayState(state: Int) { + if (state == Status.PAUSE) { + iv_play_pause.setImageResource(R.drawable.ic_play_24dp) + } else { + iv_play_pause.setImageResource(R.drawable.ic_pause_24dp) + } } } \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_read_aloud.xml b/app/src/main/res/layout/dialog_read_aloud.xml index 1e7a2c25b..e172e551b 100644 --- a/app/src/main/res/layout/dialog_read_aloud.xml +++ b/app/src/main/res/layout/dialog_read_aloud.xml @@ -75,6 +75,7 @@ android:layout_weight="1" /> Date: Mon, 26 Aug 2019 12:23:55 +0800 Subject: [PATCH 0997/1997] up --- .../io/legado/app/ui/readbook/config/ReadAloudDialog.kt | 6 ++---- app/src/main/res/layout/dialog_read_aloud.xml | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt index 02de1d2a1..880e4f3d3 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt @@ -13,10 +13,7 @@ import io.legado.app.constant.Status import io.legado.app.service.ReadAloudService import io.legado.app.ui.readbook.Help import io.legado.app.ui.readbook.ReadBookActivity -import io.legado.app.utils.getPrefBoolean -import io.legado.app.utils.observeEvent -import io.legado.app.utils.postEvent -import io.legado.app.utils.putPrefBoolean +import io.legado.app.utils.* import kotlinx.android.synthetic.main.activity_read_book.* import kotlinx.android.synthetic.main.dialog_read_aloud.* import org.jetbrains.anko.sdk27.listeners.onClick @@ -63,6 +60,7 @@ class ReadAloudDialog : DialogFragment() { cb_by_page.isChecked = requireContext().getPrefBoolean("readAloudByPage") cb_tts_follow_sys.isChecked = requireContext().getPrefBoolean("ttsFollowSys", true) seek_tts_SpeechRate.isEnabled = !cb_tts_follow_sys.isChecked + seek_tts_SpeechRate.progress = requireContext().getPrefInt("ttsSpeechRate", 10) } private fun initOnChange() { diff --git a/app/src/main/res/layout/dialog_read_aloud.xml b/app/src/main/res/layout/dialog_read_aloud.xml index e172e551b..0583b2894 100644 --- a/app/src/main/res/layout/dialog_read_aloud.xml +++ b/app/src/main/res/layout/dialog_read_aloud.xml @@ -161,7 +161,7 @@ android:layout_height="30dp" android:layout_marginStart="15dp" android:layout_marginEnd="15dp" - android:max="20" /> + android:max="50" /> From a1348e797657bf5f841c8733df03c3f1cdd5721b Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 26 Aug 2019 12:46:18 +0800 Subject: [PATCH 0998/1997] up --- .../io/legado/app/service/ReadAloudService.kt | 16 +++++++++++- .../app/ui/readbook/config/ReadAloudDialog.kt | 26 ++++++++++++++++++- app/src/main/res/layout/dialog_read_aloud.xml | 2 +- 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index e769f7991..510e5111a 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -19,6 +19,7 @@ import io.legado.app.help.MediaHelp import io.legado.app.receiver.MediaButtonReceiver import io.legado.app.service.notification.ReadAloudNotification import io.legado.app.ui.widget.page.TextChapter +import io.legado.app.utils.getPrefInt import io.legado.app.utils.postEvent import io.legado.app.utils.toast import kotlinx.coroutines.launch @@ -73,6 +74,14 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage } } + fun upTtsSpeechRate(context: Context) { + if (isRun) { + val intent = Intent(context, ReadAloudService::class.java) + intent.action = "upTtsSpeechRate" + context.startService(intent) + } + } + fun clearTTS() { textToSpeech?.stop() textToSpeech?.shutdown() @@ -107,6 +116,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage initMediaSession() initBroadcastReceiver() upMediaSessionPlaybackState() + upSpeechRate() ReadAloudNotification.upNotification(this) } @@ -132,7 +142,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage } "pause" -> pauseReadAloud(true) "resume" -> resumeReadAloud() - "stop" -> stopSelf() + "upTtsSpeechRate" -> upSpeechRate() else -> stopSelf() } } @@ -189,6 +199,10 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage } } + private fun upSpeechRate() { + textToSpeech?.setSpeechRate((this.getPrefInt("ttsSpeechRate", 5) + 5) / 10f) + } + /** * 初始化MediaSession */ diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt index 880e4f3d3..517e3d0f0 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt @@ -6,6 +6,7 @@ import android.view.Gravity import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.SeekBar import androidx.fragment.app.DialogFragment import io.legado.app.R import io.legado.app.constant.Bus @@ -60,7 +61,7 @@ class ReadAloudDialog : DialogFragment() { cb_by_page.isChecked = requireContext().getPrefBoolean("readAloudByPage") cb_tts_follow_sys.isChecked = requireContext().getPrefBoolean("ttsFollowSys", true) seek_tts_SpeechRate.isEnabled = !cb_tts_follow_sys.isChecked - seek_tts_SpeechRate.progress = requireContext().getPrefInt("ttsSpeechRate", 10) + seek_tts_SpeechRate.progress = requireContext().getPrefInt("ttsSpeechRate", 5) } private fun initOnChange() { @@ -73,8 +74,22 @@ class ReadAloudDialog : DialogFragment() { if (buttonView.isPressed) { requireContext().putPrefBoolean("ttsFollowSys", isChecked) seek_tts_SpeechRate.isEnabled = !isChecked + upTtsSpeechRate() } } + seek_tts_SpeechRate.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { + override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { + } + + override fun onStartTrackingTouch(seekBar: SeekBar?) { + } + + override fun onStopTrackingTouch(seekBar: SeekBar?) { + requireContext().putPrefInt("ttsSpeechRate", seek_tts_SpeechRate.progress) + upTtsSpeechRate() + } + + }) } private fun initOnClick() { @@ -97,4 +112,13 @@ class ReadAloudDialog : DialogFragment() { } } + private fun upTtsSpeechRate() { + val activity = activity + if (activity is ReadBookActivity) { + if (activity.readAloudStatus == Status.PLAY) { + ReadAloudService.pause(requireContext()) + ReadAloudService.resume(requireContext()) + } + } + } } \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_read_aloud.xml b/app/src/main/res/layout/dialog_read_aloud.xml index 0583b2894..34b644939 100644 --- a/app/src/main/res/layout/dialog_read_aloud.xml +++ b/app/src/main/res/layout/dialog_read_aloud.xml @@ -161,7 +161,7 @@ android:layout_height="30dp" android:layout_marginStart="15dp" android:layout_marginEnd="15dp" - android:max="50" /> + android:max="45" /> From 580a3e6783b4919bb4201ac74a587bef4981f277 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 26 Aug 2019 13:39:37 +0800 Subject: [PATCH 0999/1997] up --- .../app/ui/readbook/config/ReadAloudDialog.kt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt index 517e3d0f0..a320b4210 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt @@ -90,6 +90,19 @@ class ReadAloudDialog : DialogFragment() { } }) + seek_timer.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { + override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { + + } + + override fun onStartTrackingTouch(seekBar: SeekBar?) { + + } + + override fun onStopTrackingTouch(seekBar: SeekBar?) { + + } + }) } private fun initOnClick() { From cff5800940ddcda5b02defcb416bddc465d18e54 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 26 Aug 2019 14:14:44 +0800 Subject: [PATCH 1000/1997] up --- app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index ae660a2a6..4d2ffe7f1 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -258,6 +258,8 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } read_menu.upReadProgress(it.pageSize(), viewModel.durPageIndex) curPageChanged() + tv_pre.isEnabled = viewModel.durChapterIndex != 0 + tv_next.isEnabled = viewModel.durChapterIndex != viewModel.chapterSize - 1 } } From e541c36a2768ffd96f8a5488eb7c1caaefbc8f5c Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 26 Aug 2019 14:18:44 +0800 Subject: [PATCH 1001/1997] up --- app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 4d2ffe7f1..21089f2f7 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -126,10 +126,12 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea override fun skipPreChapter() { viewModel.durPageIndex = 0 moveToPrevChapter() + page_view.upContent() } override fun skipNextChapter() { moveToNextChapter() + page_view.upContent() } override fun openReplaceRule() { From aceccb7c5b115d63b307174397f7d96b0f000cbf Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 26 Aug 2019 14:20:54 +0800 Subject: [PATCH 1002/1997] up --- app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 21089f2f7..114b1a2b9 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -124,8 +124,8 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } override fun skipPreChapter() { - viewModel.durPageIndex = 0 moveToPrevChapter() + viewModel.durPageIndex = 0 page_view.upContent() } From 47b8cb5e20adfb9434342e044da3e076c8de005c Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 26 Aug 2019 14:41:59 +0800 Subject: [PATCH 1003/1997] up --- .../io/legado/app/ui/readbook/ReadBookActivity.kt | 13 ++++++++----- .../java/io/legado/app/ui/widget/page/PageView.kt | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 114b1a2b9..25295a158 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -124,8 +124,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } override fun skipPreChapter() { - moveToPrevChapter() - viewModel.durPageIndex = 0 + moveToPrevChapter(false) page_view.upContent() } @@ -258,7 +257,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea tv_chapter_url.text = it.url tv_chapter_url.visible() } - read_menu.upReadProgress(it.pageSize(), viewModel.durPageIndex) + read_menu.upReadProgress(it.pageSize().minus(1), viewModel.durPageIndex) curPageChanged() tv_pre.isEnabled = viewModel.durChapterIndex != 0 tv_next.isEnabled = viewModel.durChapterIndex != viewModel.chapterSize - 1 @@ -321,8 +320,12 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea curChapterChanged() } - override fun moveToPrevChapter() { - viewModel.durPageIndex = viewModel.prevTextChapter?.lastIndex() ?: 0 + override fun moveToPrevChapter(last: Boolean) { + viewModel.durPageIndex = if (last) { + viewModel.prevTextChapter?.lastIndex() ?: 0 + } else { + 0 + } viewModel.moveToPrevChapter() curChapterChanged() } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 0626f0d14..95d37a5da 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -192,7 +192,7 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att fun textChapter(chapterOnDur: Int = 0): TextChapter? fun loadContent(index: Int) fun moveToNextChapter() - fun moveToPrevChapter() + fun moveToPrevChapter(last: Boolean = true) fun setPageIndex(pageIndex: Int) fun clickCenter() } From db07f3d728fbe01b68120a06910c3d47ced4dcfb Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 26 Aug 2019 15:04:01 +0800 Subject: [PATCH 1004/1997] up --- .../java/io/legado/app/service/ReadAloudService.kt | 14 +++++++++++--- .../app/ui/readbook/config/ReadAloudDialog.kt | 1 + 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index 510e5111a..a28fbabc6 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -19,6 +19,7 @@ import io.legado.app.help.MediaHelp import io.legado.app.receiver.MediaButtonReceiver import io.legado.app.service.notification.ReadAloudNotification import io.legado.app.ui.widget.page.TextChapter +import io.legado.app.utils.getPrefBoolean import io.legado.app.utils.getPrefInt import io.legado.app.utils.postEvent import io.legado.app.utils.toast @@ -142,7 +143,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage } "pause" -> pauseReadAloud(true) "resume" -> resumeReadAloud() - "upTtsSpeechRate" -> upSpeechRate() + "upTtsSpeechRate" -> upSpeechRate(true) else -> stopSelf() } } @@ -199,8 +200,15 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage } } - private fun upSpeechRate() { - textToSpeech?.setSpeechRate((this.getPrefInt("ttsSpeechRate", 5) + 5) / 10f) + private fun upSpeechRate(reset: Boolean = false) { + if (this.getPrefBoolean("ttsFollowSys", true)) { + if (reset) { + clearTTS() + textToSpeech = TextToSpeech(this, this) + } + } else { + textToSpeech?.setSpeechRate((this.getPrefInt("ttsSpeechRate", 5) + 5) / 10f) + } } /** diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt index a320b4210..c964b162e 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt @@ -127,6 +127,7 @@ class ReadAloudDialog : DialogFragment() { private fun upTtsSpeechRate() { val activity = activity + ReadAloudService.upTtsSpeechRate(requireContext()) if (activity is ReadBookActivity) { if (activity.readAloudStatus == Status.PLAY) { ReadAloudService.pause(requireContext()) From df9fcc0e14114e48927a925debd2890ef92aaf74 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 26 Aug 2019 15:34:40 +0800 Subject: [PATCH 1005/1997] up --- .../java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt index f1d730469..1313b44b5 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt @@ -82,6 +82,7 @@ abstract class PageDelegate(protected val pageView: PageView) { protected fun stopScroll() { isRunning = false isStarted = false + bitmap?.recycle() bitmap = null invalidate() } From dce43428275b1bcb35c04597ecf6435d7658085c Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 26 Aug 2019 16:13:41 +0800 Subject: [PATCH 1006/1997] up --- .../java/io/legado/app/help/IntentHelp.kt | 2 +- .../io/legado/app/service/ReadAloudService.kt | 2 +- .../io/legado/app/ui/about/AboutFragment.kt | 13 +++--- .../ui/bookinfo/edit/BookInfoEditActivity.kt | 2 +- .../io/legado/app/ui/config/ConfigFragment.kt | 1 - .../app/ui/readbook/ReadBookActivity.kt | 13 ++++++ .../main/java/io/legado/app/utils/Toasts.kt | 45 ------------------- 7 files changed, 23 insertions(+), 55 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/IntentHelp.kt b/app/src/main/java/io/legado/app/help/IntentHelp.kt index 8d77301c5..55ee61ed0 100644 --- a/app/src/main/java/io/legado/app/help/IntentHelp.kt +++ b/app/src/main/java/io/legado/app/help/IntentHelp.kt @@ -3,7 +3,7 @@ package io.legado.app.help import android.content.Context import android.content.Intent import io.legado.app.R -import io.legado.app.utils.toast +import org.jetbrains.anko.toast object IntentHelp { diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index a28fbabc6..281a3bba0 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -22,8 +22,8 @@ import io.legado.app.ui.widget.page.TextChapter import io.legado.app.utils.getPrefBoolean import io.legado.app.utils.getPrefInt import io.legado.app.utils.postEvent -import io.legado.app.utils.toast import kotlinx.coroutines.launch +import org.jetbrains.anko.toast import java.util.* class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManager.OnAudioFocusChangeListener { diff --git a/app/src/main/java/io/legado/app/ui/about/AboutFragment.kt b/app/src/main/java/io/legado/app/ui/about/AboutFragment.kt index 5f2220b07..e98523051 100644 --- a/app/src/main/java/io/legado/app/ui/about/AboutFragment.kt +++ b/app/src/main/java/io/legado/app/ui/about/AboutFragment.kt @@ -16,18 +16,19 @@ class AboutFragment : PreferenceFragmentCompat() { findPreference("version")?.summary = App.INSTANCE.versionName } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + listView.overScrollMode = View.OVER_SCROLL_NEVER + } + override fun onPreferenceTreeClick(preference: Preference?): Boolean { when (preference?.key) { - + "mail" -> openIntent(Intent.ACTION_SENDTO, "mailto:kunfei.ge@gmail.com") + "gitHub" -> openIntent(Intent.ACTION_VIEW, getString(R.string.this_github_url)) } return super.onPreferenceTreeClick(preference) } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - listView.overScrollMode = View.OVER_SCROLL_NEVER - } - private fun openIntent(intentName: String, address: String) { try { val intent = Intent(intentName) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/edit/BookInfoEditActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/edit/BookInfoEditActivity.kt index 779cf962a..5d79d6e1c 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/edit/BookInfoEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/edit/BookInfoEditActivity.kt @@ -8,8 +8,8 @@ import io.legado.app.R import io.legado.app.base.VMBaseActivity import io.legado.app.data.entities.Book import io.legado.app.utils.getViewModel -import io.legado.app.utils.toast import kotlinx.android.synthetic.main.activity_book_info_edit.* +import org.jetbrains.anko.toast class BookInfoEditActivity : VMBaseActivity(R.layout.activity_book_info_edit) { override val viewModel: BookInfoEditViewModel diff --git a/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt index c33d584a5..2885572ae 100644 --- a/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt @@ -60,7 +60,6 @@ class ConfigFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChange preference.context.getPrefString(preference.key, "") ) } - } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 25295a158..3c0129034 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -205,6 +205,19 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea return super.dispatchKeyEvent(event) } + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { + when (keyCode) { + KeyEvent.KEYCODE_BACK -> { + if (readAloudStatus == Status.PLAY) { + ReadAloudService.pause(this) + toast(R.string.read_aloud_pause) + return true + } + } + } + return super.onKeyDown(keyCode, event) + } + /** * 书籍加载完成,开始加载章节内容 */ diff --git a/app/src/main/java/io/legado/app/utils/Toasts.kt b/app/src/main/java/io/legado/app/utils/Toasts.kt index 5fea5ad08..16c032fa0 100644 --- a/app/src/main/java/io/legado/app/utils/Toasts.kt +++ b/app/src/main/java/io/legado/app/utils/Toasts.kt @@ -1,6 +1,5 @@ package io.legado.app.utils -import android.content.Context import android.widget.Toast import androidx.fragment.app.Fragment import org.jetbrains.anko.longToast @@ -14,17 +13,6 @@ import org.jetbrains.anko.toast */ inline fun Fragment.toast(message: Int) = requireActivity().toast(message) -/** - * Display the simple Toast message with the [Toast.LENGTH_SHORT] duration. - * - * @param message the message text resource. - */ -inline fun Context.toast(message: Int): Toast = Toast - .makeText(this, message, Toast.LENGTH_SHORT) - .apply { - show() - } - /** * Display the simple Toast message with the [Toast.LENGTH_SHORT] duration. * @@ -32,17 +20,6 @@ inline fun Context.toast(message: Int): Toast = Toast */ inline fun Fragment.toast(message: CharSequence) = requireActivity().toast(message) -/** - * Display the simple Toast message with the [Toast.LENGTH_SHORT] duration. - * - * @param message the message text. - */ -inline fun Context.toast(message: CharSequence): Toast = Toast - .makeText(this, message, Toast.LENGTH_SHORT) - .apply { - show() - } - /** * Display the simple Toast message with the [Toast.LENGTH_LONG] duration. * @@ -50,31 +27,9 @@ inline fun Context.toast(message: CharSequence): Toast = Toast */ inline fun Fragment.longToast(message: Int) = requireActivity().longToast(message) -/** - * Display the simple Toast message with the [Toast.LENGTH_LONG] duration. - * - * @param message the message text resource. - */ -inline fun Context.longToast(message: Int): Toast = Toast - .makeText(this, message, Toast.LENGTH_LONG) - .apply { - show() - } - /** * Display the simple Toast message with the [Toast.LENGTH_LONG] duration. * * @param message the message text. */ inline fun Fragment.longToast(message: CharSequence) = requireActivity().longToast(message) - -/** - * Display the simple Toast message with the [Toast.LENGTH_LONG] duration. - * - * @param message the message text. - */ -inline fun Context.longToast(message: CharSequence): Toast = Toast - .makeText(this, message, Toast.LENGTH_LONG) - .apply { - show() - } \ No newline at end of file From b25124d7cc3c5e94568e41babca6d9f9d7ec1747 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 26 Aug 2019 17:29:25 +0800 Subject: [PATCH 1007/1997] up --- .../io/legado/app/service/ReadAloudService.kt | 28 +++++++++++++++++++ .../app/ui/readbook/config/ReadAloudDialog.kt | 2 ++ 2 files changed, 30 insertions(+) diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index 281a3bba0..ddfaae1f8 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -75,6 +75,22 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage } } + fun prevParagraph(context: Context) { + if (isRun) { + val intent = Intent(context, ReadAloudService::class.java) + intent.action = "prevParagraph" + context.startService(intent) + } + } + + fun nextParagraph(context: Context) { + if (isRun) { + val intent = Intent(context, ReadAloudService::class.java) + intent.action = "nextParagraph" + context.startService(intent) + } + } + fun upTtsSpeechRate(context: Context) { if (isRun) { val intent = Intent(context, ReadAloudService::class.java) @@ -144,6 +160,8 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage "pause" -> pauseReadAloud(true) "resume" -> resumeReadAloud() "upTtsSpeechRate" -> upSpeechRate(true) + "prevParagraph" -> prevP() + "nextParagraph" -> nextP() else -> stopSelf() } } @@ -211,6 +229,16 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage } } + private fun prevP() { + nowSpeak++ + playTTS() + } + + private fun nextP() { + nowSpeak-- + playTTS() + } + /** * 初始化MediaSession */ diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt index c964b162e..29314fc51 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt @@ -115,6 +115,8 @@ class ReadAloudDialog : DialogFragment() { } iv_stop.onClick { ReadAloudService.stop(requireContext()) } iv_play_pause.onClick { postEvent(Bus.READ_ALOUD_BUTTON, true) } + iv_play_prev.onClick { ReadAloudService.prevParagraph(requireContext()) } + iv_play_next.onClick { ReadAloudService.nextParagraph(requireContext()) } } private fun upPlayState(state: Int) { From 25da02eed5198e6ccb6a17068c41d659f28ba7b6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 26 Aug 2019 17:42:09 +0800 Subject: [PATCH 1008/1997] up --- .../java/io/legado/app/service/ReadAloudService.kt | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index ddfaae1f8..61d9ff5f3 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -230,13 +230,19 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage } private fun prevP() { - nowSpeak++ - playTTS() + if (nowSpeak < contentList.size - 1) { + readAloudNumber += contentList[nowSpeak].length + nowSpeak++ + playTTS() + } } private fun nextP() { - nowSpeak-- - playTTS() + if (nowSpeak > 0) { + nowSpeak-- + readAloudNumber -= contentList[nowSpeak].length + playTTS() + } } /** From 5af6820f3076bc70bc0511a817bece08c7ab3b2f Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 26 Aug 2019 17:45:22 +0800 Subject: [PATCH 1009/1997] up --- .../java/io/legado/app/service/ReadAloudService.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index 61d9ff5f3..5b4e13706 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -230,17 +230,17 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage } private fun prevP() { - if (nowSpeak < contentList.size - 1) { - readAloudNumber += contentList[nowSpeak].length - nowSpeak++ + if (nowSpeak > 0) { + nowSpeak-- + readAloudNumber -= contentList[nowSpeak].length playTTS() } } private fun nextP() { - if (nowSpeak > 0) { - nowSpeak-- - readAloudNumber -= contentList[nowSpeak].length + if (nowSpeak < contentList.size - 1) { + readAloudNumber += contentList[nowSpeak].length + nowSpeak++ playTTS() } } From fb2f4406367a2b3cc06be308bff0274f75839376 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 26 Aug 2019 17:49:12 +0800 Subject: [PATCH 1010/1997] up --- .../io/legado/app/ui/readbook/ReadBookActivity.kt | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 3c0129034..df79ef9e1 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -433,7 +433,18 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea override fun observeLiveBus() { super.observeLiveBus() - observeEvent(Bus.ALOUD_STATE) { readAloudStatus = it } + observeEvent(Bus.ALOUD_STATE) { + readAloudStatus = it + if (it == Status.STOP) { + viewModel.curTextChapter?.let { textChapter -> + val page = textChapter.page(viewModel.durPageIndex) + if (page != null && page.text is SpannableStringBuilder) { + page.text.removeSpan(ChapterProvider.readAloudSpan) + page_view.upContent() + } + } + } + } observeEvent(Bus.TIME_CHANGED) { page_view.upTime() } observeEvent(Bus.BATTERY_CHANGED) { page_view.upBattery(it) } observeEvent(Bus.OPEN_CHAPTER) { From 90acdadb9ba4bcebc399baa6671ceda337242687 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 26 Aug 2019 17:55:26 +0800 Subject: [PATCH 1011/1997] up --- app/src/main/java/io/legado/app/service/ReadAloudService.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index 5b4e13706..88930eb03 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -231,15 +231,17 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage private fun prevP() { if (nowSpeak > 0) { + textToSpeech?.stop() nowSpeak-- - readAloudNumber -= contentList[nowSpeak].length + readAloudNumber -= contentList[nowSpeak].length.minus(1) playTTS() } } private fun nextP() { if (nowSpeak < contentList.size - 1) { - readAloudNumber += contentList[nowSpeak].length + textToSpeech?.stop() + readAloudNumber += contentList[nowSpeak].length.plus(1) nowSpeak++ playTTS() } From aa261f298df22bf85f0c1bd164dcecdd5be41ba1 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 26 Aug 2019 20:05:54 +0800 Subject: [PATCH 1012/1997] up --- .../app/ui/readbook/config/ReadStyleDialog.kt | 17 +++++++++++++++++ .../main/res/layout/dialog_read_book_style.xml | 2 ++ 2 files changed, 19 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt index 6579fbf65..5ef3c30a4 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt @@ -6,6 +6,7 @@ import android.view.Gravity import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.core.view.get import androidx.fragment.app.DialogFragment import io.legado.app.R import io.legado.app.constant.Bus @@ -14,8 +15,11 @@ import io.legado.app.help.ReadBookConfig import io.legado.app.lib.theme.accentColor import io.legado.app.lib.theme.primaryColor import io.legado.app.ui.readbook.Help +import io.legado.app.utils.getPrefInt import io.legado.app.utils.postEvent +import io.legado.app.utils.putPrefInt import kotlinx.android.synthetic.main.dialog_read_book_style.* +import org.jetbrains.anko.sdk27.listeners.onCheckedChange import org.jetbrains.anko.sdk27.listeners.onClick class ReadStyleDialog : DialogFragment() { @@ -51,12 +55,25 @@ class ReadStyleDialog : DialogFragment() { } private fun initData() { + requireContext().getPrefInt("pageAnim").let { + if (it >= 0 && it < rg_page_anim.childCount) { + rg_page_anim.check(rg_page_anim[it].id) + } + } setBg() upBg() } private fun initOnClick() { + rg_page_anim.onCheckedChange { _, checkedId -> + for (i in 0 until rg_page_anim.childCount) { + if (checkedId == rg_page_anim[i].id) { + requireContext().putPrefInt("pageAnim", i) + break + } + } + } tv_bg0.onClick { ReadBookConfig.styleSelect = 0 ReadBookConfig.upBg() diff --git a/app/src/main/res/layout/dialog_read_book_style.xml b/app/src/main/res/layout/dialog_read_book_style.xml index c2fdc5d39..da1aaee91 100644 --- a/app/src/main/res/layout/dialog_read_book_style.xml +++ b/app/src/main/res/layout/dialog_read_book_style.xml @@ -34,6 +34,7 @@ app:layout_constraintTop_toBottomOf="@id/tv_page_anim"> Date: Mon, 26 Aug 2019 20:24:24 +0800 Subject: [PATCH 1013/1997] up --- .../legado/app/ui/readbook/config/ReadStyleDialog.kt | 6 ++++++ .../java/io/legado/app/ui/widget/page/PageView.kt | 11 ++++++++++- .../app/ui/widget/page/delegate/PageDelegate.kt | 9 ++++++--- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt index 5ef3c30a4..08603ddf6 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt @@ -15,9 +15,11 @@ import io.legado.app.help.ReadBookConfig import io.legado.app.lib.theme.accentColor import io.legado.app.lib.theme.primaryColor import io.legado.app.ui.readbook.Help +import io.legado.app.ui.readbook.ReadBookActivity import io.legado.app.utils.getPrefInt import io.legado.app.utils.postEvent import io.legado.app.utils.putPrefInt +import kotlinx.android.synthetic.main.activity_read_book.* import kotlinx.android.synthetic.main.dialog_read_book_style.* import org.jetbrains.anko.sdk27.listeners.onCheckedChange import org.jetbrains.anko.sdk27.listeners.onClick @@ -70,6 +72,10 @@ class ReadStyleDialog : DialogFragment() { for (i in 0 until rg_page_anim.childCount) { if (checkedId == rg_page_anim[i].id) { requireContext().putPrefInt("pageAnim", i) + val activity = activity + if (activity is ReadBookActivity) { + activity.page_view.upPageAnim() + } break } } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 95d37a5da..f10eeda81 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -7,8 +7,10 @@ import android.util.AttributeSet import android.view.MotionEvent import android.widget.FrameLayout import io.legado.app.help.ReadBookConfig +import io.legado.app.ui.widget.page.delegate.CoverPageDelegate import io.legado.app.ui.widget.page.delegate.PageDelegate import io.legado.app.ui.widget.page.delegate.SlidePageDelegate +import io.legado.app.utils.getPrefInt class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, attrs), PageDelegate.PageInterface { @@ -30,7 +32,7 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att upBg() setWillNotDraw(false) - pageDelegate = SlidePageDelegate(this) + upPageAnim() setPageFactory(TextPageFactory.create(object : DataSource { override fun pageIndex(): Int { @@ -138,6 +140,13 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att upContent() } + fun upPageAnim() { + pageDelegate = when (context.getPrefInt("pageAnim")) { + 1 -> SlidePageDelegate(this) + else -> CoverPageDelegate(this) + } + } + fun upContent() { pageFactory?.let { prevPage?.setContent(it.previousPage()) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt index 1313b44b5..229bfcb48 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt @@ -13,7 +13,10 @@ import io.legado.app.utils.screenshot import kotlin.math.abs abstract class PageDelegate(protected val pageView: PageView) { - val centerRectF = RectF() + val centerRectF = RectF( + pageView.width * 0.33f, pageView.height * 0.33f, + pageView.width * 0.66f, pageView.height * 0.66f + ) //起始点 protected var startX: Float = 0.toFloat() protected var startY: Float = 0.toFloat() @@ -97,8 +100,8 @@ abstract class PageDelegate(protected val pageView: PageView) { viewHeight = height invalidate() centerRectF.set( - width / 3f, height / 3f, - width * 2f / 3, height * 2f / 3 + width * 0.33f, height * 0.33f, + width * 0.66f, height * 0.66f ) } From ffbfc59ed5ab7efea4230b7bc67318bcdd79c3bf Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 26 Aug 2019 21:01:44 +0800 Subject: [PATCH 1014/1997] up --- .../java/io/legado/app/ui/readbook/ReadBookActivity.kt | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index df79ef9e1..b5cecfe0d 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -330,16 +330,14 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea override fun moveToNextChapter() { viewModel.durPageIndex = 0 viewModel.moveToNextChapter() + viewModel.saveRead() curChapterChanged() } override fun moveToPrevChapter(last: Boolean) { - viewModel.durPageIndex = if (last) { - viewModel.prevTextChapter?.lastIndex() ?: 0 - } else { - 0 - } + viewModel.durPageIndex = if (last) viewModel.prevTextChapter?.lastIndex() ?: 0 else 0 viewModel.moveToPrevChapter() + viewModel.saveRead() curChapterChanged() } From 82ceb97dfe45573924a50b12274ff0511ff9bbeb Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 26 Aug 2019 21:18:43 +0800 Subject: [PATCH 1015/1997] up --- app/src/main/java/io/legado/app/App.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/io/legado/app/App.kt b/app/src/main/java/io/legado/app/App.kt index f1da4ab01..742f67e7c 100644 --- a/app/src/main/java/io/legado/app/App.kt +++ b/app/src/main/java/io/legado/app/App.kt @@ -16,6 +16,7 @@ import io.legado.app.constant.AppConst.channelIdWeb import io.legado.app.data.AppDatabase import io.legado.app.help.ActivityHelp import io.legado.app.help.CrashHandler +import io.legado.app.help.ReadBookConfig import io.legado.app.lib.theme.ThemeStore import io.legado.app.utils.getCompatColor import io.legado.app.utils.getPrefInt @@ -81,6 +82,7 @@ class App : Application() { } fun applyDayNight() { + ReadBookConfig.upBg() applyTheme() initNightTheme() } From 46b5131872183c449f215dba2fd13630db4d2090 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 26 Aug 2019 21:32:54 +0800 Subject: [PATCH 1016/1997] up --- app/src/main/java/io/legado/app/help/BookHelp.kt | 10 ++++++++++ .../io/legado/app/ui/readbook/ReadBookActivity.kt | 1 + .../io/legado/app/ui/readbook/ReadBookViewModel.kt | 11 +++++++++++ 3 files changed, 22 insertions(+) diff --git a/app/src/main/java/io/legado/app/help/BookHelp.kt b/app/src/main/java/io/legado/app/help/BookHelp.kt index cda999353..ab0f5ab95 100644 --- a/app/src/main/java/io/legado/app/help/BookHelp.kt +++ b/app/src/main/java/io/legado/app/help/BookHelp.kt @@ -57,6 +57,16 @@ object BookHelp { return null } + fun delContent(book: Book, bookChapter: BookChapter) { + val filePath = getChapterPath(book, bookChapter) + kotlin.runCatching { + val file = File(filePath) + if (file.exists()) { + file.delete() + } + } + } + private fun getChapterPath(book: Book, bookChapter: BookChapter): String { val bookFolder = formatFolderName(book.name + book.bookUrl) val chapterFile = String.format("%05d-%s", bookChapter.index, formatFolderName(bookChapter.title)) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index b5cecfe0d..11b411413 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -180,6 +180,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } changeSourceDialog?.show(supportFragmentManager, ChangeSourceDialog.tag) } + R.id.menu_refresh -> viewModel.refreshContent() } return super.onCompatOptionsItemSelected(item) } diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index 7dcd4254d..fb64672df 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -228,6 +228,17 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } } + fun refreshContent() { + execute { + bookData.value?.let { book -> + App.db.bookChapterDao().getChapter(book.bookUrl, durChapterIndex)?.let { chapter -> + BookHelp.delContent(book, chapter) + loadContent(book, durChapterIndex) + } + } + } + } + override fun onCleared() { super.onCleared() ReadAloudService.stop(context) From 8a3d24e6677ecece2624da6f987f9b03955b259e Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 26 Aug 2019 21:36:22 +0800 Subject: [PATCH 1017/1997] up --- .../io/legado/app/ui/readbook/ReadBookActivity.kt | 8 +++++++- .../io/legado/app/ui/readbook/ReadBookViewModel.kt | 12 ++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 11b411413..1a7aae0a8 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -180,7 +180,13 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } changeSourceDialog?.show(supportFragmentManager, ChangeSourceDialog.tag) } - R.id.menu_refresh -> viewModel.refreshContent() + R.id.menu_refresh -> { + viewModel.bookData.value?.let { + viewModel.curTextChapter = null + page_view.upContent() + viewModel.refreshContent(it) + } + } } return super.onCompatOptionsItemSelected(item) } diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index fb64672df..767bd0849 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -214,6 +214,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { durChapterIndex++ prevTextChapter = curTextChapter curTextChapter = nextTextChapter + nextTextChapter = null bookData.value?.let { loadContent(it, durChapterIndex.plus(1)) } @@ -223,18 +224,17 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { durChapterIndex-- nextTextChapter = curTextChapter curTextChapter = prevTextChapter + prevTextChapter = null bookData.value?.let { loadContent(it, durChapterIndex.minus(1)) } } - fun refreshContent() { + fun refreshContent(book: Book) { execute { - bookData.value?.let { book -> - App.db.bookChapterDao().getChapter(book.bookUrl, durChapterIndex)?.let { chapter -> - BookHelp.delContent(book, chapter) - loadContent(book, durChapterIndex) - } + App.db.bookChapterDao().getChapter(book.bookUrl, durChapterIndex)?.let { chapter -> + BookHelp.delContent(book, chapter) + loadContent(book, durChapterIndex) } } } From 67afb552b68131259f12ccf9eed62d864df4590e Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 26 Aug 2019 21:49:03 +0800 Subject: [PATCH 1018/1997] up --- .../io/legado/app/ui/readbook/ReadBookViewModel.kt | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index 767bd0849..b95ff61ff 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -137,14 +137,20 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { private fun download(book: Book, chapter: BookChapter) { webBook?.getContent(book, chapter, scope = this) ?.onSuccess(IO) { content -> - content?.let { - BookHelp.saveContent(book, chapter, it) - callBack?.contentLoadFinish(chapter, it) + if (content.isNullOrEmpty()) { + callBack?.contentLoadFinish(chapter, context.getString(R.string.content_empty)) + synchronized(loadingLock) { + loadingChapters.remove(chapter.index) + } + } else { + BookHelp.saveContent(book, chapter, content) + callBack?.contentLoadFinish(chapter, content) synchronized(loadingLock) { loadingChapters.remove(chapter.index) } } }?.onError { + callBack?.contentLoadFinish(chapter, it.localizedMessage) synchronized(loadingLock) { loadingChapters.remove(chapter.index) } From adf2f05c9b567ea5ba641feb59408b5316e43b50 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 26 Aug 2019 21:52:29 +0800 Subject: [PATCH 1019/1997] up --- .../main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index b95ff61ff..48bb7b1fe 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -22,7 +22,6 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { val chapterListFinish = MutableLiveData() var chapterSize = 0 var bookSource: BookSource? = null - var webBook: WebBook? = null var callBack: CallBack? = null var durChapterIndex = 0 var durPageIndex = 0 @@ -30,6 +29,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { var prevTextChapter: TextChapter? = null var curTextChapter: TextChapter? = null var nextTextChapter: TextChapter? = null + private var webBook: WebBook? = null private val loadingChapters = arrayListOf() private val loadingLock = "loadingLock" From 4d3d802653ab54b634ffdf7a6deeb8b13fe50878 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 26 Aug 2019 22:08:06 +0800 Subject: [PATCH 1020/1997] up --- .../main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 1a7aae0a8..681829fc9 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -264,6 +264,12 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea viewModel.durChapterIndex + 1 -> { viewModel.nextTextChapter = ChapterProvider.getTextChapter(content_text_view, bookChapter, content) + viewModel.bookData.value?.let { + for (i in viewModel.durChapterIndex.plus(2) + ..viewModel.durChapterIndex.plus(8)) { + viewModel.download(it, i) + } + } } } } From 35968acd4ccfb91faf19d3344921675b1f079da5 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 08:03:54 +0800 Subject: [PATCH 1021/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 36 ++++++++----------- .../app/ui/readbook/ReadBookViewModel.kt | 14 +++++--- 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 681829fc9..d6e91e91f 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -249,28 +249,20 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea * 内容加载完成 */ override fun contentLoadFinish(bookChapter: BookChapter, content: String) { - launch { - when (bookChapter.index) { - viewModel.durChapterIndex -> { - viewModel.curTextChapter = - ChapterProvider.getTextChapter(content_text_view, bookChapter, content) - page_view.upContent() - curChapterChanged() - } - viewModel.durChapterIndex - 1 -> { - viewModel.prevTextChapter = - ChapterProvider.getTextChapter(content_text_view, bookChapter, content) - } - viewModel.durChapterIndex + 1 -> { - viewModel.nextTextChapter = - ChapterProvider.getTextChapter(content_text_view, bookChapter, content) - viewModel.bookData.value?.let { - for (i in viewModel.durChapterIndex.plus(2) - ..viewModel.durChapterIndex.plus(8)) { - viewModel.download(it, i) - } - } - } + when (bookChapter.index) { + viewModel.durChapterIndex -> launch { + viewModel.curTextChapter = + ChapterProvider.getTextChapter(content_text_view, bookChapter, content) + page_view.upContent() + curChapterChanged() + } + viewModel.durChapterIndex - 1 -> launch { + viewModel.prevTextChapter = + ChapterProvider.getTextChapter(content_text_view, bookChapter, content) + } + viewModel.durChapterIndex + 1 -> launch { + viewModel.nextTextChapter = + ChapterProvider.getTextChapter(content_text_view, bookChapter, content) } } } diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index 48bb7b1fe..bcb17f50c 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -101,7 +101,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { execute { App.db.bookChapterDao().getChapter(book.bookUrl, index)?.let { chapter -> BookHelp.getContent(book, chapter)?.let { - callBack?.contentLoadFinish(chapter, it) + contentLoadFinish(chapter, it) synchronized(loadingLock) { loadingChapters.remove(index) } @@ -138,25 +138,31 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { webBook?.getContent(book, chapter, scope = this) ?.onSuccess(IO) { content -> if (content.isNullOrEmpty()) { - callBack?.contentLoadFinish(chapter, context.getString(R.string.content_empty)) + contentLoadFinish(chapter, context.getString(R.string.content_empty)) synchronized(loadingLock) { loadingChapters.remove(chapter.index) } } else { BookHelp.saveContent(book, chapter, content) - callBack?.contentLoadFinish(chapter, content) + contentLoadFinish(chapter, content) synchronized(loadingLock) { loadingChapters.remove(chapter.index) } } }?.onError { - callBack?.contentLoadFinish(chapter, it.localizedMessage) + contentLoadFinish(chapter, it.localizedMessage) synchronized(loadingLock) { loadingChapters.remove(chapter.index) } } } + private fun contentLoadFinish(chapter: BookChapter, content: String) { + if (chapter.index in durChapterIndex - 1..durChapterIndex + 1) { + callBack?.contentLoadFinish(chapter, content) + } + } + fun changeTo(book: Book) { execute { bookData.value?.let { From 81d45481e67675e17cd8cd47a0e3eb43e13d1f11 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 08:05:46 +0800 Subject: [PATCH 1022/1997] up --- .../java/io/legado/app/ui/readbook/ReadBookActivity.kt | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index d6e91e91f..302e3246b 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -419,14 +419,8 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea alert { title = getString(R.string.add_to_shelf) message = getString(R.string.check_add_bookshelf, it.name) - okButton { - viewModel.inBookshelf = true - } - noButton { - viewModel.removeFromBookshelf { - super.finish() - } - } + okButton { viewModel.inBookshelf = true } + noButton { viewModel.removeFromBookshelf { super.finish() } } }.show() } else { super.finish() From 463523e37b115f8f41401efd2bdbb1dc9dd05ac5 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 08:15:36 +0800 Subject: [PATCH 1023/1997] up --- .../main/java/io/legado/app/ui/widget/page/ChapterProvider.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt index d24e411d2..a57ac31c5 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt @@ -13,7 +13,6 @@ object ChapterProvider { val readAloudSpan = ForegroundColorSpan(App.INSTANCE.accentColor) private val titleSpan = RelativeSizeSpan(1.3f) - @Synchronized fun getTextChapter(textView: ContentTextView, bookChapter: BookChapter, content: String): TextChapter { val textPages = arrayListOf() val pageLengths = arrayListOf() From a313463745db56d8cceab1389c283dc36c41ea6d Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 08:40:17 +0800 Subject: [PATCH 1024/1997] up --- .../io/legado/app/ui/readbook/ReadBookViewModel.kt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index bcb17f50c..cd0687b64 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -15,6 +15,8 @@ import io.legado.app.model.WebBook import io.legado.app.service.ReadAloudService import io.legado.app.ui.widget.page.TextChapter import kotlinx.coroutines.Dispatchers.IO +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch class ReadBookViewModel(application: Application) : BaseViewModel(application) { var inBookshelf = false @@ -229,6 +231,14 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { nextTextChapter = null bookData.value?.let { loadContent(it, durChapterIndex.plus(1)) + launch(IO) { + for (i in 2..10) { + delay(5000L) + bookData.value?.let { book -> + download(book, durChapterIndex + i) + } + } + } } } From 8ab491d573f0565d08e189a996c9e66f8f9f5570 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 11:31:33 +0800 Subject: [PATCH 1025/1997] up --- app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 302e3246b..e78986640 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -259,10 +259,12 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea viewModel.durChapterIndex - 1 -> launch { viewModel.prevTextChapter = ChapterProvider.getTextChapter(content_text_view, bookChapter, content) + page_view.upContent() } viewModel.durChapterIndex + 1 -> launch { viewModel.nextTextChapter = ChapterProvider.getTextChapter(content_text_view, bookChapter, content) + page_view.upContent() } } } From 3f43bdfb5cdb11ffe615b3bfdad24aff94754167 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 12:24:16 +0800 Subject: [PATCH 1026/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 24 +++++-------------- .../app/ui/readbook/ReadBookViewModel.kt | 23 +++++++++++++----- .../app/ui/widget/page/ChapterProvider.kt | 23 +++++++++++------- .../legado/app/ui/widget/page/ContentView.kt | 4 +++- .../io/legado/app/ui/widget/page/TextPage.kt | 5 +++- 5 files changed, 44 insertions(+), 35 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index e78986640..b71102df7 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -61,7 +61,6 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea page_view.callback = this viewModel.callBack = this viewModel.bookData.observe(this, Observer { title_bar.title = it.name }) - viewModel.chapterListFinish.observe(this, Observer { bookLoadFinish() }) viewModel.initData(intent) savedInstanceState?.let { changeSourceDialog = @@ -225,17 +224,6 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea return super.onKeyDown(keyCode, event) } - /** - * 书籍加载完成,开始加载章节内容 - */ - private fun bookLoadFinish() { - viewModel.bookData.value?.let { - viewModel.loadContent(it, viewModel.durChapterIndex) - viewModel.loadContent(it, viewModel.durChapterIndex + 1) - viewModel.loadContent(it, viewModel.durChapterIndex - 1) - } - } - /** * 加载章节内容 */ @@ -251,19 +239,19 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea override fun contentLoadFinish(bookChapter: BookChapter, content: String) { when (bookChapter.index) { viewModel.durChapterIndex -> launch { - viewModel.curTextChapter = - ChapterProvider.getTextChapter(content_text_view, bookChapter, content) + viewModel.curTextChapter = ChapterProvider + .getTextChapter(content_text_view, bookChapter, content, viewModel.chapterSize) page_view.upContent() curChapterChanged() } viewModel.durChapterIndex - 1 -> launch { - viewModel.prevTextChapter = - ChapterProvider.getTextChapter(content_text_view, bookChapter, content) + viewModel.prevTextChapter = ChapterProvider + .getTextChapter(content_text_view, bookChapter, content, viewModel.chapterSize) page_view.upContent() } viewModel.durChapterIndex + 1 -> launch { - viewModel.nextTextChapter = - ChapterProvider.getTextChapter(content_text_view, bookChapter, content) + viewModel.nextTextChapter = ChapterProvider + .getTextChapter(content_text_view, bookChapter, content, viewModel.chapterSize) page_view.upContent() } } diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index cd0687b64..5b62ba8f1 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -21,7 +21,6 @@ import kotlinx.coroutines.launch class ReadBookViewModel(application: Application) : BaseViewModel(application) { var inBookshelf = false var bookData = MutableLiveData() - val chapterListFinish = MutableLiveData() var chapterSize = 0 var bookSource: BookSource? = null var callBack: CallBack? = null @@ -61,7 +60,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { durChapterIndex = count - 1 } chapterSize = count - chapterListFinish.postValue(true) + loadChapterListFinish() } } @@ -85,7 +84,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { if (!cList.isNullOrEmpty()) { App.db.bookChapterDao().insert(*cList.toTypedArray()) chapterSize = cList.size - chapterListFinish.postValue(true) + loadChapterListFinish() } else { toast(R.string.error_load_toc) } @@ -95,6 +94,14 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } } + private fun loadChapterListFinish() { + bookData.value?.let { + loadContent(it, durChapterIndex) + loadContent(it, durChapterIndex + 1) + loadContent(it, durChapterIndex - 1) + } + } + fun loadContent(book: Book, index: Int) { synchronized(loadingLock) { if (loadingChapters.contains(index)) return @@ -193,15 +200,19 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { durPageIndex = 0 } saveRead() - chapterListFinish.postValue(true) + loadChapterListFinish() } fun saveRead() { execute { bookData.value?.let { book -> + book.durChapterTime = System.currentTimeMillis() book.durChapterIndex = durChapterIndex book.durChapterPos = durPageIndex - App.db.bookDao().update(book) + curTextChapter?.let { + book.durChapterTitle = it.title + App.db.bookDao().update(book) + } } } } @@ -233,7 +244,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { loadContent(it, durChapterIndex.plus(1)) launch(IO) { for (i in 2..10) { - delay(5000L) + delay(1000L) bookData.value?.let { book -> download(book, durChapterIndex + i) } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt index a57ac31c5..7351379a6 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt @@ -13,7 +13,10 @@ object ChapterProvider { val readAloudSpan = ForegroundColorSpan(App.INSTANCE.accentColor) private val titleSpan = RelativeSizeSpan(1.3f) - fun getTextChapter(textView: ContentTextView, bookChapter: BookChapter, content: String): TextChapter { + fun getTextChapter( + textView: ContentTextView, bookChapter: BookChapter, + content: String, chapterSize: Int + ): TextChapter { val textPages = arrayListOf() val pageLengths = arrayListOf() var surplusText = content @@ -32,24 +35,26 @@ object ChapterProvider { pageLengths.add(textView.getCharNum()) textPages.add( TextPage( - pageIndex, - spannableStringBuilder.delete( + index = pageIndex, + text = spannableStringBuilder.delete( pageLengths[pageIndex], spannableStringBuilder.length ), - bookChapter.title + title = bookChapter.title, + chapterSize = chapterSize, + chapterIndex = bookChapter.index ) ) surplusText = surplusText.substring(pageLengths[pageIndex]) pageIndex++ } + for (item in textPages) { + item.pageSize = textPages.size + } return TextChapter( - bookChapter.index, - bookChapter.title, - bookChapter.url, - textPages, - pageLengths + bookChapter.index, bookChapter.title, bookChapter.url, + textPages, pageLengths ) } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index f566e672f..3201328f7 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -1,5 +1,6 @@ package io.legado.app.ui.widget.page +import android.annotation.SuppressLint import android.content.Context import android.graphics.drawable.Drawable import android.util.AttributeSet @@ -79,9 +80,10 @@ class ContentView : FrameLayout { tv_top_right.text = context.getString(R.string.battery_show, battery) } + @SuppressLint("SetTextI18n") fun setContent(page: TextPage?) { content_text_view.text = page?.text tv_bottom_left.text = page?.title - tv_bottom_right.text = page?.index?.plus(1)?.toString() + tv_bottom_right.text = "${page?.index?.plus(1)}/${page?.pageSize}" } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextPage.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextPage.kt index ea261ff2b..503472390 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextPage.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextPage.kt @@ -3,5 +3,8 @@ package io.legado.app.ui.widget.page data class TextPage( val index: Int, val text: CharSequence, - val title: String + val title: String, + var pageSize: Int = 0, + var chapterSize: Int = 0, + var chapterIndex: Int = 0 ) From 4fb7b6cd30fac335c957f33074048cf7fbb6149f Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 12:35:07 +0800 Subject: [PATCH 1027/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 12 ++++++++++ .../app/ui/readbook/ReadBookViewModel.kt | 23 +++++-------------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index b71102df7..f447221b6 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -61,6 +61,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea page_view.callback = this viewModel.callBack = this viewModel.bookData.observe(this, Observer { title_bar.title = it.name }) + viewModel.chapterListFinish.observe(this, Observer { bookLoadFinish() }) viewModel.initData(intent) savedInstanceState?.let { changeSourceDialog = @@ -224,6 +225,17 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea return super.onKeyDown(keyCode, event) } + /** + * 书籍加载完成,开始加载章节内容 + */ + private fun bookLoadFinish() { + viewModel.bookData.value?.let { + viewModel.loadContent(it, viewModel.durChapterIndex) + viewModel.loadContent(it, viewModel.durChapterIndex + 1) + viewModel.loadContent(it, viewModel.durChapterIndex - 1) + } + } + /** * 加载章节内容 */ diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index 5b62ba8f1..83605f9cd 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -21,6 +21,7 @@ import kotlinx.coroutines.launch class ReadBookViewModel(application: Application) : BaseViewModel(application) { var inBookshelf = false var bookData = MutableLiveData() + val chapterListFinish = MutableLiveData() var chapterSize = 0 var bookSource: BookSource? = null var callBack: CallBack? = null @@ -60,7 +61,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { durChapterIndex = count - 1 } chapterSize = count - loadChapterListFinish() + chapterListFinish.postValue(true) } } @@ -84,7 +85,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { if (!cList.isNullOrEmpty()) { App.db.bookChapterDao().insert(*cList.toTypedArray()) chapterSize = cList.size - loadChapterListFinish() + chapterListFinish.postValue(true) } else { toast(R.string.error_load_toc) } @@ -94,14 +95,6 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } } - private fun loadChapterListFinish() { - bookData.value?.let { - loadContent(it, durChapterIndex) - loadContent(it, durChapterIndex + 1) - loadContent(it, durChapterIndex - 1) - } - } - fun loadContent(book: Book, index: Int) { synchronized(loadingLock) { if (loadingChapters.contains(index)) return @@ -125,7 +118,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } } - fun download(book: Book, index: Int) { + private fun download(book: Book, index: Int) { synchronized(loadingLock) { if (loadingChapters.contains(index)) return loadingChapters.add(index) @@ -200,19 +193,15 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { durPageIndex = 0 } saveRead() - loadChapterListFinish() + chapterListFinish.postValue(true) } fun saveRead() { execute { bookData.value?.let { book -> - book.durChapterTime = System.currentTimeMillis() book.durChapterIndex = durChapterIndex book.durChapterPos = durPageIndex - curTextChapter?.let { - book.durChapterTitle = it.title - App.db.bookDao().update(book) - } + App.db.bookDao().update(book) } } } From 148bdae34e256b90ee175535472e962f977cb977 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 14:07:55 +0800 Subject: [PATCH 1028/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 23 +++++-------------- .../io/legado/app/ui/widget/page/TextPage.kt | 22 +++++++++++++++++- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index f447221b6..629b69d9a 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -4,7 +4,6 @@ import android.app.Activity import android.content.Intent import android.net.Uri import android.os.Bundle -import android.text.Spannable import android.text.SpannableStringBuilder import android.view.KeyEvent import android.view.Menu @@ -91,6 +90,9 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea Help.upSystemUiVisibility(window, !read_menu.isVisible) } + /** + * 初始化View + */ private fun initView() { tv_chapter_name.onClick { viewModel.bookSource?.let { @@ -461,22 +463,9 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea launch(IO) { viewModel.curTextChapter?.let { val pageStart = chapterStart - it.getReadLength(viewModel.durPageIndex) - val page = it.page(viewModel.durPageIndex) - if (page != null && page.text is SpannableStringBuilder) { - page.text.removeSpan(ChapterProvider.readAloudSpan) - var end = page.text.indexOf("\n", pageStart) - if (end == -1) end = page.text.length - var start = page.text.lastIndexOf("\n", pageStart) - if (start == -1) start = 0 - page.text.setSpan( - ChapterProvider.readAloudSpan, - start, - end, - Spannable.SPAN_INCLUSIVE_EXCLUSIVE - ) - withContext(Main) { - page_view.upContent() - } + it.page(viewModel.durPageIndex)?.upPageAloudSpan(pageStart) + withContext(Main) { + page_view.upContent() } } } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextPage.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextPage.kt index 503472390..9871a7c7b 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextPage.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextPage.kt @@ -1,5 +1,8 @@ package io.legado.app.ui.widget.page +import android.text.Spannable +import android.text.SpannableStringBuilder + data class TextPage( val index: Int, val text: CharSequence, @@ -7,4 +10,21 @@ data class TextPage( var pageSize: Int = 0, var chapterSize: Int = 0, var chapterIndex: Int = 0 -) +) { + + fun upPageAloudSpan(pageStart: Int) { + if (text is SpannableStringBuilder) { + text.removeSpan(ChapterProvider.readAloudSpan) + var end = text.indexOf("\n", pageStart) + if (end == -1) end = text.length + var start = text.lastIndexOf("\n", pageStart) + if (start == -1) start = 0 + text.setSpan( + ChapterProvider.readAloudSpan, + start, + end, + Spannable.SPAN_INCLUSIVE_EXCLUSIVE + ) + } + } +} From befb8578fd81f0ead4c630726060485232fa444f Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 14:15:57 +0800 Subject: [PATCH 1029/1997] up --- .../io/legado/app/ui/widget/page/TextPage.kt | 11 +++- .../app/ui/widget/page/TextPageFactory.kt | 51 ++++--------------- 2 files changed, 19 insertions(+), 43 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextPage.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextPage.kt index 9871a7c7b..44f47d098 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextPage.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextPage.kt @@ -2,16 +2,25 @@ package io.legado.app.ui.widget.page import android.text.Spannable import android.text.SpannableStringBuilder +import io.legado.app.App +import io.legado.app.R data class TextPage( val index: Int, - val text: CharSequence, + val text: CharSequence = App.INSTANCE.getString(R.string.data_loading), val title: String, var pageSize: Int = 0, var chapterSize: Int = 0, var chapterIndex: Int = 0 ) { + fun removePageAloudSpan(): TextPage { + if (text is SpannableStringBuilder) { + text.removeSpan(ChapterProvider.readAloudSpan) + } + return this + } + fun upPageAloudSpan(pageStart: Int) { if (text is SpannableStringBuilder) { text.removeSpan(ChapterProvider.readAloudSpan) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt index d5d3414e1..96d646c3d 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt @@ -1,10 +1,5 @@ package io.legado.app.ui.widget.page -import android.text.SpannableStringBuilder -import io.legado.app.App -import io.legado.app.R -import io.legado.app.ui.widget.page.ChapterProvider.readAloudSpan - class TextPageFactory private constructor(dataSource: DataSource) : PageFactory(dataSource) { @@ -66,55 +61,27 @@ class TextPageFactory private constructor(dataSource: DataSource) : override fun currentPage(): TextPage? = dataSource.pageIndex().let { index -> return dataSource.getCurrentChapter()?.page(index) - ?: TextPage(index, App.INSTANCE.getString(R.string.data_loading), "index:$index") + ?: TextPage(index = index, title = "index:$index") } override fun nextPage(): TextPage? = dataSource.pageIndex().let { index -> dataSource.getCurrentChapter()?.let { if (index < it.pageSize() - 1) { - return dataSource.getCurrentChapter()?.page(index + 1)?.apply { - if (text is SpannableStringBuilder) { - text.removeSpan(readAloudSpan) - } - } ?: TextPage( - index + 1, - App.INSTANCE.getString(R.string.data_loading), - "index:${index + 1}" - ) + return dataSource.getCurrentChapter()?.page(index + 1)?.removePageAloudSpan() + ?: TextPage(index = index + 1, title = "index:${index + 1}") } } - return dataSource.getNextChapter()?.page(0)?.apply { - if (text is SpannableStringBuilder) { - text.removeSpan(readAloudSpan) - } - } ?: TextPage( - index + 1, - App.INSTANCE.getString(R.string.data_loading), - "index:${index + 1}" - ) + return dataSource.getNextChapter()?.page(0)?.removePageAloudSpan() + ?: TextPage(index = index + 1, title = "index:${index + 1}") } override fun previousPage(): TextPage? = dataSource.pageIndex().let { index -> if (index > 0) { - return dataSource.getCurrentChapter()?.page(index - 1)?.apply { - if (text is SpannableStringBuilder) { - text.removeSpan(readAloudSpan) - } - } ?: TextPage( - index - 1, - App.INSTANCE.getString(R.string.data_loading), - "index:${index - 1}" - ) + return dataSource.getCurrentChapter()?.page(index - 1)?.removePageAloudSpan() + ?: TextPage(index = index - 1, title = "index:${index - 1}") } - return dataSource.getPreviousChapter()?.lastPage()?.apply { - if (text is SpannableStringBuilder) { - text.removeSpan(readAloudSpan) - } - } ?: TextPage( - index - 1, - App.INSTANCE.getString(R.string.data_loading), - "index:${index - 1}" - ) + return dataSource.getPreviousChapter()?.lastPage()?.removePageAloudSpan() + ?: TextPage(index = index - 1, title = "index:${index - 1}") } From 053aced034e9eaa7d146f38e6d73b14d2b387a21 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 14:29:31 +0800 Subject: [PATCH 1030/1997] up --- .../java/io/legado/app/ui/readbook/ReadBookActivity.kt | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 629b69d9a..66af6e9aa 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -383,12 +383,8 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea val key = System.currentTimeMillis().toString() IntentDataHelp.putData(key, textChapter) ReadAloudService.play( - this, - book.name, - textChapter.title, - viewModel.durPageIndex, - key, - play + this, book.name, textChapter.title, + viewModel.durPageIndex, key, play ) } } @@ -401,7 +397,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea if (this.getPrefBoolean("brightnessAuto").not()) { brightness = value.toFloat() if (brightness < 1f) brightness = 1f - brightness = brightness * 1.0f / 255f + brightness /= 255f } val params = window.attributes params.screenBrightness = brightness From bf22fe9731b64087460286931c43e9301e0b23cb Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 14:39:54 +0800 Subject: [PATCH 1031/1997] up --- app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt b/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt index 7ab0db2d8..b05dca440 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt @@ -7,6 +7,7 @@ import io.legado.app.data.entities.SearchBook import io.legado.app.help.coroutine.Coroutine import io.legado.app.model.WebBook import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay class SearchViewModel(application: Application) : BaseViewModel(application) { private var task: Coroutine<*>? = null @@ -25,6 +26,7 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { //onCleared时自动取消 val bookSourceList = App.db.bookSourceDao().allEnabled for (item in bookSourceList) { + delay(100)//每隔100毫秒搜索一个书源 //task取消时自动取消 by (scope = this@execute) WebBook(item).searchBook(key, searchPage, scope = this@execute) .timeout(30000L) From ebb33769eca44587345e5787357fc0d660afb46c Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 15:08:36 +0800 Subject: [PATCH 1032/1997] up --- .../io/legado/app/ui/search/SearchActivity.kt | 8 +- .../recycler/refresh/RefreshProgressBar.kt | 195 ------------------ app/src/main/res/layout/activity_search.xml | 10 + 3 files changed, 15 insertions(+), 198 deletions(-) delete mode 100644 app/src/main/java/io/legado/app/ui/widget/recycler/refresh/RefreshProgressBar.kt diff --git a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt index 61030e62c..c37b81605 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt @@ -17,6 +17,7 @@ import io.legado.app.ui.bookinfo.BookInfoActivity import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_search.* import kotlinx.android.synthetic.main.view_search.* +import org.jetbrains.anko.sdk27.listeners.onClick import org.jetbrains.anko.startActivity class SearchActivity : VMBaseActivity(R.layout.activity_search), SearchAdapter.CallBack { @@ -31,6 +32,9 @@ class SearchActivity : VMBaseActivity(R.layout.activity_search) initRecyclerView() initSearchView() initData(0L) + intent.getStringExtra("key")?.let { + search_view.setQuery(it, true) + } } private fun initSearchView() { @@ -59,9 +63,7 @@ class SearchActivity : VMBaseActivity(R.layout.activity_search) } }) - intent.getStringExtra("key")?.let { - search_view.setQuery(it, true) - } + fb_stop.onClick { viewModel.stop() } } private fun initRecyclerView() { diff --git a/app/src/main/java/io/legado/app/ui/widget/recycler/refresh/RefreshProgressBar.kt b/app/src/main/java/io/legado/app/ui/widget/recycler/refresh/RefreshProgressBar.kt deleted file mode 100644 index 090a43ce7..000000000 --- a/app/src/main/java/io/legado/app/ui/widget/recycler/refresh/RefreshProgressBar.kt +++ /dev/null @@ -1,195 +0,0 @@ -package io.legado.app.ui.widget.recycler.refresh - -import android.content.Context -import android.graphics.Canvas -import android.graphics.Paint -import android.graphics.Rect -import android.graphics.RectF -import android.os.Looper -import android.util.AttributeSet -import android.view.View -import io.legado.app.R - -class RefreshProgressBar @JvmOverloads constructor( - context: Context, - attrs: AttributeSet? = null, - defStyleAttr: Int = 0 -) : View(context, attrs, defStyleAttr) { - internal var a = 1 - var maxProgress = 100 - private var durProgress = 0 - var secondMaxProgress = 100 - private var secondDurProgress = 0 - var bgColor = 0x00000000 - var secondColor = -0x3e3e3f - var fontColor = -0xc9c9ca - var speed = 1 - var secondFinalProgress = 0 - private set - private var paint: Paint = Paint() - private var rect = Rect() - private var rectF = RectF() - var isAutoLoading: Boolean = false - set(loading) { - if (loading && visibility != VISIBLE) { - visibility = VISIBLE - } - field = loading - if ((!this.isAutoLoading)) { - secondDurProgress = 0 - secondFinalProgress = 0 - } - maxProgress = 0 - - invalidate() - } - - init { - paint.style = Paint.Style.FILL - - val a = context.obtainStyledAttributes(attrs, R.styleable.RefreshProgressBar) - speed = a.getDimensionPixelSize(R.styleable.RefreshProgressBar_speed, speed) - maxProgress = a.getInt(R.styleable.RefreshProgressBar_max_progress, maxProgress) - durProgress = a.getInt(R.styleable.RefreshProgressBar_dur_progress, durProgress) - secondDurProgress = - a.getDimensionPixelSize(R.styleable.RefreshProgressBar_second_dur_progress, secondDurProgress) - secondFinalProgress = secondDurProgress - secondMaxProgress = - a.getDimensionPixelSize(R.styleable.RefreshProgressBar_second_max_progress, secondMaxProgress) - bgColor = a.getColor(R.styleable.RefreshProgressBar_bg_color, bgColor) - secondColor = a.getColor(R.styleable.RefreshProgressBar_second_color, secondColor) - fontColor = a.getColor(R.styleable.RefreshProgressBar_font_color, fontColor) - a.recycle() - } - - override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { - super.onSizeChanged(w, h, oldw, oldh) - } - - override fun onDraw(canvas: Canvas) { - super.onDraw(canvas) - - paint.color = bgColor - rect.set(0, 0, measuredWidth, measuredHeight) - canvas.drawRect(rect, paint) - - if (secondDurProgress > 0 && secondMaxProgress > 0) { - var secondDur = secondDurProgress - if (secondDur < 0) { - secondDur = 0 - } - if (secondDur > secondMaxProgress) { - secondDur = secondMaxProgress - } - paint.color = secondColor - val tempW = (measuredWidth.toFloat() * 1.0f * (secondDur * 1.0f / secondMaxProgress)).toInt() - rect.set(measuredWidth / 2 - tempW / 2, 0, measuredWidth / 2 + tempW / 2, measuredHeight) - canvas.drawRect(rect, paint) - } - - if (durProgress > 0 && maxProgress > 0) { - paint.color = fontColor - rectF.set( - 0f, - 0f, - measuredWidth.toFloat() * 1.0f * (durProgress * 1.0f / maxProgress), - measuredHeight.toFloat() - ) - canvas.drawRect(rectF, paint) - } - - if (this.isAutoLoading) { - if (secondDurProgress >= secondMaxProgress) { - a = -1 - } else if (secondDurProgress <= 0) { - a = 1 - } - secondDurProgress += a * speed - if (secondDurProgress < 0) - secondDurProgress = 0 - else if (secondDurProgress > secondMaxProgress) - secondDurProgress = secondMaxProgress - secondFinalProgress = secondDurProgress - invalidate() - } else { - if (secondDurProgress != secondFinalProgress) { - if (secondDurProgress > secondFinalProgress) { - secondDurProgress -= speed - if (secondDurProgress < secondFinalProgress) { - secondDurProgress = secondFinalProgress - } - } else { - secondDurProgress += speed - if (secondDurProgress > secondFinalProgress) { - secondDurProgress = secondFinalProgress - } - } - this.invalidate() - } - if (secondDurProgress == 0 && durProgress == 0 && secondFinalProgress == 0 && visibility == VISIBLE) { - visibility = View.INVISIBLE - } - } - } - - fun getDurProgress(): Int { - return durProgress - } - - fun setDurProgress(durProgress: Int) { - var durProgress = durProgress - if (durProgress < 0) { - durProgress = 0 - } - if (durProgress > maxProgress) { - durProgress = maxProgress - } - this.durProgress = durProgress - if (Looper.myLooper() == Looper.getMainLooper()) { - this.invalidate() - } else { - this.postInvalidate() - } - } - - fun getSecondDurProgress(): Int { - return secondDurProgress - } - - fun setSecondDurProgress(secondDur: Int) { - this.secondDurProgress = secondDur - this.secondFinalProgress = secondDurProgress - if (Looper.myLooper() == Looper.getMainLooper()) { - this.invalidate() - } else { - this.postInvalidate() - } - } - - fun setSecondDurProgressWithAnim(secondDur: Int) { - var secondDur = secondDur - if (secondDur < 0) { - secondDur = 0 - } - if (secondDur > secondMaxProgress) { - secondDur = secondMaxProgress - } - this.secondFinalProgress = secondDur - if (Looper.myLooper() == Looper.getMainLooper()) { - this.invalidate() - } else { - this.postInvalidate() - } - } - - fun clean() { - durProgress = 0 - secondDurProgress = 0 - secondFinalProgress = 0 - if (Looper.myLooper() == Looper.getMainLooper()) { - this.invalidate() - } else { - this.postInvalidate() - } - } -} diff --git a/app/src/main/res/layout/activity_search.xml b/app/src/main/res/layout/activity_search.xml index 6f4f88662..0450dd548 100644 --- a/app/src/main/res/layout/activity_search.xml +++ b/app/src/main/res/layout/activity_search.xml @@ -32,5 +32,15 @@ + + From e2582c9452111fcaeb7c163e33a3ca7064a11294 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 15:29:53 +0800 Subject: [PATCH 1033/1997] up --- .../java/io/legado/app/ui/readbook/ReadBookViewModel.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index 83605f9cd..c417a3fe6 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -199,9 +199,13 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { fun saveRead() { execute { bookData.value?.let { book -> + book.durChapterTime = System.currentTimeMillis() book.durChapterIndex = durChapterIndex book.durChapterPos = durPageIndex - App.db.bookDao().update(book) + curTextChapter?.let { + book.durChapterTitle = it.title + App.db.bookDao().update(book) + } } } } From d48741fb529ab5b6a7e17c7928329bd78950498c Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 15:42:11 +0800 Subject: [PATCH 1034/1997] up --- .../java/io/legado/app/data/dao/BookDao.kt | 3 ++ .../app/ui/readbook/ReadBookViewModel.kt | 54 ++++++++++--------- 2 files changed, 31 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/BookDao.kt b/app/src/main/java/io/legado/app/data/dao/BookDao.kt index 4f5401c4c..06874c7ec 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookDao.kt @@ -30,6 +30,9 @@ interface BookDao { @Query("select * from books where bookUrl = :bookUrl") fun getBook(bookUrl: String): Book? + @Query("select * from books order by durChapterTime desc limit 1") + fun getLastReadBook(): Book? + @get:Query("SELECT bookUrl FROM books") val allBookUrls: List diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index c417a3fe6..c2e70a9ee 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -36,35 +36,37 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { private val loadingLock = "loadingLock" fun initData(intent: Intent) { - inBookshelf = intent.getBooleanExtra("inBookshelf", true) - val bookUrl = intent.getStringExtra("bookUrl") - if (!bookUrl.isNullOrEmpty()) { - execute { - App.db.bookDao().getBook(bookUrl)?.let { book -> - durChapterIndex = book.durChapterIndex - durPageIndex = book.durChapterPos - isLocalBook = book.origin == BookType.local - bookData.postValue(book) - bookSource = App.db.bookSourceDao().getBookSource(book.origin) - bookSource?.let { - webBook = WebBook(it) - } - val count = App.db.bookChapterDao().getChapterCount(bookUrl) - if (count == 0) { - if (book.tocUrl.isEmpty()) { - loadBookInfo(book) - } else { - loadChapterList(book) - } + execute { + inBookshelf = intent.getBooleanExtra("inBookshelf", true) + val bookUrl = intent.getStringExtra("bookUrl") + val book = if (!bookUrl.isNullOrEmpty()) { + App.db.bookDao().getBook(bookUrl) + } else { + App.db.bookDao().getLastReadBook() + } + book?.let { + durChapterIndex = book.durChapterIndex + durPageIndex = book.durChapterPos + isLocalBook = book.origin == BookType.local + bookData.postValue(book) + bookSource = App.db.bookSourceDao().getBookSource(book.origin) + bookSource?.let { + webBook = WebBook(it) + } + val count = App.db.bookChapterDao().getChapterCount(bookUrl) + if (count == 0) { + if (book.tocUrl.isEmpty()) { + loadBookInfo(book) } else { - if (durChapterIndex > count - 1) { - durChapterIndex = count - 1 - } - chapterSize = count - chapterListFinish.postValue(true) + loadChapterList(book) + } + } else { + if (durChapterIndex > count - 1) { + durChapterIndex = count - 1 } + chapterSize = count + chapterListFinish.postValue(true) } - } } } From 5dcdc94cf332eb1ceae9ae53932dd6663f3003fc Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 16:06:45 +0800 Subject: [PATCH 1035/1997] up --- app/src/main/java/io/legado/app/data/dao/BookDao.kt | 4 ++-- .../main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/BookDao.kt b/app/src/main/java/io/legado/app/data/dao/BookDao.kt index 06874c7ec..b4dc49846 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookDao.kt @@ -30,8 +30,8 @@ interface BookDao { @Query("select * from books where bookUrl = :bookUrl") fun getBook(bookUrl: String): Book? - @Query("select * from books order by durChapterTime desc limit 1") - fun getLastReadBook(): Book? + @get:Query("select * from books order by durChapterTime desc limit 1") + val lastReadBook: Book? @get:Query("SELECT bookUrl FROM books") val allBookUrls: List diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index c2e70a9ee..358ec885c 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -42,7 +42,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { val book = if (!bookUrl.isNullOrEmpty()) { App.db.bookDao().getBook(bookUrl) } else { - App.db.bookDao().getLastReadBook() + App.db.bookDao().lastReadBook } book?.let { durChapterIndex = book.durChapterIndex From 08a6181df9417168d7d1f49b574391349e30b61c Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 16:07:48 +0800 Subject: [PATCH 1036/1997] up --- app/src/main/java/io/legado/app/data/dao/BookDao.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/BookDao.kt b/app/src/main/java/io/legado/app/data/dao/BookDao.kt index b4dc49846..064eb29b2 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookDao.kt @@ -27,10 +27,10 @@ interface BookDao { @Query("SELECT * FROM books WHERE `name` in (:names)") fun findByName(vararg names: String): List - @Query("select * from books where bookUrl = :bookUrl") + @Query("SELECT * FROM books WHERE bookUrl = :bookUrl") fun getBook(bookUrl: String): Book? - @get:Query("select * from books order by durChapterTime desc limit 1") + @get:Query("SELECT * FROM books ORDER BY durChapterTime DESC limit 1") val lastReadBook: Book? @get:Query("SELECT bookUrl FROM books") From 4843614fb6a86751e5b6ec69fa5c4dd3592931f5 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 16:20:35 +0800 Subject: [PATCH 1037/1997] up --- .../main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index 358ec885c..009c88979 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -53,7 +53,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { bookSource?.let { webBook = WebBook(it) } - val count = App.db.bookChapterDao().getChapterCount(bookUrl) + val count = App.db.bookChapterDao().getChapterCount(book.bookUrl) if (count == 0) { if (book.tocUrl.isEmpty()) { loadBookInfo(book) @@ -68,7 +68,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { chapterListFinish.postValue(true) } } - } + }.onError { it.printStackTrace() } } private fun loadBookInfo(book: Book) { From 24f8f259dd3f0c3027079b5e683c81622edd98d0 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 17:22:00 +0800 Subject: [PATCH 1038/1997] up --- .../io/legado/app/ui/readbook/ReadBookViewModel.kt | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index 009c88979..841b06199 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -236,10 +236,9 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { curTextChapter = nextTextChapter nextTextChapter = null bookData.value?.let { - loadContent(it, durChapterIndex.plus(1)) launch(IO) { - for (i in 2..10) { - delay(1000L) + for (i in 0..10) { + delay(100) bookData.value?.let { book -> download(book, durChapterIndex + i) } @@ -254,7 +253,14 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { curTextChapter = prevTextChapter prevTextChapter = null bookData.value?.let { - loadContent(it, durChapterIndex.minus(1)) + launch(IO) { + for (i in -5..0) { + delay(100) + bookData.value?.let { book -> + download(book, durChapterIndex + i) + } + } + } } } From 04a22911f4d83c6ac2ee3533686f146279409d18 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 17:29:22 +0800 Subject: [PATCH 1039/1997] up --- .../main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index 841b06199..f6b1bd219 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -234,7 +234,6 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { durChapterIndex++ prevTextChapter = curTextChapter curTextChapter = nextTextChapter - nextTextChapter = null bookData.value?.let { launch(IO) { for (i in 0..10) { @@ -251,7 +250,6 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { durChapterIndex-- nextTextChapter = curTextChapter curTextChapter = prevTextChapter - prevTextChapter = null bookData.value?.let { launch(IO) { for (i in -5..0) { From c5837f74fd794084f5dfbd4086aed155216fe882 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 17:35:04 +0800 Subject: [PATCH 1040/1997] up --- .../java/io/legado/app/ui/readbook/ReadBookViewModel.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index f6b1bd219..f1805c6bd 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -234,9 +234,11 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { durChapterIndex++ prevTextChapter = curTextChapter curTextChapter = nextTextChapter + nextTextChapter = null bookData.value?.let { + loadContent(it, durChapterIndex.plus(1)) launch(IO) { - for (i in 0..10) { + for (i in 2..10) { delay(100) bookData.value?.let { book -> download(book, durChapterIndex + i) @@ -250,9 +252,11 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { durChapterIndex-- nextTextChapter = curTextChapter curTextChapter = prevTextChapter + prevTextChapter = null bookData.value?.let { + loadContent(it, durChapterIndex.minus(1)) launch(IO) { - for (i in -5..0) { + for (i in -5..-2) { delay(100) bookData.value?.let { book -> download(book, durChapterIndex + i) From 61cfd284b76bd4380fcf59cc05e1c6d8c8f4e89c Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 17:44:13 +0800 Subject: [PATCH 1041/1997] up --- .../app/ui/readbook/ReadBookViewModel.kt | 74 ++++++++++--------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index f1805c6bd..85de3fc04 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -97,6 +97,44 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } } + fun moveToNextChapter() { + durChapterIndex++ + prevTextChapter = curTextChapter + curTextChapter = nextTextChapter + nextTextChapter = null + bookData.value?.let { + loadContent(it, durChapterIndex) + loadContent(it, durChapterIndex.plus(1)) + launch(IO) { + for (i in 2..10) { + delay(100) + bookData.value?.let { book -> + download(book, durChapterIndex + i) + } + } + } + } + } + + fun moveToPrevChapter() { + durChapterIndex-- + nextTextChapter = curTextChapter + curTextChapter = prevTextChapter + prevTextChapter = null + bookData.value?.let { + loadContent(it, durChapterIndex) + loadContent(it, durChapterIndex.minus(1)) + launch(IO) { + for (i in -5..-2) { + delay(100) + bookData.value?.let { book -> + download(book, durChapterIndex + i) + } + } + } + } + } + fun loadContent(book: Book, index: Int) { synchronized(loadingLock) { if (loadingChapters.contains(index)) return @@ -230,42 +268,6 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } } - fun moveToNextChapter() { - durChapterIndex++ - prevTextChapter = curTextChapter - curTextChapter = nextTextChapter - nextTextChapter = null - bookData.value?.let { - loadContent(it, durChapterIndex.plus(1)) - launch(IO) { - for (i in 2..10) { - delay(100) - bookData.value?.let { book -> - download(book, durChapterIndex + i) - } - } - } - } - } - - fun moveToPrevChapter() { - durChapterIndex-- - nextTextChapter = curTextChapter - curTextChapter = prevTextChapter - prevTextChapter = null - bookData.value?.let { - loadContent(it, durChapterIndex.minus(1)) - launch(IO) { - for (i in -5..-2) { - delay(100) - bookData.value?.let { book -> - download(book, durChapterIndex + i) - } - } - } - } - } - fun refreshContent(book: Book) { execute { App.db.bookChapterDao().getChapter(book.bookUrl, durChapterIndex)?.let { chapter -> From 9b93cfade53c840f305b329be9297881e985b084 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 17:52:18 +0800 Subject: [PATCH 1042/1997] up --- .../java/io/legado/app/ui/readbook/ReadBookViewModel.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index 85de3fc04..b02beea94 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -167,7 +167,13 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { App.db.bookChapterDao().getChapter(book.bookUrl, index)?.let { chapter -> if (!BookHelp.hasContent(book, chapter)) { download(book, chapter) + } else { + synchronized(loadingLock) { + loadingChapters.remove(index) + } } + } ?: synchronized(loadingLock) { + loadingChapters.remove(index) } }.onError { synchronized(loadingLock) { From 7ced66282e8ec278009143462760666d2bdfad0a Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 18:05:21 +0800 Subject: [PATCH 1043/1997] up --- .../app/ui/readbook/ReadBookViewModel.kt | 82 +++++++++---------- 1 file changed, 37 insertions(+), 45 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index b02beea94..9b9893b81 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -136,48 +136,32 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } fun loadContent(book: Book, index: Int) { - synchronized(loadingLock) { - if (loadingChapters.contains(index)) return - loadingChapters.add(index) - } - execute { - App.db.bookChapterDao().getChapter(book.bookUrl, index)?.let { chapter -> - BookHelp.getContent(book, chapter)?.let { - contentLoadFinish(chapter, it) - synchronized(loadingLock) { - loadingChapters.remove(index) - } - } ?: download(book, chapter) - } ?: synchronized(loadingLock) { - loadingChapters.remove(index) - } - }.onError { - synchronized(loadingLock) { - loadingChapters.remove(index) + if (addLoading(index)) { + execute { + App.db.bookChapterDao().getChapter(book.bookUrl, index)?.let { chapter -> + BookHelp.getContent(book, chapter)?.let { + contentLoadFinish(chapter, it) + removeLoading(chapter.index) + } ?: download(book, chapter) + } ?: removeLoading(index) + }.onError { + removeLoading(index) } } } private fun download(book: Book, index: Int) { - synchronized(loadingLock) { - if (loadingChapters.contains(index)) return - loadingChapters.add(index) - } - execute { - App.db.bookChapterDao().getChapter(book.bookUrl, index)?.let { chapter -> - if (!BookHelp.hasContent(book, chapter)) { - download(book, chapter) - } else { - synchronized(loadingLock) { - loadingChapters.remove(index) + if (addLoading(index)) { + execute { + App.db.bookChapterDao().getChapter(book.bookUrl, index)?.let { chapter -> + if (BookHelp.hasContent(book, chapter)) { + removeLoading(chapter.index) + } else { + download(book, chapter) } - } - } ?: synchronized(loadingLock) { - loadingChapters.remove(index) - } - }.onError { - synchronized(loadingLock) { - loadingChapters.remove(index) + } ?: removeLoading(index) + }.onError { + removeLoading(index) } } } @@ -187,24 +171,32 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { ?.onSuccess(IO) { content -> if (content.isNullOrEmpty()) { contentLoadFinish(chapter, context.getString(R.string.content_empty)) - synchronized(loadingLock) { - loadingChapters.remove(chapter.index) - } + removeLoading(chapter.index) } else { BookHelp.saveContent(book, chapter, content) contentLoadFinish(chapter, content) - synchronized(loadingLock) { - loadingChapters.remove(chapter.index) - } + removeLoading(chapter.index) } }?.onError { contentLoadFinish(chapter, it.localizedMessage) - synchronized(loadingLock) { - loadingChapters.remove(chapter.index) - } + removeLoading(chapter.index) } } + private fun addLoading(index: Int): Boolean { + synchronized(loadingLock) { + if (loadingChapters.contains(index)) return false + loadingChapters.add(index) + return true + } + } + + private fun removeLoading(index: Int) { + synchronized(loadingLock) { + loadingChapters.remove(index) + } + } + private fun contentLoadFinish(chapter: BookChapter, content: String) { if (chapter.index in durChapterIndex - 1..durChapterIndex + 1) { callBack?.contentLoadFinish(chapter, content) From b2c00449be670b9d2071180a409872e076ceb815 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 20:09:22 +0800 Subject: [PATCH 1044/1997] up --- .../java/io/legado/app/data/dao/SearchBookDao.kt | 12 ++++++++++-- .../io/legado/app/ui/search/SearchActivity.kt | 15 ++++++++++----- .../io/legado/app/ui/search/SearchViewModel.kt | 9 ++++++--- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt b/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt index 75e6ae895..2032c46e8 100644 --- a/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt @@ -17,8 +17,16 @@ interface SearchBookDao { @Query("SELECT * FROM searchBooks where time >= :time") fun observeNew(time: Long): DataSource.Factory - @Query("SELECT name, author, min(time) time, max(kind) kind, max(coverUrl) coverUrl, max(intro) intro, max(wordCount) wordCount, max(latestChapterTitle) latestChapterTitle, count(origin) originCount FROM searchBooks where time >= :time group by name, author") - fun observeShow(time: Long): DataSource.Factory + @Query( + """ + SELECT name, author, min(time) time, max(kind) kind, max(coverUrl) coverUrl,max(intro) intro, max(wordCount) wordCount, + max(latestChapterTitle) latestChapterTitle, count(origin) originCount + FROM searchBooks where time >= :time + group by name, author + order by case when name = :key then 1 when author = :key then 2 when name like '%'+:key+'%' then 3 when author like '%'+:key+'%' then 4 else 5 end, time + """ + ) + fun observeShow(key: String, time: Long): DataSource.Factory @Query("select * from searchBooks where bookUrl = :bookUrl") fun getSearchBook(bookUrl: String): SearchBook? diff --git a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt index c37b81605..60478c0b2 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt @@ -31,7 +31,7 @@ class SearchActivity : VMBaseActivity(R.layout.activity_search) override fun onActivityCreated(savedInstanceState: Bundle?) { initRecyclerView() initSearchView() - initData(0L) + initData() intent.getStringExtra("key")?.let { search_view.setQuery(it, true) } @@ -47,9 +47,9 @@ class SearchActivity : VMBaseActivity(R.layout.activity_search) override fun onQueryTextSubmit(query: String?): Boolean { search_view.clearFocus() query?.let { - viewModel.search(it, { startTime -> + viewModel.search(it, { content_view.showContentView() - initData(startTime) + initData() }, { }) @@ -74,9 +74,14 @@ class SearchActivity : VMBaseActivity(R.layout.activity_search) rv_search_list.adapter = adapter } - private fun initData(startTime: Long) { + private fun initData() { searchBookData?.removeObservers(this) - searchBookData = LivePagedListBuilder(App.db.searchBookDao().observeShow(startTime), 30).build() + searchBookData = LivePagedListBuilder( + App.db.searchBookDao().observeShow( + viewModel.searchKey, + viewModel.startTime + ), 30 + ).build() searchBookData?.observe(this, Observer { adapter.submitList(it) }) } diff --git a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt b/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt index b05dca440..e8276db87 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt @@ -11,17 +11,20 @@ import kotlinx.coroutines.delay class SearchViewModel(application: Application) : BaseViewModel(application) { private var task: Coroutine<*>? = null - + var searchKey: String = "" + var startTime: Long = 0 var searchPage = 0 fun search( key: String, - start: ((startTime: Long) -> Unit)? = null, + start: (() -> Unit)? = null, finally: (() -> Unit)? = null ) { if (key.isEmpty()) return task?.cancel() - start?.invoke(System.currentTimeMillis()) + searchKey = key + startTime = System.currentTimeMillis() + start?.invoke() task = execute { //onCleared时自动取消 val bookSourceList = App.db.bookSourceDao().allEnabled From 79f3b4f5a9ddd9c95312201ef1fa29053799384e Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 20:50:06 +0800 Subject: [PATCH 1045/1997] up --- .../io/legado/app/ui/search/DiffCallBack.kt | 36 ++++---- .../io/legado/app/ui/search/SearchAdapter.kt | 88 +++++++++++++++---- 2 files changed, 90 insertions(+), 34 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/search/DiffCallBack.kt b/app/src/main/java/io/legado/app/ui/search/DiffCallBack.kt index b38514f50..b974cb059 100644 --- a/app/src/main/java/io/legado/app/ui/search/DiffCallBack.kt +++ b/app/src/main/java/io/legado/app/ui/search/DiffCallBack.kt @@ -3,26 +3,28 @@ package io.legado.app.ui.search import androidx.recyclerview.widget.DiffUtil import io.legado.app.data.entities.SearchShow -class DiffCallBack(private val oldItems: List, private val newItems: List) : - DiffUtil.Callback() { - override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { - return oldItems[oldItemPosition].name == newItems[newItemPosition].name - && oldItems[oldItemPosition].author == newItems[newItemPosition].author +class DiffCallBack : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: SearchShow, newItem: SearchShow): Boolean { + return oldItem.name == newItem.name + && oldItem.author == newItem.author } - override fun getOldListSize(): Int { - return oldItems.size + override fun areContentsTheSame(oldItem: SearchShow, newItem: SearchShow): Boolean { + return oldItem.originCount == newItem.originCount + && (oldItem.coverUrl == newItem.coverUrl || !oldItem.coverUrl.isNullOrEmpty()) + && (oldItem.kind == newItem.kind || !oldItem.kind.isNullOrEmpty()) + && (oldItem.latestChapterTitle == newItem.latestChapterTitle || !oldItem.kind.isNullOrEmpty()) + && oldItem.intro?.length ?: 0 > newItem.intro?.length ?: 0 } - override fun getNewListSize(): Int { - return newItems.size - } - - override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { - return oldItems[oldItemPosition].originCount == newItems[newItemPosition].originCount - } - - override fun getChangePayload(oldItemPosition: Int, newItemPosition: Int): Any? { - return super.getChangePayload(oldItemPosition, newItemPosition) + override fun getChangePayload(oldItem: SearchShow, newItem: SearchShow): Any? { + return when { + oldItem.originCount != newItem.originCount -> 1 + oldItem.coverUrl != newItem.coverUrl -> 2 + oldItem.kind != newItem.kind -> 3 + oldItem.latestChapterTitle != newItem.latestChapterTitle -> 4 + oldItem.intro != newItem.intro -> 5 + else -> null + } } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt b/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt index d3bcf6bed..42b066235 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt @@ -4,7 +4,6 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.paging.PagedListAdapter -import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import io.legado.app.R import io.legado.app.data.entities.SearchShow @@ -16,21 +15,7 @@ import kotlinx.android.synthetic.main.item_bookshelf_list.view.tv_name import kotlinx.android.synthetic.main.item_search.view.* import org.jetbrains.anko.sdk27.listeners.onClick -class SearchAdapter : PagedListAdapter(DIFF_CALLBACK) { - - companion object { - - @JvmField - val DIFF_CALLBACK = object : DiffUtil.ItemCallback() { - override fun areItemsTheSame(oldItem: SearchShow, newItem: SearchShow): Boolean = - oldItem.name == newItem.name - && oldItem.author == newItem.author - - override fun areContentsTheSame(oldItem: SearchShow, newItem: SearchShow): Boolean = - oldItem.name == newItem.name - && oldItem.author == newItem.author - } - } +class SearchAdapter : PagedListAdapter(DiffCallBack()) { var callBack: CallBack? = null @@ -38,6 +23,16 @@ class SearchAdapter : PagedListAdapter(D return MyViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_search, parent, false)) } + override fun onBindViewHolder(holder: MyViewHolder, position: Int, payloads: MutableList) { + if (payloads.isEmpty()) { + super.onBindViewHolder(holder, position, payloads) + } else { + getItem(position)?.let { + holder.bindChange(it, payloads, callBack) + } + } + } + override fun onBindViewHolder(holder: MyViewHolder, position: Int) { getItem(position)?.let { holder.bind(it, callBack) @@ -49,8 +44,8 @@ class SearchAdapter : PagedListAdapter(D fun bind(searchBook: SearchShow, callBack: CallBack?) = with(itemView) { tv_name.text = searchBook.name - bv_originCount.setBadgeCount(searchBook.originCount) tv_author.text = context.getString(R.string.author_show, searchBook.author) + bv_originCount.setBadgeCount(searchBook.originCount) if (searchBook.latestChapterTitle.isNullOrEmpty()) { tv_lasted.gone() } else { @@ -99,6 +94,65 @@ class SearchAdapter : PagedListAdapter(D callBack?.showBookInfo(searchBook.name, searchBook.author) } } + + fun bindChange(searchBook: SearchShow, payloads: MutableList, callBack: CallBack?) = + with(itemView) { + when (payloads[0]) { + 1 -> bv_originCount.setBadgeCount(searchBook.originCount) + 2 -> searchBook.coverUrl.let { + ImageLoader.load(context, it)//Glide自动识别http://和file:// + .placeholder(R.drawable.img_cover_default) + .error(R.drawable.img_cover_default) + .centerCrop() + .setAsDrawable(iv_cover) + } + 3 -> { + val kinds = searchBook.getKindList() + if (kinds.isEmpty()) { + ll_kind.gone() + } else { + ll_kind.visible() + for (index in 0..2) { + if (kinds.size > index) { + when (index) { + 0 -> { + tv_kind.text = kinds[index] + tv_kind.visible() + } + 1 -> { + tv_kind_1.text = kinds[index] + tv_kind_1.visible() + } + 2 -> { + tv_kind_2.text = kinds[index] + tv_kind_2.visible() + } + } + } else { + when (index) { + 0 -> tv_kind.gone() + 1 -> tv_kind_1.gone() + 2 -> tv_kind_2.gone() + } + } + } + } + } + 4 -> { + if (searchBook.latestChapterTitle.isNullOrEmpty()) { + tv_lasted.gone() + } else { + tv_lasted.text = context.getString( + R.string.lasted_show, + searchBook.latestChapterTitle + ) + tv_lasted.visible() + } + } + 5 -> tv_introduce.text = + context.getString(R.string.intro_show, searchBook.intro) + } + } } interface CallBack { From 8c3e612dfd4dd6e7967b5abdbfbfa00132f953a6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 20:51:37 +0800 Subject: [PATCH 1046/1997] up --- .../java/io/legado/app/data/dao/SearchBookDao.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt b/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt index 2032c46e8..5d928c42a 100644 --- a/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt @@ -11,12 +11,6 @@ import io.legado.app.data.entities.SearchShow @Dao interface SearchBookDao { - @Query("SELECT * FROM searchBooks") - fun observeAll(): DataSource.Factory - - @Query("SELECT * FROM searchBooks where time >= :time") - fun observeNew(time: Long): DataSource.Factory - @Query( """ SELECT name, author, min(time) time, max(kind) kind, max(coverUrl) coverUrl,max(intro) intro, max(wordCount) wordCount, @@ -28,6 +22,12 @@ interface SearchBookDao { ) fun observeShow(key: String, time: Long): DataSource.Factory + @Query("SELECT * FROM searchBooks") + fun observeAll(): DataSource.Factory + + @Query("SELECT * FROM searchBooks where time >= :time") + fun observeNew(time: Long): DataSource.Factory + @Query("select * from searchBooks where bookUrl = :bookUrl") fun getSearchBook(bookUrl: String): SearchBook? From 38cdb80cdcb066001410e2351a18b8e66755ddf1 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 21:13:54 +0800 Subject: [PATCH 1047/1997] up --- .../java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt index 29314fc51..65282b558 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt @@ -113,7 +113,7 @@ class ReadAloudDialog : DialogFragment() { dismiss() } } - iv_stop.onClick { ReadAloudService.stop(requireContext()) } + iv_stop.onClick { ReadAloudService.stop(requireContext()); dismiss() } iv_play_pause.onClick { postEvent(Bus.READ_ALOUD_BUTTON, true) } iv_play_prev.onClick { ReadAloudService.prevParagraph(requireContext()) } iv_play_next.onClick { ReadAloudService.nextParagraph(requireContext()) } From 383f5d100095da6cd5d1bc1ae91ef8bd8006771b Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 21:21:42 +0800 Subject: [PATCH 1048/1997] up --- app/src/main/java/io/legado/app/model/webbook/BookList.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookList.kt b/app/src/main/java/io/legado/app/model/webbook/BookList.kt index b24e414f4..bbdd28766 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookList.kt @@ -108,8 +108,10 @@ object BookList { analyzeRule.setBook(searchBook) with(bookSource.getBookInfoRule()) { init?.let { - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "执行详情页初始化规则") - analyzeRule.setContent(analyzeRule.getElement(it)) + if (it.isNotEmpty()) { + SourceDebug.printLog(bookSource.bookSourceUrl, 1, "执行详情页初始化规则") + analyzeRule.setContent(analyzeRule.getElement(it)) + } } SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取书名") searchBook.name = analyzeRule.getString(name ?: "") ?: "" From 03b7c3b6e7ae89d58affe9430fb3a0830e451273 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 21:36:01 +0800 Subject: [PATCH 1049/1997] up --- .../legado/app/ui/changesource/ChangeSourceDialog.kt | 1 + .../app/ui/changesource/ChangeSourceViewModel.kt | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt index 854532d17..4ff4b8838 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt @@ -62,6 +62,7 @@ class ChangeSourceDialog : DialogFragment(), initRecyclerView() initSearchView() viewModel.initData() + viewModel.search() } override fun onStart() { diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt index df3041c6c..2cf667a29 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt @@ -10,6 +10,7 @@ import io.legado.app.data.entities.SearchBook import io.legado.app.model.WebBook import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.Main +import kotlinx.coroutines.delay import kotlinx.coroutines.withContext import org.jetbrains.anko.debug @@ -18,6 +19,7 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio var curBookUrl = "" var name: String = "" var author: String = "" + var screenKey: String = "" private val searchBooks = linkedSetOf() fun initData() { @@ -25,7 +27,6 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio App.db.searchBookDao().getByNameAuthorEnable(name, author).let { searchBooks.addAll(it) upAdapter() - search() } } } @@ -50,6 +51,7 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio execute { val bookSourceList = App.db.bookSourceDao().allEnabled for (item in bookSourceList) { + delay(100) //task取消时自动取消 by (scope = this@execute) WebBook(item).searchBook(name, scope = this@execute) .timeout(30000L) @@ -93,9 +95,9 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio if (chapters.isNotEmpty()) { book.latestChapterTitle = chapters.last().title val searchBook = book.toSearchBook() + App.db.searchBookDao().insert(searchBook) searchBooks.add(searchBook) upAdapter() - App.db.searchBookDao().insert(searchBook) } } }.onError { @@ -105,9 +107,13 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio } } + /** + * 筛选 + */ fun screen(key: String?) { + screenKey = key ?: "" if (key.isNullOrEmpty()) { - + initData() } else { } From 77cbd8da8f874cab829d2d5eac02e85ad64e632c Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 21:39:02 +0800 Subject: [PATCH 1050/1997] up --- .../java/io/legado/app/ui/sourceedit/SourceEditActivity.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditActivity.kt index cb9c3ed0f..5ad1c0d94 100644 --- a/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditActivity.kt @@ -1,5 +1,6 @@ package io.legado.app.ui.sourceedit +import android.app.Activity import android.graphics.Rect import android.os.Bundle import android.view.Gravity @@ -71,7 +72,7 @@ class SourceEditActivity : VMBaseActivity(R.layout.activity if (bookSource == null) { toast("书源名称和URL不能为空") } else { - viewModel.save(bookSource) { finish() } + viewModel.save(bookSource) { setResult(Activity.RESULT_OK); finish() } } } R.id.action_debug_source -> { From 503850b6905d7d7b0ebb3d4574565d49c0c81105 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 21:42:48 +0800 Subject: [PATCH 1051/1997] up --- app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index 9b9893b81..f48537b9e 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -93,6 +93,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } }?.onError { toast(R.string.error_load_toc) + it.printStackTrace() } ?: autoChangeSource() } } From d2818eead7de014a101e6798095b94bf9da86da3 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 21:47:29 +0800 Subject: [PATCH 1052/1997] up --- app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index f48537b9e..96a5711e0 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -209,6 +209,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { bookData.value?.let { App.db.bookDao().delete(it.bookUrl) } + App.db.bookDao().insert(book) bookData.postValue(book) bookSource = App.db.bookSourceDao().getBookSource(book.origin) if (book.tocUrl.isEmpty()) { From d766fc20bcc6e3fcc5ac2e3acce5c17527301538 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 22:28:22 +0800 Subject: [PATCH 1053/1997] up --- .../main/java/io/legado/app/ui/widget/page/ChapterProvider.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt index 7351379a6..68165caa5 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt @@ -24,10 +24,12 @@ object ChapterProvider { while (surplusText.isNotEmpty()) { val spannableStringBuilder = SpannableStringBuilder(surplusText) if (pageIndex == 0) { + var end = surplusText.indexOf("\n") + if (end == -1) end = surplusText.length.minus(1) spannableStringBuilder.setSpan( titleSpan, 0, - surplusText.indexOf("\n"), + end, Spannable.SPAN_INCLUSIVE_EXCLUSIVE ) } From 4412382fa2f5242697cd34a3fc6f066faef46a30 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 22:30:57 +0800 Subject: [PATCH 1054/1997] up --- .../main/java/io/legado/app/ui/widget/page/ChapterProvider.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt index 68165caa5..c69462355 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt @@ -25,7 +25,7 @@ object ChapterProvider { val spannableStringBuilder = SpannableStringBuilder(surplusText) if (pageIndex == 0) { var end = surplusText.indexOf("\n") - if (end == -1) end = surplusText.length.minus(1) + if (end == -1) end = surplusText.length spannableStringBuilder.setSpan( titleSpan, 0, From 900318da6d82b4d5218d58a27d18983dca3e11f8 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 22:51:29 +0800 Subject: [PATCH 1055/1997] up --- .../app/ui/widget/page/ChapterProvider.kt | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt index c69462355..84d987037 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt @@ -24,14 +24,15 @@ object ChapterProvider { while (surplusText.isNotEmpty()) { val spannableStringBuilder = SpannableStringBuilder(surplusText) if (pageIndex == 0) { - var end = surplusText.indexOf("\n") - if (end == -1) end = surplusText.length - spannableStringBuilder.setSpan( - titleSpan, - 0, - end, - Spannable.SPAN_INCLUSIVE_EXCLUSIVE - ) + val end = surplusText.indexOf("\n") + if (end > 0) { + spannableStringBuilder.setSpan( + titleSpan, + 0, + end, + Spannable.SPAN_INCLUSIVE_EXCLUSIVE + ) + } } textView.text = spannableStringBuilder pageLengths.add(textView.getCharNum()) From 277ea66b99b24c2e3bdca2b214fa513b1ace5d9c Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 23:03:38 +0800 Subject: [PATCH 1056/1997] up --- .../main/java/io/legado/app/model/WebBook.kt | 2 +- .../legado/app/ui/readbook/ReadBookActivity.kt | 4 ++-- .../legado/app/ui/readbook/ReadBookViewModel.kt | 17 +++++++++-------- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/WebBook.kt b/app/src/main/java/io/legado/app/model/WebBook.kt index 8ed3f812b..5eaa243c5 100644 --- a/app/src/main/java/io/legado/app/model/WebBook.kt +++ b/app/src/main/java/io/legado/app/model/WebBook.kt @@ -12,7 +12,7 @@ import io.legado.app.model.webbook.BookInfo import io.legado.app.model.webbook.BookList import kotlinx.coroutines.CoroutineScope -class WebBook(private val bookSource: BookSource) { +class WebBook(val bookSource: BookSource) { val sourceUrl: String get() = bookSource.bookSourceUrl diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 66af6e9aa..f4a9540e2 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -95,10 +95,10 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea */ private fun initView() { tv_chapter_name.onClick { - viewModel.bookSource?.let { + viewModel.webBook?.let { startActivityForResult( requestCodeEditSource, - Pair("data", it.bookSourceUrl) + Pair("data", it.bookSource.bookSourceUrl) ) } } diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index 96a5711e0..f472024f4 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -9,7 +9,6 @@ import io.legado.app.base.BaseViewModel import io.legado.app.constant.BookType import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter -import io.legado.app.data.entities.BookSource import io.legado.app.help.BookHelp import io.legado.app.model.WebBook import io.legado.app.service.ReadAloudService @@ -23,7 +22,6 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { var bookData = MutableLiveData() val chapterListFinish = MutableLiveData() var chapterSize = 0 - var bookSource: BookSource? = null var callBack: CallBack? = null var durChapterIndex = 0 var durPageIndex = 0 @@ -31,7 +29,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { var prevTextChapter: TextChapter? = null var curTextChapter: TextChapter? = null var nextTextChapter: TextChapter? = null - private var webBook: WebBook? = null + var webBook: WebBook? = null private val loadingChapters = arrayListOf() private val loadingLock = "loadingLock" @@ -49,8 +47,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { durPageIndex = book.durChapterPos isLocalBook = book.origin == BookType.local bookData.postValue(book) - bookSource = App.db.bookSourceDao().getBookSource(book.origin) - bookSource?.let { + App.db.bookSourceDao().getBookSource(book.origin)?.let { webBook = WebBook(it) } val count = App.db.bookChapterDao().getChapterCount(book.bookUrl) @@ -211,7 +208,9 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } App.db.bookDao().insert(book) bookData.postValue(book) - bookSource = App.db.bookSourceDao().getBookSource(book.origin) + App.db.bookSourceDao().getBookSource(book.origin)?.let { + webBook = WebBook(it) + } if (book.tocUrl.isEmpty()) { loadBookInfo(book) } else { @@ -262,8 +261,10 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { fun upBookSource() { execute { - bookData.value?.let { - bookSource = App.db.bookSourceDao().getBookSource(it.origin) + bookData.value?.let { book -> + App.db.bookSourceDao().getBookSource(book.origin)?.let { + webBook = WebBook(it) + } } } } From 93f817c9c703109e27c38bf84965e8065b63e4ec Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 23:06:28 +0800 Subject: [PATCH 1057/1997] up --- .../ui/changesource/ChangeSourceAdapter.kt | 19 ++++++++----------- .../app/ui/changesource/ChangeSourceDialog.kt | 3 +-- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceAdapter.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceAdapter.kt index 45e9da565..0d7d3718b 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceAdapter.kt @@ -11,25 +11,22 @@ import kotlinx.android.synthetic.main.item_change_source.view.* import org.jetbrains.anko.sdk27.listeners.onClick -class ChangeSourceAdapter(context: Context) : SimpleRecyclerAdapter(context, R.layout.item_change_source) { - - var callBack: CallBack? = null +class ChangeSourceAdapter(context: Context, val callBack: CallBack) : + SimpleRecyclerAdapter(context, R.layout.item_change_source) { override fun convert(holder: ItemViewHolder, item: SearchBook, payloads: MutableList) { holder.itemView.apply { if (payloads.isEmpty()) { this.onClick { - callBack?.changeTo(item) + callBack.changeTo(item) } tv_origin.text = item.originName tv_last.text = item.latestChapterTitle - callBack?.let { - if (it.curBookUrl() == item.bookUrl) { - iv_checked.visible() - } else { - iv_checked.invisible() - } - } ?: iv_checked.invisible() + if (callBack.curBookUrl() == item.bookUrl) { + iv_checked.visible() + } else { + iv_checked.invisible() + } } else { tv_origin.text = item.originName tv_last.text = item.latestChapterTitle diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt index 4ff4b8838..cb13679fe 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt @@ -78,8 +78,7 @@ class ChangeSourceDialog : DialogFragment(), } private fun initRecyclerView() { - changeSourceAdapter = ChangeSourceAdapter(requireContext()) - changeSourceAdapter.callBack = this + changeSourceAdapter = ChangeSourceAdapter(requireContext(), this) recycler_view.layoutManager = LinearLayoutManager(context) recycler_view.addItemDecoration(DividerItemDecoration(requireContext(), LinearLayout.VERTICAL)) recycler_view.adapter = changeSourceAdapter From 0c1a633444296a95c0e4e668d8d2d9165a798eac Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 23:07:45 +0800 Subject: [PATCH 1058/1997] up --- .../java/io/legado/app/ui/changesource/ChangeSourceAdapter.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceAdapter.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceAdapter.kt index 0d7d3718b..0231a4cea 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceAdapter.kt @@ -17,9 +17,7 @@ class ChangeSourceAdapter(context: Context, val callBack: CallBack) : override fun convert(holder: ItemViewHolder, item: SearchBook, payloads: MutableList) { holder.itemView.apply { if (payloads.isEmpty()) { - this.onClick { - callBack.changeTo(item) - } + this.onClick { callBack.changeTo(item) } tv_origin.text = item.originName tv_last.text = item.latestChapterTitle if (callBack.curBookUrl() == item.bookUrl) { From 02164d24c7205a5a79a8b99df8a85d39124aa503 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 27 Aug 2019 23:11:19 +0800 Subject: [PATCH 1059/1997] up --- .../main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt | 3 ++- .../main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index b618f29d6..ce7ba7b11 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -177,7 +177,8 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo tv_change_source.onClick { if (changeSourceDialog == null) { viewModel.bookData.value?.let { - changeSourceDialog = ChangeSourceDialog.newInstance(it.name, it.author) + changeSourceDialog = ChangeSourceDialog + .newInstance(it.name, it.author, it.origin) changeSourceDialog?.callBack = this } } diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index f4a9540e2..57d9d375d 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -176,7 +176,8 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea R.id.menu_change_source -> { if (changeSourceDialog == null) { viewModel.bookData.value?.let { - changeSourceDialog = ChangeSourceDialog.newInstance(it.name, it.author) + changeSourceDialog = ChangeSourceDialog + .newInstance(it.name, it.author, it.origin) changeSourceDialog?.callBack = this } } From f4a21709e50404e4693c494b45ae5e54d27ef041 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 28 Aug 2019 08:07:47 +0800 Subject: [PATCH 1060/1997] up --- .../app/ui/changesource/ChangeSourceAdapter.kt | 4 ++-- .../legado/app/ui/changesource/ChangeSourceDialog.kt | 12 ++++++------ .../app/ui/changesource/ChangeSourceViewModel.kt | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceAdapter.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceAdapter.kt index 0231a4cea..763574810 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceAdapter.kt @@ -20,7 +20,7 @@ class ChangeSourceAdapter(context: Context, val callBack: CallBack) : this.onClick { callBack.changeTo(item) } tv_origin.text = item.originName tv_last.text = item.latestChapterTitle - if (callBack.curBookUrl() == item.bookUrl) { + if (callBack.curOrigin() == item.origin) { iv_checked.visible() } else { iv_checked.invisible() @@ -34,6 +34,6 @@ class ChangeSourceAdapter(context: Context, val callBack: CallBack) : interface CallBack { fun changeTo(searchBook: SearchBook) - fun curBookUrl(): String + fun curOrigin(): String } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt index cb13679fe..0509ba52e 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt @@ -24,12 +24,12 @@ class ChangeSourceDialog : DialogFragment(), companion object { const val tag = "changeSourceDialog" - fun newInstance(name: String, author: String, bookUrl: String? = null): ChangeSourceDialog { + fun newInstance(name: String, author: String, origin: String): ChangeSourceDialog { val changeSourceDialog = ChangeSourceDialog() val bundle = Bundle() bundle.putString("name", name) bundle.putString("author", author) - bundle.putString("bookUrl", bookUrl) + bundle.putString("origin", origin) changeSourceDialog.arguments = bundle return changeSourceDialog } @@ -53,8 +53,8 @@ class ChangeSourceDialog : DialogFragment(), bundle.getString("author")?.let { viewModel.author = it } - bundle.getString("bookUrl")?.let { - viewModel.curBookUrl = it + bundle.getString("origin")?.let { + viewModel.curOrigin = it } } tool_bar.inflateMenu(R.menu.search_view) @@ -127,8 +127,8 @@ class ChangeSourceDialog : DialogFragment(), dismiss() } - override fun curBookUrl(): String { - return viewModel.curBookUrl + override fun curOrigin(): String { + return viewModel.curOrigin } override fun adapter(): ChangeSourceAdapter { diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt index 2cf667a29..acfba1ce3 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt @@ -16,7 +16,7 @@ import org.jetbrains.anko.debug class ChangeSourceViewModel(application: Application) : BaseViewModel(application) { var callBack: CallBack? = null - var curBookUrl = "" + var curOrigin = "" var name: String = "" var author: String = "" var screenKey: String = "" From cc8212ac8cf74ed43458785b0d4c65673c7836ae Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 28 Aug 2019 08:11:03 +0800 Subject: [PATCH 1061/1997] up --- .../main/java/io/legado/app/ui/search/SearchViewModel.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt b/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt index e8276db87..33381933b 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt @@ -35,11 +35,13 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { .timeout(30000L) .onSuccess(Dispatchers.IO) { it?.let { list -> - App.db.searchBookDao().insert(*list.toTypedArray()) + list.map { searchBook -> + if (searchBook.name.contains(key) || searchBook.author.contains(key)) + App.db.searchBookDao().insert(searchBook) + } } } } - }.onError { it.printStackTrace() } From e516824b32448f7ecb4222f23935b8ca434b8f81 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 28 Aug 2019 08:15:32 +0800 Subject: [PATCH 1062/1997] up --- app/src/main/java/io/legado/app/ui/search/SearchActivity.kt | 6 ++++-- app/src/main/res/layout/activity_search.xml | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt index 60478c0b2..c521d56b1 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt @@ -15,6 +15,8 @@ import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.primaryTextColor import io.legado.app.ui.bookinfo.BookInfoActivity import io.legado.app.utils.getViewModel +import io.legado.app.utils.invisible +import io.legado.app.utils.visible import kotlinx.android.synthetic.main.activity_search.* import kotlinx.android.synthetic.main.view_search.* import org.jetbrains.anko.sdk27.listeners.onClick @@ -50,8 +52,9 @@ class SearchActivity : VMBaseActivity(R.layout.activity_search) viewModel.search(it, { content_view.showContentView() initData() + fb_stop.visible() }, { - + fb_stop.invisible() }) } return true @@ -61,7 +64,6 @@ class SearchActivity : VMBaseActivity(R.layout.activity_search) if (newText.isNullOrBlank()) viewModel.stop() return false } - }) fb_stop.onClick { viewModel.stop() } } diff --git a/app/src/main/res/layout/activity_search.xml b/app/src/main/res/layout/activity_search.xml index 0450dd548..296dc6b9f 100644 --- a/app/src/main/res/layout/activity_search.xml +++ b/app/src/main/res/layout/activity_search.xml @@ -38,6 +38,7 @@ android:layout_height="wrap_content" android:layout_margin="16dp" android:src="@drawable/ic_stop_black_24dp" + android:visibility="invisible" app:fabSize="mini" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintRight_toRightOf="parent" /> From 15050e80e34e641570faa050b4f726e7201c2184 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 28 Aug 2019 08:41:07 +0800 Subject: [PATCH 1063/1997] up --- app/src/main/java/io/legado/app/help/BookHelp.kt | 3 +++ .../java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt | 4 ++++ app/src/main/res/layout/item_bookshelf_list.xml | 3 ++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/help/BookHelp.kt b/app/src/main/java/io/legado/app/help/BookHelp.kt index ab0f5ab95..83d8de8e5 100644 --- a/app/src/main/java/io/legado/app/help/BookHelp.kt +++ b/app/src/main/java/io/legado/app/help/BookHelp.kt @@ -85,4 +85,7 @@ object BookHelp { ?: "" } + fun getDurChapterIndexByChapterName() { + + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt index 341de51ff..90024b32c 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt @@ -12,6 +12,7 @@ import io.legado.app.data.entities.Book import io.legado.app.help.ImageLoader import io.legado.app.lib.theme.ThemeStore import io.legado.app.utils.getCompatColor +import io.legado.app.utils.invisible import kotlinx.android.synthetic.main.item_bookshelf_list.view.* import kotlinx.android.synthetic.main.item_relace_rule.view.tv_name import org.jetbrains.anko.sdk27.listeners.onClick @@ -81,9 +82,12 @@ class BookshelfAdapter : PagedListAdapter(D } callBack?.let { if (book.origin != BookType.local && it.isUpdate(book.bookUrl)) { + bv_unread.invisible() rl_loading.show() } else { rl_loading.hide() + bv_unread.setBadgeCount(book.getUnreadChapterNum()) + bv_unread.setHighlight(book.lastCheckCount > 0) } } ?: rl_loading.hide() } diff --git a/app/src/main/res/layout/item_bookshelf_list.xml b/app/src/main/res/layout/item_bookshelf_list.xml index 72376cda3..03fd1afc1 100644 --- a/app/src/main/res/layout/item_bookshelf_list.xml +++ b/app/src/main/res/layout/item_bookshelf_list.xml @@ -27,8 +27,9 @@ android:id="@+id/fl_has_new" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:layout_margin="8dp" app:layout_constraintRight_toRightOf="parent" - app:layout_constraintTop_toTopOf="@id/tv_name"> + app:layout_constraintTop_toTopOf="parent"> Date: Wed, 28 Aug 2019 08:52:50 +0800 Subject: [PATCH 1064/1997] up --- app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt b/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt index 42b066235..6ee7337eb 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt @@ -28,7 +28,7 @@ class SearchAdapter : PagedListAdapter(D super.onBindViewHolder(holder, position, payloads) } else { getItem(position)?.let { - holder.bindChange(it, payloads, callBack) + holder.bindChange(it, payloads) } } } @@ -95,7 +95,7 @@ class SearchAdapter : PagedListAdapter(D } } - fun bindChange(searchBook: SearchShow, payloads: MutableList, callBack: CallBack?) = + fun bindChange(searchBook: SearchShow, payloads: MutableList) = with(itemView) { when (payloads[0]) { 1 -> bv_originCount.setBadgeCount(searchBook.originCount) From 70f487bffbebc8586385346ae57139d49075c7d6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 28 Aug 2019 09:25:56 +0800 Subject: [PATCH 1065/1997] up --- .../main/java/io/legado/app/model/webbook/BookChapterList.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt b/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt index 56adb8278..ec6fa6fb5 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt @@ -116,6 +116,10 @@ object BookChapterList { item.index = index } book.latestChapterTitle = chapterList.last().title + if (book.totalChapterNum < chapterList.size) { + book.lastCheckCount = chapterList.size - book.totalChapterNum + book.totalChapterNum = chapterList.size + } return chapterList } From f3e7543ae1db3ca0f6f8a23aef6a0f4b23166178 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 28 Aug 2019 09:30:16 +0800 Subject: [PATCH 1066/1997] up --- .../main/java/io/legado/app/ui/widget/page/ChapterProvider.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt index 84d987037..502630b72 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt @@ -11,7 +11,7 @@ import io.legado.app.lib.theme.accentColor object ChapterProvider { val readAloudSpan = ForegroundColorSpan(App.INSTANCE.accentColor) - private val titleSpan = RelativeSizeSpan(1.3f) + private val titleSpan = RelativeSizeSpan(1.2f) fun getTextChapter( textView: ContentTextView, bookChapter: BookChapter, From f6212972d50332a27ba75f908edf3ca86dafe0c9 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 28 Aug 2019 09:33:46 +0800 Subject: [PATCH 1067/1997] up --- app/src/main/assets/readConfig.json | 20 +++++++++---------- .../java/io/legado/app/help/ReadBookConfig.kt | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/app/src/main/assets/readConfig.json b/app/src/main/assets/readConfig.json index b09b971cc..3f340c8ed 100644 --- a/app/src/main/assets/readConfig.json +++ b/app/src/main/assets/readConfig.json @@ -4,10 +4,10 @@ "bgType": 1, "darkStatusIcon": true, "textColor": "#5E432E", - "textSize": 20, + "textSize": 22, "letterSpacing": 0, "lineSpacingExtra": 10, - "lineSpacingMultiplier": 1, + "lineSpacingMultiplier": 1.2, "paddingLeft": 16, "paddingRight": 16, "paddingTop": 10, @@ -18,10 +18,10 @@ "bgType": 0, "darkStatusIcon": true, "textColor": "#5E432E", - "textSize": 20, + "textSize": 22, "letterSpacing": 0, "lineSpacingExtra": 10, - "lineSpacingMultiplier": 1, + "lineSpacingMultiplier": 1.2, "paddingLeft": 16, "paddingRight": 16, "paddingTop": 0, @@ -32,10 +32,10 @@ "bgType": 0, "darkStatusIcon": true, "textColor": "#22482C", - "textSize": 20, + "textSize": 22, "letterSpacing": 0, "lineSpacingExtra": 10, - "lineSpacingMultiplier": 1, + "lineSpacingMultiplier": 1.2, "paddingLeft": 16, "paddingRight": 16, "paddingTop": 0, @@ -46,10 +46,10 @@ "bgType": 0, "darkStatusIcon": false, "textColor": "#FFFFFF", - "textSize": 20, + "textSize": 22, "letterSpacing": 0, "lineSpacingExtra": 10, - "lineSpacingMultiplier": 1, + "lineSpacingMultiplier": 1.2, "paddingLeft": 16, "paddingRight": 16, "paddingTop": 0, @@ -60,10 +60,10 @@ "bgType": 0, "darkStatusIcon": false, "textColor": "#adadad", - "textSize": 20, + "textSize": 22, "letterSpacing": 0, "lineSpacingExtra": 10, - "lineSpacingMultiplier": 1, + "lineSpacingMultiplier": 1.2, "paddingLeft": 16, "paddingRight": 16, "paddingTop": 0, diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index 5fb46551d..7d852791c 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -102,7 +102,7 @@ object ReadBookConfig { var darkStatusIcon: Boolean = true, var letterSpacing: Float = 1f, var lineSpacingExtra: Float = 15f, - var lineSpacingMultiplier: Float = 3f, + var lineSpacingMultiplier: Float = 1.2f, var paddingBottom: Int = 0, var paddingLeft: Int = 16, var paddingRight: Int = 16, From ec6a43a3296b1add127a5813fb7961cf6f9fbc12 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 28 Aug 2019 09:47:14 +0800 Subject: [PATCH 1068/1997] up --- .../main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index f472024f4..e6090b873 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -238,13 +238,14 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { fun saveRead() { execute { bookData.value?.let { book -> + book.lastCheckCount = 0 book.durChapterTime = System.currentTimeMillis() book.durChapterIndex = durChapterIndex book.durChapterPos = durPageIndex curTextChapter?.let { book.durChapterTitle = it.title - App.db.bookDao().update(book) } + App.db.bookDao().update(book) } } } From 6c8645990af2e19c734ca0cfe5b1fb89a5856648 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 28 Aug 2019 09:50:41 +0800 Subject: [PATCH 1069/1997] up --- .../main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 57d9d375d..7aed7c0ca 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -90,6 +90,11 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea Help.upSystemUiVisibility(window, !read_menu.isVisible) } + override fun onDestroy() { + super.onDestroy() + viewModel.saveRead() + } + /** * 初始化View */ From 1f92dba5fa3b3bfdb8eb84496f88a9135c8ff25a Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 28 Aug 2019 10:15:15 +0800 Subject: [PATCH 1070/1997] up --- app/src/main/res/drawable/ic_remove.xml | 9 ++++ .../res/layout/dialog_read_book_style.xml | 44 ++++++++++++++++++- 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 app/src/main/res/drawable/ic_remove.xml diff --git a/app/src/main/res/drawable/ic_remove.xml b/app/src/main/res/drawable/ic_remove.xml new file mode 100644 index 000000000..90eec6f30 --- /dev/null +++ b/app/src/main/res/drawable/ic_remove.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/dialog_read_book_style.xml b/app/src/main/res/layout/dialog_read_book_style.xml index da1aaee91..14569bbe6 100644 --- a/app/src/main/res/layout/dialog_read_book_style.xml +++ b/app/src/main/res/layout/dialog_read_book_style.xml @@ -7,12 +7,54 @@ android:background="@color/background" android:padding="10dp"> + + + + + + + + + + + + + app:layout_constraintTop_toBottomOf="@+id/ll_text_size" /> Date: Wed, 28 Aug 2019 12:30:23 +0800 Subject: [PATCH 1071/1997] up --- .../res/layout/dialog_read_book_style.xml | 141 +++++++++++++++++- app/src/main/res/values/strings.xml | 6 +- 2 files changed, 140 insertions(+), 7 deletions(-) diff --git a/app/src/main/res/layout/dialog_read_book_style.xml b/app/src/main/res/layout/dialog_read_book_style.xml index 14569bbe6..b4f2b2c0a 100644 --- a/app/src/main/res/layout/dialog_read_book_style.xml +++ b/app/src/main/res/layout/dialog_read_book_style.xml @@ -7,15 +7,64 @@ android:background="@color/background" android:padding="10dp"> + + + + + + + + + app:layout_constraintTop_toBottomOf="@+id/tv_text_bold"> + + + + + + + + + + + + + + + + + + + + + + + + + app:layout_constraintTop_toBottomOf="@+id/ll_line_size" /> 搜索(共%d个书源) 目录(%d) 加粗 - 字体 + 字体 文字 软件主页 - 边距: + 边距 上边距 下边距 左边距 @@ -433,7 +433,7 @@ 章节: 使用正则表达式 - 缩进 + 缩进 无缩进 一字符缩进 二字符缩进 From b5246cd3a94b6f597ce28989dc8f8b63628e97a7 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 28 Aug 2019 12:40:46 +0800 Subject: [PATCH 1072/1997] up --- .../res/layout/dialog_read_book_style.xml | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/app/src/main/res/layout/dialog_read_book_style.xml b/app/src/main/res/layout/dialog_read_book_style.xml index b4f2b2c0a..948b5cc1f 100644 --- a/app/src/main/res/layout/dialog_read_book_style.xml +++ b/app/src/main/res/layout/dialog_read_book_style.xml @@ -11,7 +11,10 @@ android:id="@+id/tv_text_bold" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:padding="3dp" + android:paddingLeft="6dp" + android:paddingRight="6dp" + android:paddingTop="3dp" + android:paddingBottom="3dp" android:text="@string/text_bold" android:gravity="center" android:textSize="14sp" @@ -23,7 +26,10 @@ android:id="@+id/tv_text_font" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:padding="3dp" + android:paddingLeft="6dp" + android:paddingRight="6dp" + android:paddingTop="3dp" + android:paddingBottom="3dp" android:text="@string/text_font" android:gravity="center" android:textSize="14sp" @@ -35,7 +41,10 @@ android:id="@+id/tv_text_indent" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:padding="3dp" + android:paddingLeft="6dp" + android:paddingRight="6dp" + android:paddingTop="3dp" + android:paddingBottom="3dp" android:text="@string/text_indent" android:gravity="center" android:textSize="14sp" @@ -47,7 +56,10 @@ android:id="@+id/tv_padding" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:padding="3dp" + android:paddingLeft="6dp" + android:paddingRight="6dp" + android:paddingTop="3dp" + android:paddingBottom="3dp" android:text="@string/padding" android:gravity="center" android:textSize="14sp" @@ -67,9 +79,8 @@ app:layout_constraintTop_toBottomOf="@+id/tv_text_bold"> Date: Wed, 28 Aug 2019 14:21:41 +0800 Subject: [PATCH 1073/1997] up --- .../java/io/legado/app/help/ReadBookConfig.kt | 23 ++++++---- .../app/ui/readbook/config/ReadStyleDialog.kt | 42 ++++++++++++++++++- .../res/layout/dialog_read_book_style.xml | 4 +- 3 files changed, 57 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index 7d852791c..3708a7a1e 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -5,6 +5,9 @@ import android.graphics.drawable.ColorDrawable import android.graphics.drawable.Drawable import io.legado.app.App import io.legado.app.utils.* +import kotlinx.coroutines.Dispatchers.IO +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch import java.io.BufferedWriter import java.io.File import java.io.FileWriter @@ -60,16 +63,18 @@ object ReadBookConfig { } fun save() { - val json = GSON.toJson(configList) - val configFile = File(App.INSTANCE.filesDir.absolutePath + File.separator + fileName) - //获取流并存储 - try { - BufferedWriter(FileWriter(configFile)).use { writer -> - writer.write(json) - writer.flush() + GlobalScope.launch(IO) { + val json = GSON.toJson(configList) + val configFile = File(App.INSTANCE.filesDir.absolutePath + File.separator + fileName) + //获取流并存储 + try { + BufferedWriter(FileWriter(configFile)).use { writer -> + writer.write(json) + writer.flush() + } + } catch (e: IOException) { + e.printStackTrace() } - } catch (e: IOException) { - e.printStackTrace() } } diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt index 08603ddf6..a04803537 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt @@ -6,6 +6,7 @@ import android.view.Gravity import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.SeekBar import androidx.core.view.get import androidx.fragment.app.DialogFragment import io.legado.app.R @@ -56,18 +57,57 @@ class ReadStyleDialog : DialogFragment() { } } + override fun onDestroy() { + super.onDestroy() + ReadBookConfig.save() + } + private fun initData() { requireContext().getPrefInt("pageAnim").let { if (it >= 0 && it < rg_page_anim.childCount) { rg_page_anim.check(rg_page_anim[it].id) } } + ReadBookConfig.getConfig().let { + tv_text_bold.isSelected = it.textBold + seek_text_size.progress = it.textSize - 5 + seek_text_letter_spacing.progress = (it.letterSpacing * 10).toInt() + 5 + seek_line_size.progress = it.lineSpacingExtra.toInt() + } setBg() upBg() } - private fun initOnClick() { + private fun initOnClick() = with(ReadBookConfig.getConfig()) { + tv_text_bold.onClick { + textBold = !textBold + tv_text_bold.isSelected = textBold + postEvent(Bus.UP_CONFIG, true) + } + seek_text_size.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { + override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { + textSize = progress + 5 + postEvent(Bus.UP_CONFIG, true) + } + + override fun onStartTrackingTouch(seekBar: SeekBar?) {} + + override fun onStopTrackingTouch(seekBar: SeekBar?) { + + } + + }) + iv_text_size_add.onClick { + textSize++ + if (textSize > 50) textSize = 50 + postEvent(Bus.UP_CONFIG, true) + } + iv_line_size_remove.onClick { + textSize-- + if (textSize < 5) textSize = 5 + postEvent(Bus.UP_CONFIG, true) + } rg_page_anim.onCheckedChange { _, checkedId -> for (i in 0 until rg_page_anim.childCount) { if (checkedId == rg_page_anim[i].id) { diff --git a/app/src/main/res/layout/dialog_read_book_style.xml b/app/src/main/res/layout/dialog_read_book_style.xml index 948b5cc1f..2c84c4adf 100644 --- a/app/src/main/res/layout/dialog_read_book_style.xml +++ b/app/src/main/res/layout/dialog_read_book_style.xml @@ -97,7 +97,7 @@ android:layout_height="25dp" android:layout_gravity="center_vertical" android:layout_weight="4" - android:max="50" /> + android:max="45" /> + android:max="10" /> Date: Wed, 28 Aug 2019 14:32:56 +0800 Subject: [PATCH 1074/1997] up --- .../java/io/legado/app/ui/readbook/ReadBookActivity.kt | 9 ++++++--- .../legado/app/ui/readbook/config/ReadStyleDialog.kt | 10 +++++----- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 7aed7c0ca..989cdad40 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -60,7 +60,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea page_view.callback = this viewModel.callBack = this viewModel.bookData.observe(this, Observer { title_bar.title = it.name }) - viewModel.chapterListFinish.observe(this, Observer { bookLoadFinish() }) + viewModel.chapterListFinish.observe(this, Observer { loadContent() }) viewModel.initData(intent) savedInstanceState?.let { changeSourceDialog = @@ -234,9 +234,9 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } /** - * 书籍加载完成,开始加载章节内容 + * 加载章节内容 */ - private fun bookLoadFinish() { + private fun loadContent() { viewModel.bookData.value?.let { viewModel.loadContent(it, viewModel.durChapterIndex) viewModel.loadContent(it, viewModel.durChapterIndex + 1) @@ -460,6 +460,9 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea page_view.upBg() content_view.upStyle() page_view.upStyle() + if (it) { + loadContent() + } } observeEvent(Bus.TTS_START) { chapterStart -> launch(IO) { diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt index a04803537..ff4e6d116 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt @@ -124,31 +124,31 @@ class ReadStyleDialog : DialogFragment() { ReadBookConfig.styleSelect = 0 ReadBookConfig.upBg() upBg() - postEvent(Bus.UP_CONFIG, true) + postEvent(Bus.UP_CONFIG, false) } tv_bg1.onClick { ReadBookConfig.styleSelect = 1 ReadBookConfig.upBg() upBg() - postEvent(Bus.UP_CONFIG, true) + postEvent(Bus.UP_CONFIG, false) } tv_bg2.onClick { ReadBookConfig.styleSelect = 2 ReadBookConfig.upBg() upBg() - postEvent(Bus.UP_CONFIG, true) + postEvent(Bus.UP_CONFIG, false) } tv_bg3.onClick { ReadBookConfig.styleSelect = 3 ReadBookConfig.upBg() upBg() - postEvent(Bus.UP_CONFIG, true) + postEvent(Bus.UP_CONFIG, false) } tv_bg4.onClick { ReadBookConfig.styleSelect = 4 ReadBookConfig.upBg() upBg() - postEvent(Bus.UP_CONFIG, true) + postEvent(Bus.UP_CONFIG, false) } } From 3df63c6f939a0a3e4ed4e310197b441fcd08763f Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 28 Aug 2019 14:46:14 +0800 Subject: [PATCH 1075/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 2 ++ .../app/ui/readbook/config/ReadStyleDialog.kt | 31 ++++++++++++++----- .../res/layout/dialog_read_book_style.xml | 24 +++++++------- 3 files changed, 38 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 989cdad40..6bd81c895 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -462,6 +462,8 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea page_view.upStyle() if (it) { loadContent() + } else { + page_view.upContent() } } observeEvent(Bus.TTS_START) { chapterStart -> diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt index ff4e6d116..1ac15d2cb 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt @@ -83,29 +83,46 @@ class ReadStyleDialog : DialogFragment() { tv_text_bold.onClick { textBold = !textBold tv_text_bold.isSelected = textBold - postEvent(Bus.UP_CONFIG, true) + postEvent(Bus.UP_CONFIG, false) } seek_text_size.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { textSize = progress + 5 postEvent(Bus.UP_CONFIG, true) } - override fun onStartTrackingTouch(seekBar: SeekBar?) {} - - override fun onStopTrackingTouch(seekBar: SeekBar?) { - - } - + override fun onStopTrackingTouch(seekBar: SeekBar?) {} }) iv_text_size_add.onClick { textSize++ if (textSize > 50) textSize = 50 + seek_text_size.progress = textSize - 5 postEvent(Bus.UP_CONFIG, true) } iv_line_size_remove.onClick { textSize-- if (textSize < 5) textSize = 5 + seek_text_size.progress = textSize - 5 + postEvent(Bus.UP_CONFIG, true) + } + seek_text_letter_spacing.setOnSeekBarChangeListener(object : + SeekBar.OnSeekBarChangeListener { + override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { + letterSpacing = (progress - 5) / 10f + postEvent(Bus.UP_CONFIG, true) + } + + override fun onStartTrackingTouch(seekBar: SeekBar?) {} + override fun onStopTrackingTouch(seekBar: SeekBar?) {} + }) + iv_text_letter_spacing_add.onClick { + letterSpacing += 0.1f + seek_text_letter_spacing.progress = (letterSpacing * 10).toInt() + 5 + postEvent(Bus.UP_CONFIG, true) + } + iv_text_letter_spacing_remove.onClick { + letterSpacing -= 0.1f + seek_text_letter_spacing.progress = (letterSpacing * 10).toInt() + 5 postEvent(Bus.UP_CONFIG, true) } rg_page_anim.onCheckedChange { _, checkedId -> diff --git a/app/src/main/res/layout/dialog_read_book_style.xml b/app/src/main/res/layout/dialog_read_book_style.xml index 2c84c4adf..0bb212cf4 100644 --- a/app/src/main/res/layout/dialog_read_book_style.xml +++ b/app/src/main/res/layout/dialog_read_book_style.xml @@ -84,10 +84,10 @@ android:text="@string/text_size" /> @@ -100,10 +100,10 @@ android:max="45" /> @@ -125,10 +125,10 @@ android:text="@string/text_letter_spacing" /> @@ -141,10 +141,10 @@ android:max="10" /> @@ -166,10 +166,10 @@ android:text="@string/line_size" /> @@ -182,10 +182,10 @@ android:max="50" /> From 7e9b427297a70286610fd895eb55e709f752cade Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 28 Aug 2019 15:07:39 +0800 Subject: [PATCH 1076/1997] up --- .../app/lib/theme/view/ATERadioNoButton.kt | 9 +++++---- .../app/ui/readbook/config/ReadStyleDialog.kt | 18 ++++++++++++++++++ .../main/res/layout/dialog_read_book_style.xml | 2 +- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATERadioNoButton.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATERadioNoButton.kt index 138f05992..2e7763741 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATERadioNoButton.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATERadioNoButton.kt @@ -1,12 +1,13 @@ package io.legado.app.lib.theme.view import android.content.Context -import android.graphics.Color import android.util.AttributeSet import androidx.appcompat.widget.AppCompatRadioButton +import io.legado.app.R import io.legado.app.lib.theme.Selector import io.legado.app.lib.theme.ThemeStore import io.legado.app.utils.dp +import io.legado.app.utils.getCompatColor /** * @author Aidan Follestad (afollestad) @@ -27,11 +28,11 @@ class ATERadioNoButton : AppCompatRadioButton { private fun init(context: Context, attrs: AttributeSet?) { background = Selector.shapeBuild() - .setCornerRadius(3.dp) - .setStrokeWidth(3.dp) + .setCornerRadius(2.dp) + .setStrokeWidth(2.dp) .setCheckedBgColor(ThemeStore.accentColor(context)) .setCheckedStrokeColor(ThemeStore.accentColor(context)) - .setDefaultStrokeColor(Color.WHITE) + .setDefaultStrokeColor(context.getCompatColor(R.color.tv_text_default)) .create() } } diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt index 1ac15d2cb..e5900e141 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt @@ -125,6 +125,24 @@ class ReadStyleDialog : DialogFragment() { seek_text_letter_spacing.progress = (letterSpacing * 10).toInt() + 5 postEvent(Bus.UP_CONFIG, true) } + seek_line_size.setOnSeekBarChangeListener(object : + SeekBar.OnSeekBarChangeListener { + override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { + lineSpacingExtra = progress.toFloat() + postEvent(Bus.UP_CONFIG, true) + } + + override fun onStartTrackingTouch(seekBar: SeekBar?) {} + override fun onStopTrackingTouch(seekBar: SeekBar?) {} + }) + iv_line_size_add.onClick { + lineSpacingExtra++ + postEvent(Bus.UP_CONFIG, true) + } + iv_line_size_remove.onClick { + lineSpacingExtra-- + postEvent(Bus.UP_CONFIG, true) + } rg_page_anim.onCheckedChange { _, checkedId -> for (i in 0 until rg_page_anim.childCount) { if (checkedId == rg_page_anim[i].id) { diff --git a/app/src/main/res/layout/dialog_read_book_style.xml b/app/src/main/res/layout/dialog_read_book_style.xml index 0bb212cf4..362a1f6ae 100644 --- a/app/src/main/res/layout/dialog_read_book_style.xml +++ b/app/src/main/res/layout/dialog_read_book_style.xml @@ -182,7 +182,7 @@ android:max="50" /> Date: Wed, 28 Aug 2019 15:12:41 +0800 Subject: [PATCH 1077/1997] up --- .../legado/app/ui/readbook/config/ReadStyleDialog.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt index e5900e141..638e6c3fe 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt @@ -159,31 +159,31 @@ class ReadStyleDialog : DialogFragment() { ReadBookConfig.styleSelect = 0 ReadBookConfig.upBg() upBg() - postEvent(Bus.UP_CONFIG, false) + postEvent(Bus.UP_CONFIG, true) } tv_bg1.onClick { ReadBookConfig.styleSelect = 1 ReadBookConfig.upBg() upBg() - postEvent(Bus.UP_CONFIG, false) + postEvent(Bus.UP_CONFIG, true) } tv_bg2.onClick { ReadBookConfig.styleSelect = 2 ReadBookConfig.upBg() upBg() - postEvent(Bus.UP_CONFIG, false) + postEvent(Bus.UP_CONFIG, true) } tv_bg3.onClick { ReadBookConfig.styleSelect = 3 ReadBookConfig.upBg() upBg() - postEvent(Bus.UP_CONFIG, false) + postEvent(Bus.UP_CONFIG, true) } tv_bg4.onClick { ReadBookConfig.styleSelect = 4 ReadBookConfig.upBg() upBg() - postEvent(Bus.UP_CONFIG, false) + postEvent(Bus.UP_CONFIG, true) } } From 3bb31c83348e9737c50ffbca1b52f64c182bb668 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 28 Aug 2019 15:17:22 +0800 Subject: [PATCH 1078/1997] up --- .../legado/app/ui/chapterlist/ChapterListAdapter.kt | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListAdapter.kt b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListAdapter.kt index aff557711..aa975798a 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListAdapter.kt @@ -44,14 +44,12 @@ class ChapterListAdapter(val callback: Callback) : class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { fun bind(bookChapter: BookChapter, callback: Callback) = with(itemView) { - tv_chapter_name.text = bookChapter.title - callback.let { - if (it.durChapterIndex() == bookChapter.index) { - tv_chapter_name.setTextColor(context.accentColor) - } else { - tv_chapter_name.setTextColor(context.getCompatColor(R.color.tv_text_default)) - } + if (callback.durChapterIndex() == bookChapter.index) { + tv_chapter_name.setTextColor(context.accentColor) + } else { + tv_chapter_name.setTextColor(context.getCompatColor(R.color.tv_text_default)) } + tv_chapter_name.text = bookChapter.title itemView.onClick { callback.openChapter(bookChapter) } From a317b53ca8866603371d173de350e26f0786e978 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 28 Aug 2019 15:21:45 +0800 Subject: [PATCH 1079/1997] up --- .../io/legado/app/ui/chapterlist/ChapterListFragment.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt index dacc8a851..d237ea2dd 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt +++ b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt @@ -52,14 +52,14 @@ class ChapterListFragment : VMBaseFragment(R.layout.fragme liveData?.removeObservers(viewLifecycleOwner) liveData = LivePagedListBuilder(App.db.bookChapterDao().observeByBook(viewModel.bookUrl ?: ""), 30).build() liveData?.observe(viewLifecycleOwner, Observer { adapter.submitList(it) }) - } - - private fun initView() { viewModel.bookDate.value?.let { loadBookFinish(it) } ?: viewModel.bookDate.observe(viewLifecycleOwner, Observer { loadBookFinish(it) }) + } + + private fun initView() { iv_chapter_top.onClick { recycler_view.scrollToPosition(0) } iv_chapter_bottom.onClick { if (adapter.itemCount > 0) { From a8cfc17caabc7ae28b68e246e9131ad3cd6c7311 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 28 Aug 2019 15:34:52 +0800 Subject: [PATCH 1080/1997] up --- .../app/ui/readbook/config/ReadStyleDialog.kt | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt index 638e6c3fe..1841b6df1 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt @@ -87,11 +87,13 @@ class ReadStyleDialog : DialogFragment() { } seek_text_size.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { - textSize = progress + 5 - postEvent(Bus.UP_CONFIG, true) + } override fun onStartTrackingTouch(seekBar: SeekBar?) {} - override fun onStopTrackingTouch(seekBar: SeekBar?) {} + override fun onStopTrackingTouch(seekBar: SeekBar?) { + textSize = seek_text_size.progress + 5 + postEvent(Bus.UP_CONFIG, true) + } }) iv_text_size_add.onClick { textSize++ @@ -108,12 +110,14 @@ class ReadStyleDialog : DialogFragment() { seek_text_letter_spacing.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { - letterSpacing = (progress - 5) / 10f - postEvent(Bus.UP_CONFIG, true) + } override fun onStartTrackingTouch(seekBar: SeekBar?) {} - override fun onStopTrackingTouch(seekBar: SeekBar?) {} + override fun onStopTrackingTouch(seekBar: SeekBar?) { + letterSpacing = (seek_text_letter_spacing.progress - 5) / 10f + postEvent(Bus.UP_CONFIG, true) + } }) iv_text_letter_spacing_add.onClick { letterSpacing += 0.1f @@ -128,12 +132,14 @@ class ReadStyleDialog : DialogFragment() { seek_line_size.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { - lineSpacingExtra = progress.toFloat() - postEvent(Bus.UP_CONFIG, true) + } override fun onStartTrackingTouch(seekBar: SeekBar?) {} - override fun onStopTrackingTouch(seekBar: SeekBar?) {} + override fun onStopTrackingTouch(seekBar: SeekBar?) { + lineSpacingExtra = seek_line_size.progress.toFloat() + postEvent(Bus.UP_CONFIG, true) + } }) iv_line_size_add.onClick { lineSpacingExtra++ From b9b52ae32b16f38a9e27b732b7aa167b993eb43b Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 28 Aug 2019 15:44:57 +0800 Subject: [PATCH 1081/1997] up --- .../app/ui/readbook/config/ReadStyleDialog.kt | 22 +++++++++++++------ .../res/layout/dialog_read_book_style.xml | 13 +++++++++++ 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt index 1841b6df1..660132f04 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt @@ -71,14 +71,16 @@ class ReadStyleDialog : DialogFragment() { ReadBookConfig.getConfig().let { tv_text_bold.isSelected = it.textBold seek_text_size.progress = it.textSize - 5 + tv_text_size.text = it.textSize.toString() seek_text_letter_spacing.progress = (it.letterSpacing * 10).toInt() + 5 + tv_text_letter_spacing.text = it.letterSpacing.toString() seek_line_size.progress = it.lineSpacingExtra.toInt() + tv_line_size.text = it.lineSpacingExtra.toString() } setBg() upBg() } - private fun initOnClick() = with(ReadBookConfig.getConfig()) { tv_text_bold.onClick { textBold = !textBold @@ -87,11 +89,11 @@ class ReadStyleDialog : DialogFragment() { } seek_text_size.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { - + textSize = progress + 5 + tv_text_size.text = textSize.toString() } override fun onStartTrackingTouch(seekBar: SeekBar?) {} override fun onStopTrackingTouch(seekBar: SeekBar?) { - textSize = seek_text_size.progress + 5 postEvent(Bus.UP_CONFIG, true) } }) @@ -99,54 +101,60 @@ class ReadStyleDialog : DialogFragment() { textSize++ if (textSize > 50) textSize = 50 seek_text_size.progress = textSize - 5 + tv_text_size.text = textSize.toString() postEvent(Bus.UP_CONFIG, true) } iv_line_size_remove.onClick { textSize-- if (textSize < 5) textSize = 5 seek_text_size.progress = textSize - 5 + tv_text_size.text = textSize.toString() postEvent(Bus.UP_CONFIG, true) } seek_text_letter_spacing.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { - + letterSpacing = (seek_text_letter_spacing.progress - 5) / 10f + tv_text_letter_spacing.text = letterSpacing.toString() } override fun onStartTrackingTouch(seekBar: SeekBar?) {} override fun onStopTrackingTouch(seekBar: SeekBar?) { - letterSpacing = (seek_text_letter_spacing.progress - 5) / 10f postEvent(Bus.UP_CONFIG, true) } }) iv_text_letter_spacing_add.onClick { letterSpacing += 0.1f seek_text_letter_spacing.progress = (letterSpacing * 10).toInt() + 5 + tv_text_letter_spacing.text = letterSpacing.toString() postEvent(Bus.UP_CONFIG, true) } iv_text_letter_spacing_remove.onClick { letterSpacing -= 0.1f seek_text_letter_spacing.progress = (letterSpacing * 10).toInt() + 5 + tv_text_letter_spacing.text = letterSpacing.toString() postEvent(Bus.UP_CONFIG, true) } seek_line_size.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { - + lineSpacingExtra = seek_line_size.progress.toFloat() + tv_line_size.text = lineSpacingExtra.toString() } override fun onStartTrackingTouch(seekBar: SeekBar?) {} override fun onStopTrackingTouch(seekBar: SeekBar?) { - lineSpacingExtra = seek_line_size.progress.toFloat() postEvent(Bus.UP_CONFIG, true) } }) iv_line_size_add.onClick { lineSpacingExtra++ + tv_line_size.text = lineSpacingExtra.toString() postEvent(Bus.UP_CONFIG, true) } iv_line_size_remove.onClick { lineSpacingExtra-- + tv_line_size.text = lineSpacingExtra.toString() postEvent(Bus.UP_CONFIG, true) } rg_page_anim.onCheckedChange { _, checkedId -> diff --git a/app/src/main/res/layout/dialog_read_book_style.xml b/app/src/main/res/layout/dialog_read_book_style.xml index 362a1f6ae..a5b11670c 100644 --- a/app/src/main/res/layout/dialog_read_book_style.xml +++ b/app/src/main/res/layout/dialog_read_book_style.xml @@ -107,6 +107,10 @@ android:background="?android:attr/selectableItemBackgroundBorderless" android:tint="@color/tv_text_default" /> + + + + Date: Wed, 28 Aug 2019 15:53:06 +0800 Subject: [PATCH 1082/1997] up --- .../main/java/io/legado/app/help/ReadBookConfig.kt | 2 +- .../app/ui/readbook/config/ReadStyleDialog.kt | 4 ++-- .../io/legado/app/ui/widget/page/ContentView.kt | 2 +- app/src/main/res/layout/dialog_read_book_style.xml | 13 ++++++++++--- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index 3708a7a1e..f7c9fb905 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -106,7 +106,7 @@ object ReadBookConfig { var bgType: Int = 0, var darkStatusIcon: Boolean = true, var letterSpacing: Float = 1f, - var lineSpacingExtra: Float = 15f, + var lineSpacingExtra: Int = 12, var lineSpacingMultiplier: Float = 1.2f, var paddingBottom: Int = 0, var paddingLeft: Int = 16, diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt index 660132f04..ea2d59215 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt @@ -74,7 +74,7 @@ class ReadStyleDialog : DialogFragment() { tv_text_size.text = it.textSize.toString() seek_text_letter_spacing.progress = (it.letterSpacing * 10).toInt() + 5 tv_text_letter_spacing.text = it.letterSpacing.toString() - seek_line_size.progress = it.lineSpacingExtra.toInt() + seek_line_size.progress = it.lineSpacingExtra tv_line_size.text = it.lineSpacingExtra.toString() } setBg() @@ -138,7 +138,7 @@ class ReadStyleDialog : DialogFragment() { seek_line_size.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { - lineSpacingExtra = seek_line_size.progress.toFloat() + lineSpacingExtra = seek_line_size.progress tv_line_size.text = lineSpacingExtra.toString() } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index 3201328f7..f104bcde0 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -52,7 +52,7 @@ class ContentView : FrameLayout { } page_panel.setPadding(paddingLeft.dp, pt, paddingRight.dp, paddingBottom.dp) content_text_view.textSize = textSize.toFloat() - content_text_view.setLineSpacing(lineSpacingExtra, lineSpacingMultiplier) + content_text_view.setLineSpacing(lineSpacingExtra.toFloat(), lineSpacingMultiplier) content_text_view.letterSpacing = letterSpacing content_text_view.paint.isFakeBoldText = textBold textColor().let { diff --git a/app/src/main/res/layout/dialog_read_book_style.xml b/app/src/main/res/layout/dialog_read_book_style.xml index a5b11670c..599fe7832 100644 --- a/app/src/main/res/layout/dialog_read_book_style.xml +++ b/app/src/main/res/layout/dialog_read_book_style.xml @@ -1,6 +1,7 @@ + android:layout_height="wrap_content" + android:gravity="right" + tools:ignore="RtlHardcoded" /> + android:layout_height="wrap_content" + android:gravity="right" + tools:ignore="RtlHardcoded" /> @@ -201,7 +206,9 @@ + android:layout_height="wrap_content" + android:gravity="right" + tools:ignore="RtlHardcoded" /> Date: Wed, 28 Aug 2019 16:04:50 +0800 Subject: [PATCH 1083/1997] up --- .../main/java/io/legado/app/model/webbook/BookChapterList.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt b/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt index ec6fa6fb5..63be14066 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt @@ -118,8 +118,8 @@ object BookChapterList { book.latestChapterTitle = chapterList.last().title if (book.totalChapterNum < chapterList.size) { book.lastCheckCount = chapterList.size - book.totalChapterNum - book.totalChapterNum = chapterList.size } + book.totalChapterNum = chapterList.size return chapterList } From b736fd7ded5af4c65cd488ed60531372e4b250e3 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 28 Aug 2019 16:20:10 +0800 Subject: [PATCH 1084/1997] up --- .../app/ui/bookinfo/BookInfoActivity.kt | 8 ++++--- .../app/ui/changesource/ChangeSourceDialog.kt | 21 ++++++++++--------- .../ui/changesource/ChangeSourceViewModel.kt | 1 - .../app/ui/readbook/ReadBookActivity.kt | 8 ++++--- 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index ce7ba7b11..31af4fda5 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -50,7 +50,6 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo initOnClick() savedInstanceState?.let { changeSourceDialog = supportFragmentManager.findFragmentByTag(ChangeSourceDialog.tag) as? ChangeSourceDialog - changeSourceDialog?.callBack = this } } @@ -178,8 +177,7 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo if (changeSourceDialog == null) { viewModel.bookData.value?.let { changeSourceDialog = ChangeSourceDialog - .newInstance(it.name, it.author, it.origin) - changeSourceDialog?.callBack = this + .newInstance(it.name, it.author) } } changeSourceDialog?.show(supportFragmentManager, ChangeSourceDialog.tag) @@ -216,6 +214,10 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo } } + override fun curOrigin(): String? { + return viewModel.bookData.value?.origin + } + override fun oldBook(): Book? { return viewModel.bookData.value } diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt index 0509ba52e..15e830033 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt @@ -24,12 +24,11 @@ class ChangeSourceDialog : DialogFragment(), companion object { const val tag = "changeSourceDialog" - fun newInstance(name: String, author: String, origin: String): ChangeSourceDialog { + fun newInstance(name: String, author: String): ChangeSourceDialog { val changeSourceDialog = ChangeSourceDialog() val bundle = Bundle() bundle.putString("name", name) bundle.putString("author", author) - bundle.putString("origin", origin) changeSourceDialog.arguments = bundle return changeSourceDialog } @@ -37,7 +36,6 @@ class ChangeSourceDialog : DialogFragment(), private lateinit var viewModel: ChangeSourceViewModel private lateinit var changeSourceAdapter: ChangeSourceAdapter - var callBack: CallBack? = null override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { viewModel = getViewModel(ChangeSourceViewModel::class.java) @@ -53,9 +51,6 @@ class ChangeSourceDialog : DialogFragment(), bundle.getString("author")?.let { viewModel.author = it } - bundle.getString("origin")?.let { - viewModel.curOrigin = it - } } tool_bar.inflateMenu(R.menu.search_view) showTitle() @@ -109,9 +104,10 @@ class ChangeSourceDialog : DialogFragment(), } override fun changeTo(searchBook: SearchBook) { - callBack?.let { + val activity = activity + if (activity is CallBack) { val book = searchBook.toBook() - it.oldBook()?.let { oldBook -> + activity.oldBook()?.let { oldBook -> book.durChapterIndex = oldBook.durChapterIndex book.durChapterPos = oldBook.durChapterPos book.durChapterTitle = oldBook.durChapterTitle @@ -122,13 +118,17 @@ class ChangeSourceDialog : DialogFragment(), book.coverUrl = oldBook.getDisplayCover() } } - it.changeTo(book) + activity.changeTo(book) } dismiss() } override fun curOrigin(): String { - return viewModel.curOrigin + val activity = activity + if (activity is CallBack) { + return activity.curOrigin() ?: "" + } + return "" } override fun adapter(): ChangeSourceAdapter { @@ -136,6 +136,7 @@ class ChangeSourceDialog : DialogFragment(), } interface CallBack { + fun curOrigin(): String? fun oldBook(): Book? fun changeTo(book: Book) } diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt index acfba1ce3..fc096de5f 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt @@ -16,7 +16,6 @@ import org.jetbrains.anko.debug class ChangeSourceViewModel(application: Application) : BaseViewModel(application) { var callBack: CallBack? = null - var curOrigin = "" var name: String = "" var author: String = "" var screenKey: String = "" diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 6bd81c895..d7507a57c 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -65,7 +65,6 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea savedInstanceState?.let { changeSourceDialog = supportFragmentManager.findFragmentByTag(ChangeSourceDialog.tag) as? ChangeSourceDialog - changeSourceDialog?.callBack = this } setScreenBrightness(getPrefInt("brightness", 100)) } @@ -182,8 +181,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea if (changeSourceDialog == null) { viewModel.bookData.value?.let { changeSourceDialog = ChangeSourceDialog - .newInstance(it.name, it.author, it.origin) - changeSourceDialog?.callBack = this + .newInstance(it.name, it.author) } } changeSourceDialog?.show(supportFragmentManager, ChangeSourceDialog.tag) @@ -305,6 +303,10 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea return viewModel.chapterSize } + override fun curOrigin(): String? { + return viewModel.bookData.value?.origin + } + override fun oldBook(): Book? { return viewModel.bookData.value } From 70f1082bba185b7e86220c1d332a4a8fdf173ca3 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 28 Aug 2019 17:03:10 +0800 Subject: [PATCH 1085/1997] up --- .../app/ui/readbook/config/PaddingConfigDialog.java | 4 ++++ .../java/io/legado/app/ui/widget/page/ContentTextView.kt | 8 ++++---- 2 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.java diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.java b/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.java new file mode 100644 index 000000000..dfbfbb641 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.java @@ -0,0 +1,4 @@ +package io.legado.app.ui.readbook.config; + +public class PaddingConfigDialog { +} diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt index 680627567..0e7a7bea8 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt @@ -10,21 +10,21 @@ class ContentTextView : AppCompatTextView { constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) - constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) + : super(context, attrs, defStyleAttr) /** * 获取当前页总字数 */ fun getCharNum(): Int { - return layout.getLineEnd(getLineNum()) + return layout?.getLineEnd(getLineNum()) ?: 0 } /** * 获取当前页总行数 */ fun getLineNum(): Int { - val layout = layout val topOfLastLine = height - paddingTop - paddingBottom - lineHeight - return layout.getLineForVertical(topOfLastLine) + return layout?.getLineForVertical(topOfLastLine) ?: 0 } } From fae1bb05f5b4033800d68903cb9ac20747e04d3c Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 28 Aug 2019 17:07:42 +0800 Subject: [PATCH 1086/1997] up --- .../app/ui/widget/page/ChapterProvider.kt | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt index 502630b72..889952188 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt @@ -35,22 +35,26 @@ object ChapterProvider { } } textView.text = spannableStringBuilder - pageLengths.add(textView.getCharNum()) - textPages.add( - TextPage( - index = pageIndex, - text = spannableStringBuilder.delete( - pageLengths[pageIndex], - spannableStringBuilder.length - ), - title = bookChapter.title, - chapterSize = chapterSize, - chapterIndex = bookChapter.index + val lastCharNum = textView.getCharNum() + if (lastCharNum == 0) { + break + } else { + pageLengths.add(lastCharNum) + textPages.add( + TextPage( + index = pageIndex, + text = spannableStringBuilder.delete( + lastCharNum, + spannableStringBuilder.length + ), + title = bookChapter.title, + chapterSize = chapterSize, + chapterIndex = bookChapter.index + ) ) - ) - surplusText = surplusText.substring(pageLengths[pageIndex]) - - pageIndex++ + surplusText = surplusText.substring(lastCharNum) + pageIndex++ + } } for (item in textPages) { item.pageSize = textPages.size From 19782da9779ce7f23093d34d36e776406aeb1554 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 28 Aug 2019 17:26:32 +0800 Subject: [PATCH 1087/1997] up --- app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index f104bcde0..fcf4de01e 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -35,6 +35,7 @@ class ContentView : FrameLayout { ) init { + setBackgroundColor(context.getCompatColor(R.color.background)) addView(bgImage, LayoutParams(matchParent, matchParent)) inflate(context, R.layout.view_book_page, this) upStyle() From b1952be9e6186ec210a7155166224890b304f26e Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 28 Aug 2019 17:45:49 +0800 Subject: [PATCH 1088/1997] up --- app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index fcf4de01e..4202549e1 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -35,6 +35,7 @@ class ContentView : FrameLayout { ) init { + //设置背景防止切换背景时文字重叠 setBackgroundColor(context.getCompatColor(R.color.background)) addView(bgImage, LayoutParams(matchParent, matchParent)) inflate(context, R.layout.view_book_page, this) From af887cb0830030b9dd6127c79d6c7d03f77e9db6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 28 Aug 2019 17:51:21 +0800 Subject: [PATCH 1089/1997] up --- .../readbook/config/PaddingConfigDialog.java | 4 -- .../ui/readbook/config/PaddingConfigDialog.kt | 41 +++++++++++++++++++ 2 files changed, 41 insertions(+), 4 deletions(-) delete mode 100644 app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.java create mode 100644 app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.kt diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.java b/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.java deleted file mode 100644 index dfbfbb641..000000000 --- a/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.java +++ /dev/null @@ -1,4 +0,0 @@ -package io.legado.app.ui.readbook.config; - -public class PaddingConfigDialog { -} diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.kt new file mode 100644 index 000000000..f8405012e --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.kt @@ -0,0 +1,41 @@ +package io.legado.app.ui.readbook.config + +import android.os.Bundle +import android.util.DisplayMetrics +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.DialogFragment +import io.legado.app.R +import io.legado.app.ui.readbook.Help + +class PaddingConfigDialog : DialogFragment() { + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + return super.onCreateView(inflater, container, savedInstanceState) + } + + override fun onStart() { + super.onStart() + val dm = DisplayMetrics() + activity?.windowManager?.defaultDisplay?.getMetrics(dm) + dialog?.window?.let { + it.setBackgroundDrawableResource(R.color.transparent) + it.decorView.setPadding(0, 0, 0, 0) + val attr = it.attributes + attr.dimAmount = 0.0f + it.attributes = attr + it.setLayout((dm.widthPixels * 0.9).toInt(), ViewGroup.LayoutParams.WRAP_CONTENT) + Help.upSystemUiVisibility(it) + } + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + } + +} From 8e626e68ff78a43929a13ce7b292cd0816430876 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 28 Aug 2019 19:52:23 +0800 Subject: [PATCH 1090/1997] up --- .../java/io/legado/app/help/ReadBookConfig.kt | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index f7c9fb905..46a41c664 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -24,16 +24,8 @@ object ReadBookConfig { } var styleSelect - get() = if (App.INSTANCE.isNightTheme) { - App.INSTANCE.getPrefInt("readStyleSelectNight", 4) - } else { - App.INSTANCE.getPrefInt("readStyleSelect") - } - set(value) = if (App.INSTANCE.isNightTheme) { - App.INSTANCE.putPrefInt("readStyleSelectNight", value) - } else { - App.INSTANCE.putPrefInt("readStyleSelect", value) - } + get() = App.INSTANCE.getPrefInt("readStyleSelect") + set(value) = App.INSTANCE.putPrefInt("readStyleSelect", value) var bg: Drawable? = null fun getConfig(index: Int = styleSelect): Config { @@ -103,7 +95,9 @@ object ReadBookConfig { data class Config( var bgStr: String = "#015A86", + var bgStrNight: String = "#000000", var bgType: Int = 0, + var bgTypeNight: Int = 0, var darkStatusIcon: Boolean = true, var letterSpacing: Float = 1f, var lineSpacingExtra: Int = 12, @@ -114,16 +108,28 @@ object ReadBookConfig { var paddingTop: Int = 0, var textBold: Boolean = false, var textColor: String = "#3E3D3B", + var textColorNight: String = "#adadad", var textSize: Int = 15 ) { fun textColor(): Int { - return Color.parseColor(textColor) + return if (App.INSTANCE.isNightTheme) Color.parseColor(textColorNight) + else Color.parseColor(textColor) + } + + private fun bgStr(): String { + return if (App.INSTANCE.isNightTheme) bgStrNight + else bgStr + } + + private fun bgType(): Int { + return if (App.INSTANCE.isNightTheme) bgTypeNight + else bgType } fun bgDrawable(): Drawable { var bgDrawable: Drawable? = null - when (bgType) { - 0 -> bgDrawable = ColorDrawable(Color.parseColor(bgStr)) + when (bgType()) { + 0 -> bgDrawable = ColorDrawable(Color.parseColor(bgStr())) 1 -> bgDrawable = Drawable.createFromStream( App.INSTANCE.assets.open("bg" + File.separator + bgStr), From 3f1399b48a17c3762bfb390338d85ac55024d842 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 28 Aug 2019 19:54:09 +0800 Subject: [PATCH 1091/1997] up --- app/src/main/java/io/legado/app/help/ReadBookConfig.kt | 4 ++-- .../java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index 46a41c664..d2a9565ed 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -116,12 +116,12 @@ object ReadBookConfig { else Color.parseColor(textColor) } - private fun bgStr(): String { + fun bgStr(): String { return if (App.INSTANCE.isNightTheme) bgStrNight else bgStr } - private fun bgType(): Int { + fun bgType(): Int { return if (App.INSTANCE.isNightTheme) bgTypeNight else bgType } diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt index ea2d59215..08e730014 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt @@ -216,9 +216,9 @@ class ReadStyleDialog : DialogFragment() { else -> bg0 } ReadBookConfig.getConfig(i).apply { - when (bgType) { + when (bgType()) { 2 -> { - ImageLoader.load(requireContext(), bgStr) + ImageLoader.load(requireContext(), bgStr()) .centerCrop() .setAsFile(iv) } From 7b3e4786abe4d52d854a7dd4e15014283e0d2479 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 28 Aug 2019 20:06:47 +0800 Subject: [PATCH 1092/1997] up --- .../java/io/legado/app/model/analyzeRule/AnalyzeByJSoup.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSoup.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSoup.kt index 32e7d2a16..b937abcb6 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSoup.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSoup.kt @@ -382,7 +382,8 @@ class AnalyzeByJSoup { } } } - } catch (ignore: Exception) { + } catch (e: Exception) { + e.printStackTrace() } return textS From f5ad6aba7ff09438d1b4ccd6e9a8c89ba8e84d83 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 28 Aug 2019 20:17:11 +0800 Subject: [PATCH 1093/1997] up --- .../main/java/io/legado/app/service/ReadAloudService.kt | 8 ++------ .../java/io/legado/app/ui/readbook/ReadBookActivity.kt | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index 88930eb03..4c50925b8 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -327,18 +327,14 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage when (focusChange) { AudioManager.AUDIOFOCUS_GAIN -> { // 重新获得焦点, 可做恢复播放,恢复后台音量的操作 - if (!pause) { - resumeReadAloud() - } + if (!pause) resumeReadAloud() } AudioManager.AUDIOFOCUS_LOSS -> { // 永久丢失焦点除非重新主动获取,这种情况是被其他播放器抢去了焦点, 为避免与其他播放器混音,可将音乐暂停 } AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> { // 暂时丢失焦点,这种情况是被其他应用申请了短暂的焦点,可压低后台音量 - if (!pause) { - pauseReadAloud(false) - } + if (!pause) pauseReadAloud(false) } AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> { // 短暂丢失焦点,这种情况是被其他应用申请了短暂的焦点希望其他声音能压低音量(或者关闭声音)凸显这个声音(比如短信提示音), diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index d7507a57c..7151fbe13 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -440,7 +440,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea super.observeLiveBus() observeEvent(Bus.ALOUD_STATE) { readAloudStatus = it - if (it == Status.STOP) { + if (it == Status.STOP || it == Status.PAUSE) { viewModel.curTextChapter?.let { textChapter -> val page = textChapter.page(viewModel.durPageIndex) if (page != null && page.text is SpannableStringBuilder) { From 9584a97e8dbc849c5ef9e7af93c92834ebdad316 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 28 Aug 2019 20:29:14 +0800 Subject: [PATCH 1094/1997] up --- .../java/io/legado/app/constant/Action.kt | 13 +++++++++ .../java/io/legado/app/constant/Status.kt | 1 - .../io/legado/app/service/ReadAloudService.kt | 27 ++++++++++--------- .../notification/ReadAloudNotification.kt | 9 ++++--- 4 files changed, 32 insertions(+), 18 deletions(-) create mode 100644 app/src/main/java/io/legado/app/constant/Action.kt diff --git a/app/src/main/java/io/legado/app/constant/Action.kt b/app/src/main/java/io/legado/app/constant/Action.kt new file mode 100644 index 000000000..321eb39a6 --- /dev/null +++ b/app/src/main/java/io/legado/app/constant/Action.kt @@ -0,0 +1,13 @@ +package io.legado.app.constant + +object Action { + + const val play = "play" + const val stop = "stop" + const val resume = "resume" + const val pause = "pause" + const val setTimer = "setTimer" + const val prevParagraph = "prevParagraph" + const val nextParagraph = "nextParagraph" + const val upTtsSpeechRate = "upTtsSpeechRate" +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/constant/Status.kt b/app/src/main/java/io/legado/app/constant/Status.kt index a20ee0e34..678c62221 100644 --- a/app/src/main/java/io/legado/app/constant/Status.kt +++ b/app/src/main/java/io/legado/app/constant/Status.kt @@ -3,6 +3,5 @@ package io.legado.app.constant object Status { const val STOP = 0 const val PLAY = 1 - const val NEXT = 2 const val PAUSE = 3 } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index 4c50925b8..4b256ac93 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -11,6 +11,7 @@ import android.support.v4.media.session.MediaSessionCompat import android.support.v4.media.session.PlaybackStateCompat import io.legado.app.R import io.legado.app.base.BaseService +import io.legado.app.constant.Action import io.legado.app.constant.Bus import io.legado.app.constant.Status import io.legado.app.help.IntentDataHelp @@ -42,7 +43,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage play: Boolean = true ) { val readAloudIntent = Intent(context, ReadAloudService::class.java) - readAloudIntent.action = "play" + readAloudIntent.action = Action.play readAloudIntent.putExtra("title", title) readAloudIntent.putExtra("subtitle", subtitle) readAloudIntent.putExtra("pageIndex", pageIndex) @@ -54,7 +55,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage fun pause(context: Context) { if (isRun) { val intent = Intent(context, ReadAloudService::class.java) - intent.action = "pause" + intent.action = Action.pause context.startService(intent) } } @@ -62,7 +63,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage fun resume(context: Context) { if (isRun) { val intent = Intent(context, ReadAloudService::class.java) - intent.action = "resume" + intent.action = Action.resume context.startService(intent) } } @@ -70,7 +71,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage fun stop(context: Context) { if (isRun) { val intent = Intent(context, ReadAloudService::class.java) - intent.action = "stop" + intent.action = Action.stop context.startService(intent) } } @@ -78,7 +79,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage fun prevParagraph(context: Context) { if (isRun) { val intent = Intent(context, ReadAloudService::class.java) - intent.action = "prevParagraph" + intent.action = Action.prevParagraph context.startService(intent) } } @@ -86,7 +87,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage fun nextParagraph(context: Context) { if (isRun) { val intent = Intent(context, ReadAloudService::class.java) - intent.action = "nextParagraph" + intent.action = Action.nextParagraph context.startService(intent) } } @@ -94,7 +95,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage fun upTtsSpeechRate(context: Context) { if (isRun) { val intent = Intent(context, ReadAloudService::class.java) - intent.action = "upTtsSpeechRate" + intent.action = Action.upTtsSpeechRate context.startService(intent) } } @@ -148,7 +149,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { intent?.action?.let { action -> when (action) { - "play" -> { + Action.play -> { title = intent.getStringExtra("title") ?: "" subtitle = intent.getStringExtra("subtitle") ?: "" pageIndex = intent.getIntExtra("pageIndex", 0) @@ -157,11 +158,11 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage intent.getBooleanExtra("play", true) ) } - "pause" -> pauseReadAloud(true) - "resume" -> resumeReadAloud() - "upTtsSpeechRate" -> upSpeechRate(true) - "prevParagraph" -> prevP() - "nextParagraph" -> nextP() + Action.pause -> pauseReadAloud(true) + Action.resume -> resumeReadAloud() + Action.upTtsSpeechRate -> upSpeechRate(true) + Action.prevParagraph -> prevP() + Action.nextParagraph -> nextP() else -> stopSelf() } } diff --git a/app/src/main/java/io/legado/app/service/notification/ReadAloudNotification.kt b/app/src/main/java/io/legado/app/service/notification/ReadAloudNotification.kt index 5d980ad4f..57c8cfa2a 100644 --- a/app/src/main/java/io/legado/app/service/notification/ReadAloudNotification.kt +++ b/app/src/main/java/io/legado/app/service/notification/ReadAloudNotification.kt @@ -3,6 +3,7 @@ package io.legado.app.service.notification import android.graphics.BitmapFactory import androidx.core.app.NotificationCompat import io.legado.app.R +import io.legado.app.constant.Action import io.legado.app.constant.AppConst import io.legado.app.help.PendingIntentHelp import io.legado.app.service.ReadAloudService @@ -33,24 +34,24 @@ object ReadAloudNotification { builder.addAction( R.drawable.ic_play_24dp, service.getString(R.string.resume), - PendingIntentHelp.aloudServicePendingIntent(service, "resume") + PendingIntentHelp.aloudServicePendingIntent(service, Action.resume) ) } else { builder.addAction( R.drawable.ic_pause_24dp, service.getString(R.string.pause), - PendingIntentHelp.aloudServicePendingIntent(service, "pause") + PendingIntentHelp.aloudServicePendingIntent(service, Action.pause) ) } builder.addAction( R.drawable.ic_stop_black_24dp, service.getString(R.string.stop), - PendingIntentHelp.aloudServicePendingIntent(service, "stop") + PendingIntentHelp.aloudServicePendingIntent(service, Action.stop) ) builder.addAction( R.drawable.ic_time_add_24dp, service.getString(R.string.set_timer), - PendingIntentHelp.aloudServicePendingIntent(service, "setTimer") + PendingIntentHelp.aloudServicePendingIntent(service, Action.setTimer) ) builder.setStyle( androidx.media.app.NotificationCompat.MediaStyle() From 9190eb8edd643397069abb264f704bd760bb31f9 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 28 Aug 2019 21:05:41 +0800 Subject: [PATCH 1095/1997] up --- .../java/io/legado/app/constant/Action.kt | 1 + .../io/legado/app/service/ReadAloudService.kt | 39 +++++++++++++++++++ .../notification/ReadAloudNotification.kt | 2 +- 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/constant/Action.kt b/app/src/main/java/io/legado/app/constant/Action.kt index 321eb39a6..edccff54c 100644 --- a/app/src/main/java/io/legado/app/constant/Action.kt +++ b/app/src/main/java/io/legado/app/constant/Action.kt @@ -6,6 +6,7 @@ object Action { const val stop = "stop" const val resume = "resume" const val pause = "pause" + const val addTimer = "addTimer" const val setTimer = "setTimer" const val prevParagraph = "prevParagraph" const val nextParagraph = "nextParagraph" diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index 4b256ac93..db86d08ef 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -5,6 +5,7 @@ import android.content.* import android.media.AudioFocusRequest import android.media.AudioManager import android.os.Build +import android.os.Handler import android.speech.tts.TextToSpeech import android.speech.tts.UtteranceProgressListener import android.support.v4.media.session.MediaSessionCompat @@ -107,6 +108,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage } } + private val handler = Handler() private var ttsIsSuccess: Boolean = false private lateinit var audioManager: AudioManager private lateinit var mFocusRequest: AudioFocusRequest @@ -118,6 +120,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage private var textChapter: TextChapter? = null private var pageIndex = 0 var mediaSessionCompat: MediaSessionCompat? = null + private val dsRunnable: Runnable? = Runnable { doDs() } var pause = false var title: String = "" var subtitle: String = "" @@ -163,6 +166,8 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage Action.upTtsSpeechRate -> upSpeechRate(true) Action.prevParagraph -> prevP() Action.nextParagraph -> nextP() + Action.addTimer -> addTimer() + Action.setTimer -> setTimer(intent.getIntExtra("minute", 0)) else -> stopSelf() } } @@ -219,6 +224,40 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage } } + private fun setTimer(minute: Int) { + timeMinute = minute + if (minute > 0) { + handler.removeCallbacks(dsRunnable) + handler.postDelayed(dsRunnable, 6000) + } + ReadAloudNotification.upNotification(this) + } + + private fun addTimer() { + if (timeMinute == 60) { + timeMinute = 0 + handler.removeCallbacks(dsRunnable) + } else { + timeMinute += 10 + if (timeMinute > 60) timeMinute = 60 + handler.removeCallbacks(dsRunnable) + handler.postDelayed(dsRunnable, 6000) + } + ReadAloudNotification.upNotification(this) + } + + private fun doDs() { + if (!pause) { + timeMinute-- + if (timeMinute == 0) { + stopSelf() + } else if (timeMinute > 0) { + handler.postDelayed(dsRunnable, 6000) + } + } + ReadAloudNotification.upNotification(this) + } + private fun upSpeechRate(reset: Boolean = false) { if (this.getPrefBoolean("ttsFollowSys", true)) { if (reset) { diff --git a/app/src/main/java/io/legado/app/service/notification/ReadAloudNotification.kt b/app/src/main/java/io/legado/app/service/notification/ReadAloudNotification.kt index 57c8cfa2a..9189f17fd 100644 --- a/app/src/main/java/io/legado/app/service/notification/ReadAloudNotification.kt +++ b/app/src/main/java/io/legado/app/service/notification/ReadAloudNotification.kt @@ -51,7 +51,7 @@ object ReadAloudNotification { builder.addAction( R.drawable.ic_time_add_24dp, service.getString(R.string.set_timer), - PendingIntentHelp.aloudServicePendingIntent(service, Action.setTimer) + PendingIntentHelp.aloudServicePendingIntent(service, Action.addTimer) ) builder.setStyle( androidx.media.app.NotificationCompat.MediaStyle() From 60075bfd8512f6a5c59c052a959588f989276436 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 28 Aug 2019 21:21:39 +0800 Subject: [PATCH 1096/1997] up --- app/src/main/java/io/legado/app/constant/Bus.kt | 1 + .../java/io/legado/app/service/ReadAloudService.kt | 13 ++++++++++++- .../service/notification/ReadAloudNotification.kt | 5 ++++- .../app/ui/readbook/config/ReadAloudDialog.kt | 7 ++++--- 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/constant/Bus.kt b/app/src/main/java/io/legado/app/constant/Bus.kt index 562da87ed..96ec93b5e 100644 --- a/app/src/main/java/io/legado/app/constant/Bus.kt +++ b/app/src/main/java/io/legado/app/constant/Bus.kt @@ -6,6 +6,7 @@ object Bus { const val ALOUD_STATE = "aloud_state" const val TTS_START = "ttsStart" const val TTS_NEXT = "ttsNextPage" + const val TTS_DS = "ttsDs" const val BATTERY_CHANGED = "batteryChanged" const val TIME_CHANGED = "timeChanged" const val READ_ALOUD_BUTTON = "readAloudButton" diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index db86d08ef..cbcd06515 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -34,6 +34,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage val tag: String = ReadAloudService::class.java.simpleName var isRun = false var textToSpeech: TextToSpeech? = null + var timeMinute: Int = 0 fun play( context: Context, @@ -101,6 +102,15 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage } } + fun setTimer(context: Context, minute: Int) { + if (isRun) { + val intent = Intent(context, ReadAloudService::class.java) + intent.action = Action.setTimer + intent.putExtra("minute", minute) + context.startService(intent) + } + } + fun clearTTS() { textToSpeech?.stop() textToSpeech?.shutdown() @@ -124,7 +134,6 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage var pause = false var title: String = "" var subtitle: String = "" - var timeMinute: Int = 0 override fun onCreate() { super.onCreate() @@ -243,6 +252,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage handler.removeCallbacks(dsRunnable) handler.postDelayed(dsRunnable, 6000) } + postEvent(Bus.TTS_DS, timeMinute) ReadAloudNotification.upNotification(this) } @@ -255,6 +265,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage handler.postDelayed(dsRunnable, 6000) } } + postEvent(Bus.TTS_DS, timeMinute) ReadAloudNotification.upNotification(this) } diff --git a/app/src/main/java/io/legado/app/service/notification/ReadAloudNotification.kt b/app/src/main/java/io/legado/app/service/notification/ReadAloudNotification.kt index 9189f17fd..d7e0c51ca 100644 --- a/app/src/main/java/io/legado/app/service/notification/ReadAloudNotification.kt +++ b/app/src/main/java/io/legado/app/service/notification/ReadAloudNotification.kt @@ -16,7 +16,10 @@ object ReadAloudNotification { fun upNotification(service: ReadAloudService) { var nTitle: String = when { service.pause -> service.getString(R.string.read_aloud_pause) - service.timeMinute in 1..60 -> service.getString(R.string.read_aloud_timer, service.timeMinute) + ReadAloudService.timeMinute in 1..60 -> service.getString( + R.string.read_aloud_timer, + ReadAloudService.timeMinute + ) else -> service.getString(R.string.read_aloud_t) } nTitle += ": ${service.title}" diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt index 65282b558..dddda3b39 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt @@ -54,10 +54,12 @@ class ReadAloudDialog : DialogFragment() { private fun initData() { observeEvent(Bus.ALOUD_STATE) { upPlayState(it) } + observeEvent(Bus.TTS_DS) { seek_timer.progress = it } val activity = activity if (activity is ReadBookActivity) { upPlayState(activity.readAloudStatus) } + tv_timer.text = requireContext().getString(R.string.timer_m, ReadAloudService.timeMinute) cb_by_page.isChecked = requireContext().getPrefBoolean("readAloudByPage") cb_tts_follow_sys.isChecked = requireContext().getPrefBoolean("ttsFollowSys", true) seek_tts_SpeechRate.isEnabled = !cb_tts_follow_sys.isChecked @@ -92,15 +94,14 @@ class ReadAloudDialog : DialogFragment() { }) seek_timer.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { - + tv_timer.text = requireContext().getString(R.string.timer_m, progress) } override fun onStartTrackingTouch(seekBar: SeekBar?) { - } override fun onStopTrackingTouch(seekBar: SeekBar?) { - + ReadAloudService.setTimer(requireContext(), seek_timer.progress) } }) } From cb73104486212581cfd7b8d2fefbb15a239459aa Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 28 Aug 2019 21:24:04 +0800 Subject: [PATCH 1097/1997] up --- .../java/io/legado/app/service/ReadAloudService.kt | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index cbcd06515..69f451a6e 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -28,7 +28,8 @@ import kotlinx.coroutines.launch import org.jetbrains.anko.toast import java.util.* -class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManager.OnAudioFocusChangeListener { +class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, + AudioManager.OnAudioFocusChangeListener { companion object { val tag: String = ReadAloudService::class.java.simpleName @@ -237,7 +238,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage timeMinute = minute if (minute > 0) { handler.removeCallbacks(dsRunnable) - handler.postDelayed(dsRunnable, 6000) + handler.postDelayed(dsRunnable, 60000) } ReadAloudNotification.upNotification(this) } @@ -250,7 +251,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage timeMinute += 10 if (timeMinute > 60) timeMinute = 60 handler.removeCallbacks(dsRunnable) - handler.postDelayed(dsRunnable, 6000) + handler.postDelayed(dsRunnable, 60000) } postEvent(Bus.TTS_DS, timeMinute) ReadAloudNotification.upNotification(this) @@ -262,7 +263,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage if (timeMinute == 0) { stopSelf() } else if (timeMinute > 0) { - handler.postDelayed(dsRunnable, 6000) + handler.postDelayed(dsRunnable, 60000) } } postEvent(Bus.TTS_DS, timeMinute) @@ -310,7 +311,8 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, AudioManage mediaButtonIntent, PendingIntent.FLAG_CANCEL_CURRENT ) - mediaSessionCompat = MediaSessionCompat(this, tag, mComponent, mediaButtonReceiverPendingIntent) + mediaSessionCompat = + MediaSessionCompat(this, tag, mComponent, mediaButtonReceiverPendingIntent) mediaSessionCompat?.setCallback(object : MediaSessionCompat.Callback() { override fun onMediaButtonEvent(mediaButtonEvent: Intent): Boolean { return MediaButtonReceiver.handleIntent(this@ReadAloudService, mediaButtonEvent) From 947367bbe25700c13a0f55c302a0fc8278ad419c Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 28 Aug 2019 22:35:33 +0800 Subject: [PATCH 1098/1997] up --- .../java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt index dddda3b39..d182cfa11 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt @@ -59,6 +59,7 @@ class ReadAloudDialog : DialogFragment() { if (activity is ReadBookActivity) { upPlayState(activity.readAloudStatus) } + seek_timer.progress = ReadAloudService.timeMinute tv_timer.text = requireContext().getString(R.string.timer_m, ReadAloudService.timeMinute) cb_by_page.isChecked = requireContext().getPrefBoolean("readAloudByPage") cb_tts_follow_sys.isChecked = requireContext().getPrefBoolean("ttsFollowSys", true) From 22db0c851b8e48e9d19f5e8286c9312629a2f312 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 28 Aug 2019 22:57:30 +0800 Subject: [PATCH 1099/1997] up --- .../ui/readbook/config/PaddingConfigDialog.kt | 12 +- .../main/res/layout/dialog_read_padding.xml | 201 ++++++++++++++++++ 2 files changed, 212 insertions(+), 1 deletion(-) create mode 100644 app/src/main/res/layout/dialog_read_padding.xml diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.kt index f8405012e..e55e19ea0 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.kt @@ -16,7 +16,7 @@ class PaddingConfigDialog : DialogFragment() { container: ViewGroup?, savedInstanceState: Bundle? ): View? { - return super.onCreateView(inflater, container, savedInstanceState) + return inflater.inflate(R.layout.dialog_read_padding, container) } override fun onStart() { @@ -36,6 +36,16 @@ class PaddingConfigDialog : DialogFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + initData() + initView() + } + + private fun initData() { + + } + + private fun initView() { + } } diff --git a/app/src/main/res/layout/dialog_read_padding.xml b/app/src/main/res/layout/dialog_read_padding.xml new file mode 100644 index 000000000..7c2ce047e --- /dev/null +++ b/app/src/main/res/layout/dialog_read_padding.xml @@ -0,0 +1,201 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 9a2f32399ccf4cf48e74800019f6d7fd98f0ffe8 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 29 Aug 2019 08:22:20 +0800 Subject: [PATCH 1100/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 5 ++ .../ui/readbook/config/PaddingConfigDialog.kt | 73 ++++++++++++++++++- .../app/ui/readbook/config/ReadStyleDialog.kt | 7 ++ .../main/res/layout/dialog_read_padding.xml | 43 ++++++----- 4 files changed, 106 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 7151fbe13..70abb4271 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -23,6 +23,7 @@ import io.legado.app.service.ReadAloudService import io.legado.app.ui.changesource.ChangeSourceDialog import io.legado.app.ui.chapterlist.ChapterListActivity import io.legado.app.ui.readbook.config.MoreConfigDialog +import io.legado.app.ui.readbook.config.PaddingConfigDialog import io.legado.app.ui.readbook.config.ReadAloudDialog import io.legado.app.ui.readbook.config.ReadStyleDialog import io.legado.app.ui.replacerule.ReplaceRuleActivity @@ -167,6 +168,10 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea }) } + fun showPaddingConfig() { + PaddingConfigDialog().show(supportFragmentManager, "paddingConfig") + } + override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { menuInflater.inflate(R.menu.read_book, menu) return super.onCompatCreateOptionsMenu(menu) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.kt index e55e19ea0..6032b9884 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.kt @@ -5,9 +5,14 @@ import android.util.DisplayMetrics import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.SeekBar import androidx.fragment.app.DialogFragment import io.legado.app.R +import io.legado.app.constant.Bus +import io.legado.app.help.ReadBookConfig import io.legado.app.ui.readbook.Help +import io.legado.app.utils.postEvent +import kotlinx.android.synthetic.main.dialog_read_padding.* class PaddingConfigDialog : DialogFragment() { @@ -40,12 +45,74 @@ class PaddingConfigDialog : DialogFragment() { initView() } - private fun initData() { - + private fun initData() = with(ReadBookConfig.getConfig()) { + seek_padding_top.progress = paddingTop + seek_padding_bottom.progress = paddingBottom + seek_padding_left.progress = paddingLeft + seek_padding_right.progress = paddingRight + tv_padding_top.text = paddingTop.toString() + tv_padding_bottom.text = paddingBottom.toString() + tv_padding_left.text = paddingLeft.toString() + tv_padding_right.text = paddingRight.toString() } - private fun initView() { + private fun initView() = with(ReadBookConfig.getConfig()) { + seek_padding_top.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { + override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { + paddingTop = progress + tv_padding_top.text = paddingTop.toString() + } + + override fun onStartTrackingTouch(seekBar: SeekBar?) { + + } + + override fun onStopTrackingTouch(seekBar: SeekBar?) { + postEvent(Bus.UP_CONFIG, true) + } + }) + seek_padding_bottom.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { + override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { + paddingBottom = progress + tv_padding_bottom.text = paddingBottom.toString() + } + + override fun onStartTrackingTouch(seekBar: SeekBar?) { + + } + + override fun onStopTrackingTouch(seekBar: SeekBar?) { + postEvent(Bus.UP_CONFIG, true) + } + }) + seek_padding_left.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { + override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { + paddingLeft = progress + tv_padding_left.text = paddingLeft.toString() + } + + override fun onStartTrackingTouch(seekBar: SeekBar?) { + + } + + override fun onStopTrackingTouch(seekBar: SeekBar?) { + postEvent(Bus.UP_CONFIG, true) + } + }) + seek_padding_right.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { + override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { + paddingRight = progress + tv_padding_right.text = paddingRight.toString() + } + + override fun onStartTrackingTouch(seekBar: SeekBar?) { + + } + override fun onStopTrackingTouch(seekBar: SeekBar?) { + postEvent(Bus.UP_CONFIG, true) + } + }) } } diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt index 08e730014..bde80b8c3 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt @@ -87,6 +87,13 @@ class ReadStyleDialog : DialogFragment() { tv_text_bold.isSelected = textBold postEvent(Bus.UP_CONFIG, false) } + tv_padding.onClick { + val activity = activity + dismiss() + if (activity is ReadBookActivity) { + activity.showPaddingConfig() + } + } seek_text_size.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { textSize = progress + 5 diff --git a/app/src/main/res/layout/dialog_read_padding.xml b/app/src/main/res/layout/dialog_read_padding.xml index 7c2ce047e..498c1b91b 100644 --- a/app/src/main/res/layout/dialog_read_padding.xml +++ b/app/src/main/res/layout/dialog_read_padding.xml @@ -1,20 +1,21 @@ + android:max="100" /> + + android:max="100" /> + + android:max="100" /> + + android:max="100" /> + \ No newline at end of file From 59586b463d19d720a4e6a4d28ca3e228bc788706 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 29 Aug 2019 08:35:02 +0800 Subject: [PATCH 1101/1997] up --- .../ui/readbook/config/PaddingConfigDialog.kt | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.kt index 6032b9884..a814ef6d0 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.kt @@ -13,6 +13,7 @@ import io.legado.app.help.ReadBookConfig import io.legado.app.ui.readbook.Help import io.legado.app.utils.postEvent import kotlinx.android.synthetic.main.dialog_read_padding.* +import org.jetbrains.anko.sdk27.listeners.onClick class PaddingConfigDialog : DialogFragment() { @@ -57,6 +58,56 @@ class PaddingConfigDialog : DialogFragment() { } private fun initView() = with(ReadBookConfig.getConfig()) { + iv_padding_top_add.onClick { + paddingTop++ + if (paddingTop > 100) paddingTop = 100 + seek_padding_top.progress = paddingTop + tv_padding_top.text = paddingTop.toString() + postEvent(Bus.UP_CONFIG, true) + } + iv_padding_top_remove.onClick { + paddingTop-- + if (paddingTop < 0) paddingTop = 0 + seek_padding_top.progress = paddingTop + tv_padding_top.text = paddingTop.toString() + postEvent(Bus.UP_CONFIG, true) + } + iv_padding_bottom_add.onClick { + paddingBottom++ + if (paddingBottom > 100) paddingBottom = 100 + seek_padding_bottom.progress = paddingBottom + tv_padding_bottom.text = paddingBottom.toString() + postEvent(Bus.UP_CONFIG, true) + } + iv_padding_bottom_remove.onClick { + paddingBottom-- + if (paddingBottom < 0) paddingBottom = 0 + seek_padding_bottom.progress = paddingBottom + tv_padding_bottom.text = paddingBottom.toString() + postEvent(Bus.UP_CONFIG, true) + } + iv_padding_left_add.onClick { + paddingLeft++ + if (paddingLeft > 100) paddingLeft = 100 + seek_padding_left.progress = paddingLeft + tv_padding_left.text = paddingLeft.toString() + postEvent(Bus.UP_CONFIG, true) + } + iv_padding_left_remove.onClick { + paddingLeft++ + if (paddingLeft < 0) paddingLeft = 0 + seek_padding_left.progress = paddingLeft + tv_padding_left.text = paddingLeft.toString() + postEvent(Bus.UP_CONFIG, true) + } + iv_padding_right_add.onClick { + paddingRight++ + if (paddingRight > 100) paddingRight = 100 + seek_padding_right.progress = paddingRight + tv_padding_right.text = paddingRight.toString() + postEvent(Bus.UP_CONFIG, true) + } + seek_padding_top.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { paddingTop = progress From 744b020120e87e24d12506c6008e61e64174432c Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 29 Aug 2019 08:38:18 +0800 Subject: [PATCH 1102/1997] up --- app/src/main/res/layout/view_book_page.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/layout/view_book_page.xml b/app/src/main/res/layout/view_book_page.xml index c764d4884..db8340877 100644 --- a/app/src/main/res/layout/view_book_page.xml +++ b/app/src/main/res/layout/view_book_page.xml @@ -43,7 +43,8 @@ android:id="@+id/tv_bottom_left" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_weight="1" /> + android:layout_weight="1" + android:singleLine="true" /> Date: Thu, 29 Aug 2019 08:39:01 +0800 Subject: [PATCH 1103/1997] up --- app/src/main/assets/readConfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/assets/readConfig.json b/app/src/main/assets/readConfig.json index 3f340c8ed..5793e4dc3 100644 --- a/app/src/main/assets/readConfig.json +++ b/app/src/main/assets/readConfig.json @@ -10,7 +10,7 @@ "lineSpacingMultiplier": 1.2, "paddingLeft": 16, "paddingRight": 16, - "paddingTop": 10, + "paddingTop": 0, "paddingBottom": 0 }, { From 0a5d247139f9eb54cebb4a386938adf9f2a7e38c Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 29 Aug 2019 08:54:10 +0800 Subject: [PATCH 1104/1997] up --- .../app/ui/widget/font/FontSelectDialog.kt | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt diff --git a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt new file mode 100644 index 000000000..9fd307e94 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt @@ -0,0 +1,29 @@ +package io.legado.app.ui.widget.font + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.DialogFragment + +class FontSelectDialog : DialogFragment() { + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + return super.onCreateView(inflater, container, savedInstanceState) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + initData() + } + + private fun initData() { + + } + + +} \ No newline at end of file From 746946bea444cef1b685b1da14fa6d7a425050fe Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 29 Aug 2019 09:12:38 +0800 Subject: [PATCH 1105/1997] up --- .../java/io/legado/app/ui/widget/font/FontSelectDialog.kt | 3 ++- app/src/main/res/layout/dialog_font_select.xml | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 app/src/main/res/layout/dialog_font_select.xml diff --git a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt index 9fd307e94..72557ec3f 100644 --- a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt +++ b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt @@ -5,6 +5,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.DialogFragment +import io.legado.app.R class FontSelectDialog : DialogFragment() { @@ -13,7 +14,7 @@ class FontSelectDialog : DialogFragment() { container: ViewGroup?, savedInstanceState: Bundle? ): View? { - return super.onCreateView(inflater, container, savedInstanceState) + return inflater.inflate(R.layout.dialog_font_select, container) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { diff --git a/app/src/main/res/layout/dialog_font_select.xml b/app/src/main/res/layout/dialog_font_select.xml new file mode 100644 index 000000000..d829e291c --- /dev/null +++ b/app/src/main/res/layout/dialog_font_select.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file From ce31fa265abe831ae53c616c22bcbcb55543c36f Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 29 Aug 2019 09:23:46 +0800 Subject: [PATCH 1106/1997] up --- .../main/java/io/legado/app/ui/widget/page/ContentView.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index 4202549e1..5a0c3627f 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -47,12 +47,13 @@ class ContentView : FrameLayout { ReadBookConfig.getConfig().apply { val pt = if (context.getPrefBoolean("hideStatusBar", false)) { top_bar.visible() - paddingTop.dp + 0 } else { top_bar.gone() - paddingTop.dp + context.getStatusBarHeight() + context.getStatusBarHeight() } - page_panel.setPadding(paddingLeft.dp, pt, paddingRight.dp, paddingBottom.dp) + page_panel.setPadding(paddingLeft.dp, pt, paddingRight.dp, 0) + content_text_view.setPadding(0, paddingTop.dp, 0, paddingBottom.dp) content_text_view.textSize = textSize.toFloat() content_text_view.setLineSpacing(lineSpacingExtra.toFloat(), lineSpacingMultiplier) content_text_view.letterSpacing = letterSpacing From 4082ae52b408133330f414eb797b4fde213b436b Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 29 Aug 2019 11:11:13 +0800 Subject: [PATCH 1107/1997] up --- .../main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 70abb4271..12205427f 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -90,11 +90,6 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea Help.upSystemUiVisibility(window, !read_menu.isVisible) } - override fun onDestroy() { - super.onDestroy() - viewModel.saveRead() - } - /** * 初始化View */ @@ -244,6 +239,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea viewModel.loadContent(it, viewModel.durChapterIndex) viewModel.loadContent(it, viewModel.durChapterIndex + 1) viewModel.loadContent(it, viewModel.durChapterIndex - 1) + viewModel.saveRead() } } From f8b09dbdde5fb6343781640018bcb40100115274 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 29 Aug 2019 11:11:39 +0800 Subject: [PATCH 1108/1997] up --- app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 12205427f..29b4bb318 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -239,7 +239,6 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea viewModel.loadContent(it, viewModel.durChapterIndex) viewModel.loadContent(it, viewModel.durChapterIndex + 1) viewModel.loadContent(it, viewModel.durChapterIndex - 1) - viewModel.saveRead() } } From 69dcb551125c0d937d53b5d01328082a13a58518 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 29 Aug 2019 11:13:38 +0800 Subject: [PATCH 1109/1997] up --- .../main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index e6090b873..443543bc4 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -42,6 +42,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } else { App.db.bookDao().lastReadBook } + saveRead(book) book?.let { durChapterIndex = book.durChapterIndex durPageIndex = book.durChapterPos @@ -235,9 +236,9 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { chapterListFinish.postValue(true) } - fun saveRead() { + fun saveRead(book: Book? = bookData.value) { execute { - bookData.value?.let { book -> + book?.let { book -> book.lastCheckCount = 0 book.durChapterTime = System.currentTimeMillis() book.durChapterIndex = durChapterIndex From 9dc54f52e1c13530b363e4ca7e7a0d4563c5933c Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 29 Aug 2019 11:30:26 +0800 Subject: [PATCH 1110/1997] up --- .../io/legado/app/ui/readbook/ReadBookActivity.kt | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 29b4bb318..bb30ba243 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -18,6 +18,9 @@ import io.legado.app.constant.Status import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter import io.legado.app.help.IntentDataHelp +import io.legado.app.lib.dialogs.alert +import io.legado.app.lib.dialogs.noButton +import io.legado.app.lib.dialogs.okButton import io.legado.app.receiver.TimeElectricityReceiver import io.legado.app.service.ReadAloudService import io.legado.app.ui.changesource.ChangeSourceDialog @@ -40,8 +43,10 @@ import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import org.jetbrains.anko.* import org.jetbrains.anko.sdk27.listeners.onClick +import org.jetbrains.anko.startActivity +import org.jetbrains.anko.startActivityForResult +import org.jetbrains.anko.toast class ReadBookActivity : VMBaseActivity(R.layout.activity_read_book), PageView.CallBack, @@ -424,12 +429,11 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea override fun finish() { viewModel.bookData.value?.let { if (!viewModel.inBookshelf) { - alert { - title = getString(R.string.add_to_shelf) + this.alert(title = getString(R.string.add_to_shelf)) { message = getString(R.string.check_add_bookshelf, it.name) okButton { viewModel.inBookshelf = true } noButton { viewModel.removeFromBookshelf { super.finish() } } - }.show() + }.show().applyTint() } else { super.finish() } From 5cb6c445e3c35e27516708974b6946e155e906e5 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 29 Aug 2019 13:46:51 +0800 Subject: [PATCH 1111/1997] up --- .../legado/app/ui/widget/font/FontAdapter.kt | 34 ++++++++++++ .../main/res/layout/dialog_font_select.xml | 52 +++++++++++++++++-- app/src/main/res/layout/item_font.xml | 27 ++++++++++ 3 files changed, 110 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/widget/font/FontAdapter.kt create mode 100644 app/src/main/res/layout/item_font.xml diff --git a/app/src/main/java/io/legado/app/ui/widget/font/FontAdapter.kt b/app/src/main/java/io/legado/app/ui/widget/font/FontAdapter.kt new file mode 100644 index 000000000..44f4f9974 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/font/FontAdapter.kt @@ -0,0 +1,34 @@ +package io.legado.app.ui.widget.font + +import android.content.Context +import android.graphics.Typeface +import io.legado.app.R +import io.legado.app.base.adapter.ItemViewHolder +import io.legado.app.base.adapter.SimpleRecyclerAdapter +import io.legado.app.utils.invisible +import io.legado.app.utils.visible +import kotlinx.android.synthetic.main.item_font.view.* +import org.jetbrains.anko.sdk27.listeners.onClick +import java.io.File + +class FontAdapter(context: Context, val callBack: CallBack) : + SimpleRecyclerAdapter(context, R.layout.item_font) { + + override fun convert(holder: ItemViewHolder, item: File, payloads: MutableList) = + with(holder.itemView) { + val typeface = Typeface.createFromFile(item) + tv_font.typeface = typeface + tv_font.text = item.name + this.onClick { callBack.onClick(item) } + if (item.absolutePath == callBack.curFilePath()) { + iv_checked.visible() + } else { + iv_checked.invisible() + } + } + + interface CallBack { + fun onClick(file: File) + fun curFilePath(): String + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_font_select.xml b/app/src/main/res/layout/dialog_font_select.xml index d829e291c..3e47640d2 100644 --- a/app/src/main/res/layout/dialog_font_select.xml +++ b/app/src/main/res/layout/dialog_font_select.xml @@ -1,7 +1,53 @@ - + android:layout_height="wrap_content" + android:padding="16dp"> - \ No newline at end of file + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_font.xml b/app/src/main/res/layout/item_font.xml new file mode 100644 index 000000000..24c9be27e --- /dev/null +++ b/app/src/main/res/layout/item_font.xml @@ -0,0 +1,27 @@ + + + + + + + + \ No newline at end of file From 0e5a9c1294c76e1fdce0db10a98327d3da081b8b Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 29 Aug 2019 14:04:34 +0800 Subject: [PATCH 1112/1997] up --- .../app/ui/widget/font/FontSelectDialog.kt | 40 ++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt index 72557ec3f..52b0f3574 100644 --- a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt +++ b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt @@ -1,13 +1,24 @@ package io.legado.app.ui.widget.font +import android.annotation.SuppressLint import android.os.Bundle +import android.os.Environment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.DialogFragment +import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.R +import io.legado.app.utils.invisible +import io.legado.app.utils.visible +import kotlinx.android.synthetic.main.dialog_font_select.* +import java.io.File -class FontSelectDialog : DialogFragment() { +class FontSelectDialog : DialogFragment(), FontAdapter.CallBack { + + private val defaultFolder = + Environment.getExternalStorageDirectory().absolutePath + File.separator + "Fonts" + lateinit var adapter: FontAdapter override fun onCreateView( inflater: LayoutInflater, @@ -23,8 +34,35 @@ class FontSelectDialog : DialogFragment() { } private fun initData() { + adapter = FontAdapter(requireContext(), this) + recycler_view.layoutManager = LinearLayoutManager(requireContext()) + recycler_view.adapter = adapter + val files = getFontFiles() + if (files == null) { + tv_no_data.visible() + } else { + tv_no_data.invisible() + adapter.setItems(files.toList()) + } + } + @SuppressLint("DefaultLocale") + private fun getFontFiles(fontFolder: String = defaultFolder): Array? { + return try { + val file = File(fontFolder) + file.listFiles { pathName -> + pathName.name.toLowerCase().matches(".*\\.[ot]tf".toRegex()) + } + } catch (e: Exception) { + null + } } + override fun onClick(file: File) { + } + + override fun curFilePath(): String { + return "" + } } \ No newline at end of file From 189df7a5de7471a087bb5a32dc48c87fad3de719 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 29 Aug 2019 14:50:09 +0800 Subject: [PATCH 1113/1997] up --- .../app/ui/readbook/config/ReadStyleDialog.kt | 16 +++++- .../app/ui/widget/font/FontSelectDialog.kt | 55 +++++++++++-------- 2 files changed, 46 insertions(+), 25 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt index bde80b8c3..327480353 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt @@ -17,9 +17,8 @@ import io.legado.app.lib.theme.accentColor import io.legado.app.lib.theme.primaryColor import io.legado.app.ui.readbook.Help import io.legado.app.ui.readbook.ReadBookActivity -import io.legado.app.utils.getPrefInt -import io.legado.app.utils.postEvent -import io.legado.app.utils.putPrefInt +import io.legado.app.ui.widget.font.FontSelectDialog +import io.legado.app.utils.* import kotlinx.android.synthetic.main.activity_read_book.* import kotlinx.android.synthetic.main.dialog_read_book_style.* import org.jetbrains.anko.sdk27.listeners.onCheckedChange @@ -87,6 +86,17 @@ class ReadStyleDialog : DialogFragment() { tv_text_bold.isSelected = textBold postEvent(Bus.UP_CONFIG, false) } + tv_text_font.onClick { + FontSelectDialog(requireContext()).apply { + curPath = requireContext().getPrefString("readBookFont") + defaultFont = { + requireContext().putPrefString("readBookFont", "") + } + selectFile = { + requireContext().putPrefString("readBookFont", it) + } + }.show() + } tv_padding.onClick { val activity = activity dismiss() diff --git a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt index 52b0f3574..d582c0a3a 100644 --- a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt +++ b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt @@ -1,41 +1,49 @@ package io.legado.app.ui.widget.font import android.annotation.SuppressLint -import android.os.Bundle +import android.content.Context +import android.content.DialogInterface import android.os.Environment import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.DialogFragment import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.R +import io.legado.app.lib.dialogs.AlertBuilder +import io.legado.app.lib.dialogs.alert import io.legado.app.utils.invisible import io.legado.app.utils.visible -import kotlinx.android.synthetic.main.dialog_font_select.* +import kotlinx.android.synthetic.main.dialog_font_select.view.* import java.io.File -class FontSelectDialog : DialogFragment(), FontAdapter.CallBack { +class FontSelectDialog(context: Context) : FontAdapter.CallBack { private val defaultFolder = Environment.getExternalStorageDirectory().absolutePath + File.separator + "Fonts" - lateinit var adapter: FontAdapter + private lateinit var adapter: FontAdapter + private var builder: AlertBuilder + @SuppressLint("InflateParams") + private var view: View = LayoutInflater.from(context).inflate(R.layout.dialog_font_select, null) + var curPath: String? = null + var fontFolder: String? = null + var defaultFont: (() -> Unit)? = null + var selectFile: ((path: String) -> Unit)? = null - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - return inflater.inflate(R.layout.dialog_font_select, container) + init { + builder = context.alert(title = context.getString(R.string.select_font)) { + customView = view + positiveButton(R.string.default_font) { defaultFont?.invoke() } + negativeButton(R.string.cancel) + } + initData() } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - initData() + fun show() { + builder.show() } - private fun initData() { - adapter = FontAdapter(requireContext(), this) - recycler_view.layoutManager = LinearLayoutManager(requireContext()) + private fun initData() = with(view) { + adapter = FontAdapter(context, this@FontSelectDialog) + recycler_view.layoutManager = LinearLayoutManager(context) recycler_view.adapter = adapter val files = getFontFiles() if (files == null) { @@ -47,9 +55,12 @@ class FontSelectDialog : DialogFragment(), FontAdapter.CallBack { } @SuppressLint("DefaultLocale") - private fun getFontFiles(fontFolder: String = defaultFolder): Array? { + private fun getFontFiles(): Array? { + val path = if (fontFolder.isNullOrEmpty()) { + defaultFolder + } else fontFolder return try { - val file = File(fontFolder) + val file = File(path) file.listFiles { pathName -> pathName.name.toLowerCase().matches(".*\\.[ot]tf".toRegex()) } @@ -59,10 +70,10 @@ class FontSelectDialog : DialogFragment(), FontAdapter.CallBack { } override fun onClick(file: File) { - + selectFile?.invoke(file.absolutePath) } override fun curFilePath(): String { - return "" + return curPath ?: "" } } \ No newline at end of file From c858324d4571786abe774a0a2efbe46a713ee33b Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 29 Aug 2019 14:55:56 +0800 Subject: [PATCH 1114/1997] up --- .../main/res/layout/dialog_font_select.xml | 41 ++----------------- 1 file changed, 4 insertions(+), 37 deletions(-) diff --git a/app/src/main/res/layout/dialog_font_select.xml b/app/src/main/res/layout/dialog_font_select.xml index 3e47640d2..08e33c0a9 100644 --- a/app/src/main/res/layout/dialog_font_select.xml +++ b/app/src/main/res/layout/dialog_font_select.xml @@ -1,53 +1,20 @@ - - - + android:layout_height="wrap_content" /> - - - - + android:text="@string/fonts_folder" /> - \ No newline at end of file + \ No newline at end of file From ef915e327d1da5500452799b58172652f17afdac Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 29 Aug 2019 14:57:37 +0800 Subject: [PATCH 1115/1997] up --- .../main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt index d582c0a3a..6b343b4e4 100644 --- a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt +++ b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt @@ -46,7 +46,7 @@ class FontSelectDialog(context: Context) : FontAdapter.CallBack { recycler_view.layoutManager = LinearLayoutManager(context) recycler_view.adapter = adapter val files = getFontFiles() - if (files == null) { + if (files.isNullOrEmpty()) { tv_no_data.visible() } else { tv_no_data.invisible() From 7a8b5977485980e79605a9c808fa3883ff69178e Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 29 Aug 2019 15:30:25 +0800 Subject: [PATCH 1116/1997] up --- .../java/io/legado/app/ui/widget/font/FontSelectDialog.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt index 6b343b4e4..c21503ce0 100644 --- a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt +++ b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt @@ -21,6 +21,7 @@ class FontSelectDialog(context: Context) : FontAdapter.CallBack { Environment.getExternalStorageDirectory().absolutePath + File.separator + "Fonts" private lateinit var adapter: FontAdapter private var builder: AlertBuilder + private var dialog: DialogInterface? = null @SuppressLint("InflateParams") private var view: View = LayoutInflater.from(context).inflate(R.layout.dialog_font_select, null) var curPath: String? = null @@ -38,7 +39,7 @@ class FontSelectDialog(context: Context) : FontAdapter.CallBack { } fun show() { - builder.show() + dialog = builder.show() } private fun initData() = with(view) { @@ -71,6 +72,7 @@ class FontSelectDialog(context: Context) : FontAdapter.CallBack { override fun onClick(file: File) { selectFile?.invoke(file.absolutePath) + dialog?.dismiss() } override fun curFilePath(): String { From 388270533232dad7040dfacce21264dbfcd941f3 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 29 Aug 2019 16:00:38 +0800 Subject: [PATCH 1117/1997] up --- .../java/io/legado/app/service/ReadAloudService.kt | 14 +++++++++++--- .../io/legado/app/ui/readbook/ReadBookActivity.kt | 8 +++++++- .../app/ui/readbook/config/ReadAloudDialog.kt | 1 + 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index 69f451a6e..bb138ad9f 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -206,11 +206,19 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, private fun newReadAloud(dataKey: String?, play: Boolean) { dataKey?.let { textChapter = IntentDataHelp.getData(dataKey) as? TextChapter - textChapter?.let { + textChapter?.let { textChapter -> nowSpeak = 0 - readAloudNumber = it.getReadLength(pageIndex) + readAloudNumber = textChapter.getReadLength(pageIndex) contentList.clear() - contentList.addAll(it.getUnRead(pageIndex).split("\n")) + if (getPrefBoolean("readAloudByPage")) { + for (index in pageIndex..textChapter.lastIndex()) { + textChapter.page(index)?.text?.split("\n")?.let { + contentList.addAll(it) + } + } + } else { + contentList.addAll(textChapter.getUnRead(pageIndex).split("\n")) + } if (play) playTTS() } ?: stopSelf() } ?: stopSelf() diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index bb30ba243..7c0da36d6 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -460,7 +460,13 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea viewModel.openChapter(it) page_view.upContent() } - observeEvent(Bus.READ_ALOUD_BUTTON) { onClickReadAloud() } + observeEvent(Bus.READ_ALOUD_BUTTON) { + if (it) { + onClickReadAloud() + } else { + readAloud() + } + } observeEvent(Bus.UP_CONFIG) { Help.upSystemUiVisibility(window, !read_menu.isVisible) page_view.upBg() diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt index d182cfa11..0069e748d 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt @@ -71,6 +71,7 @@ class ReadAloudDialog : DialogFragment() { cb_by_page.setOnCheckedChangeListener { buttonView, isChecked -> if (buttonView.isPressed) { requireContext().putPrefBoolean("readAloudByPage", isChecked) + postEvent(Bus.READ_ALOUD_BUTTON, false) } } cb_tts_follow_sys.setOnCheckedChangeListener { buttonView, isChecked -> From c16b55b4df2259f2cd8b9fef2b5d431b471b3982 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 29 Aug 2019 16:16:18 +0800 Subject: [PATCH 1118/1997] up --- .../main/java/io/legado/app/ui/widget/page/ContentView.kt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index 5a0c3627f..d1b33ce0a 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -2,6 +2,7 @@ package io.legado.app.ui.widget.page import android.annotation.SuppressLint import android.content.Context +import android.graphics.Typeface import android.graphics.drawable.Drawable import android.util.AttributeSet import android.widget.FrameLayout @@ -66,6 +67,13 @@ class ContentView : FrameLayout { tv_bottom_right.setTextColor(it) } } + context.getPrefString("readBookFont")?.let { + if (it.isNotEmpty()) { + content_text_view.typeface = Typeface.createFromFile(it) + } else { + content_text_view.typeface = Typeface.DEFAULT + } + } } fun setBg(bg: Drawable?) { From 4af8a49ef8f8942cecc832fbd7b27083ae2b3237 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 29 Aug 2019 16:17:28 +0800 Subject: [PATCH 1119/1997] up --- .../java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt index 327480353..53fafd0cf 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt @@ -91,9 +91,11 @@ class ReadStyleDialog : DialogFragment() { curPath = requireContext().getPrefString("readBookFont") defaultFont = { requireContext().putPrefString("readBookFont", "") + postEvent(Bus.UP_CONFIG, true) } selectFile = { requireContext().putPrefString("readBookFont", it) + postEvent(Bus.UP_CONFIG, true) } }.show() } From ac0268eb9a876d7a4f5da47d56f8490952734b5c Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 29 Aug 2019 16:19:16 +0800 Subject: [PATCH 1120/1997] up --- .../java/io/legado/app/ui/widget/font/FontSelectDialog.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt index c21503ce0..5580f31a8 100644 --- a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt +++ b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt @@ -71,8 +71,12 @@ class FontSelectDialog(context: Context) : FontAdapter.CallBack { } override fun onClick(file: File) { - selectFile?.invoke(file.absolutePath) - dialog?.dismiss() + file.absolutePath.let { + if (it != curPath) { + selectFile?.invoke(it) + dialog?.dismiss() + } + } } override fun curFilePath(): String { From bf9803681ab9209551196e36f88234798e589581 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 29 Aug 2019 16:59:17 +0800 Subject: [PATCH 1121/1997] up --- app/src/main/AndroidManifest.xml | 1 + .../io/legado/app/ui/audio/AudioPlayActivity.kt | 17 +++++++++++++++++ .../legado/app/ui/audio/AudioPlayViewModel.kt | 9 +++++++++ app/src/main/res/layout/activity_audio_play.xml | 7 +++++++ 4 files changed, 34 insertions(+) create mode 100644 app/src/main/java/io/legado/app/ui/audio/AudioPlayActivity.kt create mode 100644 app/src/main/java/io/legado/app/ui/audio/AudioPlayViewModel.kt create mode 100644 app/src/main/res/layout/activity_audio_play.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 0984f2a72..bca5f59fb 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -60,6 +60,7 @@ + diff --git a/app/src/main/java/io/legado/app/ui/audio/AudioPlayActivity.kt b/app/src/main/java/io/legado/app/ui/audio/AudioPlayActivity.kt new file mode 100644 index 000000000..23e2dd03b --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/audio/AudioPlayActivity.kt @@ -0,0 +1,17 @@ +package io.legado.app.ui.audio + +import android.os.Bundle +import io.legado.app.R +import io.legado.app.base.VMBaseActivity +import io.legado.app.utils.getViewModel + +class AudioPlayActivity : VMBaseActivity(R.layout.activity_audio_play) { + override val viewModel: AudioPlayViewModel + get() = getViewModel(AudioPlayViewModel::class.java) + + override fun onActivityCreated(savedInstanceState: Bundle?) { + + } + + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/audio/AudioPlayViewModel.kt b/app/src/main/java/io/legado/app/ui/audio/AudioPlayViewModel.kt new file mode 100644 index 000000000..aebf4da98 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/audio/AudioPlayViewModel.kt @@ -0,0 +1,9 @@ +package io.legado.app.ui.audio + +import android.app.Application +import io.legado.app.base.BaseViewModel + +class AudioPlayViewModel(application: Application) : BaseViewModel(application) { + + +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_audio_play.xml b/app/src/main/res/layout/activity_audio_play.xml new file mode 100644 index 000000000..d829e291c --- /dev/null +++ b/app/src/main/res/layout/activity_audio_play.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file From f9525a2d2498c5c179a0cee636900650985d5df6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 29 Aug 2019 17:03:29 +0800 Subject: [PATCH 1122/1997] up --- .../java/io/legado/app/service/CheckSourceService.kt | 12 ++++-------- .../java/io/legado/app/service/DownloadService.kt | 12 ++++-------- .../main/java/io/legado/app/service/ShareService.kt | 12 ++++-------- .../main/java/io/legado/app/service/UpdateService.kt | 12 ++++-------- .../main/java/io/legado/app/service/WebService.kt | 12 ++++++------ 5 files changed, 22 insertions(+), 38 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/CheckSourceService.kt b/app/src/main/java/io/legado/app/service/CheckSourceService.kt index 060e89f19..247a137a9 100644 --- a/app/src/main/java/io/legado/app/service/CheckSourceService.kt +++ b/app/src/main/java/io/legado/app/service/CheckSourceService.kt @@ -1,12 +1,8 @@ package io.legado.app.service -import android.app.Service -import android.content.Intent -import android.os.IBinder - -class CheckSourceService : Service() { - override fun onBind(intent: Intent?): IBinder? { - return null - } +import io.legado.app.base.BaseService + +class CheckSourceService : BaseService() { + } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/service/DownloadService.kt b/app/src/main/java/io/legado/app/service/DownloadService.kt index 58baf3188..5a1233708 100644 --- a/app/src/main/java/io/legado/app/service/DownloadService.kt +++ b/app/src/main/java/io/legado/app/service/DownloadService.kt @@ -1,12 +1,8 @@ package io.legado.app.service -import android.app.Service -import android.content.Intent -import android.os.IBinder - -class DownloadService : Service() { - override fun onBind(intent: Intent?): IBinder? { - return null - } +import io.legado.app.base.BaseService + +class DownloadService : BaseService() { + } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/service/ShareService.kt b/app/src/main/java/io/legado/app/service/ShareService.kt index 0abfb5db9..49624ecc3 100644 --- a/app/src/main/java/io/legado/app/service/ShareService.kt +++ b/app/src/main/java/io/legado/app/service/ShareService.kt @@ -1,12 +1,8 @@ package io.legado.app.service -import android.app.Service -import android.content.Intent -import android.os.IBinder - -class ShareService : Service() { - override fun onBind(intent: Intent?): IBinder? { - return null - } +import io.legado.app.base.BaseService + +class ShareService : BaseService() { + } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/service/UpdateService.kt b/app/src/main/java/io/legado/app/service/UpdateService.kt index 266d0a5bd..9841d1b9a 100644 --- a/app/src/main/java/io/legado/app/service/UpdateService.kt +++ b/app/src/main/java/io/legado/app/service/UpdateService.kt @@ -1,12 +1,8 @@ package io.legado.app.service -import android.app.Service -import android.content.Intent -import android.os.IBinder - -class UpdateService : Service() { - override fun onBind(intent: Intent?): IBinder? { - return null - } +import io.legado.app.base.BaseService + +class UpdateService : BaseService() { + } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/service/WebService.kt b/app/src/main/java/io/legado/app/service/WebService.kt index 366a48ede..99334fd1c 100644 --- a/app/src/main/java/io/legado/app/service/WebService.kt +++ b/app/src/main/java/io/legado/app/service/WebService.kt @@ -1,12 +1,12 @@ package io.legado.app.service -import android.app.Service -import android.content.Intent -import android.os.IBinder +import io.legado.app.base.BaseService -class WebService : Service() { - override fun onBind(intent: Intent?): IBinder? { - return null +class WebService : BaseService() { + + + override fun onCreate() { + super.onCreate() } } \ No newline at end of file From 6843f39ccf663e96f093665b09d6e83a3299ebdf Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 29 Aug 2019 17:10:53 +0800 Subject: [PATCH 1123/1997] up --- .../java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt | 2 +- .../java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt | 2 ++ app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt index fc096de5f..938424fe2 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt @@ -50,7 +50,6 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio execute { val bookSourceList = App.db.bookSourceDao().allEnabled for (item in bookSourceList) { - delay(100) //task取消时自动取消 by (scope = this@execute) WebBook(item).searchBook(name, scope = this@execute) .timeout(30000L) @@ -68,6 +67,7 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio } } } + delay(100) } } } diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt index 451b6443f..0accc1813 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt @@ -9,6 +9,7 @@ import io.legado.app.data.entities.BookGroup import io.legado.app.model.WebBook import io.legado.app.utils.postEvent import kotlinx.coroutines.Dispatchers.IO +import kotlinx.coroutines.delay class BookshelfViewModel(application: Application) : BaseViewModel(application) { @@ -48,6 +49,7 @@ class BookshelfViewModel(application: Application) : BaseViewModel(application) } } } + delay(50) } } } diff --git a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt b/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt index 33381933b..0fbb8c772 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt @@ -29,7 +29,6 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { //onCleared时自动取消 val bookSourceList = App.db.bookSourceDao().allEnabled for (item in bookSourceList) { - delay(100)//每隔100毫秒搜索一个书源 //task取消时自动取消 by (scope = this@execute) WebBook(item).searchBook(key, searchPage, scope = this@execute) .timeout(30000L) @@ -41,6 +40,7 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { } } } + delay(100)//每隔100毫秒搜索一个书源 } }.onError { it.printStackTrace() From fd09c699eb3b321aa39126bda3f138fb285fff53 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 29 Aug 2019 18:06:17 +0800 Subject: [PATCH 1124/1997] up --- .../page/ContentSelectActionCallback.kt | 32 +++++++++++++++++++ .../legado/app/ui/widget/page/ContentView.kt | 1 + .../main/res/menu/content_select_action.xml | 9 ++++++ 3 files changed, 42 insertions(+) create mode 100644 app/src/main/java/io/legado/app/ui/widget/page/ContentSelectActionCallback.kt create mode 100644 app/src/main/res/menu/content_select_action.xml diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentSelectActionCallback.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentSelectActionCallback.kt new file mode 100644 index 000000000..91ef6e1b2 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentSelectActionCallback.kt @@ -0,0 +1,32 @@ +package io.legado.app.ui.widget.page + +import android.view.ActionMode +import android.view.Menu +import android.view.MenuItem + +import io.legado.app.R + +object ContentSelectActionCallback : ActionMode.Callback { + + override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean { + when (item?.itemId) { + R.id.menu_replace -> { + } + } + return false + } + + override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean { + mode?.menuInflater?.inflate(R.menu.content_select_action, menu) + return true + } + + override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean { + return false + } + + override fun onDestroyActionMode(mode: ActionMode?) { + + } + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index d1b33ce0a..469e2d2a6 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -42,6 +42,7 @@ class ContentView : FrameLayout { inflate(context, R.layout.view_book_page, this) upStyle() upTime() + content_text_view.customSelectionActionModeCallback = ContentSelectActionCallback } fun upStyle() { diff --git a/app/src/main/res/menu/content_select_action.xml b/app/src/main/res/menu/content_select_action.xml new file mode 100644 index 000000000..d83b82ef3 --- /dev/null +++ b/app/src/main/res/menu/content_select_action.xml @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file From c63654c811277e4261a4066e7966bfdc859fc2bc Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 29 Aug 2019 18:10:12 +0800 Subject: [PATCH 1125/1997] up --- app/src/main/res/layout/activity_replace_rule.xml | 2 +- app/src/main/res/values/strings.xml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/layout/activity_replace_rule.xml b/app/src/main/res/layout/activity_replace_rule.xml index 116ac4aef..b703b0371 100644 --- a/app/src/main/res/layout/activity_replace_rule.xml +++ b/app/src/main/res/layout/activity_replace_rule.xml @@ -11,7 +11,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_constraintTop_toTopOf="parent" - app:title="@string/replace" /> + app:title="@string/replace_purify" /> 编辑 删除 - 净化替换 + 替换 + 替换净化 暂无 启用 From bc25adb075721f786325b77fc5e937b76e4c1a3a Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 29 Aug 2019 18:14:56 +0800 Subject: [PATCH 1126/1997] up --- .../legado/app/ui/widget/page/ContentSelectActionCallback.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentSelectActionCallback.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentSelectActionCallback.kt index 91ef6e1b2..fe3264cdb 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentSelectActionCallback.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentSelectActionCallback.kt @@ -11,6 +11,9 @@ object ContentSelectActionCallback : ActionMode.Callback { override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean { when (item?.itemId) { R.id.menu_replace -> { + + mode?.finish() + return true } } return false From b840b800da77abac048db5aab1539587f183b456 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 29 Aug 2019 19:39:54 +0800 Subject: [PATCH 1127/1997] up --- .../io/legado/app/ui/widget/font/FontSelectDialog.kt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt index 5580f31a8..b276072b4 100644 --- a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt +++ b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt @@ -2,14 +2,15 @@ package io.legado.app.ui.widget.font import android.annotation.SuppressLint import android.content.Context -import android.content.DialogInterface import android.os.Environment import android.view.LayoutInflater import android.view.View +import androidx.appcompat.app.AlertDialog import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.R import io.legado.app.lib.dialogs.AlertBuilder import io.legado.app.lib.dialogs.alert +import io.legado.app.utils.applyTint import io.legado.app.utils.invisible import io.legado.app.utils.visible import kotlinx.android.synthetic.main.dialog_font_select.view.* @@ -20,8 +21,8 @@ class FontSelectDialog(context: Context) : FontAdapter.CallBack { private val defaultFolder = Environment.getExternalStorageDirectory().absolutePath + File.separator + "Fonts" private lateinit var adapter: FontAdapter - private var builder: AlertBuilder - private var dialog: DialogInterface? = null + private var builder: AlertBuilder + private var dialog: AlertDialog? = null @SuppressLint("InflateParams") private var view: View = LayoutInflater.from(context).inflate(R.layout.dialog_font_select, null) var curPath: String? = null @@ -39,7 +40,7 @@ class FontSelectDialog(context: Context) : FontAdapter.CallBack { } fun show() { - dialog = builder.show() + dialog = builder.show().applyTint() } private fun initData() = with(view) { From b59da2fa81ce7e2bfa5a92396b2ab94f454d37cc Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 29 Aug 2019 19:50:03 +0800 Subject: [PATCH 1128/1997] up --- app/src/main/java/io/legado/app/App.kt | 18 ++++++++++++++---- app/src/main/res/values-night/colors.xml | 4 ++++ app/src/main/res/values/colors.xml | 6 +++--- app/src/main/res/xml/pref_config_theme.xml | 8 ++++---- 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/io/legado/app/App.kt b/app/src/main/java/io/legado/app/App.kt index 742f67e7c..b28924a1c 100644 --- a/app/src/main/java/io/legado/app/App.kt +++ b/app/src/main/java/io/legado/app/App.kt @@ -68,14 +68,24 @@ class App : Application() { fun applyTheme() { if (isNightTheme) { ThemeStore.editTheme(this) - .primaryColor(getPrefInt("colorPrimaryNight", getCompatColor(R.color.colorPrimary))) - .accentColor(getPrefInt("colorAccentNight", getCompatColor(R.color.colorAccent))) + .primaryColor( + getPrefInt( + "colorPrimaryNight", + getCompatColor(R.color.md_blue_grey_600) + ) + ) + .accentColor( + getPrefInt( + "colorAccentNight", + getCompatColor(R.color.md_deep_orange_800) + ) + ) .backgroundColor(getPrefInt("colorBackgroundNight", getCompatColor(R.color.md_grey_800))) .apply() } else { ThemeStore.editTheme(this) - .primaryColor(getPrefInt("colorPrimary", getCompatColor(R.color.colorPrimary))) - .accentColor(getPrefInt("colorAccent", getCompatColor(R.color.colorAccent))) + .primaryColor(getPrefInt("colorPrimary", getCompatColor(R.color.md_light_blue_500))) + .accentColor(getPrefInt("colorAccent", getCompatColor(R.color.md_pink_800))) .backgroundColor(getPrefInt("colorBackground", getCompatColor(R.color.md_grey_100))) .apply() } diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml index 2e4227f8b..c10a0bfb1 100644 --- a/app/src/main/res/values-night/colors.xml +++ b/app/src/main/res/values-night/colors.xml @@ -1,5 +1,9 @@ + @color/md_blue_grey_600 + @color/md_blue_grey_700 + @color/md_deep_orange_800 + @color/md_grey_800 #353535 #282828 diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 06b21555d..d5b3e1f54 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -1,8 +1,8 @@ - @color/md_light_blue_500 - @color/md_light_blue_600 - @color/md_pink_A400 + @color/md_light_blue_600 + @color/md_light_blue_700 + @color/md_pink_800 #66666666 #eb4333 diff --git a/app/src/main/res/xml/pref_config_theme.xml b/app/src/main/res/xml/pref_config_theme.xml index 71af6eeba..35f4f46e4 100644 --- a/app/src/main/res/xml/pref_config_theme.xml +++ b/app/src/main/res/xml/pref_config_theme.xml @@ -34,7 +34,7 @@ app:iconSpaceReserved="false"> Date: Thu, 29 Aug 2019 20:11:25 +0800 Subject: [PATCH 1129/1997] up --- app/src/main/java/io/legado/app/constant/Bus.kt | 1 + .../java/io/legado/app/ui/readbook/ReadBookActivity.kt | 3 +++ .../app/ui/widget/page/ContentSelectActionCallback.kt | 7 +++++-- .../main/java/io/legado/app/ui/widget/page/ContentView.kt | 3 ++- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/constant/Bus.kt b/app/src/main/java/io/legado/app/constant/Bus.kt index 96ec93b5e..eb2783a8f 100644 --- a/app/src/main/java/io/legado/app/constant/Bus.kt +++ b/app/src/main/java/io/legado/app/constant/Bus.kt @@ -12,4 +12,5 @@ object Bus { const val READ_ALOUD_BUTTON = "readAloudButton" const val UP_CONFIG = "upConfig" const val OPEN_CHAPTER = "openChapter" + const val REPLACE = "replace" } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 7c0da36d6..5c1edd2d1 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -498,6 +498,9 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea viewModel.saveRead() } } + observeEvent(Bus.REPLACE) { + toast(it) + } } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentSelectActionCallback.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentSelectActionCallback.kt index fe3264cdb..e8e8af8d4 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentSelectActionCallback.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentSelectActionCallback.kt @@ -5,13 +5,16 @@ import android.view.Menu import android.view.MenuItem import io.legado.app.R +import io.legado.app.constant.Bus +import io.legado.app.utils.postEvent -object ContentSelectActionCallback : ActionMode.Callback { +class ContentSelectActionCallback(private val textView: ContentTextView) : ActionMode.Callback { override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean { when (item?.itemId) { R.id.menu_replace -> { - + val text = textView.text.substring(textView.selectionStart, textView.selectionEnd) + postEvent(Bus.REPLACE, text) mode?.finish() return true } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index 469e2d2a6..2608a5f94 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -42,7 +42,8 @@ class ContentView : FrameLayout { inflate(context, R.layout.view_book_page, this) upStyle() upTime() - content_text_view.customSelectionActionModeCallback = ContentSelectActionCallback + content_text_view.customSelectionActionModeCallback = + ContentSelectActionCallback(content_text_view) } fun upStyle() { From 9fce7b7c920dbae15626c1e06eeb413eaa5b9e6f Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 29 Aug 2019 21:41:31 +0800 Subject: [PATCH 1130/1997] up --- .../app/ui/readbook/config/ReadStyleDialog.kt | 37 +++++++++---------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt index 53fafd0cf..758e87fb5 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt @@ -13,6 +13,7 @@ import io.legado.app.R import io.legado.app.constant.Bus import io.legado.app.help.ImageLoader import io.legado.app.help.ReadBookConfig +import io.legado.app.lib.dialogs.selector import io.legado.app.lib.theme.accentColor import io.legado.app.lib.theme.primaryColor import io.legado.app.ui.readbook.Help @@ -99,6 +100,15 @@ class ReadStyleDialog : DialogFragment() { } }.show() } + tv_text_indent.onClick { + selector( + title = getString(R.string.text_indent), + items = resources.getStringArray(R.array.indent).toList() + ) { _, index -> + putPrefInt("textIndent", index) + postEvent(Bus.UP_CONFIG, true) + } + } tv_padding.onClick { val activity = activity dismiss() @@ -111,6 +121,7 @@ class ReadStyleDialog : DialogFragment() { textSize = progress + 5 tv_text_size.text = textSize.toString() } + override fun onStartTrackingTouch(seekBar: SeekBar?) {} override fun onStopTrackingTouch(seekBar: SeekBar?) { postEvent(Bus.UP_CONFIG, true) @@ -236,11 +247,7 @@ class ReadStyleDialog : DialogFragment() { } ReadBookConfig.getConfig(i).apply { when (bgType()) { - 2 -> { - ImageLoader.load(requireContext(), bgStr()) - .centerCrop() - .setAsFile(iv) - } + 2 -> ImageLoader.load(requireContext(), bgStr()).centerCrop().setAsFile(iv) else -> iv.setImageDrawable(bgDrawable()) } } @@ -254,21 +261,11 @@ class ReadStyleDialog : DialogFragment() { bg3.borderColor = requireContext().primaryColor bg4.borderColor = requireContext().primaryColor when (ReadBookConfig.styleSelect) { - 1 -> { - bg1.borderColor = requireContext().accentColor - } - 2 -> { - bg2.borderColor = requireContext().accentColor - } - 3 -> { - bg3.borderColor = requireContext().accentColor - } - 4 -> { - bg4.borderColor = requireContext().accentColor - } - else -> { - bg0.borderColor = requireContext().accentColor - } + 1 -> bg1.borderColor = requireContext().accentColor + 2 -> bg2.borderColor = requireContext().accentColor + 3 -> bg3.borderColor = requireContext().accentColor + 4 -> bg4.borderColor = requireContext().accentColor + else -> bg0.borderColor = requireContext().accentColor } } } \ No newline at end of file From 9bad3ddebff107485600da8d51bc4942722fdc1a Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 29 Aug 2019 22:06:23 +0800 Subject: [PATCH 1131/1997] up --- app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 5c1edd2d1..afbd7eb26 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -464,7 +464,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea if (it) { onClickReadAloud() } else { - readAloud() + readAloud(readAloudStatus == Status.PLAY) } } observeEvent(Bus.UP_CONFIG) { From ebbc4b7325790bc9dec67fe0d479cfa6e3bf6b1a Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 29 Aug 2019 22:47:33 +0800 Subject: [PATCH 1132/1997] up --- .../java/io/legado/app/ui/readbook/ReadBookActivity.kt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index afbd7eb26..780000f4c 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -3,12 +3,14 @@ package io.legado.app.ui.readbook import android.app.Activity import android.content.Intent import android.net.Uri +import android.os.Build import android.os.Bundle import android.text.SpannableStringBuilder import android.view.KeyEvent import android.view.Menu import android.view.MenuItem import android.view.WindowManager +import android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES import androidx.core.view.isVisible import androidx.lifecycle.Observer import io.legado.app.R @@ -61,6 +63,11 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea var readAloudStatus = Status.STOP override fun onActivityCreated(savedInstanceState: Bundle?) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + window.attributes = window.attributes.apply { + layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES + } + } setSupportActionBar(toolbar) initView() page_view.callback = this From c4245e171c50cbeea781e64f11456352e6c0f1d4 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 29 Aug 2019 22:56:54 +0800 Subject: [PATCH 1133/1997] up --- app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt | 1 + app/src/main/res/layout/view_book_page.xml | 1 + 2 files changed, 2 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index 2608a5f94..121280b9e 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -40,6 +40,7 @@ class ContentView : FrameLayout { setBackgroundColor(context.getCompatColor(R.color.background)) addView(bgImage, LayoutParams(matchParent, matchParent)) inflate(context, R.layout.view_book_page, this) + top_bar.layoutParams.height = context.getStatusBarHeight() upStyle() upTime() content_text_view.customSelectionActionModeCallback = diff --git a/app/src/main/res/layout/view_book_page.xml b/app/src/main/res/layout/view_book_page.xml index db8340877..59784756f 100644 --- a/app/src/main/res/layout/view_book_page.xml +++ b/app/src/main/res/layout/view_book_page.xml @@ -12,6 +12,7 @@ android:id="@+id/top_bar" android:layout_width="match_parent" android:layout_height="wrap_content" + android:gravity="center_vertical" android:orientation="horizontal"> Date: Fri, 30 Aug 2019 10:57:59 +0800 Subject: [PATCH 1134/1997] up --- .../io/legado/app/data/dao/ReplaceRuleDao.kt | 11 ++++- .../io/legado/app/data/dao/SearchBookDao.kt | 12 +++--- .../legado/app/data/entities/ReplaceRule.kt | 4 +- .../main/java/io/legado/app/help/BookHelp.kt | 42 +++++++++++++++++-- .../app/ui/readbook/ReadBookViewModel.kt | 12 +++++- 5 files changed, 65 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt b/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt index f65588378..b291ac968 100644 --- a/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt @@ -30,9 +30,18 @@ interface ReplaceRuleDao { @Query("SELECT * FROM replace_rules WHERE id in (:ids)") fun findByIds(vararg ids: Int): List - @Query("SELECT * FROM replace_rules WHERE isEnabled = 1 AND scope LIKE '%' || :scope || '%'") + @Query( + """SELECT * FROM replace_rules WHERE isEnabled = 1 + AND (scope LIKE '%' || :scope || '%' or scope = null or scope = '')""" + ) fun findEnabledByScope(scope: String): List + @Query( + """SELECT * FROM replace_rules WHERE isEnabled = 1 + AND (scope LIKE '%' || :name || '%' or scope LIKE '%' || :origin || '%' or scope = null or scope = '')""" + ) + fun findEnabledByScope(name: String, origin: String): List + @get:Query("SELECT COUNT(*) - SUM(isEnabled) FROM replace_rules") val summary: Int diff --git a/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt b/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt index 5d928c42a..a8b61a068 100644 --- a/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/SearchBookDao.kt @@ -12,13 +12,11 @@ import io.legado.app.data.entities.SearchShow interface SearchBookDao { @Query( - """ - SELECT name, author, min(time) time, max(kind) kind, max(coverUrl) coverUrl,max(intro) intro, max(wordCount) wordCount, - max(latestChapterTitle) latestChapterTitle, count(origin) originCount - FROM searchBooks where time >= :time - group by name, author - order by case when name = :key then 1 when author = :key then 2 when name like '%'+:key+'%' then 3 when author like '%'+:key+'%' then 4 else 5 end, time - """ + """SELECT name, author, min(time) time, max(kind) kind, max(coverUrl) coverUrl,max(intro) intro, max(wordCount) wordCount, + max(latestChapterTitle) latestChapterTitle, count(origin) originCount + FROM searchBooks where time >= :time + group by name, author + order by case when name = :key then 1 when author = :key then 2 when name like '%'||:key||'%' then 3 when author like '%'||:key||'%' then 4 else 5 end, time""" ) fun observeShow(key: String, time: Long): DataSource.Factory diff --git a/app/src/main/java/io/legado/app/data/entities/ReplaceRule.kt b/app/src/main/java/io/legado/app/data/entities/ReplaceRule.kt index e43699c36..65b070d57 100644 --- a/app/src/main/java/io/legado/app/data/entities/ReplaceRule.kt +++ b/app/src/main/java/io/legado/app/data/entities/ReplaceRule.kt @@ -23,6 +23,4 @@ data class ReplaceRule( var isRegex: Boolean = true, @ColumnInfo(name = "sortOrder") var order: Int = 0 -) : Parcelable - - +) : Parcelable \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/help/BookHelp.kt b/app/src/main/java/io/legado/app/help/BookHelp.kt index 83d8de8e5..9fc9206d1 100644 --- a/app/src/main/java/io/legado/app/help/BookHelp.kt +++ b/app/src/main/java/io/legado/app/help/BookHelp.kt @@ -3,6 +3,8 @@ package io.legado.app.help import io.legado.app.App import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter +import io.legado.app.data.entities.ReplaceRule +import io.legado.app.utils.getPrefInt import io.legado.app.utils.getPrefString import java.io.BufferedWriter import java.io.File @@ -11,10 +13,12 @@ import java.io.IOException object BookHelp { - private var downloadPath = App.INSTANCE.getPrefString("downloadPath") ?: App.INSTANCE.getExternalFilesDir(null) + private var downloadPath = + App.INSTANCE.getPrefString("downloadPath") ?: App.INSTANCE.getExternalFilesDir(null) fun upDownloadPath() { - downloadPath = App.INSTANCE.getPrefString("downloadPath") ?: App.INSTANCE.getExternalFilesDir(null) + downloadPath = + App.INSTANCE.getPrefString("downloadPath") ?: App.INSTANCE.getExternalFilesDir(null) } fun saveContent(book: Book, bookChapter: BookChapter, content: String) { @@ -69,7 +73,8 @@ object BookHelp { private fun getChapterPath(book: Book, bookChapter: BookChapter): String { val bookFolder = formatFolderName(book.name + book.bookUrl) - val chapterFile = String.format("%05d-%s", bookChapter.index, formatFolderName(bookChapter.title)) + val chapterFile = + String.format("%05d-%s", bookChapter.index, formatFolderName(bookChapter.title)) return "$downloadPath${File.separator}book_cache${File.separator}$bookFolder${File.separator}$chapterFile.nb" } @@ -88,4 +93,35 @@ object BookHelp { fun getDurChapterIndexByChapterName() { } + + var bookName: String? = null + var bookOrigin: String? = null + var replaceRules: List = arrayListOf() + + fun disposeContent(name: String, origin: String?, content: String, enableReplace: Boolean) + : String { + var c = content + synchronized(this) { + if (enableReplace && (bookName != name || bookOrigin != origin)) { + replaceRules = if (origin.isNullOrEmpty()) { + App.db.replaceRuleDao().findEnabledByScope(name) + } else { + App.db.replaceRuleDao().findEnabledByScope(name, origin) + } + } + } + for (item in replaceRules) { + item.pattern?.let { + if (it.isNotEmpty()) { + c = if (item.isRegex) { + c.replace(it.toRegex(), item.replacement ?: "") + } else { + c.replace(it, item.replacement ?: "") + } + } + } + } + val indent = App.INSTANCE.getPrefInt("textIndent", 2) + return c.replace("\\s*\\n+\\s*".toRegex(), "\n" + " ".repeat(indent)) + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index 443543bc4..7fe1db4fc 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -197,8 +197,16 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } private fun contentLoadFinish(chapter: BookChapter, content: String) { - if (chapter.index in durChapterIndex - 1..durChapterIndex + 1) { - callBack?.contentLoadFinish(chapter, content) + execute { + if (chapter.index in durChapterIndex - 1..durChapterIndex + 1) { + val c = BookHelp.disposeContent( + bookData.value?.name ?: "", + webBook?.bookSource?.bookSourceUrl, + content, + bookData.value?.useReplaceRule ?: true + ) + callBack?.contentLoadFinish(chapter, c) + } } } From d7f66b83e0afa36d360b78c0ce5dbb06f6daee31 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 30 Aug 2019 11:55:00 +0800 Subject: [PATCH 1135/1997] up --- .../main/java/io/legado/app/help/BookHelp.kt | 27 ++++++++++++- .../app/ui/changesource/ChangeSourceDialog.kt | 2 +- .../io/legado/app/utils/StringExtensions.kt | 39 ++++++++++++++++++- 3 files changed, 64 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/BookHelp.kt b/app/src/main/java/io/legado/app/help/BookHelp.kt index 9fc9206d1..c121e1781 100644 --- a/app/src/main/java/io/legado/app/help/BookHelp.kt +++ b/app/src/main/java/io/legado/app/help/BookHelp.kt @@ -6,10 +6,13 @@ import io.legado.app.data.entities.BookChapter import io.legado.app.data.entities.ReplaceRule import io.legado.app.utils.getPrefInt import io.legado.app.utils.getPrefString +import io.legado.app.utils.similarity import java.io.BufferedWriter import java.io.File import java.io.FileWriter import java.io.IOException +import kotlin.math.max +import kotlin.math.min object BookHelp { @@ -90,8 +93,28 @@ object BookHelp { ?: "" } - fun getDurChapterIndexByChapterName() { - + fun getDurChapterIndexByChapterTitle( + title: String, + index: Int, + chapters: List + ): Int { + if (chapters.size > index && title == chapters[index].title) { + return index + } + var similarity = 0F + var newIndex = index + val start = max(index - 10, 0) + val end = min(index + 10, chapters.size - 1) + if (start < end) { + for (i in start..end) { + val s = title.similarity(chapters[i].title) + if (s > similarity) { + similarity = s + newIndex = i + } + } + } + return newIndex } var bookName: String? = null diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt index 15e830033..b4ff6b8ba 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt @@ -117,8 +117,8 @@ class ChangeSourceDialog : DialogFragment(), if (book.coverUrl.isNullOrEmpty()) { book.coverUrl = oldBook.getDisplayCover() } + activity.changeTo(book) } - activity.changeTo(book) } dismiss() } diff --git a/app/src/main/java/io/legado/app/utils/StringExtensions.kt b/app/src/main/java/io/legado/app/utils/StringExtensions.kt index 0100b5f9f..856a6c2d9 100644 --- a/app/src/main/java/io/legado/app/utils/StringExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/StringExtensions.kt @@ -1,5 +1,7 @@ package io.legado.app.utils +import kotlin.math.min + // import org.apache.commons.text.StringEscapeUtils fun String?.safeTrim() = if (this.isNullOrBlank()) null else this.trim() @@ -33,4 +35,39 @@ fun String.splitNotBlank(regex: Regex, limit: Int = 0): Array = run { fun String.startWithIgnoreCase(start: String): Boolean { return if (this.isBlank()) false else startsWith(start, true) -} \ No newline at end of file +} + + +fun String.similarity(target: String): Float { + //计算两个字符串的长度。 + val len1 = this.length + val len2 = target.length + //建立上面说的数组,比字符长度大一个空间 + val dif = Array(len1 + 1) { IntArray(len2 + 1) } + //赋初值,步骤B。 + for (a in 0..len1) { + dif[a][0] = a + } + for (a in 0..len2) { + dif[0][a] = a + } + //计算两个字符是否一样,计算左上的值 + var temp: Int + for (i in 1..len1) { + for (j in 1..len2) { + temp = if (this[i - 1] == target[j - 1]) { + 0 + } else { + 1 + } + //取三个值中最小的 + dif[i][j] = min( + min(dif[i - 1][j - 1] + temp, dif[i][j - 1] + 1), + dif[i - 1][j] + 1 + ) + } + } + //计算相似度 + return 1 - dif[len1][len2].toFloat() / Math.max(length, target.length) +} + From ce60781a3fb68a7720c907eeda677544cab3e4ee Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 30 Aug 2019 12:17:44 +0800 Subject: [PATCH 1136/1997] up --- .../main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt | 6 ++++++ app/src/main/res/menu/book_info.xml | 1 - 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index 31af4fda5..639e260eb 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -67,6 +67,12 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo } } } + R.id.menu_refresh -> { + upLoading(true) + viewModel.bookData.value?.let { + viewModel.loadBookInfo(it) + } + } } return super.onCompatOptionsItemSelected(item) } diff --git a/app/src/main/res/menu/book_info.xml b/app/src/main/res/menu/book_info.xml index 762942705..382762455 100644 --- a/app/src/main/res/menu/book_info.xml +++ b/app/src/main/res/menu/book_info.xml @@ -10,7 +10,6 @@ From 1eab69c288ea85d7bca5a6b539818f49c82d7518 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 30 Aug 2019 12:21:49 +0800 Subject: [PATCH 1137/1997] up --- .../io/legado/app/ui/bookinfo/BookInfoViewModel.kt | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt index 7b6c093bd..01308e15f 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt @@ -53,8 +53,13 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { isLoadingData.postValue(true) App.db.bookSourceDao().getBookSource(book.origin)?.let { bookSource -> WebBook(bookSource).getBookInfo(book, this) - .onSuccess { - it?.let { loadChapter(it) } + .onSuccess(IO) { + it?.let { + if (inBookshelf) { + App.db.bookDao().update(book) + } + loadChapter(it) + } }.onError { toast(R.string.error_get_book_info) } @@ -62,7 +67,7 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { } } - fun loadChapter(book: Book) { + private fun loadChapter(book: Book) { execute { isLoadingData.postValue(true) App.db.bookSourceDao().getBookSource(book.origin)?.let { bookSource -> @@ -71,6 +76,7 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { it?.let { if (it.isNotEmpty()) { if (inBookshelf) { + App.db.bookDao().update(book) App.db.bookChapterDao().insert(*it.toTypedArray()) } chapterListData.postValue(it) From 1b2ace5e81e512d0cec206d4bd1b7a1af32e8742 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 30 Aug 2019 12:46:12 +0800 Subject: [PATCH 1138/1997] up --- .../main/java/io/legado/app/help/BookHelp.kt | 7 ++- .../app/ui/bookinfo/BookInfoViewModel.kt | 43 ++++++++++++++++--- 2 files changed, 41 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/BookHelp.kt b/app/src/main/java/io/legado/app/help/BookHelp.kt index c121e1781..187064ed8 100644 --- a/app/src/main/java/io/legado/app/help/BookHelp.kt +++ b/app/src/main/java/io/legado/app/help/BookHelp.kt @@ -94,17 +94,20 @@ object BookHelp { } fun getDurChapterIndexByChapterTitle( - title: String, + title: String?, index: Int, chapters: List ): Int { + if (title.isNullOrEmpty()) { + return min(index, chapters.lastIndex) + } if (chapters.size > index && title == chapters[index].title) { return index } var similarity = 0F var newIndex = index val start = max(index - 10, 0) - val end = min(index + 10, chapters.size - 1) + val end = min(index + 10, chapters.lastIndex) if (start < end) { for (i in start..end) { val s = title.similarity(chapters[i].title) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt index 01308e15f..21a1b83ca 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt @@ -8,6 +8,7 @@ import io.legado.app.R import io.legado.app.base.BaseViewModel import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter +import io.legado.app.help.BookHelp import io.legado.app.model.WebBook import kotlinx.coroutines.Dispatchers.IO @@ -48,7 +49,10 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { } } - fun loadBookInfo(book: Book) { + fun loadBookInfo( + book: Book, + changeDruChapterIndex: ((chapters: List) -> Unit)? = null + ) { execute { isLoadingData.postValue(true) App.db.bookSourceDao().getBookSource(book.origin)?.let { bookSource -> @@ -58,7 +62,7 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { if (inBookshelf) { App.db.bookDao().update(book) } - loadChapter(it) + loadChapter(it, changeDruChapterIndex) } }.onError { toast(R.string.error_get_book_info) @@ -67,7 +71,10 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { } } - private fun loadChapter(book: Book) { + private fun loadChapter( + book: Book, + changeDruChapterIndex: ((chapters: List) -> Unit)? = null + ) { execute { isLoadingData.postValue(true) App.db.bookSourceDao().getBookSource(book.origin)?.let { bookSource -> @@ -79,12 +86,19 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { App.db.bookDao().update(book) App.db.bookChapterDao().insert(*it.toTypedArray()) } - chapterListData.postValue(it) - isLoadingData.postValue(false) + if (changeDruChapterIndex == null) { + chapterListData.postValue(it) + isLoadingData.postValue(false) + } else { + changeDruChapterIndex(it) + } + } else { + toast(R.string.chapter_list_empty) } } }.onError { toast(R.string.error_get_chapter_list) + it.printStackTrace() } } ?: toast(R.string.error_no_source) } @@ -100,13 +114,28 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { } bookData.postValue(book) if (book.tocUrl.isEmpty()) { - loadBookInfo(book) + loadBookInfo(book) { upChangeDurChapterIndex(book, it) } } else { - loadChapter(book) + loadChapter(book) { upChangeDurChapterIndex(book, it) } } } } + private fun upChangeDurChapterIndex(book: Book, chapters: List) { + execute { + book.durChapterIndex = BookHelp.getDurChapterIndexByChapterTitle( + book.durChapterTitle, + book.durChapterIndex, + chapters + ) + book.durChapterTitle = chapters[book.durChapterIndex].title + App.db.bookDao().update(book) + App.db.bookChapterDao().insert(*chapters.toTypedArray()) + bookData.postValue(book) + chapterListData.postValue(chapters) + } + } + fun saveBook(success: (() -> Unit)?) { execute { bookData.value?.let { book -> From 4be2f8d2b1abb0030fe32fa0002a1696ba589ca6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 30 Aug 2019 13:49:07 +0800 Subject: [PATCH 1139/1997] up --- .../app/ui/readbook/ReadBookViewModel.kt | 42 +++++++++++++++---- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index 7fe1db4fc..78b743705 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -69,23 +69,33 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { }.onError { it.printStackTrace() } } - private fun loadBookInfo(book: Book) { + private fun loadBookInfo( + book: Book, + changeDruChapterIndex: ((chapters: List) -> Unit)? = null + ) { execute { webBook?.getBookInfo(book, this) ?.onSuccess { - loadChapterList(book) + loadChapterList(book, changeDruChapterIndex) } } } - private fun loadChapterList(book: Book) { + private fun loadChapterList( + book: Book, + changeDruChapterIndex: ((chapters: List) -> Unit)? = null + ) { execute { webBook?.getChapterList(book, this) ?.onSuccess(IO) { cList -> if (!cList.isNullOrEmpty()) { - App.db.bookChapterDao().insert(*cList.toTypedArray()) - chapterSize = cList.size - chapterListFinish.postValue(true) + if (changeDruChapterIndex == null) { + App.db.bookChapterDao().insert(*cList.toTypedArray()) + chapterSize = cList.size + chapterListFinish.postValue(true) + } else { + changeDruChapterIndex(cList) + } } else { toast(R.string.error_load_toc) } @@ -221,9 +231,9 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { webBook = WebBook(it) } if (book.tocUrl.isEmpty()) { - loadBookInfo(book) + loadBookInfo(book) { upChangeDurChapterIndex(book, it) } } else { - loadChapterList(book) + loadChapterList(book) { upChangeDurChapterIndex(book, it) } } } } @@ -232,6 +242,22 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } + private fun upChangeDurChapterIndex(book: Book, chapters: List) { + execute { + durChapterIndex = BookHelp.getDurChapterIndexByChapterTitle( + book.durChapterTitle, + book.durChapterIndex, + chapters + ) + book.durChapterIndex = durChapterIndex + book.durChapterTitle = chapters[durChapterIndex].title + App.db.bookDao().update(book) + App.db.bookChapterDao().insert(*chapters.toTypedArray()) + chapterSize = chapters.size + chapterListFinish.postValue(true) + } + } + fun openChapter(chapter: BookChapter) { prevTextChapter = null curTextChapter = null From 8679723300b1e2ecb5e95d9015a2385f23f27784 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 30 Aug 2019 14:17:37 +0800 Subject: [PATCH 1140/1997] up --- .../java/io/legado/app/ui/readbook/ReadBookActivity.kt | 5 +++++ .../java/io/legado/app/ui/readbook/ReadBookViewModel.kt | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 780000f4c..46944a4ea 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -190,6 +190,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { R.id.menu_change_source -> { + read_menu.runMenuOut() if (changeSourceDialog == null) { viewModel.bookData.value?.let { changeSourceDialog = ChangeSourceDialog @@ -287,6 +288,10 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } + override fun upContent() { + page_view.upContent() + } + private fun curChapterChanged() { viewModel.curTextChapter?.let { tv_chapter_name.text = it.title diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index 78b743705..b1d706b33 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -42,7 +42,6 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } else { App.db.bookDao().lastReadBook } - saveRead(book) book?.let { durChapterIndex = book.durChapterIndex durPageIndex = book.durChapterPos @@ -66,6 +65,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { chapterListFinish.postValue(true) } } + saveRead(book) }.onError { it.printStackTrace() } } @@ -225,6 +225,10 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { bookData.value?.let { App.db.bookDao().delete(it.bookUrl) } + prevTextChapter = null + curTextChapter = null + nextTextChapter = null + callBack?.upContent() App.db.bookDao().insert(book) bookData.postValue(book) App.db.bookSourceDao().getBookSource(book.origin)?.let { @@ -321,5 +325,6 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { interface CallBack { fun contentLoadFinish(bookChapter: BookChapter, content: String) + fun upContent() } } \ No newline at end of file From 99a5105cd2bff0446722442008a9684bf833a323 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 30 Aug 2019 14:23:57 +0800 Subject: [PATCH 1141/1997] up --- .../java/io/legado/app/ui/readbook/ReadBookViewModel.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index b1d706b33..5bfac5ea9 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -14,8 +14,10 @@ import io.legado.app.model.WebBook import io.legado.app.service.ReadAloudService import io.legado.app.ui.widget.page.TextChapter import kotlinx.coroutines.Dispatchers.IO +import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.delay import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext class ReadBookViewModel(application: Application) : BaseViewModel(application) { var inBookshelf = false @@ -228,7 +230,9 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { prevTextChapter = null curTextChapter = null nextTextChapter = null - callBack?.upContent() + withContext(Main) { + callBack?.upContent() + } App.db.bookDao().insert(book) bookData.postValue(book) App.db.bookSourceDao().getBookSource(book.origin)?.let { From 94fdb645577137c76bf7887169b611a61d30223f Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 30 Aug 2019 14:48:53 +0800 Subject: [PATCH 1142/1997] up --- app/src/main/java/io/legado/app/lib/webdav/WebDav.kt | 4 ++-- .../java/io/legado/app/lib/webdav/http/HttpAuth.kt | 5 ----- .../main/java/io/legado/app/lib/webdav/http/OkHttp.kt | 10 +++------- 3 files changed, 5 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt b/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt index 4ca1966c8..f35e41db3 100644 --- a/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt +++ b/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt @@ -32,7 +32,7 @@ constructor(url: String) { return field } - private val okHttpClient: OkHttpClient = OkHttp.SingletonHelper.okHttpClient + private val okHttpClient: OkHttpClient = OkHttp.okHttpClient val path: String get() = url.toString() @@ -207,7 +207,7 @@ constructor(url: String) { fun upload(localPath: String, contentType: String? = null): Boolean { val file = File(localPath) if (!file.exists()) return false - val mediaType = if (contentType == null) null else contentType.toMediaTypeOrNull() + val mediaType = contentType?.toMediaTypeOrNull() // 务必注意RequestBody不要嵌套,不然上传时内容可能会被追加多余的文件信息 val fileBody = RequestBody.create(mediaType, file) getUrl()?.let { diff --git a/app/src/main/java/io/legado/app/lib/webdav/http/HttpAuth.kt b/app/src/main/java/io/legado/app/lib/webdav/http/HttpAuth.kt index 3a6f31b48..07cab5855 100644 --- a/app/src/main/java/io/legado/app/lib/webdav/http/HttpAuth.kt +++ b/app/src/main/java/io/legado/app/lib/webdav/http/HttpAuth.kt @@ -3,11 +3,6 @@ package io.legado.app.lib.webdav.http object HttpAuth { var auth: Auth? = null - private set - - fun setAuth(user: String, password: String) { - auth = Auth(user, password) - } class Auth internal constructor(val user: String, val pass: String) diff --git a/app/src/main/java/io/legado/app/lib/webdav/http/OkHttp.kt b/app/src/main/java/io/legado/app/lib/webdav/http/OkHttp.kt index f088fc785..6861deb62 100644 --- a/app/src/main/java/io/legado/app/lib/webdav/http/OkHttp.kt +++ b/app/src/main/java/io/legado/app/lib/webdav/http/OkHttp.kt @@ -2,10 +2,6 @@ package io.legado.app.lib.webdav.http import okhttp3.OkHttpClient -class OkHttp private constructor() { - - object SingletonHelper { - val okHttpClient: OkHttpClient = OkHttpClient.Builder().build() - } - -} +object OkHttp { + val okHttpClient: OkHttpClient = OkHttpClient.Builder().build() +} \ No newline at end of file From c8466bc2147c63ca250cdd081f447da4d8efabf0 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 30 Aug 2019 15:38:14 +0800 Subject: [PATCH 1143/1997] up --- app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index 639e260eb..1709391b2 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -229,6 +229,7 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo } override fun changeTo(book: Book) { + upLoading(true) viewModel.changeTo(book) } From b1187f04638351727deea8e58dd49e224912c9cb Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 30 Aug 2019 16:06:54 +0800 Subject: [PATCH 1144/1997] up --- .../java/io/legado/app/help/ReadBookConfig.kt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index d2a9565ed..01e199eb8 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -8,6 +8,7 @@ import io.legado.app.utils.* import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch +import okhttp3.internal.toHexString import java.io.BufferedWriter import java.io.File import java.io.FileWriter @@ -111,6 +112,24 @@ object ReadBookConfig { var textColorNight: String = "#adadad", var textSize: Int = 15 ) { + fun setBg(bgType: Int, bg: String) { + if (App.INSTANCE.isNightTheme) { + bgTypeNight = bgType + bgStrNight = bg + } else { + this.bgType = bgType + bgStr = bg + } + } + + fun setTextColor(color: Int) { + if (App.INSTANCE.isNightTheme) { + textColorNight = "#${color.toHexString()}" + } else { + textColor = "#${color.toHexString()}" + } + } + fun textColor(): Int { return if (App.INSTANCE.isNightTheme) Color.parseColor(textColorNight) else Color.parseColor(textColor) From cd11ae95806d81a8566eaa2a1fd0ab9944c5b10b Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 30 Aug 2019 18:02:24 +0800 Subject: [PATCH 1145/1997] up --- .../ui/readbook/config/BgTextConfigDiolog.kt | 43 +++++++++++++++++++ .../main/res/layout/dialog_read_bg_text.xml | 12 ++++++ app/src/main/res/values/strings.xml | 2 +- 3 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDiolog.kt create mode 100644 app/src/main/res/layout/dialog_read_bg_text.xml diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDiolog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDiolog.kt new file mode 100644 index 000000000..89feb7a7b --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDiolog.kt @@ -0,0 +1,43 @@ +package io.legado.app.ui.readbook.config + +import android.os.Bundle +import android.util.DisplayMetrics +import android.view.Gravity +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.DialogFragment +import io.legado.app.R +import io.legado.app.ui.readbook.Help + +class BgTextConfigDiolog : DialogFragment() { + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + return super.onCreateView(inflater, container, savedInstanceState) + } + + override fun onStart() { + super.onStart() + val dm = DisplayMetrics() + activity?.windowManager?.defaultDisplay?.getMetrics(dm) + dialog?.window?.let { + it.setBackgroundDrawableResource(R.color.transparent) + it.decorView.setPadding(0, 0, 0, 0) + val attr = it.attributes + attr.dimAmount = 0.0f + attr.gravity = Gravity.BOTTOM + it.attributes = attr + it.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) + Help.upSystemUiVisibility(it) + } + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + } + +} \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_read_bg_text.xml b/app/src/main/res/layout/dialog_read_bg_text.xml new file mode 100644 index 000000000..1faa34fc2 --- /dev/null +++ b/app/src/main/res/layout/dialog_read_bg_text.xml @@ -0,0 +1,12 @@ + + + + + + \ 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 861a4bb0a..79e0f93f1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -218,7 +218,7 @@ 无最新章节信息 显示时间和电量 显示分隔线 - 深色状态栏图标 + 深色状态栏图标 内容 拷贝内容 一键缓存 From 57f488b35363c57f6d4b01d2116b347c2313635f Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 30 Aug 2019 18:20:02 +0800 Subject: [PATCH 1146/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 9 ++- .../ui/readbook/config/BgTextConfigDiolog.kt | 6 +- .../app/ui/readbook/config/ReadStyleDialog.kt | 28 +++++++ .../main/res/layout/dialog_read_bg_text.xml | 76 ++++++++++++++++++- 4 files changed, 113 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 46944a4ea..02f3bdfa6 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -27,10 +27,7 @@ import io.legado.app.receiver.TimeElectricityReceiver import io.legado.app.service.ReadAloudService import io.legado.app.ui.changesource.ChangeSourceDialog import io.legado.app.ui.chapterlist.ChapterListActivity -import io.legado.app.ui.readbook.config.MoreConfigDialog -import io.legado.app.ui.readbook.config.PaddingConfigDialog -import io.legado.app.ui.readbook.config.ReadAloudDialog -import io.legado.app.ui.readbook.config.ReadStyleDialog +import io.legado.app.ui.readbook.config.* import io.legado.app.ui.replacerule.ReplaceRuleActivity import io.legado.app.ui.sourceedit.SourceEditActivity import io.legado.app.ui.widget.page.ChapterProvider @@ -179,6 +176,10 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea PaddingConfigDialog().show(supportFragmentManager, "paddingConfig") } + fun showBgTextConfig() { + BgTextConfigDiolog().show(supportFragmentManager, "bgTextConfig") + } + override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { menuInflater.inflate(R.menu.read_book, menu) return super.onCompatCreateOptionsMenu(menu) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDiolog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDiolog.kt index 89feb7a7b..63923a093 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDiolog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDiolog.kt @@ -17,7 +17,7 @@ class BgTextConfigDiolog : DialogFragment() { container: ViewGroup?, savedInstanceState: Bundle? ): View? { - return super.onCreateView(inflater, container, savedInstanceState) + return inflater.inflate(R.layout.dialog_read_bg_text, container) } override fun onStart() { @@ -38,6 +38,10 @@ class BgTextConfigDiolog : DialogFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + initData() } + private fun initData() { + + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt index 758e87fb5..82a633dd4 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt @@ -24,6 +24,7 @@ import kotlinx.android.synthetic.main.activity_read_book.* import kotlinx.android.synthetic.main.dialog_read_book_style.* import org.jetbrains.anko.sdk27.listeners.onCheckedChange import org.jetbrains.anko.sdk27.listeners.onClick +import org.jetbrains.anko.sdk27.listeners.onLongClick class ReadStyleDialog : DialogFragment() { @@ -205,30 +206,57 @@ class ReadStyleDialog : DialogFragment() { upBg() postEvent(Bus.UP_CONFIG, true) } + tv_bg0.onLongClick { + showBgTextConfig() + false + } tv_bg1.onClick { ReadBookConfig.styleSelect = 1 ReadBookConfig.upBg() upBg() postEvent(Bus.UP_CONFIG, true) } + tv_bg1.onLongClick { + showBgTextConfig() + false + } tv_bg2.onClick { ReadBookConfig.styleSelect = 2 ReadBookConfig.upBg() upBg() postEvent(Bus.UP_CONFIG, true) } + tv_bg2.onLongClick { + showBgTextConfig() + false + } tv_bg3.onClick { ReadBookConfig.styleSelect = 3 ReadBookConfig.upBg() upBg() postEvent(Bus.UP_CONFIG, true) } + tv_bg3.onLongClick { + showBgTextConfig() + false + } tv_bg4.onClick { ReadBookConfig.styleSelect = 4 ReadBookConfig.upBg() upBg() postEvent(Bus.UP_CONFIG, true) } + tv_bg4.onLongClick { + showBgTextConfig() + false + } + } + + private fun showBgTextConfig() { + val activity = activity + if (activity is ReadBookActivity) { + activity.showBgTextConfig() + } } private fun setBg() { diff --git a/app/src/main/res/layout/dialog_read_bg_text.xml b/app/src/main/res/layout/dialog_read_bg_text.xml index 1faa34fc2..b1fb23a81 100644 --- a/app/src/main/res/layout/dialog_read_bg_text.xml +++ b/app/src/main/res/layout/dialog_read_bg_text.xml @@ -1,12 +1,86 @@ + android:layout_height="match_parent" + android:padding="10dp"> + + + + + + + + + + + + + + + + + + \ No newline at end of file From 4d1134a964204e770ae0aecd8a7a3e4c21487777 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 30 Aug 2019 18:22:08 +0800 Subject: [PATCH 1147/1997] up --- .../java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt | 1 + app/src/main/res/layout/dialog_read_bg_text.xml | 1 + 2 files changed, 2 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt index 82a633dd4..efc603a13 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt @@ -253,6 +253,7 @@ class ReadStyleDialog : DialogFragment() { } private fun showBgTextConfig() { + dismiss() val activity = activity if (activity is ReadBookActivity) { activity.showBgTextConfig() diff --git a/app/src/main/res/layout/dialog_read_bg_text.xml b/app/src/main/res/layout/dialog_read_bg_text.xml index b1fb23a81..3f0541eb6 100644 --- a/app/src/main/res/layout/dialog_read_bg_text.xml +++ b/app/src/main/res/layout/dialog_read_bg_text.xml @@ -4,6 +4,7 @@ android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" + android:background="@color/background" android:padding="10dp"> Date: Fri, 30 Aug 2019 19:05:15 +0800 Subject: [PATCH 1148/1997] up --- .../app/ui/readbook/config/ReadStyleDialog.kt | 71 ++++++------------- 1 file changed, 20 insertions(+), 51 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt index efc603a13..8c44a480c 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt @@ -200,64 +200,33 @@ class ReadStyleDialog : DialogFragment() { } } } - tv_bg0.onClick { - ReadBookConfig.styleSelect = 0 - ReadBookConfig.upBg() - upBg() - postEvent(Bus.UP_CONFIG, true) - } - tv_bg0.onLongClick { - showBgTextConfig() - false - } - tv_bg1.onClick { - ReadBookConfig.styleSelect = 1 - ReadBookConfig.upBg() - upBg() - postEvent(Bus.UP_CONFIG, true) - } - tv_bg1.onLongClick { - showBgTextConfig() - false - } - tv_bg2.onClick { - ReadBookConfig.styleSelect = 2 - ReadBookConfig.upBg() - upBg() - postEvent(Bus.UP_CONFIG, true) - } - tv_bg2.onLongClick { - showBgTextConfig() - false - } - tv_bg3.onClick { - ReadBookConfig.styleSelect = 3 - ReadBookConfig.upBg() - upBg() - postEvent(Bus.UP_CONFIG, true) - } - tv_bg3.onLongClick { - showBgTextConfig() - false - } - tv_bg4.onClick { - ReadBookConfig.styleSelect = 4 - ReadBookConfig.upBg() - upBg() - postEvent(Bus.UP_CONFIG, true) - } - tv_bg4.onLongClick { - showBgTextConfig() - false - } + tv_bg0.onClick { changeBg(0) } + tv_bg0.onLongClick { showBgTextConfig(0) } + tv_bg1.onClick { changeBg(1) } + tv_bg1.onLongClick { showBgTextConfig(1) } + tv_bg2.onClick { changeBg(2) } + tv_bg2.onLongClick { showBgTextConfig(2) } + tv_bg3.onClick { changeBg(3) } + tv_bg3.onLongClick { showBgTextConfig(3) } + tv_bg4.onClick { changeBg(4) } + tv_bg4.onLongClick { showBgTextConfig(4) } + } + + private fun changeBg(index: Int) { + ReadBookConfig.styleSelect = index + ReadBookConfig.upBg() + upBg() + postEvent(Bus.UP_CONFIG, true) } - private fun showBgTextConfig() { + private fun showBgTextConfig(index: Int): Boolean { dismiss() + changeBg(index) val activity = activity if (activity is ReadBookActivity) { activity.showBgTextConfig() } + return true } private fun setBg() { From 395f95aff19a85581e24fc15563dcd709704607c Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 30 Aug 2019 20:12:38 +0800 Subject: [PATCH 1149/1997] up --- app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 2 +- .../config/{BgTextConfigDiolog.kt => BgTextConfigDialog.kt} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename app/src/main/java/io/legado/app/ui/readbook/config/{BgTextConfigDiolog.kt => BgTextConfigDialog.kt} (96%) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 02f3bdfa6..99fd1f0fd 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -177,7 +177,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } fun showBgTextConfig() { - BgTextConfigDiolog().show(supportFragmentManager, "bgTextConfig") + BgTextConfigDialog().show(supportFragmentManager, "bgTextConfig") } override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDiolog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt similarity index 96% rename from app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDiolog.kt rename to app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt index 63923a093..a1a29eeb5 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDiolog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt @@ -10,7 +10,7 @@ import androidx.fragment.app.DialogFragment import io.legado.app.R import io.legado.app.ui.readbook.Help -class BgTextConfigDiolog : DialogFragment() { +class BgTextConfigDialog : DialogFragment() { override fun onCreateView( inflater: LayoutInflater, From 8db3d708596257ca7f304e8a82093f9c219be994 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 30 Aug 2019 21:05:01 +0800 Subject: [PATCH 1150/1997] up --- .../io/legado/app/lib/theme/TintHelper.kt | 5 ++-- .../app/lib/theme/view/ATEAccentBgTextView.kt | 18 ++++++------- .../lib/theme/view/ATEAccentStrokeTextView.kt | 26 +++++++++---------- .../lib/theme/view/ATEAutoCompleteTextView.kt | 18 ++++++------- .../legado/app/lib/theme/view/ATECheckBox.kt | 18 ++++++------- .../legado/app/lib/theme/view/ATEEditText.kt | 18 ++++++------- .../app/lib/theme/view/ATEPrimaryTextView.kt | 18 ++++++------- .../app/lib/theme/view/ATEProgressBar.kt | 22 +++++++--------- .../app/lib/theme/view/ATERadioButton.kt | 18 ++++++------- .../app/lib/theme/view/ATERadioNoButton.kt | 18 ++++++------- .../lib/theme/view/ATESecondaryTextView.kt | 22 +++++++--------- .../app/lib/theme/view/ATEStrokeTextView.kt | 18 ++++++------- .../io/legado/app/lib/theme/view/ATESwitch.kt | 26 +++++++------------ .../app/lib/theme/view/ATETextInputLayout.kt | 23 ++++++---------- .../app/ui/readbook/config/ReadStyleDialog.kt | 10 ++++--- .../main/res/layout/dialog_read_bg_text.xml | 11 +++++--- app/src/main/res/values/strings.xml | 3 +++ 17 files changed, 132 insertions(+), 160 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt b/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt index cbff84976..fc79f4584 100644 --- a/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt +++ b/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt @@ -206,7 +206,7 @@ object TintHelper { intArrayOf(android.R.attr.state_enabled, -android.R.attr.state_checked), intArrayOf(android.R.attr.state_enabled, android.R.attr.state_checked) ), intArrayOf( - // Rdio button includes own alpha for disabled state + // Radio button includes own alpha for disabled state ColorUtils.stripAlpha( ContextCompat.getColor( radioButton.context, @@ -223,11 +223,10 @@ object TintHelper { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { radioButton.buttonTintList = sl } else { - val d = createTintedDrawable( + radioButton.buttonDrawable = createTintedDrawable( ContextCompat.getDrawable(radioButton.context, R.drawable.abc_btn_radio_material), sl ) - radioButton.buttonDrawable = d } } diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATEAccentBgTextView.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATEAccentBgTextView.kt index 6de1037b9..6aef2175a 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATEAccentBgTextView.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATEAccentBgTextView.kt @@ -10,19 +10,17 @@ import io.legado.app.lib.theme.ThemeStore import io.legado.app.utils.dp class ATEAccentBgTextView : AppCompatTextView { - constructor(context: Context) : super(context) { - init(context) - } + constructor(context: Context) : super(context) - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { - init(context) - } + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { - init(context) - } + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) - private fun init(context: Context) { + init { background = Selector.shapeBuild() .setCornerRadius(3.dp) .setDefaultBgColor(ThemeStore.accentColor(context)) diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATEAccentStrokeTextView.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATEAccentStrokeTextView.kt index c6aea80f0..30ff4da44 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATEAccentStrokeTextView.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATEAccentStrokeTextView.kt @@ -7,33 +7,31 @@ import io.legado.app.R import io.legado.app.lib.theme.Selector import io.legado.app.lib.theme.ThemeStore import io.legado.app.utils.dp +import io.legado.app.utils.getCompatColor class ATEAccentStrokeTextView : AppCompatTextView { - constructor(context: Context) : super(context) { - init(context) - } + constructor(context: Context) : super(context) - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { - init(context) - } + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { - init(context) - } + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) - @Suppress("DEPRECATION") - private fun init(context: Context) { + init { background = Selector.shapeBuild() .setCornerRadius(3.dp) .setStrokeWidth(1.dp) - .setDisabledStrokeColor(context.resources.getColor(R.color.md_grey_500)) + .setDisabledStrokeColor(context.getCompatColor(R.color.md_grey_500)) .setDefaultStrokeColor(ThemeStore.accentColor(context)) - .setPressedBgColor(context.resources.getColor(R.color.transparent30)) + .setPressedBgColor(context.getCompatColor(R.color.transparent30)) .create() setTextColor( Selector.colorBuild() .setDefaultColor(ThemeStore.accentColor(context)) - .setDisabledColor(context.resources.getColor(R.color.md_grey_500)) + .setDisabledColor(context.getCompatColor(R.color.md_grey_500)) .create() ) } diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt index 4a4688fbb..f54f24eb4 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt @@ -10,19 +10,17 @@ import io.legado.app.lib.theme.ThemeStore class ATEAutoCompleteTextView : AppCompatAutoCompleteTextView { - constructor(context: Context) : super(context) { - init(context) - } + constructor(context: Context) : super(context) - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { - init(context) - } + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { - init(context) - } + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) - private fun init(context: Context) { + init { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { backgroundTintList = Selector.colorBuild() .setFocusedColor(ThemeStore.accentColor(context)) diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATECheckBox.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATECheckBox.kt index 643299f35..a9bef21b0 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATECheckBox.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATECheckBox.kt @@ -11,19 +11,17 @@ import io.legado.app.lib.theme.ThemeStore */ class ATECheckBox : AppCompatCheckBox { - constructor(context: Context) : super(context) { - init(context) - } + constructor(context: Context) : super(context) - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { - init(context) - } + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { - init(context) - } + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) - private fun init(context: Context) { + init { ATH.setTint(this, ThemeStore.accentColor(context)) } } diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATEEditText.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATEEditText.kt index c70ea4eda..b38bdd6ab 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATEEditText.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATEEditText.kt @@ -11,19 +11,17 @@ import io.legado.app.lib.theme.ThemeStore */ class ATEEditText : AppCompatEditText { - constructor(context: Context) : super(context) { - init(context, null) - } + constructor(context: Context) : super(context) - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { - init(context, attrs) - } + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { - init(context, attrs) - } + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) - private fun init(context: Context, attrs: AttributeSet?) { + init { ATH.setTint(this, ThemeStore.accentColor(context)) } } diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATEPrimaryTextView.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATEPrimaryTextView.kt index 97d4d08b1..44d1e1acd 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATEPrimaryTextView.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATEPrimaryTextView.kt @@ -10,19 +10,17 @@ import io.legado.app.lib.theme.ThemeStore */ class ATEPrimaryTextView : AppCompatTextView { - constructor(context: Context) : super(context) { - init(context) - } + constructor(context: Context) : super(context) - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { - init(context) - } + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { - init(context) - } + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) - private fun init(context: Context) { + init { setTextColor(ThemeStore.textColorPrimary(context)) } } diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATEProgressBar.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATEProgressBar.kt index 3a1809f16..aae4d914a 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATEProgressBar.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATEProgressBar.kt @@ -13,17 +13,15 @@ import io.legado.app.lib.theme.ThemeStore */ class ATEProgressBar : ProgressBar { - constructor(context: Context) : super(context) { - init(context, null) - } + constructor(context: Context) : super(context) - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { - init(context, attrs) - } + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { - init(context, attrs) - } + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) @TargetApi(Build.VERSION_CODES.LOLLIPOP) constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super( @@ -31,11 +29,9 @@ class ATEProgressBar : ProgressBar { attrs, defStyleAttr, defStyleRes - ) { - init(context, attrs) - } + ) - private fun init(context: Context, attrs: AttributeSet?) { + init { ATH.setTint(this, ThemeStore.accentColor(context)) } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATERadioButton.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATERadioButton.kt index 8af025c2f..c8715728e 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATERadioButton.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATERadioButton.kt @@ -11,19 +11,17 @@ import io.legado.app.lib.theme.accentColor */ class ATERadioButton : AppCompatRadioButton { - constructor(context: Context) : super(context) { - init(context) - } + constructor(context: Context) : super(context) - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { - init(context) - } + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { - init(context) - } + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) - private fun init(context: Context) { + init { ATH.setTint(this@ATERadioButton, context.accentColor) } } diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATERadioNoButton.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATERadioNoButton.kt index 2e7763741..41ce5dbe5 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATERadioNoButton.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATERadioNoButton.kt @@ -14,19 +14,17 @@ import io.legado.app.utils.getCompatColor */ class ATERadioNoButton : AppCompatRadioButton { - constructor(context: Context) : super(context) { - init(context, null) - } + constructor(context: Context) : super(context) - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { - init(context, attrs) - } + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { - init(context, attrs) - } + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) - private fun init(context: Context, attrs: AttributeSet?) { + init { background = Selector.shapeBuild() .setCornerRadius(2.dp) .setStrokeWidth(2.dp) diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATESecondaryTextView.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATESecondaryTextView.kt index f84814b90..d7dc8ca3d 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATESecondaryTextView.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATESecondaryTextView.kt @@ -3,26 +3,24 @@ package io.legado.app.lib.theme.view import android.content.Context import android.util.AttributeSet import androidx.appcompat.widget.AppCompatTextView -import io.legado.app.lib.theme.ThemeStore +import io.legado.app.lib.theme.secondaryTextColor /** * @author Aidan Follestad (afollestad) */ class ATESecondaryTextView : AppCompatTextView { - constructor(context: Context) : super(context) { - init(context) - } + constructor(context: Context) : super(context) - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { - init(context) - } + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { - init(context) - } + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) - private fun init(context: Context) { - setTextColor(ThemeStore.textColorSecondary(context)) + init { + setTextColor(context.secondaryTextColor) } } diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATEStrokeTextView.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATEStrokeTextView.kt index ee6697224..04416929c 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATEStrokeTextView.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATEStrokeTextView.kt @@ -9,19 +9,17 @@ import io.legado.app.lib.theme.ThemeStore import io.legado.app.utils.dp class ATEStrokeTextView : AppCompatTextView { - constructor(context: Context) : super(context) { - init(context, null) - } + constructor(context: Context) : super(context) - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { - init(context, attrs) - } + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { - init(context, attrs) - } + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) - private fun init(context: Context, attrs: AttributeSet?) { + init { background = Selector.shapeBuild() .setCornerRadius(1.dp) .setStrokeWidth(1.dp) diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATESwitch.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATESwitch.kt index 8009d817a..1a1c331a4 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATESwitch.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATESwitch.kt @@ -2,33 +2,27 @@ package io.legado.app.lib.theme.view import android.content.Context import android.util.AttributeSet -import android.view.View import androidx.appcompat.widget.SwitchCompat import io.legado.app.lib.theme.ATH -import io.legado.app.lib.theme.ThemeStore +import io.legado.app.lib.theme.accentColor /** * @author Aidan Follestad (afollestad) */ class ATESwitch : SwitchCompat { - constructor(context: Context) : super(context) { - init(context, null) - } + constructor(context: Context) : super(context) - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { - init(context, attrs) - } + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { - init(context, attrs) - } + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) - private fun init(context: Context, attrs: AttributeSet?) { - ATH.setTint(this, ThemeStore.accentColor(context)) + init { + ATH.setTint(this, context.accentColor) } - override fun isShown(): Boolean { - return parent != null && visibility == View.VISIBLE - } } diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATETextInputLayout.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATETextInputLayout.kt index e09b03e2c..b420f3e01 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATETextInputLayout.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATETextInputLayout.kt @@ -1,31 +1,24 @@ package io.legado.app.lib.theme.view import android.content.Context -import android.graphics.Canvas import android.util.AttributeSet import com.google.android.material.textfield.TextInputLayout import io.legado.app.lib.theme.Selector import io.legado.app.lib.theme.ThemeStore class ATETextInputLayout : TextInputLayout { - constructor(context: Context) : super(context) { - init(context) - } + constructor(context: Context) : super(context) - constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { - init(context) - } + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) - constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { - init(context) - } + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) - private fun init(context: Context) { + init { defaultHintTextColor = Selector.colorBuild().setDefaultColor(ThemeStore.accentColor(context)).create() } - override fun draw(canvas: Canvas) { - - super.draw(canvas) - } } diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt index 8c44a480c..7f8281eeb 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt @@ -213,10 +213,12 @@ class ReadStyleDialog : DialogFragment() { } private fun changeBg(index: Int) { - ReadBookConfig.styleSelect = index - ReadBookConfig.upBg() - upBg() - postEvent(Bus.UP_CONFIG, true) + if (ReadBookConfig.styleSelect != index) { + ReadBookConfig.styleSelect = index + ReadBookConfig.upBg() + upBg() + postEvent(Bus.UP_CONFIG, true) + } } private fun showBgTextConfig(index: Int): Boolean { diff --git a/app/src/main/res/layout/dialog_read_bg_text.xml b/app/src/main/res/layout/dialog_read_bg_text.xml index 3f0541eb6..073e9b720 100644 --- a/app/src/main/res/layout/dialog_read_bg_text.xml +++ b/app/src/main/res/layout/dialog_read_bg_text.xml @@ -8,8 +8,10 @@ android:padding="10dp"> @@ -39,10 +42,11 @@ android:layout_gravity="center" android:layout_margin="6dp" android:layout_weight="1" + android:background="?attr/selectableItemBackground" android:singleLine="true" android:gravity="center" android:padding="6dp" - android:text="背景颜色" + android:text="@string/bg_color" android:textSize="14sp" tools:ignore="HardcodedText" /> @@ -53,6 +57,7 @@ android:layout_gravity="center" android:layout_margin="6dp" android:layout_weight="1" + android:background="?attr/selectableItemBackground" android:singleLine="true" android:gravity="center" android:padding="6dp" @@ -74,7 +79,7 @@ android:layout_height="wrap_content" android:paddingStart="10dp" android:paddingEnd="10dp" - android:text="背景图片" /> + android:text="@string/bg_image" /> %d分钟 自动亮度%s 按页 + 背景图片 + 背景颜色 + 文字颜色 From 0bed92879da0143e7c97d0c830a54fa9ada22066 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 30 Aug 2019 21:31:39 +0800 Subject: [PATCH 1151/1997] up --- .../io/legado/app/lib/theme/TintHelper.kt | 37 +++++++++++++++---- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt b/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt index fc79f4584..0caf1b8a8 100644 --- a/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt +++ b/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt @@ -250,7 +250,10 @@ object TintHelper { } @JvmOverloads - fun setTint(progressBar: ProgressBar, @ColorInt color: Int, skipIndeterminate: Boolean = false) { + fun setTint( + progressBar: ProgressBar, @ColorInt color: Int, + skipIndeterminate: Boolean = false + ) { val sl = ColorStateList.valueOf(color) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { progressBar.progressTintList = sl @@ -272,7 +275,11 @@ object TintHelper { val editTextColorStateList = ColorStateList( arrayOf( intArrayOf(-android.R.attr.state_enabled), - intArrayOf(android.R.attr.state_enabled, -android.R.attr.state_pressed, -android.R.attr.state_focused), + intArrayOf( + android.R.attr.state_enabled, + -android.R.attr.state_pressed, + -android.R.attr.state_focused + ), intArrayOf() ), intArrayOf( @@ -314,7 +321,12 @@ object TintHelper { box.buttonTintList = sl } else { val drawable = - createTintedDrawable(ContextCompat.getDrawable(box.context, R.drawable.abc_btn_check_material), sl) + createTintedDrawable( + ContextCompat.getDrawable( + box.context, + R.drawable.abc_btn_check_material + ), sl + ) box.buttonDrawable = drawable } } @@ -380,7 +392,6 @@ object TintHelper { } fun setTint(switchView: Switch, @ColorInt color: Int, useDarker: Boolean) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) return if (switchView.trackDrawable != null) { switchView.trackDrawable = modifySwitchDrawable( switchView.context, @@ -390,7 +401,11 @@ object TintHelper { if (switchView.thumbDrawable != null) { switchView.thumbDrawable = modifySwitchDrawable( switchView.context, - switchView.thumbDrawable, color, true, false, useDarker + switchView.thumbDrawable, + color, + thumb = true, + compatSwitch = false, + useDarker = useDarker ) } } @@ -399,13 +414,21 @@ object TintHelper { if (switchView.trackDrawable != null) { switchView.trackDrawable = modifySwitchDrawable( switchView.context, - switchView.trackDrawable, color, false, true, useDarker + switchView.trackDrawable, + color, + thumb = false, + compatSwitch = true, + useDarker = useDarker ) } if (switchView.thumbDrawable != null) { switchView.thumbDrawable = modifySwitchDrawable( switchView.context, - switchView.thumbDrawable, color, true, true, useDarker + switchView.thumbDrawable, + color, + thumb = true, + compatSwitch = true, + useDarker = useDarker ) } } From 19605699f891fa805fce7d146a48fa3fa1073d1b Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 30 Aug 2019 21:52:50 +0800 Subject: [PATCH 1152/1997] up --- app/src/main/java/io/legado/app/lib/theme/TintHelper.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt b/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt index 0caf1b8a8..b7b042ebc 100644 --- a/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt +++ b/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt @@ -127,7 +127,7 @@ object TintHelper { view: View, @ColorInt color: Int, isBackground: Boolean ) { - setTintAuto(view, color, isBackground, ATHUtils.isWindowBackgroundDark(view.context)) + setTintAuto(view, color, isBackground, view.context.isDarkTheme) } fun setTintAuto( From 31737fa4f60a12f062c0696bee09a3456616fd1e Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 30 Aug 2019 21:53:57 +0800 Subject: [PATCH 1153/1997] up --- app/src/main/java/io/legado/app/help/ReadBookConfig.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index 01e199eb8..cfa7aafc9 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -100,6 +100,7 @@ object ReadBookConfig { var bgType: Int = 0, var bgTypeNight: Int = 0, var darkStatusIcon: Boolean = true, + var darkStatusIconNight: Boolean = false, var letterSpacing: Float = 1f, var lineSpacingExtra: Int = 12, var lineSpacingMultiplier: Float = 1.2f, From 193939d1ec1c4ecf5a2d812113243db8faaa553c Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 30 Aug 2019 21:56:21 +0800 Subject: [PATCH 1154/1997] up --- app/src/main/java/io/legado/app/help/ReadBookConfig.kt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index cfa7aafc9..9a480d5cd 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -131,6 +131,14 @@ object ReadBookConfig { } } + fun setStatusIconDark(isDark: Boolean) { + if (App.INSTANCE.isNightTheme) { + darkStatusIconNight = isDark + } else { + darkStatusIcon = isDark + } + } + fun textColor(): Int { return if (App.INSTANCE.isNightTheme) Color.parseColor(textColorNight) else Color.parseColor(textColor) From 71d0b7ceb28ea74fb3922becf234afb92a697fad Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 30 Aug 2019 22:04:40 +0800 Subject: [PATCH 1155/1997] up --- app/src/main/java/io/legado/app/help/ReadBookConfig.kt | 8 ++++++++ .../legado/app/ui/readbook/config/BgTextConfigDialog.kt | 6 ++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index 9a480d5cd..196a88c36 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -139,6 +139,14 @@ object ReadBookConfig { } } + fun statusIconDark(): Boolean { + return if (App.INSTANCE.isNightTheme) { + darkStatusIconNight + } else { + darkStatusIcon + } + } + fun textColor(): Int { return if (App.INSTANCE.isNightTheme) Color.parseColor(textColorNight) else Color.parseColor(textColor) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt index a1a29eeb5..d1ee637d4 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt @@ -8,7 +8,9 @@ import android.view.View import android.view.ViewGroup import androidx.fragment.app.DialogFragment import io.legado.app.R +import io.legado.app.help.ReadBookConfig import io.legado.app.ui.readbook.Help +import kotlinx.android.synthetic.main.dialog_read_bg_text.* class BgTextConfigDialog : DialogFragment() { @@ -41,7 +43,7 @@ class BgTextConfigDialog : DialogFragment() { initData() } - private fun initData() { - + private fun initData() = with(ReadBookConfig.getConfig()) { + sw_dark_status_icon.isChecked = statusIconDark() } } \ No newline at end of file From 0f7e071ff7c88d9aadb33b0cf9be43cbbdf25eff Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 30 Aug 2019 23:01:59 +0800 Subject: [PATCH 1156/1997] up --- .../ui/readbook/config/BgTextConfigDialog.kt | 55 ++++++++++++++++++- .../main/res/layout/dialog_read_bg_text.xml | 6 +- 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt index d1ee637d4..3e72e6df6 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt @@ -1,5 +1,6 @@ package io.legado.app.ui.readbook.config +import android.graphics.Color import android.os.Bundle import android.util.DisplayMetrics import android.view.Gravity @@ -7,12 +8,21 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.DialogFragment +import com.jaredrummler.android.colorpicker.ColorPickerDialog +import com.jaredrummler.android.colorpicker.ColorPickerDialogListener import io.legado.app.R +import io.legado.app.constant.Bus import io.legado.app.help.ReadBookConfig import io.legado.app.ui.readbook.Help +import io.legado.app.utils.postEvent import kotlinx.android.synthetic.main.dialog_read_bg_text.* +import okhttp3.internal.toHexString +import org.jetbrains.anko.sdk27.listeners.onClick -class BgTextConfigDialog : DialogFragment() { +class BgTextConfigDialog : DialogFragment(), ColorPickerDialogListener { + + val selectTextColor = 121 + val selectBgColor = 122 override fun onCreateView( inflater: LayoutInflater, @@ -41,9 +51,52 @@ class BgTextConfigDialog : DialogFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) initData() + initView() } private fun initData() = with(ReadBookConfig.getConfig()) { sw_dark_status_icon.isChecked = statusIconDark() } + + private fun initView() = with(ReadBookConfig.getConfig()) { + tv_text_color.onClick { + ColorPickerDialog.newBuilder() + .setColor(textColor()) + .setShowAlphaSlider(false) + .setDialogType(ColorPickerDialog.TYPE_CUSTOM) + .setDialogId(selectTextColor) + .show(requireActivity()) + } + tv_bg_color.onClick { + val bgColor = + if (bgType() == 0) Color.parseColor(bgStr()) + else Color.parseColor("#015A86") + ColorPickerDialog.newBuilder() + .setColor(bgColor) + .setShowAlphaSlider(false) + .setDialogType(ColorPickerDialog.TYPE_CUSTOM) + .setDialogId(selectTextColor) + .show(requireActivity()) + } + tv_default.onClick { + + } + } + + override fun onColorSelected(dialogId: Int, color: Int) = with(ReadBookConfig.getConfig()) { + when (dialogId) { + selectTextColor -> { + setTextColor(color) + postEvent(Bus.UP_CONFIG, false) + } + selectBgColor -> { + setBg(0, "#${color.toHexString()}") + postEvent(Bus.UP_CONFIG, false) + } + } + } + + override fun onDialogDismissed(dialogId: Int) { + + } } \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_read_bg_text.xml b/app/src/main/res/layout/dialog_read_bg_text.xml index 073e9b720..b1d5df162 100644 --- a/app/src/main/res/layout/dialog_read_bg_text.xml +++ b/app/src/main/res/layout/dialog_read_bg_text.xml @@ -21,7 +21,7 @@ android:padding="6dp"> Date: Fri, 30 Aug 2019 23:22:25 +0800 Subject: [PATCH 1157/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 25 ++++++++++++++- .../ui/readbook/config/BgTextConfigDialog.kt | 31 +++++-------------- 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 99fd1f0fd..86eeefc15 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -13,6 +13,7 @@ import android.view.WindowManager import android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES import androidx.core.view.isVisible import androidx.lifecycle.Observer +import com.jaredrummler.android.colorpicker.ColorPickerDialogListener import io.legado.app.R import io.legado.app.base.VMBaseActivity import io.legado.app.constant.Bus @@ -20,6 +21,7 @@ import io.legado.app.constant.Status import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter import io.legado.app.help.IntentDataHelp +import io.legado.app.help.ReadBookConfig import io.legado.app.lib.dialogs.alert import io.legado.app.lib.dialogs.noButton import io.legado.app.lib.dialogs.okButton @@ -28,6 +30,8 @@ import io.legado.app.service.ReadAloudService import io.legado.app.ui.changesource.ChangeSourceDialog import io.legado.app.ui.chapterlist.ChapterListActivity import io.legado.app.ui.readbook.config.* +import io.legado.app.ui.readbook.config.BgTextConfigDialog.Companion.BG_COLOR +import io.legado.app.ui.readbook.config.BgTextConfigDialog.Companion.TEXT_COLOR import io.legado.app.ui.replacerule.ReplaceRuleActivity import io.legado.app.ui.sourceedit.SourceEditActivity import io.legado.app.ui.widget.page.ChapterProvider @@ -42,6 +46,7 @@ import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import okhttp3.internal.toHexString import org.jetbrains.anko.sdk27.listeners.onClick import org.jetbrains.anko.startActivity import org.jetbrains.anko.startActivityForResult @@ -50,7 +55,8 @@ import org.jetbrains.anko.toast class ReadBookActivity : VMBaseActivity(R.layout.activity_read_book), PageView.CallBack, ChangeSourceDialog.CallBack, - ReadBookViewModel.CallBack { + ReadBookViewModel.CallBack, + ColorPickerDialogListener { override val viewModel: ReadBookViewModel get() = getViewModel(ReadBookViewModel::class.java) @@ -430,6 +436,23 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea window.attributes = params } + override fun onColorSelected(dialogId: Int, color: Int) = with(ReadBookConfig.getConfig()) { + when (dialogId) { + TEXT_COLOR -> { + setTextColor(color) + postEvent(Bus.UP_CONFIG, false) + } + BG_COLOR -> { + setBg(0, "#${color.toHexString()}") + postEvent(Bus.UP_CONFIG, false) + } + } + } + + override fun onDialogDismissed(dialogId: Int) { + + } + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (resultCode == Activity.RESULT_OK) { diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt index 3e72e6df6..80b06e58a 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt @@ -9,20 +9,18 @@ import android.view.View import android.view.ViewGroup import androidx.fragment.app.DialogFragment import com.jaredrummler.android.colorpicker.ColorPickerDialog -import com.jaredrummler.android.colorpicker.ColorPickerDialogListener import io.legado.app.R -import io.legado.app.constant.Bus import io.legado.app.help.ReadBookConfig import io.legado.app.ui.readbook.Help -import io.legado.app.utils.postEvent import kotlinx.android.synthetic.main.dialog_read_bg_text.* -import okhttp3.internal.toHexString import org.jetbrains.anko.sdk27.listeners.onClick -class BgTextConfigDialog : DialogFragment(), ColorPickerDialogListener { +class BgTextConfigDialog : DialogFragment() { - val selectTextColor = 121 - val selectBgColor = 122 + companion object { + const val TEXT_COLOR = 121 + const val BG_COLOR = 122 + } override fun onCreateView( inflater: LayoutInflater, @@ -64,7 +62,7 @@ class BgTextConfigDialog : DialogFragment(), ColorPickerDialogListener { .setColor(textColor()) .setShowAlphaSlider(false) .setDialogType(ColorPickerDialog.TYPE_CUSTOM) - .setDialogId(selectTextColor) + .setDialogId(TEXT_COLOR) .show(requireActivity()) } tv_bg_color.onClick { @@ -75,7 +73,7 @@ class BgTextConfigDialog : DialogFragment(), ColorPickerDialogListener { .setColor(bgColor) .setShowAlphaSlider(false) .setDialogType(ColorPickerDialog.TYPE_CUSTOM) - .setDialogId(selectTextColor) + .setDialogId(TEXT_COLOR) .show(requireActivity()) } tv_default.onClick { @@ -83,20 +81,5 @@ class BgTextConfigDialog : DialogFragment(), ColorPickerDialogListener { } } - override fun onColorSelected(dialogId: Int, color: Int) = with(ReadBookConfig.getConfig()) { - when (dialogId) { - selectTextColor -> { - setTextColor(color) - postEvent(Bus.UP_CONFIG, false) - } - selectBgColor -> { - setBg(0, "#${color.toHexString()}") - postEvent(Bus.UP_CONFIG, false) - } - } - } - override fun onDialogDismissed(dialogId: Int) { - - } } \ No newline at end of file From ce1d17f12f2dcc6ee437ed90e7238c826a934a3e Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 30 Aug 2019 23:25:02 +0800 Subject: [PATCH 1158/1997] up --- .../java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt index 80b06e58a..381c23f00 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt @@ -73,7 +73,7 @@ class BgTextConfigDialog : DialogFragment() { .setColor(bgColor) .setShowAlphaSlider(false) .setDialogType(ColorPickerDialog.TYPE_CUSTOM) - .setDialogId(TEXT_COLOR) + .setDialogId(BG_COLOR) .show(requireActivity()) } tv_default.onClick { From 91b12a5beb1475b7a18fb1a0010d7c7fdb429ffa Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 30 Aug 2019 23:27:28 +0800 Subject: [PATCH 1159/1997] up --- app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 86eeefc15..cb6e1b66a 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -444,6 +444,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } BG_COLOR -> { setBg(0, "#${color.toHexString()}") + ReadBookConfig.upBg() postEvent(Bus.UP_CONFIG, false) } } From 806c3227ca9fada659edd182f00b233ed5bdb79a Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 30 Aug 2019 23:28:13 +0800 Subject: [PATCH 1160/1997] up --- .../io/legado/app/ui/readbook/config/BgTextConfigDialog.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt index 381c23f00..be505737d 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt @@ -1,5 +1,6 @@ package io.legado.app.ui.readbook.config +import android.content.DialogInterface import android.graphics.Color import android.os.Bundle import android.util.DisplayMetrics @@ -52,6 +53,11 @@ class BgTextConfigDialog : DialogFragment() { initView() } + override fun onDismiss(dialog: DialogInterface) { + super.onDismiss(dialog) + ReadBookConfig.save() + } + private fun initData() = with(ReadBookConfig.getConfig()) { sw_dark_status_icon.isChecked = statusIconDark() } From dea372a03c5c16b887dd48cde56b85dde6d7b6f9 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 31 Aug 2019 10:58:41 +0800 Subject: [PATCH 1161/1997] up --- .../ui/readbook/config/BgTextConfigDialog.kt | 57 +++++++++++++++++++ app/src/main/res/drawable/ic_image.xml | 14 +++++ .../main/res/layout/dialog_read_bg_text.xml | 4 +- app/src/main/res/layout/item_bg_image.xml | 21 +++++++ app/src/main/res/values/strings.xml | 1 + 5 files changed, 94 insertions(+), 3 deletions(-) create mode 100644 app/src/main/res/drawable/ic_image.xml create mode 100644 app/src/main/res/layout/item_bg_image.xml diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt index be505737d..73da06e09 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt @@ -1,6 +1,9 @@ package io.legado.app.ui.readbook.config +import android.annotation.SuppressLint +import android.content.Context import android.content.DialogInterface +import android.content.Intent import android.graphics.Color import android.os.Bundle import android.util.DisplayMetrics @@ -9,11 +12,20 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.DialogFragment +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView import com.jaredrummler.android.colorpicker.ColorPickerDialog import io.legado.app.R +import io.legado.app.base.adapter.ItemViewHolder +import io.legado.app.base.adapter.SimpleRecyclerAdapter +import io.legado.app.help.ImageLoader import io.legado.app.help.ReadBookConfig +import io.legado.app.help.permission.Permissions +import io.legado.app.help.permission.PermissionsCompat import io.legado.app.ui.readbook.Help +import io.legado.app.utils.getCompatColor import kotlinx.android.synthetic.main.dialog_read_bg_text.* +import kotlinx.android.synthetic.main.item_bg_image.view.* import org.jetbrains.anko.sdk27.listeners.onClick class BgTextConfigDialog : DialogFragment() { @@ -23,6 +35,9 @@ class BgTextConfigDialog : DialogFragment() { const val BG_COLOR = 122 } + private val ResultSelectBg = 123 + private lateinit var adapter: BgAdapter + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -58,8 +73,23 @@ class BgTextConfigDialog : DialogFragment() { ReadBookConfig.save() } + @SuppressLint("InflateParams") private fun initData() = with(ReadBookConfig.getConfig()) { sw_dark_status_icon.isChecked = statusIconDark() + adapter = BgAdapter(requireContext()) + recycler_view.layoutManager = + LinearLayoutManager(requireContext(), RecyclerView.HORIZONTAL, false) + recycler_view.adapter = adapter + val headerView = LayoutInflater.from(requireContext()) + .inflate(R.layout.item_bg_image, recycler_view, false) + adapter.addHeaderView(headerView) + headerView.tv_name.text = getString(R.string.select_image) + headerView.iv_bg.setImageResource(R.drawable.ic_image) + headerView.iv_bg.setColorFilter(getCompatColor(R.color.tv_text_default)) + headerView.onClick { selectImage() } + requireContext().assets.list("bg/")?.let { + adapter.setItems(it.toList()) + } } private fun initView() = with(ReadBookConfig.getConfig()) { @@ -87,5 +117,32 @@ class BgTextConfigDialog : DialogFragment() { } } + private fun selectImage() { + PermissionsCompat.Builder(this) + .addPermissions(Permissions.READ_EXTERNAL_STORAGE, Permissions.WRITE_EXTERNAL_STORAGE) + .rationale(R.string.bg_image_per) + .onGranted { + val intent = Intent(Intent.ACTION_GET_CONTENT) + intent.addCategory(Intent.CATEGORY_OPENABLE) + intent.type = "image/*" + startActivityForResult(intent, ResultSelectBg) + Unit + } + .request() + } + + class BgAdapter(context: Context) : + SimpleRecyclerAdapter(context, R.layout.item_bg_image) { + + override fun convert(holder: ItemViewHolder, item: String, payloads: MutableList) { + with(holder.itemView) { + ImageLoader.load(context, context.assets.open("bg/$item").readBytes()) + .centerCrop() + .setAsFile(iv_bg) + tv_name.text = item + } + } + + } } \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_image.xml b/app/src/main/res/drawable/ic_image.xml new file mode 100644 index 000000000..bfd8e5c65 --- /dev/null +++ b/app/src/main/res/drawable/ic_image.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_read_bg_text.xml b/app/src/main/res/layout/dialog_read_bg_text.xml index b1d5df162..e5618b955 100644 --- a/app/src/main/res/layout/dialog_read_bg_text.xml +++ b/app/src/main/res/layout/dialog_read_bg_text.xml @@ -77,12 +77,10 @@ diff --git a/app/src/main/res/layout/item_bg_image.xml b/app/src/main/res/layout/item_bg_image.xml new file mode 100644 index 000000000..c3e4a81e0 --- /dev/null +++ b/app/src/main/res/layout/item_bg_image.xml @@ -0,0 +1,21 @@ + + + + + + + + \ 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 7e93d73f8..95a6d72ef 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -489,5 +489,6 @@ 背景图片 背景颜色 文字颜色 + 选择图片 From f8c459640e1cefb7f20b4795b54af63a6715004e Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 31 Aug 2019 10:59:35 +0800 Subject: [PATCH 1162/1997] up --- app/src/main/res/layout/item_bg_image.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/layout/item_bg_image.xml b/app/src/main/res/layout/item_bg_image.xml index c3e4a81e0..d8ed15e7a 100644 --- a/app/src/main/res/layout/item_bg_image.xml +++ b/app/src/main/res/layout/item_bg_image.xml @@ -2,6 +2,7 @@ Date: Sat, 31 Aug 2019 11:07:46 +0800 Subject: [PATCH 1163/1997] up --- .../io/legado/app/ui/readbook/config/BgTextConfigDialog.kt | 4 ++-- app/src/main/res/layout/item_bg_image.xml | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt index 73da06e09..a12072c7e 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt @@ -138,8 +138,8 @@ class BgTextConfigDialog : DialogFragment() { with(holder.itemView) { ImageLoader.load(context, context.assets.open("bg/$item").readBytes()) .centerCrop() - .setAsFile(iv_bg) - tv_name.text = item + .setAsBitmap(iv_bg) + tv_name.text = item.substring(0, item.lastIndexOf(".")) } } diff --git a/app/src/main/res/layout/item_bg_image.xml b/app/src/main/res/layout/item_bg_image.xml index d8ed15e7a..57c74b182 100644 --- a/app/src/main/res/layout/item_bg_image.xml +++ b/app/src/main/res/layout/item_bg_image.xml @@ -1,8 +1,8 @@ \ No newline at end of file From 195c681818f8f5032de1b75670ca1c1b2b6e2bd9 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 31 Aug 2019 11:35:45 +0800 Subject: [PATCH 1164/1997] up --- app/src/main/assets/bg/中国红.png | Bin 0 -> 49779 bytes app/src/main/assets/bg/午后沙滩.jpg | Bin 0 -> 46926 bytes app/src/main/assets/bg/宁静夜色.jpg | Bin 0 -> 38530 bytes app/src/main/assets/bg/小清新.jpg | Bin 0 -> 177012 bytes app/src/main/assets/bg/山水墨影.jpg | Bin 0 -> 39970 bytes app/src/main/assets/bg/山水画.jpg | Bin 0 -> 20265 bytes app/src/main/assets/bg/护眼漫绿.jpg | Bin 0 -> 114471 bytes app/src/main/assets/bg/新羊皮纸.jpg | Bin 0 -> 42643 bytes app/src/main/assets/bg/明媚倾城.jpg | Bin 0 -> 66271 bytes app/src/main/assets/bg/浅黄飘带.jpg | Bin 0 -> 34431 bytes app/src/main/assets/bg/深宫魅影.jpg | Bin 0 -> 50170 bytes app/src/main/assets/bg/清新.jpg | Bin 0 -> 59206 bytes app/src/main/assets/bg/清新时光.jpg | Bin 0 -> 42584 bytes app/src/main/assets/bg/羊皮纸1.jpg | Bin 0 -> 251439 bytes .../main/assets/bg/{bg1.jpg => 羊皮纸2.jpg} | Bin app/src/main/assets/bg/羊皮纸3.jpg | Bin 0 -> 127459 bytes app/src/main/assets/bg/羊皮纸4.jpg | Bin 0 -> 135087 bytes app/src/main/assets/bg/边彩画布.jpg | Bin 0 -> 294258 bytes app/src/main/assets/bg/雾花.jpg | Bin 0 -> 40326 bytes app/src/main/assets/readConfig.json | 6 ++-- .../ui/readbook/config/BgTextConfigDialog.kt | 26 ++++++++++-------- 21 files changed, 18 insertions(+), 14 deletions(-) create mode 100644 app/src/main/assets/bg/中国红.png create mode 100644 app/src/main/assets/bg/午后沙滩.jpg create mode 100644 app/src/main/assets/bg/宁静夜色.jpg create mode 100644 app/src/main/assets/bg/小清新.jpg create mode 100644 app/src/main/assets/bg/山水墨影.jpg create mode 100644 app/src/main/assets/bg/山水画.jpg create mode 100644 app/src/main/assets/bg/护眼漫绿.jpg create mode 100644 app/src/main/assets/bg/新羊皮纸.jpg create mode 100644 app/src/main/assets/bg/明媚倾城.jpg create mode 100644 app/src/main/assets/bg/浅黄飘带.jpg create mode 100644 app/src/main/assets/bg/深宫魅影.jpg create mode 100644 app/src/main/assets/bg/清新.jpg create mode 100644 app/src/main/assets/bg/清新时光.jpg create mode 100644 app/src/main/assets/bg/羊皮纸1.jpg rename app/src/main/assets/bg/{bg1.jpg => 羊皮纸2.jpg} (100%) create mode 100644 app/src/main/assets/bg/羊皮纸3.jpg create mode 100644 app/src/main/assets/bg/羊皮纸4.jpg create mode 100644 app/src/main/assets/bg/边彩画布.jpg create mode 100644 app/src/main/assets/bg/雾花.jpg diff --git a/app/src/main/assets/bg/中国红.png b/app/src/main/assets/bg/中国红.png new file mode 100644 index 0000000000000000000000000000000000000000..32eedc092edbbb907b2516c4b40c87a3d80e8093 GIT binary patch literal 49779 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±QnKRN0yS#3C`1vi|9B>j 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 literal 0 HcmV?d00001 diff --git a/app/src/main/assets/bg/午后沙滩.jpg b/app/src/main/assets/bg/午后沙滩.jpg new file mode 100644 index 0000000000000000000000000000000000000000..afe088dd9399ee54b59deb5c1fdbce87557bf235 GIT binary patch literal 46926 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 UBF;G-d9CG#ZCLA}h+7~3*$IBv3;+NC literal 0 HcmV?d00001 diff --git a/app/src/main/assets/bg/宁静夜色.jpg b/app/src/main/assets/bg/宁静夜色.jpg new file mode 100644 index 0000000000000000000000000000000000000000..501a467487e6e3bc62d59bac03aa00593b6ee83d GIT binary patch literal 38530 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 SsOHg?Nc#bH0x}8Q5C7RscWjsd literal 0 HcmV?d00001 diff --git a/app/src/main/assets/bg/小清新.jpg b/app/src/main/assets/bg/小清新.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d9f229e1c1aced5394dda00a17ebeb6ad3729e6f GIT binary patch literal 177012 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 z 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 literal 0 HcmV?d00001 diff --git a/app/src/main/assets/bg/山水墨影.jpg b/app/src/main/assets/bg/山水墨影.jpg new file mode 100644 index 0000000000000000000000000000000000000000..588374c68a9d6a2bda5396eeb21d568dc89df0ea GIT binary patch literal 39970 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 literal 0 HcmV?d00001 diff --git a/app/src/main/assets/bg/护眼漫绿.jpg b/app/src/main/assets/bg/护眼漫绿.jpg new file mode 100644 index 0000000000000000000000000000000000000000..daf109e8d627d3e0c72f0efad45f96a276499b16 GIT binary patch literal 114471 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
  • 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 J`qBU9{twx&!2JLK literal 0 HcmV?d00001 diff --git a/app/src/main/assets/bg/新羊皮纸.jpg b/app/src/main/assets/bg/新羊皮纸.jpg new file mode 100644 index 0000000000000000000000000000000000000000..eec310669d084af2c89dd7d024d2489c27c564c8 GIT binary patch literal 42643 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 OY8H{{!zTwd#>c^$$lXh8l1=b}N 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 literal 0 HcmV?d00001 diff --git a/app/src/main/assets/bg/明媚倾城.jpg b/app/src/main/assets/bg/明媚倾城.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a68967cf266234126067ab0c47adfb4e35dfd95d GIT binary patch literal 66271 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 TBOGM)r~oW|Dcl1zTxb8;zw0q2 literal 0 HcmV?d00001 diff --git a/app/src/main/assets/bg/浅黄飘带.jpg b/app/src/main/assets/bg/浅黄飘带.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ed033c0571dedba5e766b7360698fcc24a5b0aca GIT binary patch literal 34431 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 literal 0 HcmV?d00001 diff --git a/app/src/main/assets/bg/清新时光.jpg b/app/src/main/assets/bg/清新时光.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4bdd5aba63bb0463c2451131b24c900454811d94 GIT binary patch literal 42584 zcmeFZcT^Nz*Wg=ClcSO|NDhMJ92$|FK|m1{C4=M)0u6`+$w4x-lB1F(BS@6cK#Sxo zIY&XjTRhMEzB6m?Gk0e0x_7Pb4|>s6MV+eZ6ZYP}z4tlYf5!hTKqwWwY%BplLj&Lf z000}ngir$*;1L9T8$f9ObNm#-0YLvcj|LX<1K<`Q1mBhrfxnJP!DF{j8vy;UYXBe& z+*bm)7jOVzzxD6Er>7^cy@idNJFl6eJs`lxFDk*uFCien$S*7*%qJnh4**aEL{fO(kz&~v8uD>q%Kid3h18!qu0BA@k74lW*eLCq}y4FXmb9eQ0+@M=G>96-N~L41c_4wFRZITn*MsX$=d zdu-82?>jciiu0eKTuFqQdUvbd#G<<_~@~b znYo3fm9>qntDC!rr@d=4Z?~+qe(>~e~9o{=wnV@yY40v-9hAfusMQUjMsg|3kaL zPJp1HqeIcLuGIeLI1B>_Me9Rw{}ee_)rKqc+lH`EO2$j0SY!87r5Eobis`j+$h40 zEx0jvrG`ykV4GnK-ctgV*8s5vrG`ykV z4GnK-ctgV*8s5K&?AOXMwkOJBe z7{-609i{~GzgC6*D|OCIUH(hS>dkQ649AVJ`ac2)PTU3u&~r=*r2iO$6Krn6FprNB zP@i)onj`%iIKdJU32E}721H}zO3x)|+ z5F#~X3uvq&wINOCxPWN399Z0J4H59u0H|d0;l%%&UK_*(yg^Ky&KrS+h4qmXIRF2| z<0oN8X=}_q$GfMV-5wMS_8#=rkS$Kt4!umg*%#DMgZVoBgauMgN1owKYt@G!bu<)|x(U3?dVz9KNIFiwTgNSv%l#{>&>m_vES%hmE+nX?x z>;HK}u5Y4SA)H5|?LIRC+|e`_m(SBM{}z-tSer0Hu*>MnqCdb{5gOwh=sTqN|BGN5 z{VtXs44>Cm8>&WfguwhC956ICK|!asqV;%}cHfyKJyB)&dK z9w@k>2Af#iu%(?Ulb_UPvc0L$vnmJb&SzJd4jZCO478>oc+>0a>OQ^i_{_-T`5|aS z6jF|v%|0LH3cVo)dJ(Cr8$DqavZ|OP8=$BK1%nUO4Dt^B4GMd|>?|p8eF&!k%@Et} zr;yOX0VvAj4{*|I1l4H-O%jUia{m{Sf9ek~c?s(Am&+wsIqzTPn3CX=&_bo#gz%6~ z&T|o%VtiZHBoET3#*zFRUz(%P=wRI?W<_EM9BTl9g~=R^!YPSopCQGOR?^n~pV~+? zhc9wm8e59St8k9HHZQCp)qgwWY)XY-U$;~PbN><+;JQa2T}#2&-eVyk5xBNIB>y&? z|5m&IsGQ;bvn&+u)pKx2?xm!II_QIWxW+*M{Y#dvN2HpdL0p$|hX@fEfUMcVEGg>XLJv(P)@b|gx zTPW}XSvO%4b`)yHL$EbvIz~q;)dP=r5gaPxEl}E9s$D-dJpe_BHc~v<6x?(3t(d$% zlrB2pKjbf!ld_CfG|08@yQ;ZUL?9A=^4g+Xt64rO0_B+6WIOM{E1UM*;SBLeomtlm1#1Z<$Unrza?xa*y;p&p$xT`RJ+AA;BMD+rQd37iWcNms)zHv@wD~nsRt2p8fh0PGK6Gn@SD( zKTM}(dkY4`LBqz7dCyw%&HlDl>dCE{Riy3-Ts#{K(AmbE>DrYEit*y@07cH1pP=_x z*f?x-5=T#_%lt0lfN0@y(qPYHO-Qe>CJ&Y*qX%=K5+{ql=`lm5ic$DVKn7C3soT3{ zQ_kouILtV$u`O2LP%A<9%R)U$x)_*g(Zp^&xtSe0i!cf5=Y{jD6$6mMy`@omNZ~%? zmfSf~ha=#rHJi+X;;T@m!1MSLtKcy>E1}X;YrObiWH78ZDcF}9h|?sh0eTCGJ?S&G zMgrsi2UGYjXAi3K2VjFUTh9D#Eb*ct$IsyHt7W_o z84m*{FFEQ`h(L{(RQ7zn;wN2L{rX;7R`t$r!i5!Iz0YT_50&ax6?!QG&W=CKi-{dG zg+D38HebyOpf%MoSP6Q2Z?P$D5Gl!aEmcV z{sGR{(3sf~2v4dN*V7O*T9)H4q`=PvR2+=(&~E_4R!UjxJ^@-IsYLdE<{XoTk?TkUzjCqU3$ci$B0Sgi)CJAHZ6_lTE9di0=>JrE|co z^Y@rU3jd|APkM$jqYsHrLnuswGs9P|byCNX>A|&@Q<%U5(sw{x%ysqRnrbCUj||N` zq0_q6a+0^i45h{LdcGQ(e%rBLe(utm)*()-)6*u;DRqD~Rx$za5Y1Ow*QXpu{|!5q z&7=*(c9eueIl|RKrgPvBfAOntWk41(f}@|mYvS%YndEN^p_CC z63ne>9p*z{BeGK>3}7H94wh@?aI3`(8c7 zi^B&!3_4^Z=!2v`(3so4N+fd=s*rX*(^gG>{+iI=2#?8KYClf32e(quki~uXv8o7K z3HehmGDh|^zdwKk5UbJ!Aq9?NLC^PM&Q;D+{%eXDyAbY``3LoTX4|mGp6rHnO4>f! zHbu{$NqY%l=Ju@y25DfBhfv1v{k%s=jLc0E3mvWTpm@QRm?RmmD zWEW=3pT{uUX~@h^X@0`KVcW7;KRzUGU6`sxkQR_w0 zUb&URt&_7JrJ1U%td=W-{n@nRI)K)y^Xd;^i?*i2NWTr^UwoEagm{4?AQ*{M8+{?q zu{}BoPYn6X%&_m!vOrq`s0lC*X($KKKJNf5U--DJE=MR8GhG9!e z8BB*j+82><_(Qe_EEkFttU|Mhq}N^exFnQI1qiu}KH)UYFS{P+qDRaVHv8&5HIBSmJ>wQjU#Uq3TmHm+ZDrS&x z>TWYm&-%LDgQp%u;^*3061UX41S2p!?xkN1BP!bUE)Ou!4{e-{o;tVf!d&0CKl}K! z3yyM1r~MfMDO?a^E<^t<*KYsyFbz%jfSzSbRGSQg*y>jpqD;j=ZqOScOwqp`98-qL z{I#Wkp$u~}{95VpRbCAWwh569b`pDt%OnzChaOm1_)coKVT9N5D1Nq{oM)JWO!X~R zfRqfOO^tybf-%bkhAcRrtFaYXtQe92`GgH?p!ejW5W)eWG{4=c79n) zV6TTpS1zI?;T`w zFV={x={;LFVW2-ax_gGCoi%&iO({g-b}xHdPSlhY+G5R|8Sg#&2PlIKb_||gT8ogX zf-%U@E-mY7(S(v1vtDoyU7JPfwbKsZ18{pmSqYbe3Zt%m1h<#RtfEFuthl@4t%oq|==X0d;zN`g{ zuO*0wRg^YbxN}x(6rfsVRe!NYxz9m&s8NEQ&_5)n?773?FWz%ieF^momukl{x=+ul z7Xf&HA!(Vs|I(b0vC;c8nf%Q0V0P39ng*ChLIde??Pq}R?*&!Y`GgZwQLNvIzAzdc z4~W7z1|wbLWzt2_Oqwrj=Bn@NVfYI3AZ&9eKsEm&I5R?=sz?Z>*d@*ck1SUlE^#5` zvY>hW5gA^#CqP7>lx~3JEfrjOszt`i)Nh~N1;5+XhJQIK=kwAys=@Ub(X3|e-3ckO zr$Ov+;P_*Nh*Kd*P}QLjm6gECBZgO(98|XdlmxAX4CXek&#(3nSswI`bPABc?z2oUQo?89?PZ`xuz*hEAp#5Z-Ql;?eq1cVS%_UxF|Ux&uPsaa2&{1Ia}ewo z(>`f{_SxEX#%hRN1_fc$?;3d<0Tf8b%Qy$FcLL@E7I#e(zu{sn>%7=dc2Zh^y$OfV zx=y75I(M$P?0T@M1d$czda<}Hy&DS3gkX>fVNVN~yjU-s#*xpu7=bKmOUA*74qasS z5IE%bt0DJN528`PuBeom^crLlCg5G*fRG(nlG3q63m02YgQ?@tan(15bg-jFn_w;# zJM8}sU3QmQ_rU}nA=t@s0EfBpmT zt8L!iGOS|qv(iHU1LU#!f5;xY{j@VyG)$<4+Eew9=b{AtHSvo9Da%>XB%brC_HA_&HRoan^j*Ofiv1Tflf|>wD@V> zhSfGUKD@5*IA1j>xSviC=34Pa-4)KkVs#zkf}T5}M5H#rBIP361$vIYVD=G=f@h+M zi9lB#^dxtwfxi+lM8x#)U>I)Y?`05SU|5(0aHO}mg0~YDBFdCXXA6!IPqw7gCHaJ~ zy<)SRun}0LIaSm^syRA75?U8|xtj-YK93}cgWdXuE)X0m>b4G}5?nXO?>-hIg`}*r zSP_OsA3-n=r_=1q;nK#m%Mmc%{b>+1htlKP=vii-;-HK3PHqr%HUD;ufrM*AiKdX8 zueAzFW(6`(-(nhv{3(_&quL55W$y)7f-ix0JhvyQST#XOeCV;H(#JfO_DSOuWm1cY zM?Ncgjc8H*((+#$G*d##KQc!~Ybq~RdA)x7a7t?E@vpgsGCm1;CthQ#*Ho7Z&!udI z9%gkX+qPB{Y_&faIa<$_rrP6w^o?eGR!HZ|vkRmB=Bp*5BwLz%?@sw5-j&%w>1Yov z%3rhd7B%6CzC0EZm1`Xn-4&Gk_adh#$5ye{b+%cjTOLaOw(1gC@~?7g0-dIUA*OnY zSngl>u7?|^8xngc->(xM!aVk`w4KaQyWvs?w$w?T=57YHGJLOy>SoR81P#eVQEwI< zpLjWTdNSWDG>P^xh!EJZ@;Z?yxre@Ko}*S|5{#N3efUJsRb_npr4)q=n&9-{{9*6r z6UAWP_>D~cx;Ij#4zY0QO?{QE2L*WpJxA%j&IxyHXN8{dos^W^5>x`_57Talma;DuF7>5|-kRca}-a0;z%iW-GRh2K{y7U>-xA!C1b7vbX-8FT& zAGe;iDy=ND^4dNNOBHB{ilp_k7C|*d`uJ$;I1_PMQ^eU2i6KnzPFnq15=o!_gF0}a zWwdTm!#O40rPt7^IKfThXR1jB^lvW`V}7KS>ygMPK?{UzQ%G4~xjEQrzzTN+{H#&9 zG3-<;X>3;(hRJjUeDA(uYD#nPGuueGrU4=8EankFWN%C(3};2uADlX`m<8O3^5fT!;(guuu;;l(M=*_!i zLy_7z(@w7#Qug)T$Ia?uemZFKYj4+m!;|X26mtdX59L#8Nw#S5COOtSV7Rh93 zpYLwys%4GiDEP(vN=YXC4M&7>?wl7b=orO31rsNXQdK)H>I!fD;sCo`U|v%eseP-bRCarP zp7A7Ujf}^>Qs<17p0|CqvO*JVY0!UZ@>8Y>Vc|%{vS;w4@3}VaG*cz-*u{9AjYsM$ zRc_0_ukT`BT1SmI-PcvjcuE(WQEDYkL}%+4@lt%ageb(^{71eGDo>>ck6Tp3pX3amO#z zPL+uM$a|R^*TGep+^$EwAzF6WbDty@%eF7iyjm#lO_8vN-K6!-7ClU=SFM_y06yhCy{^g}}9sbcK-_ACW>-Eq9O5g4_jH9AD|XRuR9B zcNfk_SoO^)Xp@?pN$tbPSQ7I2%`!OS%n?o)%w(I3_b z%y0oO*$_aeRw511cWx{XCI5mT_Di21081Z0w zfQ02Mn4W?J@K1%FhW><2(HfgCAHq84x;$yMp}`qMsu-41Vsu(EsN1`Qgc8e0VLMy3 z6<__wo_BqEyNzEYdV=19M63;jYalwbz!r#ARvFSUDq&%aAtZIbYTX zHPp>KxMM6L%g11HA6#{ODJYExvsK^d_q`D5Qj{Fg(?Y1yMRG?8?9kue)zK$=&#lpa zp!yEKG;}s^a0b$T`4Wk>tR;f4Oj`vyINo2W33XUugu6688wq(Ki{_ zIwHzF*wiaI#II_2BCA;^%ea#s?W0age+s`yeBvRs^z}-@&gsPGzIWBpy>Y|4`4dfy zUISy%cl?vys-$;5d9mI4ro)UgyD%RSv1-{wPlX=zf=)8xRamB@ zt1S^;QTI;U>PTA7vSgLzTnDzO{}wUl?>jUeljv$=w-o)j_0i3?<7zNNsXu~@CoW?QH0K{BH3Q)A=k>D<`1!w zIohvN@iR?bgWL~MZc=AUKSfZQwtiN6txjYqg!A-Cgw3_I9H{iu@G>{wl6ORW&RO2& z5=kbfl4}-4CDraHJ}mqg_-*Hr2Cue`*Gxwy=t#*wbtxrAV2wnbqPA+Pg>oQEgvCB7gq*gF(R9AidS;9rp z8j@P+@K|$by@6R{qd64rXiMxjD6u_!^S^34y(aMxH>|Mqdq~-&5%YXV>_= zNCC$|!LdMFF&PRcgn3}kW)C>6bf&T^$NT$^JPFbhL7qkoPO5saiEIf~46$c%5}x4V zHW2)ktjCj^ni>n7!2z`gj|oi3%E|Kg$(@p7i3B&beeO9y_{12nT#ZOL+8+PY3y3&zF*dUNq#1NP|1- z*P3#dU3~t_u?ofE+=+p?3*{eW!A&w0@ek-+E=!{G-SuBa7mHC2w7BBPaCJ(Cx%1rK zW;w>n<5(SVi250?@XW zz3V1Zef3ehhfaBb#0KY^8omG|1I{J>T5uc6DCj^sY68^b=OlY#2iKQwsCKqXWR!ml za4oDdni6FFH2+D~r#@o>g)n>a>y;U+;O?dpH)kV_$T=}rBqM#3K9|O=4G-b>Be(F; zSJy|<^4UdfI&$HH)dmr1(*upvIC%+C#T1iu6cW5&3gTiZ04LXx{2$Ze!{|RI^-Hsq zQcgvguO8oTG4mIj_h$=1SI=*VRVms?F|*2>guyQcJjJwg=E!V`-oNd9(B1fhpz+1; zP6?CRho96W%{UqMn2r357mHHz-miML2%`)hyOz$XVKdz8DN2(mchM475_R1tJ`p|> zmR8X!OenM4(iuF|BX*21YR__)esHgdaV6$O$YpV4ZwvP`ekK#uh4W}Lbbqk|8y-U2 z&*y@}DXv~;pc?q7gOiA0y z8W?q(O;j`7@)Fd>t)FGcgcHzCWNv3J} z=wQcB2(tSY4o(uVHhHSxx@|N`=7S{%~7P8kd-1Ux@Gt)j^#RK7Oy( zv%Xps{yLbGs&-)%WO10@*HVNJB{i&Ws%NS?EU^U>lfOKNz{pa2=RudAJU|n4^4MZy zn+ecb<;dz7+5^L$A+;4t<=Dl*Ob>L~tOorU<*^9qgeEma8?KL%qC39OxG-~Cf!n`D z2CvJ}Zt1FsBU;>em##E0nZVFF*j`Z^%*2Q@v#h|Q8{^G=Vt#J~y0mm8Rb`lZAYRQ- zUUpxkL1)N}gVRR0lFijw+BS%mbjX}+7adn6-`M8y2D5Z$JwO28y z8<;9%(TC*>bJ9kk5u%A>9V4VzPRlV zJr|8V>rt)IN;-UyR{1t6=IO9|e$oR`Gh!=9$w>PmTeVea_i73W^80-wgJ%mUw#+Orh5sf!|4;fiK4lZ|Id^iGW0`b6mGD3dA&eY&@| zY>Mbf3-4`4>P3=$8JO(K@L=4pL%OXSea@?oPq6q^3Nv}F7umq4XQCE2nd_f&x@%~M zRn3aYap3g%Sg5|tg}3Z|X0hEnABBpn<1m)zOwXF{9HCXNP{-F6u(OVp6tQO(SFP8w zuc&co()}1y+CCy1Rg5~eqI;>IP@z+kTKXYtP7CL`Lq}2wjD3I8M5c>9N{>Pmwe-;{ zsV=_%Yeuc6tC7ot!_~)i_5CJ-uO`F?Z8Ann*mJ}szc0g;u||TiXsQyMtU7?NOULCw z;%?%N8L@I_p+5M=`h)(f@0aJP2X)ONOz`VdJ=u4<_|FY2q&)?xbxTVda~SvJsWmxN zZLHlzWOy4RSZkYW>re=+JGsv?{HXIr)sOjpof4$3Wzqf03&?4x%`TiSeQ;>!=9%Nm zDb4*ZkJXRJ3NNisYu1NB*-L)WA#~AOu7FsZ$q*6QfT~(hXjPy%Y3l%u}da z&Ydi2YwoHl&3HJCF}n}L>Zm#h69Ydi`(cg2dAp`F+({w+f*DARUqe!ELZl589~`oi zFnsS%(kmm%G$a{X=Ct+@IjaAZC&S;&J}y|}AgvWN7e8MKOf-K!B&&*p8b~}|2`1sS z9P}NV3{2%--ft^d!+cq`sh)n8dceP$hOg=(A~*mTSTTY@72!-90vm_D2!XlmI;4u> zMiY3v4#Uapa~=!w&T1E&pT|WTA$v5R22IalRe=m@KvDk3J!tT;rB58}+t=wSG6YCp zG=mM%SJ}(j)X__q*<(TC6T;}YBA0Tf>vFXpw5cOR3bFFNhMGl!b$%ybejJPo1E;Nu zmo4|l!KGqaagk1@ijW-r&&2ooy;ma~5hTS<{B3!hZfJdPy3rwz#qCU~SXOv~FQ2ag zyT?WD#M5~+u|0w$CbkrKR_0B$OK_Q%nht~a!?^63o7u#RH3W7Gl4PHq4=(d{La1<@P(o3ku&d1LO}joaNjR5I9E4jZO&7> zCGiSMFJUhR6)(N7d$!u$w2>wJQnWuxLO*)GUtF{nF4{Udd>e*t{xi``eDj%HXrb3J zla<;XqMtF%vkl%8{YypTHa@O*ar+6Cdr3zdQNz~d4xP4S9`l&O#ftXHF9Jzj9!C3Q z)qG@PGF($xQM$e6s-?3bT<#j%8loZRGIyWPq*9qZ=4lO|QT&;X(aOeb`GJbt+AFNdD+sg6RGoAc2v3H6BHyVl%Lz}nI@-Bp5Krx)wAULzNxthtkK@RGBs;m zoYpaSzPtFOR7LLUBw-bi4tn%UW(h{%Th$Ml?2$%mx~7%Cp&Pt^96jPXB$QL1cp|Qr zKmCZLak7puRNQTzlM!h;Xt|?s*0mFQQ0f!JznUEjr9Iu%73#w{cvQR7%t5IC`KW6t z>a!5!J*^ofJ2&$8sB=SoGusGq_ESR^z7YQKeDozZ&KC#w=li;m$1-idES4T0b1;t_ zi{tl`-qj`Pk)0WE)#NtY{4^fz?mDUM{6<_j@k5M)OlJrSBsiLz?;i8&B>bMD_tGYe zB4?vj71snWOcSXjMEoo=rVK+S?`TslKR+qvy!#K}0XHF#!2O4>-uz1`p%OY@*5=0G z0+v`Aw6xk*+C5nY>cJz$GzldZIIOw?G_p~23fyjjY%c_V9F#FT1PSK8kUJkeW_v<4 z=-eqNzM~fhKS!$Qq|+X=!I>Dn`c(`gvn=v1ph6gdyz z`1n@Y{)x8-kY2`|RA3&EFlYbjA!hCc-w8sPJowh%*&Imwec1X)@#I9h%N=lKkiPr0 z_$@HWn9W3Zy&^4dt0RukUoj(|~m0md}fd^p|VFcOU<ptT2r^2-0#rB;@=9pS?luy?(W!R#wnIV{jZNc z8sg~sX;F}=DCrHmW%7S?oajrSt}F97s+m4m85ut!sOU~&rt!IL!msn}wx$h_>PL54 ztH>;lOyz=|m>F|fYa48czmct{l2m$2a4?_}2Pboi>R&bDf4Xnrr#prsHb%qr5}v^4 zcGxu=EK5_A6nxjZA9zll!b@+mLyx1tpE9h!0trU63d+Xg7xh_~vIu1y z*B@&->sWsyGN|5QJE>nwqt7EO`0#k6e=7#OExR_@RMPRBf)#htPA`)vyij6QZiGif?GJysJVrRG^A6*k8oTF7$z-UCH53b!12&}5YMM0|d*>RbAe z>l+x?`VCc)g-ta|eiA(HbnP=C%3pu~oH8EMiBk>nt%o8|8)LlZLK3OldjH@S_G%~@^nQA4p z4h$C4CRC(ffA1qcU3{&@#M$RMJ<2xBS!KnNhRt|agE5alCInxb1mr)Eu5X+Y#6r0~bNF zGrkp@#+Ai8_Sigw;PTL~6ch_(Zn+}w3f{yLrCwzvCD^ao#w*}SlU1@jf9IffyZ0Pb zIBlhdnNk9;2=cRg)ZS(VuJPdDvx zpeZwuJ7JdUV9X{9)!|xFT@CTdUNY>Mp<8~dz3(?$$I8{^p|eNk9PG6+&we@)bkvd3sFp71 z(A_wHKv4KAy3?)k!C7kWn)DxlYxgy+u%&PXuJcdn(++=*QDHh($LdstuLAV6Zr!#= z9Jzy>iqaYu4OuVLWW~#eUQ7%~Js^)%abye$@Mgpp|Jh)G+Vgw7vdBLi-7V?2xJd(h zU|;Y2Lz=rX6T86DTiEsSBp8nPE=DJrzfq~d&NC2fU_x)Au3-C7zW1X)_nhsB zkOWy?=XB~MjZNEyUFuTinNBk;>1uAo-Y?(or>xE=n+27D(W*hN5q<7+@-6Sw>>tmq z&*37fY8pQC{*d_4zKbWm&L(yt81b`6WXOop9b1w)WRLwT`(Aao7D{SmIJ3usab@`M z(A3j-48_{#oS%j|cNo0-W>6CWifco}`9PQaox#x^?%^owjG8-sVeEqtmh%HKG9{@c zGqmmK)suC(0gjAv#4kdeXIgn!f}Ua;suullVld=26LFGATIGdYawAq8-*?UoG_pGn zpo^NNe|FcHV3#$*N0rqlo{F)mKx@pTdtI3ySI#u->)K$wFR~M5&LR*gb;LrhF}ghR zS&cj)J*uekG?0*%z$=;h{Iay{XJb?BwldOc|J=YODQPfLgj{38FL`gXjbOn1PsZb^Lt1`RwWNVO|+!cO|{H9QKOZt)jG~cmBDkuy3w5!IkKJ}&W{5%(J^X+R0fhUSm6XR~RB?7F!H%+g9epKB_@-?{=Xx6X*l^pke5 zB;D!dq8Isw&qos-*tT3wMNUOJbE`a3CAJ34tmx1rt##iThonAlV6aM;3Z7eknBS8e z_x=vPD02zt>83$`xaWqx!$o$Uu6ZoIU>fkce*RT8PD$KO?{3x+&Xz<_Koixr=Hz%; zY-WqGF8c*bm;}87hOL@h*xeLefofp;cNoJxBOnb_x?}`CdtWG(+DfFFB~ZEC_6v&sPDl{FAxWL4)z0|k)?}&84?zE} z^f5!7)ra)}?7MQhV|}XyQe(p%-o}0TcaEh=G=4qFHG)4KVU)<6DN#_xa|_cqpFnkf z_~oe4_08HM);R>NwuZH`Lf9%lvX*yA*8rOsW6-%SLpN&IItMEv!rXU2 zqx5GeMD^$-6J2WC3^IP9h26UPg|X~vq7E(0SF$5CD*J?)EdI)mbS$W1 z&k617h~6o3dw6?oZDg43R5`X~(`kjj{8*mX81v#)-|fSL-(y$3a?@u8X{sgF>Kax{ zB{Ku8<)LIV$8Bd`_hG`{3@KPYNUS|y6)o#;RFe&t;gc16*FJt^DR#+?^;B<8{(C{t zlSfB9MDw{%;!QkO?9LiuXE2mlkJXQCv~|{EoQ9jIa@MsuYHO;)F~u2y0BYNG4<+>+ z^!n8Aa_C$hjNzf`yy9i#^vXJ4ex@C<7B$5rmos}WwF%5Bc%3w z!ouC|p2YofEOhrSpNIE(cD#N~+|OY5#1eZfA?~GIdEpDr zW3iIwtS9bbGe+|zV(#WWJq}$(%7^UabxK*bf<<$0(3c{qzq1T~6Yq3%jc6L;IjxdU zP!yf1 z=~21ayi^#`kL!r*~0DyLjW#Mgmi-&g+3A^{YAs=02a*^C!Q1SPj!tBc<5q$ILJBu8zPwP-l;}t4DB{I@g;jex>%-7|7h6-zGW>}XqQLD&qjLtfuwl$9YX-(@P z^71dg3V-w;>>da7?O5JB?um$ud`zWz&VzMVs%CY0ubB9Fd*{hF5s^E>AI)4V=Lvm; zRXu3}pQ^A1C&|2IA1y4_{OTf5Umv~T5-qrZRyj>eb&4w>{Xcu zzn1yBxN^9uXr6pU2vmNO-c;_J*LM+w%XQl#sJ*20q8Du!cV4bWCoX(`f(Q(w#EST6 z$xhm9Xb0_<-tcz+}*}v?0 z2930ewjcG@3Of`;+s@wGPYxq1yQ_4;+~9nLt+Y!UP(5SEPTuW4-Z^@KIr{A+J&xs+ zpf_H=zE#j@G|#=T+_S+ma69MryD;B?D4U*e*NW-Kzn)^(u8_`~u{y_;8FS{<(~nl< z+gCT<5^eH6qFkv_q3SDe!TfHfKV<{K`rVa~eUK_%P@gH>iP~&su{4~u^$S)NL?qQ9aYt~Px4qho(s;YA0!*kAzlq1_7-BL;iFPL zmufBj;g1*Nv0U#Q+T3MTN8EJ<^9KBeROuPA&d10bBKr6`B+XyR{(PkR!G}IWKWQk{ zU*rOCBwsrf@bY}zu(wi2!Bx@nBB^3HAgvU(!qR@```x3rjmx&H9Ufbl)I$qPZN6oa=5cIVT#uaib@-Kh!7T045up>6z$ngO^leIo?%9*~JaII28~wN3_g1Gq))UEhje);IeHBe=I_NDuJgJ5`fFhp_y6y^pH;ocj zXpH=5b*AV-O9-v=x-3z(o`|@2)g8-Y09n9R?sh+m#=J&y{CNAZDgWcC&fF=pohe0T z$|JFyEXDZZ`R4Wp;~`1McY1>KD`k>7oCb+G13UxYgl7A2CY$}M``@!oj7~ihQm>eL z?|h*&Qk7^jq?owP>?7F;;Gnt#Gtve+il(^wRuVO%i+kjuyN?GX(~Bb%*5DSKL0r@o zbzC*WHXer!u^h?FEM}O2)chpyfK0&pzK@@?9P+7V=%(B~x0jE=>6(C3YmR?5pbTlZDRNkm{MDOW(eDuW%|4ZRabT`%bhT=P1?WhY$J5 z4erU82$}T<>D*<{u&i>ib1mi(uIEb|`2)C4sq*ZE>dVxq8Zzlr;Izg=e?HAYlN_sv z{}d_|@vWK4MC(4cTEbxDX39I*mml0?K^DuVGe$kB@wZqsH)DRPeC=Nn=Aj-rs(2_e z8tocMJ@~L3i?_~a1^$&Ze&>f&911sFDM2^Be$?iQb@Z4_K_HjJjcZzmD*u=?uBo&V zQW1PleQaX}$Dtk2+{vJI))3*J@;8|%*427|1`Q%0-hy5X**Yh~=m}v$KY3stiZQWemp&TB`=#DX-8S;&J27{EkJzsNT_Bt->%>;t zmI4WEE7Gm!PwJWYa^_8{YQRzBNTN)w^6Xo9y*DnYG1hes+*w58*ZkP!G#B>tw8ctIuSNQnty!qAy4r$s*Q8&VP)4O*Wh@ zQ(^y-kWRnRL2SUs?GtWRrEeBFv!uNd$Keq1h03sy^>X|lK=%zT{*o6}Sza%h+tBUr zCAvxjEo{F|y^Fr_guZtBU1sFkUU_GdXsqdcyt`6bRs2cXm{RPogoW&FjD048;mx9j z&$%0Mms>uTP3wJ*2175R(KzYr_9Ra{_5*@``eyo?kj#i*E)c|DEq@2Hk=;iksvU&yK$H!zk_FP|}bcogLzS?Nor7WJ=UIsz0-#Y2~`(!9?Fj5j3@yi0V z40oK5%fsZDJG(Rnb{-A8eS0fX@=i@@XK;HHwUM+oG>Mml+5JN6<NN{{g6N3>v*u&QDrxZCMkmjCkaV$Fqo)3rO>;!QTsMvDsIcbD z+Y=|FT&89Bp;g^8U#QB$Pys?Qpz@8>jsi?*KY#wWlf$e?}PLFyFz(~2xC z=^_rB+#$r(L*gaZFx1h^m#pcnfK|CnW#&O)#c?B=&wZO5bzX#Y>#km-H<#$^AKMnge*Uw~{*w&7%EEvhv7N*M>Vexid{ZhTl$l{{7(q zmKGmj;)j`IQJn^4!@deNUYUrq5LN~>?x@>#Zj$Qr!FyBGhvZw+{)-NMGek@JRK`9D z5?TIEvW3O`f;-!cp8+ZJPdm*DfNS#PtGyE94~tV&EPnHxs@Z(0?azMsbZgJJnl4f) znY6b1fho>lp*Jh6VBVaFK;`EQXMHVu@DJv(Pb*36{kEPBTH$VGI*Jpoih6&l%#R^U zf7VAPok%b$BIVGnf+rjFC2g(Bj&Bi63>lT%-_;)BQ~n?cKXP~*QQuuitQYwbVgP{= z8NQ76MY%AtmcqFo_05wmaR&;NPcN@jpgE;5t|a{i9N3-kf|^}*c*wevdTYCB18f`G zzluQ{vu%GS4lHO@m^58#BzudTygfCe>wYc@$0V}{89LUD?{O}Ds3lDbC0x7*9Xv7l=1GZ*JIVAl*&7s zniuT#d8%DUsQAxTy4C0Fv6~3Lg?aPlZ1?c_d{VnUh4B9X!@UPUf;jB-*dyD(!u9%^ z(rU>aaKof`(b%K`LZX56=~*2f&c>8#k(FYqaqCqn7NSgU6c*?h{*?-MW~w&S#nd(E z?GU7Abo~xb-LA@X+tr-a@d_(L&hK?uu4XMGysSE8*Gy^mK6?>~mC7lrU0Sl3XDZ{S zPZhfOM+%MvuKtGhdY11;9Ot3dY%N05Rw$3yCW8ab|7 zkGpfQ*L8Kd)n|$}0^S4VMgilFrhqfel~x_vD^__QTVkyeAb)4xMtg34MR@7w4H&8p8al$2mR4KW18X41(_6a!DSQ5?u{q z?ntb2)P5bSDu&Q~3ut;{zg{X-tZNry^m*WtN1>@UQdc)D?&X1%l=SOW$jkPQ=WSuA z$8Z9%#D=n(JsMRy9ULb(Ki0Epqfks><`Os3`n$#2& z08jxy1ppKPPys*%02BaF0YDfUhx++Gf`BmYG1H&Qf_V|h>iT?FQMx(?6cFHe{=1~# zX`!XIQ#>8i_7vkLj!N_{v^=j=OI=78RxsQz;K*xuO+C*VwJE{f9NbM$w#|`R4+vP`c6BQI(84{UX}wjPakb-FA@&2kJZ0QFjSS=QVX} zEK&J7rLOpi{{USYReMFhX>b?wZBDt({@9?%6|qw7~-C+kt{z$z246Dk4kRVj1= zL4nEVxc022D`*4vj12WXsODF(QH{$b5)@N9v&eqxbtL=xS2XHe-ZX8k!aF%`r4wC% zU-(zDeJhh&*x6~Jr{%?OADKG^QCkeRbanL%ADM~5jmu{FsGFuP4i5#ob_%=uBC;Om8@{r$3hD2>S5gLP{g~CZtb~` zAC-D^Fi9)3<}rEmZptT~_=m@ueT*_od#FPSAjvMlK&|Cg6!b{)s@JPg-5)(`e;w!4 zt`3>t%_{R=xMs%q(1^kJZuQ4o8_^@94VF%C-)2N!3iz$#%uC`;PHhuRcE{PR^O8N< zxFuRrK8B7{6ng&vguVp$UquTg#fZGTBj%D}y^p?4WT5ZwGuEYtgjKA2U51BmWdcP6 z2^yyyD8?wPv|PFy(~5heayTQ6PC~Xvr%Fn8(0rY4IE6=2yeJ%s&9>RDqZ&X5&fs&O zr80iWPU7UQFvA(eOr>CoyD;?~MC4mqvl-cUI}hMbU#(p@-(JReipncfkG#4$*k3sB zj!)LTI5lol=POonb~)*;a9m_&v?Wb-DLuf>;zJSMf@LDD#F0FSlgB6CgP(J~ z_+sfEs$w7p&VHh$LsPaba}%WoV6Xwg4o!IG3FEbibcCpgix%vKVW2HV{GpdaFUCkw*dZ=P}>rdG( zcTe0P)tetLX%Q=U4SIZBMKbT-G80B!!YqK%3= z3qnIyo3lY^J`(Go`<`H%+&N}wP>C@xzo`tHBj1~m(aIYPk(V) zH6+hfIJ9^1Lu0DjjY~tjTZJ8v;nezn`s=neBV(P#l3Qx?z}{A*jPZf~xmWIcF#fco zCfgf&8%oI}VpyGJjfPQ_4>rtm;&ow^?U1`%BjVeb$oQU^ueulZHO4}Mneakvm zjjy!HMW(2-9B|vegnetBIVNkN>Q)-PhNl|6q}!VrBE1?llUkfrQ*P#xkVhH7^%UhR zvY_s@6dpkwudM?m-VYq}KnjVI+uD`IsXBl$k+jiqj{`gkU@ix!sOLa66{KWDLhMff zbBdYNRw^(rCfEY3U{82>!08{>xaU(-brVL~&6S#Yq|CipiO=CnQ*yoTuVZ4R5<=4+ z0Pp!xsXb11L8%--)e)~MU zPHz}KRjJBe_?Rj&h{tNZ2013Zg@=VTsq@&Z+H&|$7x9n9{{RhmWg1OORDosA0t327 zJ%C!mc=$!~o@{7Vtoe@{pT@rv{C7J+;O`90r`b8?^7Iw?eL{LyHEd@xvOTI9T#~yw zEf4m8pINvU-aFT|9dcZ6^0T%jKEQRaKiW09?BOseM^t?g;r{>t=z0~sygGK5Yig=6 zHlPI3a$QeSofyRIg@kY@`8fcL=ZeOpyBj2)#PGr+0OLPeMSC&(oL~S7=bvFp{X!`f zq<_3Kw07sMG4j6UX(v?WzEh4p=pQMcJir5kyN*4m7c1^_x|Xj6gc3Se|38;dN_JY$Ia#yUpAW@_Mtw~dk)`9=y9>gz7I2yp8N-VvkV_v zL>cd?s5~(yfGSIWxl?O?@lPK9)ExC4wmQ!XYu{wlEwv@yv7y^C4oDuf3Y^*R`tOJI zA0KJ3-%kLZ?PCMXjkY=bNA;_6xvOcT!!=KbqeqqJit_7Fw;dyrEHr$A#a1U=vwwOj;jRlpLoxuGEO4>Uk6+63J>2$kjWq~HR zBoa#z;)QO>P$0|VM`BABob~;-;A+b~IDa=&cl% z&l#p{r=il@3;;dzK%(_JD`Ucux88$eq_sIGj1O9wO2+B+Ma#QsFYWxOn1F;6?^F)` z3{r1wWMyzl=hBl`93`chy=8i{0g`i{UX_&hH;cKq83&=y7^yXZeKUn552k1|G~zgH z=XFk|(T$CWJ7?0dDA}}g8>t7qTw`-&?Q0#TpK-Vd&s=05Uuwo^^r_Ts8cC38w~$g#u!oU_hZ>;3e;@6BR=VYAo1*1qrGeO=e@+J6TB zi~;gaL`Nb30s#O>^a1`10d{}{SX^8jEFn5bNJvORWThaYA-8Lnw5)=hqN0MFf`ZZ> z#9k%keJTnHFfG_VH8l+l4W+%>C~b8VLR~}se-{CX{tA(VK&7Oh>dFer>i<8FKWsoj zO7atU01VOw#1uea1<;>&fQINkB|!h@0RHa*5(A5i?ovuxW|!!M7xI7@2n-ez-MlS10ox2m}R_X}m>ACV$0vu7_1zE5YruAV;H z^l!66SaS=z!$*kr4vtP9o?a)sPo6qW3JAOqbTRl+RY9eChosf{3HI8*@H42*IE1@wEq*?|98Mr{{KSu{{Z`caeW13 z!64DY11kV{U_R+5(h!`=VDI3PE6lwYcri=tx0o58IBBus7R+6m2fA^PZW-VAcKvm3 z`TPMon~BJN;=*}jx&Z<+)4(0(I3-Q_L|jI4oLDK5uy_jxduc3p4yQk@KtF8Y43?L( zVg}(mm~EE=4j3FBzYYs4`jOaDECH3vKRc8S>C3 znU`NkKJ{#1EM5`+Bta&J7xA-mN+D%XU`75QUUgx}kpD^|!yH+<9bAgY96uS5wKaE+ z76*-&g(kh&Ki5Uj&#E}N2i&io{MdNE_Q=aU{w?vrJyuDtg)WKjGA>|;IQFs_2fKXU z=F!lzW&c3%Mv!lPqu0yY6bd|EJ+O>M#0d#UY>MBPe+857Stcf;9aZiq?hOvFh#L!1 z2HJs(!s7Q-0Gj$O^U{PyBb5%_wYxR>iBrtwd@dsO02fF8ru^C4y}Ax{dbtW-0B}F{ zAr{4+DEJ;CP0BGh6qdQYOu(`j?v0WF!+1N*^$yzR(v#Zr2%2!tUHh*Bin5;gGMC@? zq*+YcPs{d{!_byp<+;)2T!8s9TnggbBbf6**M~=AWn#sl#Q5Z_LqX>pIs?>OiUA}0 z*R049nU`{=A%0qgHm?&u!a`+ChH&jW`LhApB^RAv*(d!0x{LUcPo0K}GYdhd}3>b}Zra^rCffa+oxopqa_$HY!+9ILazsf838gz zj;q$Je%Xt9y%Z`~uY;)$#ab^vJ+N1f!Pb{`t^EAQBIMB}DN^|<~HmqF}^H-aii<+JotQd8JhLv%KxcW>aWc~Z4yku0^JZt(|Lsjet$N1M`Ikkqw|khoO@ zzZq~qyi2!TmytI3W}-D4`Qx}(PRoCP0CJ(N$*XAn;T?SUgFCo~FUl@{x#_FV*oTGMq^@Ia`Gjfb=+O!0?7AvMJ*y~h- zSVTpGB9Ry)npd8F6X6c-q=PBV`Jj?t9LrA?>u1$%n)B7|-(b1ZcLH3P-(5`p8ehuF%1|@cgB? z4dFCFK6IP+Rq~VWK{|Pw^=_kYoYwx5sImXQlDk_Qo|#_`{Cmt7K`&)N&I>>13k2V^ zu``o=CTVNOQ=%h+u$jUk4HM0lLu7sB{BnaIWhsPq$=72K3d2Yom%h5{lWH9`X>p;$ zE?5C-m7lra7sZemR$jx(LVSXRrIN8&OD9CScwmD%>&-}YRmJ#Vjh7jfstJeBWD7r6 zIJ|Qc_X@wKtf(Szso4 zzN5j_4mo#WUMGhOs_=r$VxO)0S2g#abk%+{=HD~@@-+&OKX*tcW!aBjl5tub9}?DS zYPAPDA;`Y$#0YrOF=Rh740L2)x;`Jn2H7$9xc!LX52c=v++!fPxSL7+Oo2&Vv>q)+? zpgiobeOTpmYfpb4jrLy<$g|cFudhC_T5-WRh*SWmz`DKRThn>5cXhsY(w)_s@aG?c zb=Y!@nlr&*jklF=;`?;G@`AnCHcPA`_7BJFBpQjhC@Afm%a`9M!C-2%r z*l#}$7O7^<{3w-ziiIWpqBtO#ey~YJ74pM)7R)9FTtb-+1ygSKtIPfSx2Rpc|~He}K=G z_Ubl4S#{+hmIQM_$>p8q{gdkr0hFO7<&}w`nH^F+F)Lc0JI)Jg=Et;#M+kO93>EIgen5 zCb`}W$iU|!`R5YlGVqgyJCcTHSdr5+zxyVJCil7z%0xXh5}*Xx&izYgy1R_V)J>Qq zI;7zbaGI$Crtaf1#v%qag?;^zTR+5%$F+65lio@t%niqHQu8t?Te%AgsWOYq#KmQt zGrmW~s0S!r>}MYgND5DG z{zaZyE`6`wGkRdZiv-0rauE704OdVmt;MMI25kn_;%vCW2k7j-T@&~+r`p>E;yERg z1gM9qMXrsj%Lm?YY2@$Knpw(`#%Ez{7?K9cS*Lmahpzv6vbbf&Yzek=-sN+Cy3BZn zDn`qX0SRyHshYYbZd@N(XBL@VKpf%HG24mNrGYQ2b~TO#j0r#T>+S~xe0Q~R^`t|g zxJItil_1?Hb|fc~hCobgd`~&z_EI^r(5+J}X69pj^hWQ!lmGc}hG3Hs=DNC-4J*of z19OCvw1BV^aC2_u=mRk^0WyLaHl0(_OOcK?rFz}eKPMgLBWZe69r{j{$772xnXp$X z6$$QV$Pp)1INoYa90_f;o)HpqoTYFIqR}9X*Gp0PlE4Cdjiljf z&2byc_luXFGHd=S9T5?+o@6I9#ZUE~vDqgBmk%@F06D=?dHm1zbMflsAU5P%>ED{` z7kt)3xJ(5K6z}FTq6&3tlp$y?m0@Q#JZTAM_Sw=lOK1UnlrXyuwiP@HHCjY#;h2YT zJq?#G{Qfm~bJ9%+#2(=B@sE#*S(F)ArZAP@sQ89zjd4Q9nxqyogEGbn^bx?SnIXeZ z9iNYdX$FZ4dCOCUnse%Q#!3vyVMfz(C4m-oOJP0J=u9Jue8*6HF-?adCIwmSIkuCi z5B)y7%ka}>XJ+(j5iqNr0(0a@S`(O25wg=-TBHYFB85A?U(9HNsYu}QX5PzQ6LbxwU|M%x=ytTk+UvqiZ!D$QN~*{--1oOU1C$#J$zpGPJC=wJl2wiBeYaJ1ac=akp3W*~Vr*<4p)`68wC3O? z-T%aVOu$Iq7q(>c)lR}ZLc?ks^8s@UdI~C^)nO)J-Bz9?t`}X|-8c*TVc{xX`m_*c zD35r$g6BK1bNUl|ot^iJ$OafVWgbe|Gi-$Ue81y%QF@3zGHg_u6SFlYPA z!#C{Gmxu_=NAiIAa(OO+tM$n#i~W$CDysWW#nYVGzu(e=)YdonnUd+R^fBwHnlxYP zx5}mRJDQ|UBP1$3^^Md_f3J(Qe?^hePckQltNsTVcPAupt`66947QD>vRfg|fcGs8 z)3zvMK=(Ht_ivo%b!zVZ5JuUgCf|Go{Mg`HMn|3^#aZ=DB$Hoz>F|$7Hw$+aoH$=Z z+d2DVS2|IQTLK^Ts4a|(@8x+kfrFdJvMpt{;I=a zXKkMfbgfKe&K;mv>Nf3ozSrrO#SXoQ3gdAinH!sZ5At?3mWFPP zJ0H?;d0^3-a^I#tv(D`W_6w8MSW3DudKA5Ikhy;c(y#HZUmBrk0^=7Ly;IZxt8x3l zD-R8$`+~B8@4mB4yxl&M(h3ci=EHFoo;RknX30V`BM6Qji-Y_PbL~Y} ziH9RC>7MEliT~1E#hfd4O zLte_YkTVlPwHrx$b~;{#b6HIb)RMuTD34gbK&CnTG zukS1AE@})KeE14gJi(+BBWLD3oUBiHf+t{rT*&eQ;rcMrampMaEgnzTYctVQ zltfx)V1GKS{cTbZ_>Ep3_48tu?fvnTQcwgj{)+X^GVnRO%U;4eN=P9>eDds$s9O3P z4TTdR4LIDo>0HZ!XJS9Z#w`M_;6F1b3d4~;;BQpw_E+FiJ;tyLJ+Edj5sL__bbc;; z?u*>xPhM;6d2Dz{ljs{Wp)`;g%UNiInyV5`24zJ&3Am=v08-TqXa7p>4*u`y;o0j+ z9*y)e*6(TNyZ+IFEUu0&ADb2zP+-bO-3HqI(Jh{*&h?;oNG$FSX>q;sBc74pP&yFkOt4M8fqUIdLr;BCCu99Aa%c4foE|N0MP-Um^HdO zFML<~<>GPdh=HRaNPN$^+kXJ;RApdDz1}WNJL*@93s?E$BShMum;JCNmATR*And+< zhxnozemMCW7cFME(?W+c8g*rK`>U9M3%6-CF2cbE)?^mf5 zXPNd=_zcAlQ+=|&t$z(sf1_=W6?!pywZ{GN>oi$oV7y5!Zl^$%C{5heJv(6Nx|X=ffg+^2rsd1{9C2RJ`X zP&6_ZuV?=tce`k0p(u6hWf6zMEfG*r-F7Rdl#CYeurg&RGLt--bM5Y-Jr_9$WwjI#)){_QrSQUvAhk*PgKM`5kw|@>t`!}k{Kd)YFlC7-wLl%n z8~V&(-z)HJ5wBl=N)TyJISyriI;rJg!EhT&PDpb%CGhxrz>6 zR5*!-h|GSsyoFX4F)m`Y(03w=6JfK$!4NtlUP*SC#s~q|Hu1P^m%mj_-q;S=7v=#? zd`j$CWQicts`ILzV1n;rSElto*YJop=Q6}gaJ2==; z``|w?0~N%qm)_Rr-up0W%9pVGp_Nj}(DB#{@S*4Q40_~Ge6eLP(cpTGXGwnhTC-f! z{}@WeOLPH^aV?^ag4xC{KR`dde-BL@&&w{FSnjz57}eaCv1>TUOc-rcIr}!$uD-tA z|0Yeyv0Qx^L3~`OBfUH4`5as0bXGBq-gYSjrNYLlmu}txE{%Uj@l-PDQMu93EoeI9 z*{i%Z(3(w%ipa^A&FB=T!Y+iljH>@$=zaJsJlf&x%Q1?ihzw1CrR?+6^C|*sY3lDv z0XB9_Il(G}xlK{6HUk4c@Ea=zIjEgxly1gLdsZGB$1}X7VlPw@1NEszxEH zeXd~FH{=~VxOS+_-GbY|Rz91$=dMjAdjbRfgOBg0}n=h|$ zUmTs1-rE^$o%jxD({b@zpzFaEj`-)s9xL5??qlG>#oZEiSi=4&twD>xu2T;J?QhRv=)J7wE&iooRj(_v_I% zkSgxE7e@NUB1heiVx+tRKqun*0visR=y~hxy*DPC3>7&OGlbi+XU+rYLmh|GuslI_ zHP197LeU8sz?W$HVI;lbRhX7<;P+Bxlbhn$oxGj+ucy1*?e=bdQ?VtLRnkE{d15d( zG-}+@GBf4%vWWaS=^M4)JRnIDs&$B^vSL=IkAP9(J7-{h2~I<|?g4)Q8(O9<)G_LS zDwr;rys>TKe)w*_9!fH@v1(FTv~ZWEohj%Cy)}=#r+VyY;H~%IyO>{V zWyaa{>VNS=1e%AY4Q>$qwy`*tb8(51Db5Vw-b@#9|N zyT8S!_H+=I0+9E+245o~xc!p=dzC%H?r zd8SLMWE8}Pt=rP_nbP>`kTyE;za9<#@w049auMklCx-u->2F|U+hnCk#Qp*B-35pK z08$1MVJMm&cconG5oLauHo^@{#Fq#hZf^GOHHglQK4eFoc9#@aT61V`6=WVW=B7B+ zi%gaC+#eS~w#Dz8(3P-N{OJpya?k78!}teZv4%Y>oEp7`oaEVqIQ`I{-A&RwkgKD`wLF zi~J4Yo-8k(&Ve|)sOLAj+ao_xr;q2{ox(5(=gO~4QQ#)#FnBj%jPw|-^gKPQtd%Xm z3RWtj4Oo7zP#655kW7NsGSSklTqjG)vZkUh1eHnwc z_PJX1{SR=0i-;2E!>~J7fN||6SRSfsWM1ljbuH4MrbD^7W5@$8dLf|o@$rmI4x*a@z^ulu@y4mN9`w5 z*PQ+UirH~W;D|cu^tbd^b>@OaWne%taF65O=o+d}mMPa!8in5D6`auc8xcg-_;85} zj;uByT2rFRWve>(Rdz^sOIk#?mP+kXE{Nzz6;04#7}RBjTd_;iy{i{}%}Ue*Q(v*T zak5O}hN~=f>%0>kM$qXL2UvUOCst+%vL`HsZ2***oLLYS@Gi_%{zEGmS-H;bE#MKp z8J_ZxvgyQ3i#+1af3epm#Ztu3(Q1DH4VO!j7VhxXmn#=KQYv$L`f4wo_~CBXDB;^} zZ@#u#^YPhxv3VMpPIUB}#aZXyqr8l@K5>Jp-%z)_!HOw8%&0nB^Mh@KP-=|xjpAxN z*7sHOa_K11vo%)>hg1%HEgKz|wFzXaezNJog}YSZ^w|v?&&R!--#T(I+Y8*sfW_Yu zs=?t7P*2%CEA1=1IfAEQ-5aZRDYV!U)++DghDRAqVc!Ho-N-1StYPXB{MOXSzYYw= zqa+j^yWuMCDsjQBF%0@ed_GVOyFB5MXW6EyP;1k^z^yQ#-cdl&YbuOAE~_P590^E# z0yCt5IwsGs?CW{oQ_@FBm+#6B`HR!4d&XHYRmH`2$TPKX=e<#Lu4Twy)pk~XD27;9 zi_yqiC2HTIMixf_@g~9%&Tx&-CdQ;p!Pj<;#^UEKrgK3gkTdv?kips>=CN!8|sw?US(VzbTZc|XdBAMzh&=PN% zWTUztl2F{GaB4jdZq7a@;=sqe zEN_5ZkfN?JUikH<1ZQ?4_jPn9X-K2^Z)d`&4XO3W71~A3 zdje0?Y?Rq=a{jn0G@;C;De8FT>e-ZA$&Zp96oQKT!A}9SDv7eP%CRaJ|D$u ziBmyVVp3r?RTFeuv)iyIMtd>9KZ=(J&=V?MD0Z!Z&4E_gauxdbL#Q4D!M7T6Z#fKMgayu0;f?Ut8J2 zxTEJgL~#q=8V+CZ_kHi(Q}RIT7{3CrLz*)FLKPlkybc=BxHaS8n)e*^T%Jt7hFE?m zkt+WP%ZGgY1LPbZtcIifjT#Tq6d`dyT1&L5xvvRr&v@)cGAsBjJbmwEs|+zh4%hSB zgJrhv{3(C~|2K+H-}+uY#?Wz{bTG$9TlWJzItPMOGlq=#Y{vIr*mEi%;iXiozmZKl zigtBv3*DwsBuHti#cp^wfA6}NeTx#UKH3ig6BF2?0&4Cr4N*^3OWr5bK2-?UsdIrN z=^6c=ADW4A(6YMw{xFr%UA5*tqUDrgx_-wBDhcfT*hoI@6KF#OXT1Zrseene^b`Lj z#gW?G?Xa-nwx;Gi>G@S25xM>mEa^DZFu2G?2v(}zre7|;Sq&5a<-ke4y^Z$NX$MQ3 zu?kv`@2!?NS#?fMC&SK(ugw`s%#%%){#qU-^83y9+o`ORKQiUxS;5@fnFULIHFcsc zxo2kMTc&J)Iv4xB$R}&$=%bpSo>UsWvSHe3c2@khaRfo6$OJ8)%ZFvEEeRoroV+`Z z9@1-kZ;ny?)mfar&*39x84-(=4~?3Lps$R%Vdqbz)-WT&syV-5;0{?cu&xQE5z=oW zJ~-P|88+4naq-RLGWcLD;4yRz0HNzq9f{G${nC+ORU zDK-abslx*EYX1{|O#C(imR3@4&-Jb%T&vQC8&8yKHDN04Qx zXfn=Z-{!5aZX8zrjpY$euUjkaCjT4iT3;w?2b7t)t^q{++nRI!mrLjLX&6X4YC~Q_ zP6{pyABn$Kxzy0U5%tezwel@+Dl-ws{X6Iq@`nH5^)iyaJN@~v5_!b?h$CAo2ZS5HWzVEJL5rS_b=gTZe^9c1-SU=7|AS@-dTkiPQ zumb>-l?N&BPuY>c$OErtwlW0H>t3FGsrVI6yj-0Bo3Y2~JdwK_VF6xPE*1ZAn4H2z z@o^^I`YxmEL*WP0VenSLlb6Anch8W=?czvNxMZu|@j%=8dmQq!%OU*5QXoxuyTB_` zk<84E>@odbGkbF~us>HCoJw!$O8OhFvvl;S{#P@RDbl#ZTG8z=^2E+VBEKz`O6c9& z@eB|bh+i?KDkH>(PEKSszmnaIbW;9z%JZwk1b8DUDW5(LHc6OcI4qY+vcs1w|v4yrcWV;kLg50?4?yYjAPsBeb8x+ualn>7+z*5u4HF1?j7fsxeYW z6~mR57CuvS-Mbp0gPM{DQb04zwdJb+9M^3^+dyisz|4}i<$L4y;0Spb016=w2z!<) zXW^QhQ=arP6s@tqPL&+=VAMAzp*#?L?*Im{aiYR>%aRedobC-ML zg5B1qXQFh(AU z1VOi2ZG)x%KKhu-FQaHi+y;m%tZ?XcRLM+1M%ZwHZ9U+?YePwEp9$eGi}eYSL)DD( zj}qn$Y6w3+So*}WdqHloqV|7mG_L1%$>BdH;Vz2pzy9XqPud~b47{Ei?|*84JSul@ z*y!+v@VLY9%ihRTjuAQ4Map%~3qpI+rwo+nUua!-Mg2N3N56t*tkZ8zChVwb7R{7uvRf;2+q?aRC)#eKL19GY7NYE_k82T zYS~59)@zodm6(2jY9r|G3>&NzCJKYi*zrk*Qzv^)Khwk3lE0p9pMc zea5oN`V}2Z0c7l}d_@_-R^;(7a93O>G+FjeWR|d6oL2P{DvG~az#>%1Ka>RnqC$Nn zU9%08Hb=qqhzqRyzqBc@-&n6tfkI9LK81$oA;lm129zIFbc$6DKMW6+WuWIT@P?a} zT3`jX`QpVkYyeVLBN$|myf0*bk&bLIPqao`?PS|;l2&t}Vy zm@)(Funcih=>xNqMPE|W;DNq!=TGN&szAsP+}=geTuan{1RS40TEpiUSW=Gvo^OwGC@P1?CN?OqJ1FPJ<$7?c+HouIKrU_Eg>nER<9WvKN zEG6at{&ZcI8;)&7vY5i-CvY~JLA!Ej8!Oe0Z+$UVvgBThe2P4Stxf=!s+YT~xR*sQ z7+HrvC2^OIg}@F9NxHhs?ci(KMd+usWCpIORI>Q4vlO@#jW5uLuS=gWkmM7zl>MxI z1lWn*tCmNB5#YlCibUt-(Bc?WfMDzU9XVZ{Lo5gGPYKyU-v~DAmCcqOIMQqlWzbOuELpl0Y2A{AlT%Ao440k}#py)k zN9HyfIxD*ZRv*beop9t-K@q5RIBMrqx$&M0?sq9TDjbN?rN1!F`p|C}qdOe;5o}9+ z0joncArQ$BF&JJeZ(N9dj&N+lE#X>V=}%ds%;@-oKb~ zLo6KyDs;9GWi3}W`uKj6DI^$so9aUGLImy*RP>aJIcg#Z;v~O-{@;K(a?IXYm)&+5U z*kub_z>>^Jl%94;18b+HIY2-+gDxX0CpY>kRWmxZjv##FjwHiu#)e*0@1 zA~)H@X7}V=n>O9XYormxb>bBGk=T&VBgZBf!Bd&20x~tOx3D zpS&$Osn>YHC-5YlJkxvU*}8A6BW>x;>B(n5lhyUT_WDY^W|vvQ9XBHBZ*Ru@2Qv*b z_O3b>5TubIER`BIfwg<3om7-NS02W#47=oi)1dR;)5jz_>Of$9q}(fdS#F|``?sRRE>um@Mxnch z)s>l#{uQ0ES=t(ZhwlRTtd?~A+dB_6ZLi;a`%BJlz)GVwvX=rk+|H&JeigO(awEHO z@sTU{%NePK*G%R@^oR1Xu$h5oWl*s6*+KuFI$1;PYEN89_#+uR_%5YJ%!DlYcU=Fg zt!KH)`kFK*xaSf*rhW8iHZydb4q9C+2SYYSJ=NyYY4kynALdlV_zfXk;PPf%KmmE zntxgMjc8Un1&|cOM#rACtSpQ&LG5iMam1?N$s_^LD#~j4Ywg*z6YtTPr0vH!v>dwr zu<4Sq?D>dYrtajQsWCSuHwbk(m;FiZINMr&yQpo#7W; zOEbV$EdB07dBsh#Mv%)M&aDwTpzGp$kO-3aqR3ELcXSi#w+cRI?3x0ie6!CT(QL!~ zEE5T&q&C7WG9^ybX3UqRM^2BXBuA&~Jfra+=u7E5l@jF9OFwEMCST5*tGQHJ z_rLc-7ECs(CYm_?IMqLolr@U~UM@AF(u!g}>DyQ?$H?3Yy}db{5_6#B(m$bojdT}6 zjHbx4%d4T!^q_+fJK+UBRJ5r7SfNfOBxN6I^Ily+*Pdf9zGGcor45$%bs&FdlhTsKxDKI^2` zNp$T=eH{mDrhn1H`n|qdacFw7-1#^IOInT@H^a9J(pf057Hssr)t2P0wKV6(_Z7(l z2Icj94Zho7x0_S{QupKbAru@)>Lyv`yt}tlx%i2GstH?^L!}AX4~p-*M@wqiz`Lcb zf`01rWF%Z&tkf-1KT{Cvo?q>MP4IK&KIiS6s&co9T){0}WXy%VvbU9Vme7PqI4hIW z-P%hfpR$aUCxp4lE)n`YS>+^gaw=Eg?wgaL(*UMcZ2bTsZn)4YX$R(1k`}Mx-`!|>Wx@eA7dq&&w1O(v| z%cA*5+{?X557yQ#G7R}B3?cW+I-cDTqaJqEp*)3BgEETp!Ug7S2zu(!XY7i!t45`7)Vw3#k3+r2qOSeCdgLfxe|-9l}@r%VM_r6Xct?Aoc9M5$VtnQ$ocRNgw3$p>M_pDtXqeRUSWHYBF0SDo zw;kN&twZI=*wC#|O2Xma<&( zG{bOW@M-$nW13lyTvX4D=G^dm7G|6n3o94Ht~(DaLV)c-)=%J@{xc zk^u#LSHDY^qPO;U;q^ z(5$R-5L1-o`04=fS(@RRu68g>QF&{Q4+_0F%Dcb7=I+?pq>r{{=8}2Jn2tHXS zWSt-C4pw(Ia*lJy%iN054!g3O}*r)_?^EkWorsWq&f2@Sr^JC z(Ud;k0Z2-W$H*|?5TsP(!(WhY0IkmdkTVzATKldaFivCpK%+`*vW0Wb9VNHWCuIed z%0P`6^#*)fIItyjfOk&~<7kyK-_Er{B4 zu53$ar%i1v;>5D8mI&B+J@8r@?OOVe(jZZMBFp^n#fZI{bd_}6@dF^$@!N3?R`S-a z_LngAZ>Nl~BV1k6&|PoS!{lVh^sU}fO9~K?nCxUA?r!x@Mu;K=RxMVaMSquYMRVzS zk>t73;@8Em5v$hyHDqr`))`y$mW&wh=@*(%?p z1rlj5$tm``7T#M%4X2H#I{<4_`So14S1oaXFK5XcXRPAl?&2bRPo!`m9T?uox4doh zYR}@%97-%AijVL(BkOZtkuA7vv)o=0uHE>h&7p$2?q%NsOqDsRW=JUqO`#^lEcn9r z$9Y-_m4p&wA=j?8iepCt)tRFNc_I}$K={ZzS}ivP6{wnvS zU72y}DvxkhqI(AHLj^$zfV_0)A+NPHfilN*ukr1M6loCQN4Pn@#B`}tWqZt$-q!$7 zEaT-CtLA!fH2>j8@*F(0W#?ay`Zj6XthuHfVze)R{ntemt|@umTWI#I_EYHanCLay zjN?O}+(29%Z+aYc<$HN})OseBH}MzTAU^1YX%(%8u}Ke?6D32%CRC5MHoj(*MJQ|B zHQ%<}rvN~e6ROOv`3(l?4o{UAVh3}HG2nmlxRong)jI80Wz3E~r$jC>*VbkToQ}iM zG7dvcl4I-u5|fqew8!PHls~-Z|KRA{1DW3cKmM7Gp_yx^?HH!5T)G(!8^%y>$=oWZ zRB9xBrHyh~VTj6^xtE;Tblg>LDI_(Cp)v<2a%Pa0EzWUE0>LKx69~LR$STT+aEj7;Nr0kAu<(L5~8{bL2L* zcFhGy7=dqWX=P@)M(H;r5OH?0K9=t1X2^<-?&}B_O5hvjm6>)shVk(Wa9F?FOW=<;Ghgz0^i@W z2rq+Gk#901wx4av3x~AY1cN~U<8wRp|4?|t;F%ajCagBlHom#;p6bM_J->vOeKvwV ze&PI1*sJWQt9aBCg0hhmmcZ&X7ZbIU!08_H1D}u)0X9N!8gY}A-wopA@->y9S(UD6 z394|n6fVO`t3#C!0Ty4%VZp?nkf=)8Uaeq*earVvbd2D#gJkA`%M7m?C^oa+a@z{| zBIWS@?X?`M;4CwtY`ln(;U6Zzau_3P{j}}G@5xdai`7LG=qWu<00pl zlw}wEnZZx?^N%&6?aK9?^R}ww^5E{hH*gugzntMF zWLP2kGoz|dCIZ=bwqC3Lbd=g_-GZ$giwVuJoeruVf6VbieQNxF*WUId?i-mfxM6I8 zsCW~4>A6O@87Fs7FccQRO~Iwoa2X`51{0i#Qj&wthwmKWiociBZ&Z*V$6>lkx_QeL z_fUkM(Q4v6^@n%RA1nUM?00~9jh-1ht%=r8652i5iLm&%H)6KG%zSP8^+&JEg*c9q z-XMCTVr}zpL#lnJPHgR=La<(nkqt06$F-ywsxkTb!BbOToMQk;QWhT^=ecDIB|F8*Lg?!$wr-uDjnAFO)xH*&?C2)DLtimk6WAc^2K<)Eil zc7_6}5RO$rYYVzaUF+T^^7o4DY~eeTVGqD!2D;rQamT(TBZFL&(A{%SY7%bBkhCCJ z?>o!Yh+H%!S7;`^q5;7+OHNu<;T9QSry;5o^6LZRXNwOD5$vlg#Rf?Yk)r_;ZhykI zOzu?!8&Co>8WOB|CU7>(YgE#e%b@(uq}jFeTuRrPBAzjm{;gz|1I0*Yg$l{q>EBG3 zg<66DJJZ^;?A48mwlLzT3wqYc_9k)8dEENe7|-fzAxzO#5`zCPE^*%4fF!cN~6kPCC-RAZM8hcvfvh!ya=*7YHB)8)8K7xW^BqKda3%$!O_|Av zHEIe%NpN;I2l}PEAf2*Os`(8~{n3y5GYLt2CJGS*V=n|Pyfc=acl^dFc)Z0ptQU83 z^Wpd6plK_)(JH$F{o4eCA8IN?v+JNde%<{()quwh#(2}P--*l95nJ(ArbBjyJ+30A z+$T3V=cJ?#(n{%#%S7pJ%DQa!V98x>Qb&w#&JE2B%=f8;Tk7Gcjg4<2vXPUC z!VcmzQLjLyCh4(_m_xPsw&snQaGNv0MhNthfjtSW`&w}?FY0K`jiPVMQ|1<^6m*>+ zxMq3vzLT$n)Z-DC13@2Q+eJsCNKi09KI=XT3@e>Z${_HWIYuOFXqK>=%=j1hykV5A zhz-01XM_EpN#$CvdRlcEs32q=9Z$kdei4WhJZv5W8q1VFbhcYE@Bs(>0fiWBCPgl@ zKDZo67(iNi7lF;ohU-_>dq2R8Gsa9Qv+wh@t?8o?>36jNc2AWuJ2O*6JsqzcX|d=u z!A=<1Qb=g9zUM&_V0>>CKmD>@vbDDSiG}lY+#Z%R^2Da2ntxP8hRivnAh#c7odz)3 z3x_jkJpkOM!T)D0!-1j?2%9ko7JNzT6>G6D3j)jDsCe62G~D_pbbeWA{tNB}JQTrl zW&)QxN1wWMoa8O%o%>*H@l!XpT#{w)pj{!UX4=>E*b8ff;D1_`4Fs-<^y}<#Gn+=f z6?$fxY+m%J5p?55m9viX``mP26y({eq%T9=QrU9B`q`Ww$4L2s(U}ZHfIKLI$BRzb zj9xl_Y6vxxRy4D)X$TEl#MyAu8b4o)z19o!?r_VY2x_FV+L`tK;v;qYqgdfcYq|op z#bzF-On+z^Bb98|c6xB2XFCg+Y=KwH-1i@ro4-YS12NU!1apG+4wbhx_dRjQZbq%$ z0*~Mmj8|*y5eI|Vmsg@hOB*5R!9De19u|qwcphZKh}B!^qWvONtqFs)JAwYoA>!6Q zH75cIPGF|0@8Xfp=1rJvY7aLomsk@ ztK1*q{5TugzQHPITorSwI1ob6UvpLVP5*N+_43;$kSG=@;U-$Fi24%P0n*1@Lg%qi zdfUsD(l?rW%YQl2jS3rMOYof77OVby{?1EwZ|=;DuE(3XW>xW@AuIwPhr5dGe}FHy z*dSNh)x99Qfa81pfOy#s<{6U=mCpS6qYLxjC9LGg&Rc)pcClZ*+l2onn(#8t8d6WJ zvvuv#+fNd`4DAK}u85+L?3zR6EUxKZ`~JQ3z@71c3=1XPo1+~rI-Lu%L+d`Nw*%GZ z_5CNDaV*>K*Z7mEE=Br(g;s{5w{cfwHee-`f;{gVgxIC;Y8O@gL-q1SquOV61_evI z<8QzCDpW`XYEfMX^_&Ca-i-zy$Evmz`ZTwHnz0hAmGm}+YZHLzTu8X+) zcc4h#+N9ZZkNVq+t>@%w93p&|j1sPWFUP4j6HfaDT4K0M$B@@+ z6L;{NXXYsCrM>}Twiq%Lxe+4NrVIBCt@D}N{|MBz*9p-wqGoGHG-q}d!XMv`b$JC2XcLP-Bs@SDc+Gysm6wNpC`H zM~fM*8g*Hw1U4A^PbREiBF^;}7V?UQ_9V}%F0S79RTEgk=h^YR3lNVl0I3!G&8_eH z2kR*5S(ll16Rlrad?!gU<#kfh8)s}>kpwl#NXLv+H)8xcP?XJQeZ~z+3iM%u54RtCuP~92wlqo{vlK zZy@y8Suu78Jel4#kgJ{}c@WWCVR}X3rEM%X#8+x5*-+a_ObMmo7Ylz598`-j2p2Ob z!W2N`bD5`GhZ?5ajtBlC}miP0#-Ug zQm1Ek5apjHe75pd-y>D2sMob*{_35FGU|v68!FcKyF}|ul z>d14GRs$9ArBz&YXlylLy?A+g&1TCS=&(*r=wYy~{pv7uRQ{+vOmimvgm!qM=R9s8 z_Ty=za5Mz}jg7dfx5;pU8!dT4>k~<<%k5-jWX2ei16lW8KHKBONSN`^7NAgMlQ9#c z;@!xe?ia-fS*dkjZkKqI_}8JX4@+SyP|!dD6^+s=lQ&P+0}^dtmJl@P(=o#_@P6}u zwEZ=rMQ7gUnC5+J(=d_y%3RjHsWo-J&D4@)91d!BX`br*Je+##TC@&$u>&GE>HxDO z(bzkP8=HAA+GGhBNO{UvEhNtv8_mUj3r zM7%C*`HcNxU9sZYBGA3{yPaD^1@QF)85!|D|6>GPwuc?hU+T+4vNa%LXg@ra?&)Iy zOP5hPY1}*TAJ3MHQBe5?K-H^jBjon&)$~rGPRlzY+*G0UUmzI1QW|*4p|ufB(jgl< z6kgTO+cL<9aDv*x&3GOjwkbtJE+hOr>Hg8U_($%U+<+8+>2|O8_X8?px@DYLGyaSt z%*b8tury#XmK@SdFNs7JY}%C?ACjSf{3Wq7sC_X3 z$T`)}^V~KB9N{`M@F_+9CQ;5r5&Jv;flk^ zOYQgs-+-`J|9OF%&EAk=q|@=A&->V`dRL?hGft+yEJe{^!)GH@Mr-8CWDD8uk$&pC z9^z?*{>=*_uhp1^k4D$6HbwP zsbgcE*wvNqC7G^73>(_HKvB=c82 zP0dSLPRzKRlpD%lPRhpk6UEuKr(LA7d7hcGx2NO+G$Y#lK{q$8uK`@oS-`imrIoC-B%dga~;pZDel05^= zc>alV50s872G2)Jw7z~2cn_gQ5=P7sF5QWy$$-#nP;cU(`za=GbFFMQWv_%`vuGzW zpU$a-GzQybj*wjo71RsvgNjQK-((rO5L5|!?Z9LXn(3tE*+CS%Mqq(sU_E$ zPz1OVzzl^r49y}a*ROu!dDUh-%FJdFL0A}yLsc1sH`+u{QkSv^SVGbl z>-hDG%-pNUR!Wzb$ZIygPF!I?4?YJ02l?Ii8)08sy$Rq~$>4oL;&xo*qFoCoa!c#= z=yaemfLHIK=tNhf&Ktaq&tVZ!B65UFW%$G`JdcbdePUsqt#dYBU;lYq&rJ0qbKd%v zCvt*|)H=s?>Me9r!h>hTfk}^6Uwyw9*MiGlE)~Mq5Z+PmgdZO2Z?gS3p>u~m@;Fl;Wm-i)bytG}YM4jgTytFrW*3!p>*CR_G zm}zNPb{Fj;aMv|m{CIv3)C84fC^E~A+QY&%svC|Z2LqPfEp=pLgLJ|aL08g+`Z+`- zi6+*LX5Dy9`yZH_a+*sdla1K+-X;HFz-9(`PKD- z2UC0Q1`(1HmhAMX)#Pj6jwA;vZIzv$npP6;N4&aG|blD6e;({~4)j#o>(x=hf~w`0ZIp&UpLwbby}Uw^SY zw67lC1t7l6Zl=Luk~c$#SvF*sQAjl+E)DsCBP~pe%SU!;{u1c zS{Qi#Sa_GV;!-0*%I0hpl&76IxH&a*bOirW+g@mQzd}0x?ZMp(w*&$Y6Q*qE-8Y8- zXI5q7$e_W;uZ7CtL76;@V}MT27*a_9Uf@Eyw12TaNZoCzPqIPUo)Na716qrNLu0>^ z9L0?TqkPYJ_OwjMfnC#MM=*OZMzVfIa#EIl)V#I|Ym zFP6btj(VqdjUEZRx)EzsdA$4gz|8QE?cD6lxjw$=-i@I#q*-FUFx7PA?b*nx(d@LM z{_(_vK5dCkN&*aLG{WOpdc5-StXNZ5S?a+(DX(g08Z#4Ss2#g(4BoX_hEwKT{(+Cxa96hAKHjI(o0nC#7t%;>%Blb!w9?TEh9)y`L zS|h@#dIP=sk&opdLoPqtYD+E^D4m|Hxuz;}*e=20=%3?7=2;p+f_=GL`Wz;0xm4dZ zc&}AJfNoy-q_0g~MmRnG#&X%+9xd?_zjly98SDwT`lOTC>_ zMlHiauRs&lJt?j5GU7I_Uc|ythM%g>ozTrm=*H3!%tUR6sl7N#rdzMl%vv-G5Ea$~~IdYDArxE;8`!U_T0xRztm2Hi8eEox=24&`(c|Pb4Ksh|t?$O@8MddIF z99^8rA=DFl6czH6z5bkR1p>ffM^SITsgOg}JAu=7HZ~hjAM(N;v%k}cm4iP4eoLS= zpjMVkE5b>T-%lpOFUG)&BxDLEiKAlSa9E{Sw>aT%Mt^#VqI}xX+>`UH4>LVxe3?&s zie5ZWi zPyw19NYxWJxZ9TCT<5vX{FImW%1pSUI{=%zT8Gkef2Pty+b<^1ay9Vf)c% zS3VOrFVG=fBV5+F2hNArAMKQ;=e!l|Xl`F~4ba(7<`uL30L3RANk?4CM_oQ20yXF7H8S7O0wc#WgfQ<|45j4?3(4KX04`FsH6lcMUYmn z8P^^P470iu{4R}2G_l)6;S2QL z&c}#~P>W~@ZmBRct&P}fcL3`}mxqPnH`+dy<5(dduxtyDXz0s^Czdd-R87gweql?? zcKeI-owTHS8n>4ft*Ew99FUYWyA`iYeHImVHU(Yy)S0-Cs}6>t(jawz`s#W_aF9l~ zGUFB(9J`3J-FcrO!}fXyyqNlys5Cs^%U_y+iL8Os&@c{H33Z&8$w#BN6cG`y}c_Fv#Rv1h*M>-IgNc=-;c zw#ZLK`r)lNuOoE%$;b&tCG;v|5YDkL4XF0C2h)~w?S7zN6g!F}ymPEK@3#2Ll$0;8 zFS*{o!H@o8y9FlwOf({&1>N*tZFe6vQMOa>*RAh8nsL2lN9~sozx`$*T`--Zg$U6J zZLsYS)} zKd0KDf{qY5$SZaV`G;Krgih?bTxyl-3l9^6QW06iG)24GMPoF1V7FMe*Ee>Qv{I<}U9VZtiS7cGt(6L`OKW#+4&agS-}JZDvy^3MS@!aM2z0MWTYB}{ zO0lQPI|G}j9z!fmKSrk|#7|9%5r0*h10gF%mE`R)OCy|*ZZPu$*K0r$!kUjGQ0a9t zjQEA9Gb26g-1$KS8FD z{U$TY8btUktMnod0lURj-P;FIGPEAG#5hauK0r4c>aRi9RMDfMA3UQ*^B@92>U%yhsdqP2JCkAXIAx+&fDU%;l9;7EiS z3Ga7=$M+cTpx_;QEO^(Do5sflpu7y=5nDNK#ZSdd8vpBZAq{fsgGvTfH?Jfuyim;& zB3dp7tJEElyds@wp>6K&{+CkH$WX2DjK?zY!3v?CXxgYF`WL7y=paqpLfcKa-&J;- z;Mnh~&0Y6eEZrPa1v2|}F31I+d(8ox^tLOyU+#1aq69kYNEJf^>7G>&dpkGhfb38& zA!dE^0;J@YykKN;X%oIScO==Z`99-GN_bNF$~xH5e2Ggd`~`(i!T#4U>dUBG>@Exj z&Nf}X4B|Smf>VW8P&PlWly5xGJ%F;2)utbBw*#jz&K!6V z+^LPtB7&IY(?);RMJ5(r#n3n(laZ|=A`Fvkpttqx&~VSq^Qc6>@6b|1NZsCt0=C(e zAw>b1x#@8s{l=26`<>aOg!x0Hwo$f-+FDFB#8iabi$zHFmS|Ilx-H9HNXtnj5{;(o#N^Mkv8+jy$V*~dUUxicY z)Qb^?t&xWeNUb)I(WyW03XSbC6I7J#&G)>@mnOk$hr`W!nR=nU(1U@tCnJfFmWaW! zi#X5wxir$W2eXe|^$G9ALMl$vi6v<-PM-@}OGk;hOX=X-bTGNdPon80Epur4uXN$% z{R-37xW3ujmU##Z?KW)`oXt$)_YdDWf6RFa*v1yK5#XiR`&)9(k%TUiO#s6^`$Ff3 z6d0sa%0CgHI8Xn}RGitAfWl!U(?`g+H3EdmE4W7_&5LI##$_CV%x?2?cflKr-bqI0 zyj4U#@ISZhTG!unfWWY=*z$-JZKR%^#h0%}4o^2Od77%e>nc7P?6{Qd|7~`#1Tdcb zIMtn$XgUV=ontHh&V|rP28El>i{&2}Y{_KDXj1k#_oVUf-PI%2I@l4*;1tCa=hW?cBkW3_R zMg45|etHp67`j}>p7*ISWl_l&AYZdIS&BkNU%pe|o>m00^>YX<_tZUKDWg*gFn#hY zJ|QPMd#uu#=hUI0KqGm}OElpYwOx3xmp4YPcx9LO^ovRxo|*2(=t}=VH)F4^tpBQZ z%YLtaaHI=p_#tCw95TBAur(FG)V`l^8~^h)M0i3@_Qs+0Ck+#O0Ww=}W&GkFatfU! zIuX_5gi82GcJvKt1Af1o)*M@Tp}d9=iqj$xtgocpUW zOqq>I;MF%n3EnPPZqPMJi()eO@^Is4XOb-8V6bUz_%``vaFBi2SEIt#_y2`U6oikA%hf^24T)L?bpN_58@?7ur&70`SVMFP*jGpe)hEbu zfVih~n(6xo3dk5SAuaTQGjG8DDV>{8yRFK-J9bi}bDbzG2${{vqM&y<#n_#QK69_m zRQ3MWm5N509ubDPV(z#9P`woKy;JhCFMm3UW+N$O`nEbE?$}6W4ZS{*lPRO(<<1$` z!p2l~+Nw5grnSsa-fw#-(s|Gv`w^>O+W_ZH@e1o>tW!v!w2f`#8+wj)t^HZ*QqpEj zR{(mfI4$Iv*K%c-mC4QChTbml`!jPMuV{W&cjS|ph;VQie^ovV*C7mD8~BqFVCvFg zYV@GXCTeANg#Z2zppeyRY2h3(vlU%h?(6BK2xs#mxDm^R3CYT?-lh>9r28i;#eoUU zoE%{Ps2b(8@I}m2<}G-5Ij&GQ=V5o7O(JRSh;d@=)00zBQU^HXP!5JSB4Ydz-))zt zKX{-5BD%=wkBBsgHe)p2?V_B?P&bna>YWl;)hEY5-l5&}=2hvQSVOz0vl4?4*p=lH zNciu!K2!X!K;Ksi_Pfl!L16R-74BkLH?hH-Ys&wt*upIJkT;FGSzpFFLnR1inK!^L$!+5kA}* z$P{`o+z17NVD#tcLKyPVV|aDpXZby$gcK>q1n%#ZL4|6^=v9R%9jVL{VV1UH4IvNx zonvx`O;lZ) zJ<{QI>!&P<_m7cJ!~Yl{k8}X^fy3Qaw9KK`Yfvv-t>e5#{^Lx%W@o&qXS0zZ&8b-) zNWvZ4S9k2|`Og&BqNg%mll(Ok;rl*^K&0gXu^=C6SU^~|$+C_rfuI`E)-h-u@SFH| z)p0IpLP`)t!t(;zSG(3>k5$Z(O3ia;J4?lL>m zPUaS_-NLWyu4o3`1~A`IU?EwpsyM(j8NMicq&``MD9W-2c=gv`qrUGs%alDLY3&bh zMsX;TbP&fLuW0RLPyX>KLp9IBekdYyCS7*q23MLfUNp|D)Fy@^G!*RkGeOp z{m8XZk_ZuCX&LZGmW;99+^!Lk-3doW+e;I!Ley*)!M<~?;VTKxD|%$%p5f$T@Utj; z!6W<;4(YZkqS*4^C$O{2+b->O4XvURM1A>1dW5uy2JPFT8E;!cO%s^?5wvPm{=sEO zBz!E5NCo}}lwIU)aA_c@(Xg|}lAYe0|GyOFzOYtWkC++n_B&*vF%-jH(TM>$&x(L? zbL(055=h2Vxf>8Kwka1~ZZoeexfhutJo0+!hqrozhH1i3Z4VV>kk2O4k3&nHUoMxs zS9Rq=YT1E|cP@hM)2}70Hr|bXuphy?rtn489Yp>pG$`1OYdABRE#T4x<(Ff=2>l+r=8@jh842bh`y`?#wlbKs`D+I|IR=m;3bn>tvIc0JpVT9_Tt z`tHQpY5l0-^8wFvRt;Sldtm+thy4oZn zUB*V>Ba5Y-jibc@COB5i!eA|E^#eOX0QQ|uiQY}H08)g#F_NVJAtmfjPQ2T77Rmuo zmPY+7V(0r`+7HEKsQxrCXqcp^rD)&Y6{EL%a;9r}qvi8qfBC)acX#HAox2MrH~s~# zB^EV!y|a}g)aZM{N#Eyq%fO&-&>rkLmpRewA#ImiSFh4$-!OywQYofd0fA|mP+h<$ zBVvnv=*!jT@uCkz2!$hvD!@Lf7o3A*ATaABk1$);i~~QDwi3%D+kj zQG)Oo;UjRPip_pvm(tAKnos)Mmjo;`p@0Zox^hFE70F`=;OLDDncNP4_2vtE!L3pn zYuH?J%j10K)^l8wR(v9*P|l>p)JqYc<%}kqxw-BIv3Mqed18sT1$Vz6a@zs9X}D!7@ug;F>l*x5t!*Ghx}@S3UZt8gp=mpkzM2?3fi#2NurC|+H^v}m`jf} zZO!M2AUyyGB9dE-yiQ)$&_${?Za4I5JYd6ronhtUP|#@X#v2oq1!yOtwT#)zr*pN9 zC%HGzsrEy0B`$)ej*wO~d|6Oz*cuM(dCA?1DF!6_xOYf+1UTXD%v8&AJ?D=>#B=7~CB?7Ab!nvP%K+cUg5h&sPv?HL1uidF z_*ln~gs2YEoI4%9-yV7g3}5)%wMi3XS@8x~VP9V}54;goKQS&pAF5?Q5{Tn==N8$X z$;&LK&CFl(H1T^Ze>#R(764o;hlVMHeELlSZczYn#_4wjVvT5YPh9=-u~9msiOKYF z(5W#ReO+Udl+UibX=natp^WsO^Bvxpr;q z0`D{@n5+-R5!qc^2Oh~aX^43Qu9^z@Thgm!Sm3pIt|$9V%FmYCjTs>isy^*((dAMHt3jVmzfEPmlZB%F;G<)`XE>$$PknRrB}KiXH$9P-pC6 zYK56kB3eJ2z4J^m^j+db@P4e8sc%4@F0FlAXZkRjquxUFu3Yo+Rgvk}F&cRhZl8AH z6m36m!o56{fe*s_z^Z7ew4CH=1r?%%T1D)@W&~|0;{8JfX|gs4AlV(54zW}zv(ak? z6F&3z57QYuE6i2hw1;*a$&D0=A-BE?+Z`#K8BUDg^r zR~0>N!SW#5=H#hdy>3DbBX$)bDmnn01JM3QSa_r&0PV0!{oUo%>#vaIO(QKFhyp() zydcB=8a?c`QOu54TUc;Hqf=7=)w`)jN8h3r73U+`&7q2G4ZzFOZBOk^go|~Z{^m~( z-(&NdV~8MgLMpHC5_(A%wO9=Gtq_r&9i3rk?F~xl@zjeK`I%4`R04Od6}Ou=I$0B$ z42M6F)6b0xu06Yk9GJS$;b;^q!?4xc@oZafISI;E)&dK1fdlM7Uxa_KL0IJ14-4;b z!TT*(in7b*g>u4$02$vuQtQ(V&}gz@2*Yv&$%6}l0lG@UP#=^^JDq|fVPFC^~g_TB5(o4Hs3=W}dtMg2t6$A)6O! z5c_WR5R$fj`}NK_rJy}*HEYcJKsz-O{UuiZpjQ`gz=zGF$F^LcIi|l$8?i^@b(d4a zlednYM}a{-FHGj0;T=3P@Mp6UWPS5a(NxbhZxpMbxK7N2eD;WK_BlRv>gLS_P8oP2 zOl}KvA(x+m414J^zL?!rJg@?$(x(jmPnlGaQ2VO>F*40 zjS7Zxz?5CzoNWMUw52X0AGW{uBla_CXZ}y7sf>Hztw%^tr52hQSU&d-cks1TrT(NwAmb)`tc)*(5yWN+VcogX9=h!4~f zcB0&)r0E{25|49bS;vz`21}Gt7&=+i|6hO)k}I=Q40z6GLa&r|Q?PaA?u(`&^TpD+ zj+joJ+ID1kx83kOsa-$wp0au(G_c_1#F6vc7DH(~Bs^~5Ilkr88-h)>4xE{3e|)Iw zcPEmNdcAkYP6O7CurDC(^&-w&HiZ^>f*F0|M3a~vCL{e~NII<|fFx!;2UD~j%x6`M z{$B4YM{XDnbS~UjF2qra3}d+Ry{NjoI2XOvGA&2qUt|%oY`q5gWz5UFBH0OClj+8J z>J!(UlZ`MrXC20@)8C7AlSq0?W1+&gnzZIXqP##1ITBl~t(Pl|v&;DJ5Sn*Lo4h&R zy~NIU&=Q+oLJK5vEF7ysLOW|!v9J|W)->9F3w&T>XsNqM5NMfu7`{K4vRlIm@8@Qy zIQJ?mrgg&*GRb@@whFe9;rdGmb>E(fPr?xVyZ6gRzxpOtCfzZ>s(Zm&GmPsRDBxWo z705~ae0ZsWWYDNnxmQ#7cbtK|B5YL}LB;J?47LWBkFDH~c{SfR#T-+WM;ZX8Z2&tzbi6jFbj_Vp8)e#q*Cg3)RyDf{XJbDZ4&quF~P? zR`VJKCuM0a96~iRO=VwO- z8&M-VVJK%htF3uwBuQ{4jxn3>SLFTo{Pp=(Y2f;|Sr6%+h+eUj4KmpgE^?+o=eqi5 z+j_`Oke=?331+WgB36o{d+V}BzJoE9M>bBySHzQzI&t-*#!p9|YESKQ9{cN6)9!ZT z;!AjBxD~T+g6^@{(quy;+tyz%3_CPR=u+Vrn=L-j+soy+iLrNJ1@-tVQF`T~x5 z7s}4gBmNbyuoiMW(e@kB{88haHGrOW_5t?_1{4xHdf_mzl$Q2Y;nQ2B73+}sd6c;snFVVDqic~54K-TLO|GtWkD`Rkg%sU6uF#gO`SsIXzB6v`UOvPJ}x zHbUO2-Wvj}z;0M~h6M!R3b1rpE_ShA`t_#klQ1n}jI_Z`u zLF=#yv)^Io@G;Mg^mwY*5pC9a9R&)syg~ri_S5W%nKvqo-zGnLoFOdJGKWz#8-KCU z^UcK?u3EUNH{*ToLqazzen)5^vrj_5^!lkall%9! zJ(xKe`qWs(TNA6S(Tt0Iy_pZvx>IAI+7TSXqn$QM4MZW49G{D2n@%LaBA4G8FFG^0 zSEe$QP~&d}bRpTwTP{i-(Y$Ep0VIzkLN*9)MWl|2x%mqaI^vH+3mG`Z{)$ok^(NcGM(6&A1D%D!VXS<1k3|rIv~~e3D#@%FoT_5q6FkA3*@@3B0i31{L(=` zZUg=p~eemJm_y$qdU<$bnv5ho49uy*SpfL=$D=iWmzqyFB%~w3SW{~ z@wYVlwZ!!MR#z_PNm9KZ^-S<$&>Q7l8jwazLkVCVc6dMhv{~26r%W#e7kfSp?4A`Q z6%^q@B-{+Et@^@RfTi68i(0L$xnX-ce8(N(8Fys;1e--19%V77{@guouY4Gi@v$dg zTQ(ZSDuZ&E>z>dA>m0R6u7W@?GdP}1D-bF>Qd5Qp>VI744n7ttP7QfWH#P09TC=6T#be4`>-PTFgCcfJZrRaCT zG}$!b<~1LIwhKP+s{emQ>X6Vx?U239;1c4bCudD8S?^^5u&meNO3?lmbI9M6VL1Hj z{Y;luyD!i{<`D(&gG$; z0g#9V3+6DD{f5-EEI=!k>G*5A)1 z;BV&8&k{ZtAgrgJ%N^_Rg(mQBeq9(Zv6)lh272yREQ;F3xX_`C@_{w&L3rkhqLZpUg>k}h3Rfzh-e)1#yQak0-FD>;fq3NQH zpS^N~H*;%rBy;6A-MYg@`M&M->13Jr5ygb=6?w;+cZS{pcQu4D1H<<%?CGCp2U?N-i^2iXn{!LySZs zIc9bBoq0e8lNEkgb+ETD6sjCf5P|K`ZBI=n<-Cwx|X%)g`dty&rrAXS~`L zcUDMvEP8DGrteh1*zwDu>dRtgFU01g1P7A=(%>2X`y7Sz3-~OvBu+iw1Zx(EbmNrS zz9=vXRL!gjT<%~b3_b#gVbBW(iq>q}cwWN2?u4WUEK=C?&PAbp@+6*CeR=DNWtj6g zrEqgR-U{#&?mi?7h6cwC`1tA+Hk^6(UxjWDt3$74v@witB&OMLSId%}uiqc_yCkJE z4#u0?n+P&nvCOD4%FRhVOCo7HE=Q1i_-ve~YB-bq%{`kWEd{xApcherQ%_1f88tZT zPQ(`NSG}(HjJO$cEAu4kj6IKR^w6xH0NWEO{??yQ4}wk}4PAx>=Kn9zCl^q6cT9lG zFCLb`fyjA7^yp#DM$ET<+!KRQX&v`UX$5Jfb8BbJJFG#62hicPP1B*~>e;3d&ZfAtB+a8QvWgcay*b8vhzNe#l_8xpAYU2df8iHn}`4GAnEX^3aM3#&?SZ9_06 z8&f%na*M(+1s7>QWshOdtHhWNW?<@(LQCT)nl*#kEx)&|y2R+{FfbH9ytO~aZ@<$Q zPm{AFHoTB;^H6;7<(GE3yT?sP*kC+}Q6DC4IGXRBO4bLfsWd#7?Bx;oKF1GumCio_ope@K!B=(Sx-Al)ENCNs{>i9 zT`>+2;@G?qA?56ne2=T{*o&M?{u)ky_v0!`^`rEj$H-oS>jOd!!_2Z2R8Rab!|NpE zWR;RkYbD4qia-i$EQQKtnYh(1+sR7Y8%6NiR-MllqkvBXi;-#X?PME(wl}bu%7Z@j z=v8obUlx^MJI{A#F_$)Gq%yLzjhYE4HLbpIoEg+H4A@V(R4g@lXGp^90)kCL2S#?H zGe)<5L&2f?|0p{9cqaG%k6*Jfw1(1Y%f_6o+|+RlWy2Uwj5N2EN~dW``jvK5Zo@_> zXJ+n7T0^->ryHG9nIpBOHdLE~Z^`Xy(~^+8MC$vyzW;kXc(}If^LfACuh;V>Od-{a zEO4fOHsi!R3gv^RZEvABAS8G zqbUx9bk7{{emYd7;Xz+ z$3Sp)dIGX50dLiJ&?^pRRu!8wfDew_5ui3>>io2q8DlRSu<8RDJ<*WA#Uhe+uI3zp zD~Okrjj2Z4gsh-1Za1TNEoAk<&-DhY2eJ7fIR)lxSW*n4V0~!^#Y2A!g{5JY@X91e z{`60vy39u!l3Yt}1inz#v$%afER~&Wh>-$zs9`56R*Ixz9n*M)A}}VkVAr&8{c{jb zf`q8&*0~cnw_0n^*E>LqBJh(2w86?yyw)ev%HvG8)&qM=%+4&&fRkY83l3x{J@P;# zdKXzf-t&huo+G=@nYag*AI5 z4c)y4c887kwg4RX&lk(L_=eG)_gB#!G8x-)cvP}-JQ#4~xVytCa3j9piSVooq;nri zlZZ(SS4Zq5&p{>kBDzs!YPFxhsXfMs??4OPY4Qk~( z{4ul`#@z^tN95k9@*_J(N95x_xI0*pIE}sc5~0`0YVmL$;N36^+ItuZrt;Dp@N7G& z5$V#JWi2VwWAK0Q0w;=K_YlcYj1z`nxf)XTD13fG{gSq_@!jrAV))ZWWD&yRXO{{&7jpPI=8i+;_#_; z*A8=<9JPGa>j=AbOjlfoqzce4i4}*P0GK;;OX#sk9AYsK9n>v#>068}6rF zo3ksp{}HBA8qdb9i{R#fW>dwq1}z**80%j%U*fTruw+sjgKxgU>1~Q8ML_a zs5)$ESVerr`zb2mwCHg|c<(@E!3~4_Uz#aDj`wILKRp+Gr!-!B$OFf~zMP5eyxm|- zs_G1KyDiD;5>01Kao9`$FL0TXqJMk~2iczt%l6E)%x7ba08NQ&Cw9CRImBHKGl~{W zLFXnyH|C?5rE&wlz$)jYhRO4}wFU_1%XUpjIg}f_eI9B>z9hT0z_xS1YF#7Ygl;yW ze-BE)@rARnK?>Kw�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

    B1QefcV#@+7VrWqNY$Ki_SEM$$IY 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

    R>B0ez~<<RW>>7q0Xhz4y-y|X5 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 literal 0 HcmV?d00001 diff --git a/app/src/main/assets/bg/bg1.jpg b/app/src/main/assets/bg/羊皮纸2.jpg similarity index 100% rename from app/src/main/assets/bg/bg1.jpg rename to app/src/main/assets/bg/羊皮纸2.jpg diff --git a/app/src/main/assets/bg/羊皮纸3.jpg b/app/src/main/assets/bg/羊皮纸3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..31b99a870f521292ef61795cf9bf49235772b834 GIT binary patch literal 127459 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 literal 0 HcmV?d00001 diff --git a/app/src/main/assets/bg/羊皮纸4.jpg b/app/src/main/assets/bg/羊皮纸4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cee31be5858bab581996d38903cffe8b38de68b6 GIT binary patch literal 135087 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 literal 0 HcmV?d00001 diff --git a/app/src/main/assets/bg/边彩画布.jpg b/app/src/main/assets/bg/边彩画布.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6638b9f21484ae220674011f9adaafd49685fb9f GIT binary patch literal 294258 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%0DJ5?1Y5SLz&7vg`0N1Y4gIi2B{cfuaw$awS;o! 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⁣bU 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

    yJmi`e>UC)zN*|=PIKY# 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, R.layout.item_bg_image) { - - override fun convert(holder: ItemViewHolder, item: String, payloads: MutableList) { - with(holder.itemView) { - ImageLoader.load(context, context.assets.open("bg/$item").readBytes()) - .centerCrop() - .setAsBitmap(iv_bg) - tv_name.text = item.substring(0, item.lastIndexOf(".")) - } + CommonRecyclerAdapter(context) { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder { + return super.onCreateViewHolder(parent, viewType) } + +// override fun convert(holder: ItemViewHolder, item: String, payloads: MutableList) { +// with(holder.itemView) { +// ImageLoader.load(context, context.assets.open("bg/$item").readBytes()) +// .centerCrop() +// .setAsBitmap(iv_bg) +// tv_name.text = item.substring(0, item.lastIndexOf(".")) +// } +// } + } } \ No newline at end of file From 56d3acb6a0314da7071f8cca9d41cf7ad6ea02e4 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 31 Aug 2019 11:40:10 +0800 Subject: [PATCH 1165/1997] up --- .../java/io/legado/app/help/ReadBookConfig.kt | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index 196a88c36..df282cfb1 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -95,7 +95,7 @@ object ReadBookConfig { } data class Config( - var bgStr: String = "#015A86", + var bgStr: String = "#EEEEEE", var bgStrNight: String = "#000000", var bgType: Int = 0, var bgTypeNight: Int = 0, @@ -164,15 +164,17 @@ object ReadBookConfig { fun bgDrawable(): Drawable { var bgDrawable: Drawable? = null - when (bgType()) { - 0 -> bgDrawable = ColorDrawable(Color.parseColor(bgStr())) - 1 -> bgDrawable = - Drawable.createFromStream( - App.INSTANCE.assets.open("bg" + File.separator + bgStr), - "bg" - ) - else -> runCatching { - bgDrawable = Drawable.createFromPath(bgStr) + kotlin.runCatching { + when (bgType()) { + 0 -> bgDrawable = ColorDrawable(Color.parseColor(bgStr())) + 1 -> bgDrawable = + Drawable.createFromStream( + App.INSTANCE.assets.open("bg" + File.separator + bgStr), + "bg" + ) + else -> runCatching { + bgDrawable = Drawable.createFromPath(bgStr) + } } } return bgDrawable ?: ColorDrawable(Color.parseColor("#015A86")) From 13a5a7747d4b99f4869e9a9df2e7d7230b50b279 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 31 Aug 2019 12:49:29 +0800 Subject: [PATCH 1166/1997] up --- .../ui/readbook/config/BgTextConfigDialog.kt | 37 ++++++++++--------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt index 3b8ade501..104e8f788 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt @@ -16,8 +16,9 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.jaredrummler.android.colorpicker.ColorPickerDialog import io.legado.app.R -import io.legado.app.base.adapter.CommonRecyclerAdapter import io.legado.app.base.adapter.ItemViewHolder +import io.legado.app.base.adapter.SimpleRecyclerAdapter +import io.legado.app.help.ImageLoader import io.legado.app.help.ReadBookConfig import io.legado.app.help.permission.Permissions import io.legado.app.help.permission.PermissionsCompat @@ -34,7 +35,7 @@ class BgTextConfigDialog : DialogFragment() { const val BG_COLOR = 122 } - private val ResultSelectBg = 123 + private val resultSelectBg = 123 private lateinit var adapter: BgAdapter override fun onCreateView( @@ -124,29 +125,31 @@ class BgTextConfigDialog : DialogFragment() { val intent = Intent(Intent.ACTION_GET_CONTENT) intent.addCategory(Intent.CATEGORY_OPENABLE) intent.type = "image/*" - startActivityForResult(intent, ResultSelectBg) + startActivityForResult(intent, resultSelectBg) Unit } .request() } class BgAdapter(context: Context) : - CommonRecyclerAdapter(context) { - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder { - return super.onCreateViewHolder(parent, viewType) + SimpleRecyclerAdapter(context, R.layout.item_bg_image) { + + override fun convert(holder: ItemViewHolder, item: String, payloads: MutableList) { + with(holder.itemView) { + ImageLoader.load(context, context.assets.open("bg/$item").readBytes()) + .centerCrop() + .setAsBitmap(iv_bg) + tv_name.text = item.substring(0, item.lastIndexOf(".")) + } } - -// override fun convert(holder: ItemViewHolder, item: String, payloads: MutableList) { -// with(holder.itemView) { -// ImageLoader.load(context, context.assets.open("bg/$item").readBytes()) -// .centerCrop() -// .setAsBitmap(iv_bg) -// tv_name.text = item.substring(0, item.lastIndexOf(".")) -// } -// } - } + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + when (requestCode) { + resultSelectBg -> { + } + } + } } \ No newline at end of file From d6959d1ae82656d28c9291b178688ed50e677372 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 31 Aug 2019 12:57:31 +0800 Subject: [PATCH 1167/1997] up --- .../java/io/legado/app/base/adapter/CommonRecyclerAdapter.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/base/adapter/CommonRecyclerAdapter.kt b/app/src/main/java/io/legado/app/base/adapter/CommonRecyclerAdapter.kt index 16108e2f9..a83b97374 100644 --- a/app/src/main/java/io/legado/app/base/adapter/CommonRecyclerAdapter.kt +++ b/app/src/main/java/io/legado/app/base/adapter/CommonRecyclerAdapter.kt @@ -343,7 +343,7 @@ abstract class CommonRecyclerAdapter(protected val context: Context) : Rec final override fun onBindViewHolder(holder: ItemViewHolder, position: Int, payloads: MutableList) { if (!isHeader(holder.layoutPosition) && !isFooter(holder.layoutPosition)) { - getItem(holder.layoutPosition)?.let { + getItem(holder.layoutPosition - getHeaderCount())?.let { itemDelegates.getValue(getItemViewType(holder.layoutPosition)) .convert(holder, it, payloads) } From 94a69f75350efa696466f44d7e802f5355bcb65f Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 31 Aug 2019 13:06:52 +0800 Subject: [PATCH 1168/1997] up --- app/src/main/java/io/legado/app/help/ReadBookConfig.kt | 3 ++- .../legado/app/ui/readbook/config/BgTextConfigDialog.kt | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index df282cfb1..c2114b9b6 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -4,6 +4,7 @@ import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.graphics.drawable.Drawable import io.legado.app.App +import io.legado.app.R import io.legado.app.utils.* import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.GlobalScope @@ -177,7 +178,7 @@ object ReadBookConfig { } } } - return bgDrawable ?: ColorDrawable(Color.parseColor("#015A86")) + return bgDrawable ?: ColorDrawable(App.INSTANCE.getCompatColor(R.color.background)) } } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt index 104e8f788..c0192ad9c 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt @@ -18,12 +18,14 @@ import com.jaredrummler.android.colorpicker.ColorPickerDialog import io.legado.app.R import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter +import io.legado.app.constant.Bus import io.legado.app.help.ImageLoader import io.legado.app.help.ReadBookConfig import io.legado.app.help.permission.Permissions import io.legado.app.help.permission.PermissionsCompat import io.legado.app.ui.readbook.Help import io.legado.app.utils.getCompatColor +import io.legado.app.utils.postEvent import kotlinx.android.synthetic.main.dialog_read_bg_text.* import kotlinx.android.synthetic.main.item_bg_image.view.* import org.jetbrains.anko.sdk27.listeners.onClick @@ -140,6 +142,11 @@ class BgTextConfigDialog : DialogFragment() { .centerCrop() .setAsBitmap(iv_bg) tv_name.text = item.substring(0, item.lastIndexOf(".")) + this.onClick { + ReadBookConfig.getConfig().setBg(1, item) + ReadBookConfig.upBg() + postEvent(Bus.UP_CONFIG, false) + } } } @@ -149,6 +156,7 @@ class BgTextConfigDialog : DialogFragment() { super.onActivityResult(requestCode, resultCode, data) when (requestCode) { resultSelectBg -> { + } } } From 902d9a102803052e628595f06c4883f54760ce36 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 31 Aug 2019 13:29:56 +0800 Subject: [PATCH 1169/1997] up --- .../app/ui/readbook/config/BgTextConfigDialog.kt | 12 +++++++++++- .../legado/app/ui/readbook/config/ReadStyleDialog.kt | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt index c0192ad9c..92b8108d0 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt @@ -1,6 +1,7 @@ package io.legado.app.ui.readbook.config import android.annotation.SuppressLint +import android.app.Activity.RESULT_OK import android.content.Context import android.content.DialogInterface import android.content.Intent @@ -24,6 +25,7 @@ import io.legado.app.help.ReadBookConfig import io.legado.app.help.permission.Permissions import io.legado.app.help.permission.PermissionsCompat import io.legado.app.ui.readbook.Help +import io.legado.app.utils.FileUtils import io.legado.app.utils.getCompatColor import io.legado.app.utils.postEvent import kotlinx.android.synthetic.main.dialog_read_bg_text.* @@ -156,7 +158,15 @@ class BgTextConfigDialog : DialogFragment() { super.onActivityResult(requestCode, resultCode, data) when (requestCode) { resultSelectBg -> { - + if (resultCode == RESULT_OK) { + data?.data?.let { + FileUtils.getPath(requireContext(), it)?.let { path -> + ReadBookConfig.getConfig().setBg(2, path) + ReadBookConfig.upBg() + postEvent(Bus.UP_CONFIG, false) + } + } + } } } } diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt index 7f8281eeb..20851e59f 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt @@ -247,7 +247,7 @@ class ReadStyleDialog : DialogFragment() { } ReadBookConfig.getConfig(i).apply { when (bgType()) { - 2 -> ImageLoader.load(requireContext(), bgStr()).centerCrop().setAsFile(iv) + 2 -> ImageLoader.load(requireContext(), bgStr()).centerCrop().setAsDrawable(iv) else -> iv.setImageDrawable(bgDrawable()) } } From 6642ab539be289c9038daa4becaae567864273e5 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 31 Aug 2019 13:34:38 +0800 Subject: [PATCH 1170/1997] up --- app/src/main/java/io/legado/app/help/ReadBookConfig.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index c2114b9b6..48c9bc27b 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -170,11 +170,11 @@ object ReadBookConfig { 0 -> bgDrawable = ColorDrawable(Color.parseColor(bgStr())) 1 -> bgDrawable = Drawable.createFromStream( - App.INSTANCE.assets.open("bg" + File.separator + bgStr), + App.INSTANCE.assets.open("bg" + File.separator + bgStr()), "bg" ) else -> runCatching { - bgDrawable = Drawable.createFromPath(bgStr) + bgDrawable = Drawable.createFromPath(bgStr()) } } } From 38ee046f3b30e4aacdba35183f4b214cde39094f Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 31 Aug 2019 15:29:43 +0800 Subject: [PATCH 1171/1997] up --- app/src/main/java/io/legado/app/data/entities/ReplaceRule.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/data/entities/ReplaceRule.kt b/app/src/main/java/io/legado/app/data/entities/ReplaceRule.kt index 65b070d57..9235543aa 100644 --- a/app/src/main/java/io/legado/app/data/entities/ReplaceRule.kt +++ b/app/src/main/java/io/legado/app/data/entities/ReplaceRule.kt @@ -16,6 +16,7 @@ data class ReplaceRule( @PrimaryKey(autoGenerate = true) var id: Int = 0, var name: String? = null, + var group: String? = null, var pattern: String? = null, var replacement: String? = null, var scope: String? = null, From 76d8e641c004c535176cd6c27ef5e68d2c63fc8f Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 31 Aug 2019 15:45:23 +0800 Subject: [PATCH 1172/1997] up --- app/src/main/assets/readConfig.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/main/assets/readConfig.json b/app/src/main/assets/readConfig.json index b0d04a524..2dc96caa8 100644 --- a/app/src/main/assets/readConfig.json +++ b/app/src/main/assets/readConfig.json @@ -14,7 +14,7 @@ "paddingBottom": 0 }, { - "bgStr": "羊皮纸2.jpg", + "bgStr": "新羊皮纸.jpg", "bgType": 1, "darkStatusIcon": true, "textColor": "#5E432E", @@ -28,10 +28,10 @@ "paddingBottom": 0 }, { - "bgStr": "#E1F1DA", + "bgStr": "#015A86", "bgType": 0, - "darkStatusIcon": true, - "textColor": "#22482C", + "darkStatusIcon": false, + "textColor": "#FFFFFF", "textSize": 22, "letterSpacing": 0, "lineSpacingExtra": 10, @@ -42,10 +42,10 @@ "paddingBottom": 0 }, { - "bgStr": "#015A86", + "bgStr": "宁静夜色", "bgType": 0, "darkStatusIcon": false, - "textColor": "#FFFFFF", + "textColor": "#adadad", "textSize": 22, "letterSpacing": 0, "lineSpacingExtra": 10, From 95ba4c3a13add6cc1b2d4514a01b31006153a5de Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 31 Aug 2019 16:36:24 +0800 Subject: [PATCH 1173/1997] up --- .../io/legado/app/lib/theme/TintHelper.kt | 21 ++++++++----------- .../legado/app/lib/theme/view/ATECheckBox.kt | 4 ++-- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt b/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt index b7b042ebc..8346e2525 100644 --- a/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt +++ b/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt @@ -317,18 +317,15 @@ object TintHelper { color ) ) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - box.buttonTintList = sl - } else { - val drawable = - createTintedDrawable( - ContextCompat.getDrawable( - box.context, - R.drawable.abc_btn_check_material - ), sl - ) - box.buttonDrawable = drawable - } + box.buttonTintList = sl + val drawable = + createTintedDrawable( + ContextCompat.getDrawable( + box.context, + R.drawable.abc_btn_check_material + ), sl + ) + box.buttonDrawable = drawable } fun setTint(image: ImageView, @ColorInt color: Int) { diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATECheckBox.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATECheckBox.kt index a9bef21b0..f910115df 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATECheckBox.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATECheckBox.kt @@ -4,7 +4,7 @@ import android.content.Context import android.util.AttributeSet import androidx.appcompat.widget.AppCompatCheckBox import io.legado.app.lib.theme.ATH -import io.legado.app.lib.theme.ThemeStore +import io.legado.app.lib.theme.accentColor /** * @author Aidan Follestad (afollestad) @@ -22,6 +22,6 @@ class ATECheckBox : AppCompatCheckBox { ) init { - ATH.setTint(this, ThemeStore.accentColor(context)) + ATH.setTint(this, context.accentColor) } } From 864c417ccf38d2a9ac22d648469ba0144e7f9cc8 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 31 Aug 2019 17:06:47 +0800 Subject: [PATCH 1174/1997] up --- .../io/legado/app/lib/theme/TintHelper.kt | 21 +++++++++++-------- app/src/main/res/layout/dialog_read_aloud.xml | 10 ++------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt b/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt index 8346e2525..b7b042ebc 100644 --- a/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt +++ b/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt @@ -317,15 +317,18 @@ object TintHelper { color ) ) - box.buttonTintList = sl - val drawable = - createTintedDrawable( - ContextCompat.getDrawable( - box.context, - R.drawable.abc_btn_check_material - ), sl - ) - box.buttonDrawable = drawable + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + box.buttonTintList = sl + } else { + val drawable = + createTintedDrawable( + ContextCompat.getDrawable( + box.context, + R.drawable.abc_btn_check_material + ), sl + ) + box.buttonDrawable = drawable + } } fun setTint(image: ImageView, @ColorInt color: Int) { diff --git a/app/src/main/res/layout/dialog_read_aloud.xml b/app/src/main/res/layout/dialog_read_aloud.xml index 34b644939..68c0282e4 100644 --- a/app/src/main/res/layout/dialog_read_aloud.xml +++ b/app/src/main/res/layout/dialog_read_aloud.xml @@ -74,13 +74,10 @@ android:layout_height="1dp" android:layout_weight="1" /> - @@ -142,14 +139,11 @@ android:textColor="@color/tv_text_default" android:textSize="14sp" /> - From d168b2f752ab1c066ccf868c1fda0409175c803e Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 31 Aug 2019 17:15:58 +0800 Subject: [PATCH 1175/1997] up --- app/src/main/res/menu/book_source.xml | 47 ++++++++++++++------------- app/src/main/res/values/strings.xml | 1 + 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/app/src/main/res/menu/book_source.xml b/app/src/main/res/menu/book_source.xml index bbae899ff..ec7a62b18 100644 --- a/app/src/main/res/menu/book_source.xml +++ b/app/src/main/res/menu/book_source.xml @@ -18,36 +18,39 @@ tools:ignore="AlwaysShowAction"> - - + - + - + - + - + - + - + - + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 95a6d72ef..4cf8c832e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -490,5 +490,6 @@ 背景颜色 文字颜色 选择图片 + 分组管理 From 36535998367285f7acfd28dcdb0de8675e4aa3a7 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 31 Aug 2019 17:27:41 +0800 Subject: [PATCH 1176/1997] up --- app/src/main/java/io/legado/app/App.kt | 23 +++++++++---------- .../app/ui/widget/page/ChapterProvider.kt | 5 +++- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/io/legado/app/App.kt b/app/src/main/java/io/legado/app/App.kt index b28924a1c..54238a6ad 100644 --- a/app/src/main/java/io/legado/app/App.kt +++ b/app/src/main/java/io/legado/app/App.kt @@ -18,6 +18,7 @@ import io.legado.app.help.ActivityHelp import io.legado.app.help.CrashHandler import io.legado.app.help.ReadBookConfig import io.legado.app.lib.theme.ThemeStore +import io.legado.app.ui.widget.page.ChapterProvider import io.legado.app.utils.getCompatColor import io.legado.app.utils.getPrefInt import io.legado.app.utils.isNightTheme @@ -69,18 +70,14 @@ class App : Application() { if (isNightTheme) { ThemeStore.editTheme(this) .primaryColor( - getPrefInt( - "colorPrimaryNight", - getCompatColor(R.color.md_blue_grey_600) - ) + getPrefInt("colorPrimaryNight", getCompatColor(R.color.md_blue_grey_600)) ) .accentColor( - getPrefInt( - "colorAccentNight", - getCompatColor(R.color.md_deep_orange_800) - ) + getPrefInt("colorAccentNight", getCompatColor(R.color.md_deep_orange_800)) + ) + .backgroundColor( + getPrefInt("colorBackgroundNight", getCompatColor(R.color.md_grey_800)) ) - .backgroundColor(getPrefInt("colorBackgroundNight", getCompatColor(R.color.md_grey_800))) .apply() } else { ThemeStore.editTheme(this) @@ -89,6 +86,7 @@ class App : Application() { .backgroundColor(getPrefInt("colorBackground", getCompatColor(R.color.md_grey_100))) .apply() } + ChapterProvider.upReadAloudSpan() } fun applyDayNight() { @@ -113,7 +111,8 @@ class App : Application() { */ @RequiresApi(Build.VERSION_CODES.O) private fun createChannelId() { - val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as? NotificationManager + val notificationManager = + getSystemService(Context.NOTIFICATION_SERVICE) as? NotificationManager notificationManager?.let { //用唯一的ID创建渠道对象 val downloadChannel = NotificationChannel( @@ -153,8 +152,8 @@ class App : Application() { } } - private fun registerActivityLife(){ - registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks{ + private fun registerActivityLife() { + registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks { override fun onActivityPaused(activity: Activity) { } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt index 889952188..7579ee9b6 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt @@ -10,7 +10,7 @@ import io.legado.app.lib.theme.accentColor object ChapterProvider { - val readAloudSpan = ForegroundColorSpan(App.INSTANCE.accentColor) + var readAloudSpan = ForegroundColorSpan(App.INSTANCE.accentColor) private val titleSpan = RelativeSizeSpan(1.2f) fun getTextChapter( @@ -65,4 +65,7 @@ object ChapterProvider { ) } + fun upReadAloudSpan() { + readAloudSpan = ForegroundColorSpan(App.INSTANCE.accentColor) + } } \ No newline at end of file From 77eb21b1adee66ff7308b55cc0a6b4833494498b Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 31 Aug 2019 17:45:58 +0800 Subject: [PATCH 1177/1997] up --- .../io/legado/app/ui/booksource/BookSourceActivity.kt | 9 ++------- .../io/legado/app/ui/booksource/BookSourceAdapter.kt | 1 - .../io/legado/app/ui/booksource/BookSourceViewModel.kt | 7 +++++++ 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt index 3486589a8..c1a0c6e36 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt @@ -4,7 +4,6 @@ import android.content.Intent import android.os.Bundle import android.view.Menu import android.view.MenuItem -import android.view.View import androidx.appcompat.widget.SearchView import androidx.lifecycle.LiveData import androidx.lifecycle.Observer @@ -125,15 +124,11 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity } override fun del(bookSource: BookSource) { - launch(IO) { App.db.bookSourceDao().delete(bookSource) } - } - - override fun update(bookSource: BookSource) { - launch(IO) { App.db.bookSourceDao().update(bookSource) } + viewModel.del(bookSource) } override fun update(vararg bookSource: BookSource) { - launch(IO) { App.db.bookSourceDao().update(*bookSource) } + viewModel.update(*bookSource) } override fun edit(bookSource: BookSource) { diff --git a/app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt b/app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt index 1d6869cb4..a89a01b68 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt @@ -92,7 +92,6 @@ class BookSourceAdapter : PagedListAdapter Date: Sat, 31 Aug 2019 19:22:42 +0800 Subject: [PATCH 1178/1997] up --- .../io/legado/app/data/dao/BookSourceDao.kt | 4 +++ .../app/model/analyzeRule/AnalyzeByJSoup.kt | 2 +- .../app/ui/booksource/BookSourceActivity.kt | 27 ++++++++++++++++++- .../ui/changesource/ChangeSourceViewModel.kt | 2 +- .../ui/readbook/config/BgTextConfigDialog.kt | 2 +- app/src/main/res/menu/book_source.xml | 2 +- 6 files changed, 34 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt index f39599888..bbacd2c9a 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt @@ -1,5 +1,6 @@ package io.legado.app.data.dao +import androidx.lifecycle.LiveData import androidx.paging.DataSource import androidx.room.* import io.legado.app.data.entities.BookSource @@ -13,6 +14,9 @@ interface BookSourceDao { @Query("select * from book_sources where bookSourceName like :searchKey or `bookSourceGroup` like :searchKey or bookSourceUrl like :searchKey order by customOrder asc") fun observeSearch(searchKey: String = ""): DataSource.Factory + @Query("select bookSourceGroup from book_sources") + fun observeGroup(): LiveData> + @Query("select distinct enabled from book_sources where bookSourceName like :searchKey or `bookSourceGroup` like :searchKey or bookSourceUrl like :searchKey") fun searchIsEnable(searchKey: String = ""): List diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSoup.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSoup.kt index b937abcb6..570262f17 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSoup.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSoup.kt @@ -114,7 +114,7 @@ class AnalyzeByJSoup { } if (results.size > 0) { if ("%" == elementsType) { - for (i in 0 until results[0].size) { + for (i in results[0].indices) { for (temp in results) { if (i < temp.size) { textS.add(temp[i]) diff --git a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt index c1a0c6e36..d2329cf27 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt @@ -4,6 +4,7 @@ import android.content.Intent import android.os.Bundle import android.view.Menu import android.view.MenuItem +import android.view.SubMenu import androidx.appcompat.widget.SearchView import androidx.lifecycle.LiveData import androidx.lifecycle.Observer @@ -22,6 +23,7 @@ import io.legado.app.lib.theme.primaryTextColor import io.legado.app.ui.qrcode.QrCodeActivity import io.legado.app.ui.sourceedit.SourceEditActivity import io.legado.app.utils.getViewModel +import io.legado.app.utils.splitNotBlank import kotlinx.android.synthetic.main.activity_book_source.* import kotlinx.android.synthetic.main.view_search.* import kotlinx.android.synthetic.main.view_title_bar.* @@ -36,9 +38,11 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity override val viewModel: BookSourceViewModel get() = getViewModel(BookSourceViewModel::class.java) + private val qrRequestCode = 101 private lateinit var adapter: BookSourceAdapter private var bookSourceLiveDate: LiveData>? = null - private val qrRequestCode = 101 + private var groups = hashSetOf() + private var groupMenu: SubMenu? = null override fun onActivityCreated(savedInstanceState: Bundle?) { setSupportActionBar(toolbar) @@ -52,6 +56,12 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity return super.onCompatCreateOptionsMenu(menu) } + override fun onPrepareOptionsMenu(menu: Menu?): Boolean { + groupMenu = menu?.findItem(R.id.menu_group)?.subMenu + upGroupMenu() + return super.onPrepareOptionsMenu(menu) + } + override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { R.id.action_add_book_source -> { @@ -106,6 +116,21 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity val dataFactory = App.db.bookSourceDao().observeSearch("%$searchKey%") bookSourceLiveDate = LivePagedListBuilder(dataFactory, 2000).build() bookSourceLiveDate?.observe(this, Observer { adapter.submitList(it) }) + + App.db.bookSourceDao().observeGroup().observe(this, Observer { + groups.clear() + it.map { group -> + groups.addAll(group.splitNotBlank(",", ";")) + } + upGroupMenu() + }) + } + + private fun upGroupMenu() { + groupMenu?.removeGroup(R.id.source_group) + groups.map { + groupMenu?.add(R.id.source_group, Menu.NONE, Menu.NONE, it) + } } override fun onQueryTextChange(newText: String?): Boolean { diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt index 938424fe2..df0caee90 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt @@ -18,7 +18,7 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio var callBack: CallBack? = null var name: String = "" var author: String = "" - var screenKey: String = "" + private var screenKey: String = "" private val searchBooks = linkedSetOf() fun initData() { diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt index 92b8108d0..bd67d8352 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt @@ -143,7 +143,7 @@ class BgTextConfigDialog : DialogFragment() { ImageLoader.load(context, context.assets.open("bg/$item").readBytes()) .centerCrop() .setAsBitmap(iv_bg) - tv_name.text = item.substring(0, item.lastIndexOf(".")) + tv_name.text = item.substringBeforeLast(".") this.onClick { ReadBookConfig.getConfig().setBg(1, item) ReadBookConfig.upBg() diff --git a/app/src/main/res/menu/book_source.xml b/app/src/main/res/menu/book_source.xml index ec7a62b18..6660208ae 100644 --- a/app/src/main/res/menu/book_source.xml +++ b/app/src/main/res/menu/book_source.xml @@ -11,7 +11,7 @@ tools:ignore="AlwaysShowAction" /> Date: Sat, 31 Aug 2019 19:28:09 +0800 Subject: [PATCH 1179/1997] up --- .../java/io/legado/app/ui/booksource/BookSourceActivity.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt index d2329cf27..7125a2e7b 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt @@ -82,6 +82,9 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity } } } + if (item.groupId == R.id.source_group) { + search_view.setQuery(item.title, true) + } return super.onCompatOptionsItemSelected(item) } From ff3af56226f1655f39747a32607c52efbd889090 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 31 Aug 2019 20:33:02 +0800 Subject: [PATCH 1180/1997] up --- .../app/ui/booksource/BookSourceActivity.kt | 7 ++++--- app/src/main/res/menu/book_source.xml | 18 +++++++++--------- app/src/main/res/menu/source_edit.xml | 2 +- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt index 7125a2e7b..6cfd7fa7e 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt @@ -64,13 +64,13 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { - R.id.action_add_book_source -> { + R.id.menu_add_book_source -> { this.startActivity() } - R.id.action_import_book_source_qr -> { + R.id.menu_import_book_source_qr -> { this.startActivityForResult(qrRequestCode) } - R.id.action_select_all -> { + R.id.menu_select_all -> { launch(IO) { val isEnableList = App.db.bookSourceDao().searchIsEnable("%${search_view.query}%") @@ -81,6 +81,7 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity } } } + } if (item.groupId == R.id.source_group) { search_view.setQuery(item.title, true) diff --git a/app/src/main/res/menu/book_source.xml b/app/src/main/res/menu/book_source.xml index 6660208ae..36b9b8952 100644 --- a/app/src/main/res/menu/book_source.xml +++ b/app/src/main/res/menu/book_source.xml @@ -4,7 +4,7 @@ xmlns:tools="http://schemas.android.com/tools"> diff --git a/app/src/main/res/menu/source_edit.xml b/app/src/main/res/menu/source_edit.xml index f1ee15173..ac204a22a 100644 --- a/app/src/main/res/menu/source_edit.xml +++ b/app/src/main/res/menu/source_edit.xml @@ -40,7 +40,7 @@ app:showAsAction="never" /> From 7f4b0a45e684f0b44eee471f61807d69cc14a10d Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 31 Aug 2019 21:52:39 +0800 Subject: [PATCH 1181/1997] up --- app/src/debug/res/values/strings.xml | 4 ++ app/src/debug/res/xml/shortcuts.xml | 35 +++++++++++ .../app/ui/booksource/GroupManageDialog.kt | 58 +++++++++++++++++++ .../main/res/layout/dialog_recycler_view.xml | 17 ++++++ app/src/main/res/layout/item_group_manage.xml | 28 +++++++++ app/src/main/res/xml/shortcuts.xml | 35 +++++++++++ 6 files changed, 177 insertions(+) create mode 100644 app/src/debug/res/values/strings.xml create mode 100644 app/src/debug/res/xml/shortcuts.xml create mode 100644 app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt create mode 100644 app/src/main/res/layout/dialog_recycler_view.xml create mode 100644 app/src/main/res/layout/item_group_manage.xml create mode 100644 app/src/main/res/xml/shortcuts.xml diff --git a/app/src/debug/res/values/strings.xml b/app/src/debug/res/values/strings.xml new file mode 100644 index 000000000..b91572ada --- /dev/null +++ b/app/src/debug/res/values/strings.xml @@ -0,0 +1,4 @@ + + 阅读.debug + 阅读.debug·搜索 + \ No newline at end of file diff --git a/app/src/debug/res/xml/shortcuts.xml b/app/src/debug/res/xml/shortcuts.xml new file mode 100644 index 000000000..340b48f86 --- /dev/null +++ b/app/src/debug/res/xml/shortcuts.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt b/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt new file mode 100644 index 000000000..738a71338 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt @@ -0,0 +1,58 @@ +package io.legado.app.ui.booksource + +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.DialogFragment +import androidx.lifecycle.Observer +import androidx.recyclerview.widget.LinearLayoutManager +import io.legado.app.App +import io.legado.app.R +import io.legado.app.base.adapter.ItemViewHolder +import io.legado.app.base.adapter.SimpleRecyclerAdapter +import io.legado.app.utils.splitNotBlank +import kotlinx.android.synthetic.main.dialog_recycler_view.* + +class GroupManageDialog : DialogFragment() { + + private lateinit var adapter: GroupAdapter + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + return inflater.inflate(R.layout.dialog_recycler_view, container) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + initData() + } + + private fun initData() { + tool_bar.title = getString(R.string.group_manage) + adapter = GroupAdapter(requireContext()) + recycler_view.layoutManager = LinearLayoutManager(requireContext()) + recycler_view.adapter = adapter + App.db.bookSourceDao().observeGroup().observe(viewLifecycleOwner, Observer { + val groups = linkedSetOf() + it.map { group -> + groups.addAll(group.splitNotBlank(",", ";")) + } + adapter.setItems(groups.toList()) + }) + } + + + class GroupAdapter(context: Context) : + SimpleRecyclerAdapter(context, R.layout.item_group_manage) { + + override fun convert(holder: ItemViewHolder, item: String, payloads: MutableList) { + + } + + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_recycler_view.xml b/app/src/main/res/layout/dialog_recycler_view.xml new file mode 100644 index 000000000..6ac7d8c01 --- /dev/null +++ b/app/src/main/res/layout/dialog_recycler_view.xml @@ -0,0 +1,17 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_group_manage.xml b/app/src/main/res/layout/item_group_manage.xml new file mode 100644 index 000000000..de089dbb4 --- /dev/null +++ b/app/src/main/res/layout/item_group_manage.xml @@ -0,0 +1,28 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/shortcuts.xml b/app/src/main/res/xml/shortcuts.xml new file mode 100644 index 000000000..05445a90b --- /dev/null +++ b/app/src/main/res/xml/shortcuts.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + From 8e352f26b37c4658f854324b9534d62b4ab6549c Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 31 Aug 2019 21:55:02 +0800 Subject: [PATCH 1182/1997] up --- app/src/debug/res/xml/shortcuts.xml | 4 ++-- app/src/main/res/xml/shortcuts.xml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/debug/res/xml/shortcuts.xml b/app/src/debug/res/xml/shortcuts.xml index 340b48f86..d653992cc 100644 --- a/app/src/debug/res/xml/shortcuts.xml +++ b/app/src/debug/res/xml/shortcuts.xml @@ -4,7 +4,7 @@ Date: Sat, 31 Aug 2019 22:52:10 +0800 Subject: [PATCH 1183/1997] up --- .../app/ui/booksource/BookSourceActivity.kt | 5 +- .../app/ui/booksource/BookSourceViewModel.kt | 8 +++ .../app/ui/booksource/GroupManageDialog.kt | 62 +++++++++++++++++-- app/src/main/res/layout/item_group_manage.xml | 8 ++- app/src/main/res/values/strings.xml | 1 + 5 files changed, 75 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt index 6cfd7fa7e..eceeb0845 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt @@ -81,7 +81,10 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity } } } - + R.id.menu_group_manage -> GroupManageDialog().show( + supportFragmentManager, + "groupManage" + ) } if (item.groupId == R.id.source_group) { search_view.setQuery(item.title, true) diff --git a/app/src/main/java/io/legado/app/ui/booksource/BookSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/booksource/BookSourceViewModel.kt index aed90d952..cc9cc3bf9 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/BookSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/BookSourceViewModel.kt @@ -23,4 +23,12 @@ class BookSourceViewModel(application: Application) : BaseViewModel(application) fun update(vararg bookSource: BookSource) { execute { App.db.bookSourceDao().update(*bookSource) } } + + fun upGroup(oldGroup: String, newGroup: String?) { + + } + + fun delGroup(group: String) { + + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt b/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt index 738a71338..4a41914dd 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt @@ -1,24 +1,48 @@ package io.legado.app.ui.booksource +import android.annotation.SuppressLint import android.content.Context import android.os.Bundle +import android.util.DisplayMetrics import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.EditText import androidx.fragment.app.DialogFragment import androidx.lifecycle.Observer +import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView import io.legado.app.App import io.legado.app.R import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter +import io.legado.app.lib.dialogs.alert +import io.legado.app.lib.dialogs.customView +import io.legado.app.lib.dialogs.noButton +import io.legado.app.lib.dialogs.yesButton +import io.legado.app.lib.theme.ATH +import io.legado.app.utils.applyTint +import io.legado.app.utils.getViewModelOfActivity +import io.legado.app.utils.requestInputMethod import io.legado.app.utils.splitNotBlank +import kotlinx.android.synthetic.main.dialog_edittext.view.* import kotlinx.android.synthetic.main.dialog_recycler_view.* +import kotlinx.android.synthetic.main.item_book_group.view.tv_group +import kotlinx.android.synthetic.main.item_group_manage.view.* +import org.jetbrains.anko.sdk27.listeners.onClick class GroupManageDialog : DialogFragment() { - + private val viewModel = getViewModelOfActivity(BookSourceViewModel::class.java) private lateinit var adapter: GroupAdapter + override fun onStart() { + super.onStart() + val dm = DisplayMetrics() + activity?.windowManager?.defaultDisplay?.getMetrics(dm) + dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.9).toInt()) + } + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -34,8 +58,11 @@ class GroupManageDialog : DialogFragment() { private fun initData() { tool_bar.title = getString(R.string.group_manage) - adapter = GroupAdapter(requireContext()) + adapter = GroupAdapter(requireContext(), this) recycler_view.layoutManager = LinearLayoutManager(requireContext()) + recycler_view.addItemDecoration( + DividerItemDecoration(requireContext(), RecyclerView.VERTICAL) + ) recycler_view.adapter = adapter App.db.bookSourceDao().observeGroup().observe(viewLifecycleOwner, Observer { val groups = linkedSetOf() @@ -46,13 +73,38 @@ class GroupManageDialog : DialogFragment() { }) } + @SuppressLint("InflateParams") + private fun editGroup(group: String) { + alert(title = getString(R.string.group_edit)) { + var editText: EditText? = null + customView { + layoutInflater.inflate(R.layout.dialog_edittext, null).apply { + editText = edit_view.apply { + ATH.applyAccentTint(this) + hint = "分组名称" + } + } + } + + yesButton { + viewModel.upGroup(group, editText?.text?.toString()) + } + + noButton() - class GroupAdapter(context: Context) : + }.show().applyTint().requestInputMethod() + } + + class GroupAdapter(context: Context, val dialog: GroupManageDialog) : SimpleRecyclerAdapter(context, R.layout.item_group_manage) { override fun convert(holder: ItemViewHolder, item: String, payloads: MutableList) { - + with(holder.itemView) { + tv_group.text = item + tv_edit.onClick { dialog.editGroup(item) } + tv_del.onClick { dialog.viewModel.delGroup(item) } + } } - } + } \ No newline at end of file diff --git a/app/src/main/res/layout/item_group_manage.xml b/app/src/main/res/layout/item_group_manage.xml index de089dbb4..493bf7998 100644 --- a/app/src/main/res/layout/item_group_manage.xml +++ b/app/src/main/res/layout/item_group_manage.xml @@ -1,12 +1,12 @@ @@ -15,6 +15,7 @@ android:id="@+id/tv_edit" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:background="?attr/selectableItemBackground" android:padding="8dp" android:text="@string/edit" /> @@ -22,6 +23,7 @@ android:id="@+id/tv_del" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:background="?attr/selectableItemBackground" android:padding="8dp" android:text="@string/delete" /> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4cf8c832e..86d6d28ce 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -491,5 +491,6 @@ 文字颜色 选择图片 分组管理 + 编辑分组 From 7eb051e398ee5f32b37633d0e524bed4436685b9 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 31 Aug 2019 23:01:06 +0800 Subject: [PATCH 1184/1997] up --- .../java/io/legado/app/ui/booksource/GroupManageDialog.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt b/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt index 4a41914dd..7cb017ff4 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt @@ -23,7 +23,7 @@ import io.legado.app.lib.dialogs.noButton import io.legado.app.lib.dialogs.yesButton import io.legado.app.lib.theme.ATH import io.legado.app.utils.applyTint -import io.legado.app.utils.getViewModelOfActivity +import io.legado.app.utils.getViewModel import io.legado.app.utils.requestInputMethod import io.legado.app.utils.splitNotBlank import kotlinx.android.synthetic.main.dialog_edittext.view.* @@ -33,7 +33,7 @@ import kotlinx.android.synthetic.main.item_group_manage.view.* import org.jetbrains.anko.sdk27.listeners.onClick class GroupManageDialog : DialogFragment() { - private val viewModel = getViewModelOfActivity(BookSourceViewModel::class.java) + private lateinit var viewModel: BookSourceViewModel private lateinit var adapter: GroupAdapter override fun onStart() { @@ -48,6 +48,7 @@ class GroupManageDialog : DialogFragment() { container: ViewGroup?, savedInstanceState: Bundle? ): View? { + viewModel = getViewModel(BookSourceViewModel::class.java) return inflater.inflate(R.layout.dialog_recycler_view, container) } @@ -82,6 +83,7 @@ class GroupManageDialog : DialogFragment() { editText = edit_view.apply { ATH.applyAccentTint(this) hint = "分组名称" + setText(group) } } } From d3ebd8477e38d01216cee8b2bbcf944330e9b9f0 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 31 Aug 2019 23:05:30 +0800 Subject: [PATCH 1185/1997] up --- .../java/io/legado/app/ui/booksource/BookSourceViewModel.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/booksource/BookSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/booksource/BookSourceViewModel.kt index cc9cc3bf9..03579febc 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/BookSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/BookSourceViewModel.kt @@ -25,10 +25,14 @@ class BookSourceViewModel(application: Application) : BaseViewModel(application) } fun upGroup(oldGroup: String, newGroup: String?) { + execute { + } } fun delGroup(group: String) { + execute { + } } } \ No newline at end of file From ac0fc7a16e091be5ac69775e0006fceb6e87deb8 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 1 Sep 2019 00:04:30 +0800 Subject: [PATCH 1186/1997] up --- .../java/io/legado/app/ui/booksource/GroupManageDialog.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt b/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt index 7cb017ff4..15004660e 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt @@ -23,7 +23,7 @@ import io.legado.app.lib.dialogs.noButton import io.legado.app.lib.dialogs.yesButton import io.legado.app.lib.theme.ATH import io.legado.app.utils.applyTint -import io.legado.app.utils.getViewModel +import io.legado.app.utils.getViewModelOfActivity import io.legado.app.utils.requestInputMethod import io.legado.app.utils.splitNotBlank import kotlinx.android.synthetic.main.dialog_edittext.view.* @@ -48,7 +48,7 @@ class GroupManageDialog : DialogFragment() { container: ViewGroup?, savedInstanceState: Bundle? ): View? { - viewModel = getViewModel(BookSourceViewModel::class.java) + viewModel = getViewModelOfActivity(BookSourceViewModel::class.java) return inflater.inflate(R.layout.dialog_recycler_view, container) } From 1a94dbd14e956676e0456b8086d77334702b4860 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 1 Sep 2019 08:55:55 +0800 Subject: [PATCH 1187/1997] up --- .../io/legado/app/data/dao/BookSourceDao.kt | 3 +++ .../app/ui/booksource/BookSourceViewModel.kt | 24 +++++++++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt index bbacd2c9a..9c53671f1 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt @@ -26,6 +26,9 @@ interface BookSourceDao { @Query("select * from book_sources where enabledExplore = 1 order by customOrder asc") fun observeFind(): DataSource.Factory + @Query("select * from book_sources where bookSourceGroup like '%' || :group || '%'") + fun getByGroup(group: String): List + @get:Query("select * from book_sources order by customOrder asc") val all: List diff --git a/app/src/main/java/io/legado/app/ui/booksource/BookSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/booksource/BookSourceViewModel.kt index 03579febc..a2d28eeb6 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/BookSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/BookSourceViewModel.kt @@ -1,9 +1,11 @@ package io.legado.app.ui.booksource import android.app.Application +import android.text.TextUtils import io.legado.app.App import io.legado.app.base.BaseViewModel import io.legado.app.data.entities.BookSource +import io.legado.app.utils.splitNotBlank class BookSourceViewModel(application: Application) : BaseViewModel(application) { @@ -26,13 +28,31 @@ class BookSourceViewModel(application: Application) : BaseViewModel(application) fun upGroup(oldGroup: String, newGroup: String?) { execute { - + val sources = App.db.bookSourceDao().getByGroup(oldGroup) + sources.map { source -> + source.bookSourceGroup?.splitNotBlank(",")?.toHashSet()?.let { + it.remove(oldGroup) + if (!newGroup.isNullOrEmpty()) + it.add(newGroup) + source.bookSourceGroup = TextUtils.join(",", it) + } + } + App.db.bookSourceDao().update(*sources.toTypedArray()) } } fun delGroup(group: String) { execute { - + execute { + val sources = App.db.bookSourceDao().getByGroup(group) + sources.map { source -> + source.bookSourceGroup?.splitNotBlank(",")?.toHashSet()?.let { + it.remove(group) + source.bookSourceGroup = TextUtils.join(",", it) + } + } + App.db.bookSourceDao().update(*sources.toTypedArray()) + } } } } \ No newline at end of file From d0d4d335b3a35a27cc6b89c1dfca0ed1d8d4a0a3 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 1 Sep 2019 08:59:03 +0800 Subject: [PATCH 1188/1997] up --- app/src/main/res/layout/dialog_read_padding.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/layout/dialog_read_padding.xml b/app/src/main/res/layout/dialog_read_padding.xml index 498c1b91b..22bb10e50 100644 --- a/app/src/main/res/layout/dialog_read_padding.xml +++ b/app/src/main/res/layout/dialog_read_padding.xml @@ -168,7 +168,7 @@ + android:text="@string/padding_right" /> Date: Sun, 1 Sep 2019 09:03:15 +0800 Subject: [PATCH 1189/1997] up --- .../app/ui/booksource/BookSourceAdapter.kt | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt b/app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt index a89a01b68..f9314073b 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt @@ -14,7 +14,8 @@ import io.legado.app.lib.theme.ThemeStore import kotlinx.android.synthetic.main.item_book_source.view.* import org.jetbrains.anko.sdk27.listeners.onClick -class BookSourceAdapter : PagedListAdapter(DIFF_CALLBACK) { +class BookSourceAdapter : + PagedListAdapter(DIFF_CALLBACK) { companion object { @@ -54,13 +55,22 @@ class BookSourceAdapter : PagedListAdapter?, currentList: PagedList?) { + override fun onCurrentListChanged( + previousList: PagedList?, + currentList: PagedList? + ) { super.onCurrentListChanged(previousList, currentList) callBack?.upCount(itemCount) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { - return MyViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_book_source, parent, false)) + return MyViewHolder( + LayoutInflater.from(parent.context).inflate( + R.layout.item_book_source, + parent, + false + ) + ) } @@ -76,7 +86,12 @@ class BookSourceAdapter : PagedListAdapter Date: Sun, 1 Sep 2019 09:35:17 +0800 Subject: [PATCH 1190/1997] up --- .../io/legado/app/data/dao/BookSourceDao.kt | 3 ++ .../app/ui/booksource/BookSourceViewModel.kt | 10 +++++ .../app/ui/booksource/GroupManageDialog.kt | 39 +++++++++++++++++-- app/src/main/res/menu/group_manage.xml | 9 +++++ app/src/main/res/values/strings.xml | 1 + 5 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 app/src/main/res/menu/group_manage.xml diff --git a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt index 9c53671f1..b616d1733 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt @@ -29,6 +29,9 @@ interface BookSourceDao { @Query("select * from book_sources where bookSourceGroup like '%' || :group || '%'") fun getByGroup(group: String): List + @get:Query("select * from book_sources where bookSourceGroup = null or bookSourceGroup = ''") + val noGroup: List + @get:Query("select * from book_sources order by customOrder asc") val all: List diff --git a/app/src/main/java/io/legado/app/ui/booksource/BookSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/booksource/BookSourceViewModel.kt index a2d28eeb6..ab58abc35 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/BookSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/BookSourceViewModel.kt @@ -26,6 +26,16 @@ class BookSourceViewModel(application: Application) : BaseViewModel(application) execute { App.db.bookSourceDao().update(*bookSource) } } + fun addGroup(group: String) { + execute { + val sources = App.db.bookSourceDao().noGroup + sources.map { source -> + source.bookSourceGroup = group + } + App.db.bookSourceDao().update(*sources.toTypedArray()) + } + } + fun upGroup(oldGroup: String, newGroup: String?) { execute { val sources = App.db.bookSourceDao().getByGroup(oldGroup) diff --git a/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt b/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt index 15004660e..8b13dc647 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt @@ -5,9 +5,11 @@ import android.content.Context import android.os.Bundle import android.util.DisplayMetrics import android.view.LayoutInflater +import android.view.MenuItem import android.view.View import android.view.ViewGroup import android.widget.EditText +import androidx.appcompat.widget.Toolbar import androidx.fragment.app.DialogFragment import androidx.lifecycle.Observer import androidx.recyclerview.widget.DividerItemDecoration @@ -32,7 +34,7 @@ import kotlinx.android.synthetic.main.item_book_group.view.tv_group import kotlinx.android.synthetic.main.item_group_manage.view.* import org.jetbrains.anko.sdk27.listeners.onClick -class GroupManageDialog : DialogFragment() { +class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { private lateinit var viewModel: BookSourceViewModel private lateinit var adapter: GroupAdapter @@ -59,6 +61,8 @@ class GroupManageDialog : DialogFragment() { private fun initData() { tool_bar.title = getString(R.string.group_manage) + tool_bar.inflateMenu(R.menu.group_manage) + tool_bar.setOnMenuItemClickListener(this) adapter = GroupAdapter(requireContext(), this) recycler_view.layoutManager = LinearLayoutManager(requireContext()) recycler_view.addItemDecoration( @@ -74,6 +78,36 @@ class GroupManageDialog : DialogFragment() { }) } + override fun onMenuItemClick(item: MenuItem?): Boolean { + when (item?.itemId) { + R.id.menu_group_manage -> addGroup() + } + return true + } + + @SuppressLint("InflateParams") + private fun addGroup() { + alert(title = getString(R.string.add_group)) { + var editText: EditText? = null + customView { + layoutInflater.inflate(R.layout.dialog_edittext, null).apply { + editText = edit_view.apply { + ATH.applyAccentTint(this) + hint = "分组名称" + } + } + } + yesButton { + editText?.text?.toString()?.let { + if (it.isNotBlank()) { + viewModel.addGroup(it) + } + } + } + noButton() + }.show().applyTint().requestInputMethod() + } + @SuppressLint("InflateParams") private fun editGroup(group: String) { alert(title = getString(R.string.group_edit)) { @@ -87,13 +121,10 @@ class GroupManageDialog : DialogFragment() { } } } - yesButton { viewModel.upGroup(group, editText?.text?.toString()) } - noButton() - }.show().applyTint().requestInputMethod() } diff --git a/app/src/main/res/menu/group_manage.xml b/app/src/main/res/menu/group_manage.xml new file mode 100644 index 000000000..0ddbb4f12 --- /dev/null +++ b/app/src/main/res/menu/group_manage.xml @@ -0,0 +1,9 @@ + + + + + \ 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 86d6d28ce..cb28dabaf 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -492,5 +492,6 @@ 选择图片 分组管理 编辑分组 + 添加分组 From 669d50b98ce9cb62687d4d62d202394c68210fe2 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 1 Sep 2019 09:54:05 +0800 Subject: [PATCH 1191/1997] up --- .../io/legado/app/data/dao/BookChapterDao.kt | 4 +- .../app/ui/chapterlist/ChapterListAdapter.kt | 51 +++++-------------- .../app/ui/chapterlist/ChapterListFragment.kt | 21 ++++---- 3 files changed, 24 insertions(+), 52 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/BookChapterDao.kt b/app/src/main/java/io/legado/app/data/dao/BookChapterDao.kt index 6473da76f..fdbff2bf1 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookChapterDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookChapterDao.kt @@ -1,6 +1,6 @@ package io.legado.app.data.dao -import androidx.paging.DataSource +import androidx.lifecycle.LiveData import androidx.room.Dao import androidx.room.Insert import androidx.room.OnConflictStrategy @@ -11,7 +11,7 @@ import io.legado.app.data.entities.BookChapter interface BookChapterDao { @Query("select * from chapters where bookUrl = :bookUrl") - fun observeByBook(bookUrl: String): DataSource.Factory + fun observeByBook(bookUrl: String): LiveData> @Query("select * from chapters where bookUrl = :bookUrl") fun getChapterList(bookUrl: String): List diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListAdapter.kt b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListAdapter.kt index aa975798a..c7adcf2bb 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListAdapter.kt @@ -1,12 +1,9 @@ package io.legado.app.ui.chapterlist -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.paging.PagedListAdapter -import androidx.recyclerview.widget.DiffUtil -import androidx.recyclerview.widget.RecyclerView +import android.content.Context import io.legado.app.R +import io.legado.app.base.adapter.ItemViewHolder +import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter import io.legado.app.help.BookHelp @@ -15,46 +12,22 @@ import io.legado.app.utils.getCompatColor import kotlinx.android.synthetic.main.item_bookmark.view.* import org.jetbrains.anko.sdk27.listeners.onClick -class ChapterListAdapter(val callback: Callback) : - PagedListAdapter(DIFF_CALLBACK) { +class ChapterListAdapter(context: Context, val callback: Callback) : + SimpleRecyclerAdapter(context, R.layout.item_chapter_list) { - companion object { - - @JvmField - val DIFF_CALLBACK = object : DiffUtil.ItemCallback() { - override fun areItemsTheSame(oldItem: BookChapter, newItem: BookChapter): Boolean = - oldItem.bookUrl == newItem.bookUrl - && oldItem.url == newItem.url - - override fun areContentsTheSame(oldItem: BookChapter, newItem: BookChapter): Boolean = - oldItem.title == newItem.title - } - } - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { - return MyViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_chapter_list, parent, false)) - } - - override fun onBindViewHolder(holder: MyViewHolder, position: Int) { - getItem(position)?.let { - holder.bind(it, callback) - } - } - - class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { - - fun bind(bookChapter: BookChapter, callback: Callback) = with(itemView) { - if (callback.durChapterIndex() == bookChapter.index) { + override fun convert(holder: ItemViewHolder, item: BookChapter, payloads: MutableList) { + with(holder.itemView) { + if (callback.durChapterIndex() == item.index) { tv_chapter_name.setTextColor(context.accentColor) } else { tv_chapter_name.setTextColor(context.getCompatColor(R.color.tv_text_default)) } - tv_chapter_name.text = bookChapter.title - itemView.onClick { - callback.openChapter(bookChapter) + tv_chapter_name.text = item.title + this.onClick { + callback.openChapter(item) } callback.book()?.let { - tv_chapter_name.paint.isFakeBoldText = BookHelp.hasContent(it, bookChapter) + tv_chapter_name.paint.isFakeBoldText = BookHelp.hasContent(it, item) } } } diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt index d237ea2dd..4d3e947b6 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt +++ b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt @@ -3,10 +3,7 @@ package io.legado.app.ui.chapterlist import android.os.Bundle import android.view.View import android.widget.LinearLayout -import androidx.lifecycle.LiveData import androidx.lifecycle.Observer -import androidx.paging.LivePagedListBuilder -import androidx.paging.PagedList import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.App @@ -26,7 +23,6 @@ class ChapterListFragment : VMBaseFragment(R.layout.fragme get() = getViewModelOfActivity(ChapterListViewModel::class.java) lateinit var adapter: ChapterListAdapter - private var liveData: LiveData>? = null private var durChapterIndex = 0 override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -37,7 +33,7 @@ class ChapterListFragment : VMBaseFragment(R.layout.fragme } private fun initRecyclerView() { - adapter = ChapterListAdapter(this) + adapter = ChapterListAdapter(requireContext(), this) recycler_view.layoutManager = LinearLayoutManager(requireContext()) recycler_view.addItemDecoration( DividerItemDecoration( @@ -49,14 +45,17 @@ class ChapterListFragment : VMBaseFragment(R.layout.fragme } private fun initData() { - liveData?.removeObservers(viewLifecycleOwner) - liveData = LivePagedListBuilder(App.db.bookChapterDao().observeByBook(viewModel.bookUrl ?: ""), 30).build() - liveData?.observe(viewLifecycleOwner, Observer { adapter.submitList(it) }) - viewModel.bookDate.value?.let { - loadBookFinish(it) - } ?: viewModel.bookDate.observe(viewLifecycleOwner, Observer { + viewModel.bookDate.observe(viewLifecycleOwner, Observer { loadBookFinish(it) }) + viewModel.bookUrl?.let { bookUrl -> + App.db.bookChapterDao().observeByBook(bookUrl).observe(viewLifecycleOwner, Observer { + adapter.setItems(it) + viewModel.bookDate.value?.let { book -> + loadBookFinish(book) + } + }) + } } private fun initView() { From f83898320ad1b6d2ccb8353abb6f7e6ea8564c19 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 1 Sep 2019 10:00:28 +0800 Subject: [PATCH 1192/1997] up --- .../legado/app/ui/widget/recycler/scroller/FastScroller.kt | 4 +--- app/src/main/res/layout/view_fastscroller.xml | 6 ++---- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/recycler/scroller/FastScroller.kt b/app/src/main/java/io/legado/app/ui/widget/recycler/scroller/FastScroller.kt index eee187a85..9086f50db 100644 --- a/app/src/main/java/io/legado/app/ui/widget/recycler/scroller/FastScroller.kt +++ b/app/src/main/java/io/legado/app/ui/widget/recycler/scroller/FastScroller.kt @@ -103,9 +103,7 @@ class FastScroller : LinearLayout { @IdRes val recyclerViewId = mRecyclerView?.id ?: View.NO_ID val marginTop = resources.getDimensionPixelSize(R.dimen.fastscroll_scrollbar_margin_top) val marginBottom = resources.getDimensionPixelSize(R.dimen.fastscroll_scrollbar_margin_bottom) - if (recyclerViewId == View.NO_ID) { - throw IllegalArgumentException("RecyclerView must have a view ID") - } + require(recyclerViewId != View.NO_ID) { "RecyclerView must have a view ID" } when (viewGroup) { is ConstraintLayout -> { val constraintSet = ConstraintSet() diff --git a/app/src/main/res/layout/view_fastscroller.xml b/app/src/main/res/layout/view_fastscroller.xml index 7256c640f..d2c3b71d5 100644 --- a/app/src/main/res/layout/view_fastscroller.xml +++ b/app/src/main/res/layout/view_fastscroller.xml @@ -21,10 +21,6 @@ android:id="@+id/fastscroll_scrollbar" android:layout_width="wrap_content" android:layout_height="match_parent" - android:paddingEnd="@dimen/fastscroll_scrollbar_padding_end" - android:paddingLeft="@dimen/fastscroll_scrollbar_padding_start" - android:paddingRight="@dimen/fastscroll_scrollbar_padding_end" - android:paddingStart="@dimen/fastscroll_scrollbar_padding_start" android:visibility="gone" tools:visibility="visible"> @@ -41,6 +37,8 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" + android:paddingEnd="@dimen/fastscroll_scrollbar_padding_end" + android:paddingStart="@dimen/fastscroll_scrollbar_padding_start" tools:ignore="ContentDescription" tools:src="@drawable/fastscroll_handle" /> From b431ba01d971345d9d6b4652aabe1c5909bb4389 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 1 Sep 2019 10:08:18 +0800 Subject: [PATCH 1193/1997] up --- .../java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt index 90024b32c..6c6c3de6e 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt @@ -30,6 +30,7 @@ class BookshelfAdapter : PagedListAdapter(D oldItem.bookUrl == newItem.bookUrl && oldItem.durChapterTitle == newItem.durChapterTitle && oldItem.latestChapterTitle == newItem.latestChapterTitle + && oldItem.durChapterTime == newItem.durChapterTime } } From 24d20d8a2971c7fc886f68c33e79a45a2095431a Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 1 Sep 2019 10:09:50 +0800 Subject: [PATCH 1194/1997] up --- .../main/java/io/legado/app/ui/bookshelf/BookshelfAdapter.kt | 3 ++- .../java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/bookshelf/BookshelfAdapter.kt b/app/src/main/java/io/legado/app/ui/bookshelf/BookshelfAdapter.kt index 4f8a20e7f..24822211d 100644 --- a/app/src/main/java/io/legado/app/ui/bookshelf/BookshelfAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/bookshelf/BookshelfAdapter.kt @@ -10,7 +10,6 @@ import io.legado.app.R import io.legado.app.data.entities.Book import io.legado.app.help.ImageLoader import io.legado.app.lib.theme.ATH -import io.legado.app.lib.theme.ThemeStore import kotlinx.android.synthetic.main.item_bookshelf_list.view.* import kotlinx.android.synthetic.main.item_relace_rule.view.tv_name @@ -26,6 +25,8 @@ class BookshelfAdapter : PagedListAdapter(D oldItem.bookUrl == newItem.bookUrl && oldItem.durChapterTitle == newItem.durChapterTitle && oldItem.latestChapterTitle == newItem.latestChapterTitle + && oldItem.durChapterTime == newItem.durChapterTime + && oldItem.lastCheckTime == newItem.lastCheckTime } } diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt index 6c6c3de6e..f7d9cda78 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt @@ -31,6 +31,7 @@ class BookshelfAdapter : PagedListAdapter(D && oldItem.durChapterTitle == newItem.durChapterTitle && oldItem.latestChapterTitle == newItem.latestChapterTitle && oldItem.durChapterTime == newItem.durChapterTime + && oldItem.lastCheckTime == newItem.lastCheckTime } } From e15740c6d986f56161879a1ae617e976f6c4f265 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 1 Sep 2019 10:27:37 +0800 Subject: [PATCH 1195/1997] up --- app/src/main/res/menu/replace_rule.xml | 70 ++++++++++++++++++++++++++ app/src/main/res/values/strings.xml | 1 + 2 files changed, 71 insertions(+) create mode 100644 app/src/main/res/menu/replace_rule.xml diff --git a/app/src/main/res/menu/replace_rule.xml b/app/src/main/res/menu/replace_rule.xml new file mode 100644 index 000000000..b0551eee4 --- /dev/null +++ b/app/src/main/res/menu/replace_rule.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index cb28dabaf..574d0e454 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -493,5 +493,6 @@ 分组管理 编辑分组 添加分组 + 新建替换 From 941d8954b97fae5e1fe3d545bf8ae3bc7cf99103 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 1 Sep 2019 10:36:52 +0800 Subject: [PATCH 1196/1997] up --- .../app/ui/replacerule/ReplaceRuleActivity.kt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt index 2957d9953..0348ef71a 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt @@ -1,6 +1,8 @@ package io.legado.app.ui.replacerule import android.os.Bundle +import android.view.Menu +import android.view.MenuItem import androidx.core.content.ContextCompat import androidx.lifecycle.LiveData import androidx.lifecycle.Observer @@ -34,6 +36,18 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi initSwipeToDelete() } + override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { + menuInflater.inflate(R.menu.replace_rule, menu) + return super.onCompatCreateOptionsMenu(menu) + } + + override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + + } + return super.onCompatOptionsItemSelected(item) + } + private fun initRecyclerView() { ATH.applyEdgeEffectColor(rv_replace_rule) rv_replace_rule.layoutManager = LinearLayoutManager(this) @@ -71,6 +85,7 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi }) } + private fun initDataObservers() { rulesLiveData?.removeObservers(this) rulesLiveData = LivePagedListBuilder(App.db.replaceRuleDao().observeAll(), 30).build() From 235f12dd4029ee9fc12348f168b58b8399cdc184 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 1 Sep 2019 11:00:39 +0800 Subject: [PATCH 1197/1997] up --- app/build.gradle | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 990b59760..250200bea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -94,7 +94,7 @@ dependencies { //lifecycle def lifecycle_version = '2.0.0' implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version" - kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version" + implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version" //room def room_version = '2.1.0' @@ -133,6 +133,10 @@ dependencies { //Glide implementation 'com.github.bumptech.glide:glide:4.9.0' + //webServer + implementation 'org.nanohttpd:nanohttpd:2.3.1' + implementation 'org.nanohttpd:nanohttpd-websocket:2.3.1' + //二维码 implementation 'cn.bingoogolapple:bga-qrcode-zxing:1.3.6' From 59b68e45d46b52916b5413c8da9da34af1185086 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 1 Sep 2019 12:16:44 +0800 Subject: [PATCH 1198/1997] up --- .../java/io/legado/app/data/dao/BookDao.kt | 3 + app/src/main/java/io/legado/app/web/ReadMe.md | 1 + .../app/web/controller/BookshelfController.kt | 56 +++++++++++++ .../app/web/controller/SourceController.kt | 79 ++++++++++++++++++ .../web/controller/SourceDebugWebSocket.kt | 82 +++++++++++++++++++ .../java/io/legado/app/web/utils/AssetsWeb.kt | 44 ++++++++++ .../io/legado/app/web/utils/ReturnData.kt | 39 +++++++++ 7 files changed, 304 insertions(+) create mode 100644 app/src/main/java/io/legado/app/web/ReadMe.md create mode 100644 app/src/main/java/io/legado/app/web/controller/BookshelfController.kt create mode 100644 app/src/main/java/io/legado/app/web/controller/SourceController.kt create mode 100644 app/src/main/java/io/legado/app/web/controller/SourceDebugWebSocket.kt create mode 100644 app/src/main/java/io/legado/app/web/utils/AssetsWeb.kt create mode 100644 app/src/main/java/io/legado/app/web/utils/ReturnData.kt diff --git a/app/src/main/java/io/legado/app/data/dao/BookDao.kt b/app/src/main/java/io/legado/app/data/dao/BookDao.kt index 064eb29b2..04e76d3bd 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookDao.kt @@ -30,6 +30,9 @@ interface BookDao { @Query("SELECT * FROM books WHERE bookUrl = :bookUrl") fun getBook(bookUrl: String): Book? + @get:Query("SELECT * FROM books") + val allBooks: List + @get:Query("SELECT * FROM books ORDER BY durChapterTime DESC limit 1") val lastReadBook: Book? diff --git a/app/src/main/java/io/legado/app/web/ReadMe.md b/app/src/main/java/io/legado/app/web/ReadMe.md new file mode 100644 index 000000000..cd5544c3e --- /dev/null +++ b/app/src/main/java/io/legado/app/web/ReadMe.md @@ -0,0 +1 @@ +# web服务 \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/web/controller/BookshelfController.kt b/app/src/main/java/io/legado/app/web/controller/BookshelfController.kt new file mode 100644 index 000000000..e0d9cae21 --- /dev/null +++ b/app/src/main/java/io/legado/app/web/controller/BookshelfController.kt @@ -0,0 +1,56 @@ +package io.legado.app.web.controller + +import io.legado.app.App +import io.legado.app.data.entities.Book +import io.legado.app.utils.GSON +import io.legado.app.utils.fromJsonObject +import io.legado.app.web.utils.ReturnData + +class BookshelfController { + + val bookshelf: ReturnData + get() { + val books = App.db.bookDao().allBooks + val returnData = ReturnData() + return if (books.isEmpty()) { + returnData.setErrorMsg("还没有添加小说") + } else returnData.setData(books) + } + + fun getChapterList(parameters: Map>): ReturnData { + val strings = parameters["url"] + val returnData = ReturnData() + if (strings == null) { + return returnData.setErrorMsg("参数url不能为空,请指定书籍地址") + } + val chapterList = App.db.bookChapterDao().getChapterList(strings[0]) + return returnData.setData(chapterList) + } + + fun getBookContent(parameters: Map>): ReturnData { + val strings = parameters["url"] + val returnData = ReturnData() + if (strings == null) { + return returnData.setErrorMsg("参数url不能为空,请指定内容地址") + } + val book = App.db.bookDao().getBook(strings[0]) + val chapter = App.db.bookChapterDao().getChapter(strings[0], strings[1].toInt()) + if (book == null || chapter == null) { + returnData.setErrorMsg("未找到") + } else { + + } + return returnData + } + + fun saveBook(postData: String): ReturnData { + val book = GSON.fromJsonObject(postData) + val returnData = ReturnData() + if (book != null) { + App.db.bookDao().insert(book) + return returnData.setData("") + } + return returnData.setErrorMsg("格式不对") + } + +} diff --git a/app/src/main/java/io/legado/app/web/controller/SourceController.kt b/app/src/main/java/io/legado/app/web/controller/SourceController.kt new file mode 100644 index 000000000..dafeb1c7d --- /dev/null +++ b/app/src/main/java/io/legado/app/web/controller/SourceController.kt @@ -0,0 +1,79 @@ +package io.legado.app.web.controller + + +import android.text.TextUtils +import io.legado.app.App +import io.legado.app.data.entities.BookSource +import io.legado.app.utils.GSON +import io.legado.app.utils.fromJsonArray +import io.legado.app.utils.fromJsonObject +import io.legado.app.web.utils.ReturnData + +class SourceController { + + val sources: ReturnData + get() { + val bookSources = App.db.bookSourceDao().all + val returnData = ReturnData() + return if (bookSources.isEmpty()) { + returnData.setErrorMsg("设备书源列表为空") + } else returnData.setData(bookSources) + } + + fun saveSource(postData: String): ReturnData { + val returnData = ReturnData() + try { + val bookSource = GSON.fromJsonObject(postData) + if (bookSource != null) { + if (TextUtils.isEmpty(bookSource.bookSourceName) || TextUtils.isEmpty(bookSource.bookSourceUrl)) { + returnData.setErrorMsg("书源名称和URL不能为空") + } else { + App.db.bookSourceDao().insert(bookSource) + returnData.setData("") + } + } else { + returnData.setErrorMsg("转换书源失败") + } + } catch (e: Exception) { + returnData.setErrorMsg(e.localizedMessage) + } + return returnData + } + + fun saveSources(postData: String): ReturnData { + val okSources = arrayListOf() + kotlin.runCatching { + val bookSources = GSON.fromJsonArray(postData) + if (bookSources != null) { + for (bookSource in bookSources) { + if (bookSource.bookSourceName.isBlank() || bookSource.bookSourceUrl.isBlank()) { + continue + } + App.db.bookSourceDao().insert(bookSource) + okSources.add(bookSource) + } + } + } + return ReturnData().setData(okSources) + } + + fun getSource(parameters: Map>): ReturnData { + val strings = parameters["url"] + val returnData = ReturnData() + if (strings == null) { + return returnData.setErrorMsg("参数url不能为空,请指定书源地址") + } + val bookSource = App.db.bookSourceDao().getBookSource(strings[0]) + ?: return returnData.setErrorMsg("未找到书源,请检查书源地址") + return returnData.setData(bookSource) + } + + fun deleteSources(postData: String): ReturnData { + kotlin.runCatching { + GSON.fromJsonArray(postData)?.let { + App.db.bookSourceDao().delete(*it.toTypedArray()) + } + } + return ReturnData().setData("已执行"/*okSources*/) + } +} diff --git a/app/src/main/java/io/legado/app/web/controller/SourceDebugWebSocket.kt b/app/src/main/java/io/legado/app/web/controller/SourceDebugWebSocket.kt new file mode 100644 index 000000000..999ae7872 --- /dev/null +++ b/app/src/main/java/io/legado/app/web/controller/SourceDebugWebSocket.kt @@ -0,0 +1,82 @@ +package io.legado.app.web.controller + + +import fi.iki.elonen.NanoHTTPD +import fi.iki.elonen.NanoWSD +import io.legado.app.App +import io.legado.app.R +import io.legado.app.model.WebBook +import io.legado.app.model.webbook.SourceDebug +import io.legado.app.utils.GSON +import io.legado.app.utils.fromJsonObject +import io.legado.app.utils.isJson +import kotlinx.coroutines.* +import kotlinx.coroutines.Dispatchers.IO +import java.io.IOException + + +class SourceDebugWebSocket(handshakeRequest: NanoHTTPD.IHTTPSession) : + NanoWSD.WebSocket(handshakeRequest), + CoroutineScope by MainScope(), + SourceDebug.Callback { + + + override fun onOpen() { + launch(IO) { + do { + delay(30000) + runCatching { + ping(byteArrayOf("ping".toByte())) + } + } while (isOpen) + } + } + + override fun onClose( + code: NanoWSD.WebSocketFrame.CloseCode, + reason: String, + initiatedByRemote: Boolean + ) { + cancel() + SourceDebug.cancelDebug(true) + } + + override fun onMessage(message: NanoWSD.WebSocketFrame) { + if (!message.textPayload.isJson()) return + kotlin.runCatching { + val debugBean = GSON.fromJsonObject>(message.textPayload) + if (debugBean != null) { + val tag = debugBean["tag"] + val key = debugBean["key"] + if (tag.isNullOrBlank() || key.isNullOrBlank()) { + kotlin.runCatching { + send(App.INSTANCE.getString(R.string.cannot_empty)) + close(NanoWSD.WebSocketFrame.CloseCode.NormalClosure, "调试结束", false) + } + return + } + App.db.bookSourceDao().getBookSource(tag)?.let { + SourceDebug(WebBook(it), this).startDebug(key) + } + } + } + } + + override fun onPong(pong: NanoWSD.WebSocketFrame) { + + } + + override fun onException(exception: IOException) { + SourceDebug.cancelDebug(true) + } + + override fun printLog(state: Int, msg: String) { + kotlin.runCatching { + send(msg) + if (state == -1 || state == 1000) { + SourceDebug.cancelDebug(true) + } + } + } + +} diff --git a/app/src/main/java/io/legado/app/web/utils/AssetsWeb.kt b/app/src/main/java/io/legado/app/web/utils/AssetsWeb.kt new file mode 100644 index 000000000..503f7aad5 --- /dev/null +++ b/app/src/main/java/io/legado/app/web/utils/AssetsWeb.kt @@ -0,0 +1,44 @@ +package io.legado.app.web.utils + +import android.content.res.AssetManager +import android.text.TextUtils +import fi.iki.elonen.NanoHTTPD +import io.legado.app.App +import java.io.File +import java.io.IOException + + +class AssetsWeb(rootPath: String) { + private val assetManager: AssetManager = App.INSTANCE.assets + private var rootPath = "web" + + init { + if (!TextUtils.isEmpty(rootPath)) { + this.rootPath = rootPath + } + } + + @Throws(IOException::class) + fun getResponse(path: String): NanoHTTPD.Response { + var path1 = path + path1 = (rootPath + path1).replace("/+".toRegex(), File.separator) + val inputStream = assetManager.open(path1) + return NanoHTTPD.newChunkedResponse( + NanoHTTPD.Response.Status.OK, + getMimeType(path1), + inputStream + ) + } + + private fun getMimeType(path: String): String { + val suffix = path.substring(path.lastIndexOf(".")) + return when { + suffix.equals(".html", ignoreCase = true) + || suffix.equals(".htm", ignoreCase = true) -> "text/html" + suffix.equals(".js", ignoreCase = true) -> "text/javascript" + suffix.equals(".css", ignoreCase = true) -> "text/css" + suffix.equals(".ico", ignoreCase = true) -> "image/x-icon" + else -> "text/html" + } + } +} diff --git a/app/src/main/java/io/legado/app/web/utils/ReturnData.kt b/app/src/main/java/io/legado/app/web/utils/ReturnData.kt new file mode 100644 index 000000000..5ea07243f --- /dev/null +++ b/app/src/main/java/io/legado/app/web/utils/ReturnData.kt @@ -0,0 +1,39 @@ +package io.legado.app.web.utils + + +class ReturnData { + + var isSuccess: Boolean = false + + var errorCode: Int = 0 + + private var errorMsg: String? = null + + private var data: Any? = null + + init { + this.isSuccess = false + this.errorMsg = "未知错误,请联系开发者!" + } + + fun getErrorMsg(): String? { + return errorMsg + } + + fun setErrorMsg(errorMsg: String): ReturnData { + this.isSuccess = false + this.errorMsg = errorMsg + return this + } + + fun getData(): Any? { + return data + } + + fun setData(data: Any): ReturnData { + this.isSuccess = true + this.errorMsg = "" + this.data = data + return this + } +} From b2401f60e0cb2b6eaee3b963cf4120293e751581 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 1 Sep 2019 12:21:27 +0800 Subject: [PATCH 1199/1997] up --- .../main/java/io/legado/app/web/HttpServer.kt | 75 +++++++++++++++++++ .../app/web/controller/BookshelfController.kt | 2 +- .../app/web/controller/SourceController.kt | 6 +- 3 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 app/src/main/java/io/legado/app/web/HttpServer.kt diff --git a/app/src/main/java/io/legado/app/web/HttpServer.kt b/app/src/main/java/io/legado/app/web/HttpServer.kt new file mode 100644 index 000000000..34b196d60 --- /dev/null +++ b/app/src/main/java/io/legado/app/web/HttpServer.kt @@ -0,0 +1,75 @@ +package io.legado.app.web + +import com.google.gson.Gson +import fi.iki.elonen.NanoHTTPD +import io.legado.app.web.controller.BookshelfController +import io.legado.app.web.controller.SourceController +import io.legado.app.web.utils.AssetsWeb +import io.legado.app.web.utils.ReturnData +import java.util.* + +class HttpServer(port: Int) : NanoHTTPD(port) { + private val assetsWeb = AssetsWeb("web") + + + override fun serve(session: NanoHTTPD.IHTTPSession): NanoHTTPD.Response { + var returnData: ReturnData? = null + var uri = session.uri + + try { + when (session.method.name) { + "OPTIONS" -> { + val response = NanoHTTPD.newFixedLengthResponse("") + response.addHeader("Access-Control-Allow-Methods", "POST") + response.addHeader("Access-Control-Allow-Headers", "content-type") + response.addHeader("Access-Control-Allow-Origin", session.headers["origin"]) + //response.addHeader("Access-Control-Max-Age", "3600"); + return response + } + + "POST" -> { + val files = HashMap() + session.parseBody(files) + val postData = files["postData"] + + when (uri) { + "/saveSource" -> returnData = SourceController().saveSource(postData) + "/saveSources" -> returnData = SourceController().saveSources(postData) + "/saveBook" -> returnData = BookshelfController().saveBook(postData) + "/deleteSources" -> returnData = SourceController().deleteSources(postData) + } + } + + "GET" -> { + val parameters = session.parameters + + when (uri) { + "/getSource" -> returnData = SourceController().getSource(parameters) + "/getSources" -> returnData = SourceController().sources + "/getBookshelf" -> returnData = BookshelfController().bookshelf + "/getChapterList" -> returnData = + BookshelfController().getChapterList(parameters) + "/getBookContent" -> returnData = + BookshelfController().getBookContent(parameters) + } + } + } + + if (returnData == null) { + if (uri.endsWith("/")) { + uri += "index.html" + } + return assetsWeb.getResponse(uri) + } + + val response = NanoHTTPD.newFixedLengthResponse(Gson().toJson(returnData)) + response.addHeader("Access-Control-Allow-Methods", "GET, POST") + response.addHeader("Access-Control-Allow-Origin", session.headers["origin"]) + return response + } catch (e: Exception) { + return NanoHTTPD.newFixedLengthResponse(e.message) + } + + } + +} diff --git a/app/src/main/java/io/legado/app/web/controller/BookshelfController.kt b/app/src/main/java/io/legado/app/web/controller/BookshelfController.kt index e0d9cae21..d41d4117c 100644 --- a/app/src/main/java/io/legado/app/web/controller/BookshelfController.kt +++ b/app/src/main/java/io/legado/app/web/controller/BookshelfController.kt @@ -43,7 +43,7 @@ class BookshelfController { return returnData } - fun saveBook(postData: String): ReturnData { + fun saveBook(postData: String?): ReturnData { val book = GSON.fromJsonObject(postData) val returnData = ReturnData() if (book != null) { diff --git a/app/src/main/java/io/legado/app/web/controller/SourceController.kt b/app/src/main/java/io/legado/app/web/controller/SourceController.kt index dafeb1c7d..3711092fc 100644 --- a/app/src/main/java/io/legado/app/web/controller/SourceController.kt +++ b/app/src/main/java/io/legado/app/web/controller/SourceController.kt @@ -20,7 +20,7 @@ class SourceController { } else returnData.setData(bookSources) } - fun saveSource(postData: String): ReturnData { + fun saveSource(postData: String?): ReturnData { val returnData = ReturnData() try { val bookSource = GSON.fromJsonObject(postData) @@ -40,7 +40,7 @@ class SourceController { return returnData } - fun saveSources(postData: String): ReturnData { + fun saveSources(postData: String?): ReturnData { val okSources = arrayListOf() kotlin.runCatching { val bookSources = GSON.fromJsonArray(postData) @@ -68,7 +68,7 @@ class SourceController { return returnData.setData(bookSource) } - fun deleteSources(postData: String): ReturnData { + fun deleteSources(postData: String?): ReturnData { kotlin.runCatching { GSON.fromJsonArray(postData)?.let { App.db.bookSourceDao().delete(*it.toTypedArray()) From 00e5da3683e0604ab8f375daf0aa2a15afc82c3e Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 1 Sep 2019 12:23:18 +0800 Subject: [PATCH 1200/1997] up --- .../main/java/io/legado/app/web/WebSocketServer.kt | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 app/src/main/java/io/legado/app/web/WebSocketServer.kt diff --git a/app/src/main/java/io/legado/app/web/WebSocketServer.kt b/app/src/main/java/io/legado/app/web/WebSocketServer.kt new file mode 100644 index 000000000..c885a1e0a --- /dev/null +++ b/app/src/main/java/io/legado/app/web/WebSocketServer.kt @@ -0,0 +1,13 @@ +package io.legado.app.web + +import fi.iki.elonen.NanoWSD +import io.legado.app.web.controller.SourceDebugWebSocket + +class WebSocketServer(port: Int) : NanoWSD(port) { + + override fun openWebSocket(handshake: IHTTPSession): WebSocket? { + return if (handshake.uri == "/sourceDebug") { + SourceDebugWebSocket(handshake) + } else null + } +} From c7660cf30307017783ce294f61b84bfc5b29899c Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 1 Sep 2019 12:50:18 +0800 Subject: [PATCH 1201/1997] up --- .../io/legado/app/ui/readbook/ReadBookActivity.kt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index cb6e1b66a..eaf619d83 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -247,10 +247,25 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea return true } } + KeyEvent.KEYCODE_VOLUME_UP -> { + } + KeyEvent.KEYCODE_VOLUME_DOWN -> { + } + KeyEvent.KEYCODE_SPACE -> { + } } return super.onKeyDown(keyCode, event) } + override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean { + when (keyCode) { + KeyEvent.KEYCODE_VOLUME_UP, KeyEvent.KEYCODE_VOLUME_DOWN -> { + + } + } + return super.onKeyUp(keyCode, event) + } + /** * 加载章节内容 */ From 3bcacef191d6a8c2385ad90c4696499d773553cc Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 1 Sep 2019 13:34:27 +0800 Subject: [PATCH 1202/1997] up --- .../main/java/io/legado/app/ui/booksource/GroupManageDialog.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt b/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt index 8b13dc647..f7b821088 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt @@ -80,7 +80,7 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { override fun onMenuItemClick(item: MenuItem?): Boolean { when (item?.itemId) { - R.id.menu_group_manage -> addGroup() + R.id.menu_add_empty -> addGroup() } return true } From 119a1be7542fe764f2c91ef2fefc90112164d88c Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 1 Sep 2019 15:10:28 +0800 Subject: [PATCH 1203/1997] up --- app/src/main/res/menu/group_manage.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/menu/group_manage.xml b/app/src/main/res/menu/group_manage.xml index 0ddbb4f12..90784e23e 100644 --- a/app/src/main/res/menu/group_manage.xml +++ b/app/src/main/res/menu/group_manage.xml @@ -3,7 +3,8 @@ xmlns:android="http://schemas.android.com/apk/res/android"> \ No newline at end of file From 44d138c63dca5c43bf10baa1348122a15b79f57e Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 1 Sep 2019 15:12:04 +0800 Subject: [PATCH 1204/1997] up --- .../main/java/io/legado/app/ui/booksource/GroupManageDialog.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt b/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt index f7b821088..ad5643a3a 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt @@ -80,7 +80,7 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { override fun onMenuItemClick(item: MenuItem?): Boolean { when (item?.itemId) { - R.id.menu_add_empty -> addGroup() + R.id.menu_add -> addGroup() } return true } From 528b7554b2cb60c488812199396e059a5f9957fa Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 1 Sep 2019 15:21:31 +0800 Subject: [PATCH 1205/1997] up --- app/src/main/res/menu/book_source.xml | 3 +++ app/src/main/res/menu/search_book.xml | 15 +++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 app/src/main/res/menu/search_book.xml diff --git a/app/src/main/res/menu/book_source.xml b/app/src/main/res/menu/book_source.xml index 36b9b8952..ce1ab7368 100644 --- a/app/src/main/res/menu/book_source.xml +++ b/app/src/main/res/menu/book_source.xml @@ -28,6 +28,9 @@ android:title="@string/sort"> + + + + + + + + + From 425a24bd1cf6f4f31aa30543ce5bb68c916fe261 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 1 Sep 2019 15:30:54 +0800 Subject: [PATCH 1206/1997] up --- .../main/java/io/legado/app/ui/welcome/WelcomeActivity.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/welcome/WelcomeActivity.kt b/app/src/main/java/io/legado/app/ui/welcome/WelcomeActivity.kt index efe7a36ff..77ef26284 100644 --- a/app/src/main/java/io/legado/app/ui/welcome/WelcomeActivity.kt +++ b/app/src/main/java/io/legado/app/ui/welcome/WelcomeActivity.kt @@ -2,10 +2,10 @@ package io.legado.app.ui.welcome import android.animation.Animator import android.animation.ValueAnimator +import android.content.Intent import android.os.Bundle import io.legado.app.R import io.legado.app.base.BaseActivity -import io.legado.app.lib.theme.ThemeStore import io.legado.app.lib.theme.accentColor import io.legado.app.ui.main.MainActivity import kotlinx.android.synthetic.main.activity_welcome.* @@ -15,6 +15,11 @@ class WelcomeActivity : BaseActivity(R.layout.activity_welcome) { override fun onActivityCreated(savedInstanceState: Bundle?) { iv_bg.setColorFilter(accentColor) + // 避免从桌面启动程序后,会重新实例化入口类的activity + if (intent.flags and Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT != 0) { + finish() + return + } val welAnimator = ValueAnimator.ofFloat(1f, 0f).setDuration(800) welAnimator.startDelay = 100 welAnimator.addUpdateListener { animation -> From debcf6836de982bdb9545b933e9a222e6bdc5af7 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 1 Sep 2019 18:21:04 +0800 Subject: [PATCH 1207/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 33 ++++++++++++++++++- .../io/legado/app/ui/widget/page/PageView.kt | 4 +-- .../legado/app/ui/widget/page/TextChapter.kt | 2 +- .../app/ui/widget/page/TextPageFactory.kt | 5 +-- 4 files changed, 38 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index eaf619d83..efafce804 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -37,6 +37,7 @@ import io.legado.app.ui.sourceedit.SourceEditActivity import io.legado.app.ui.widget.page.ChapterProvider import io.legado.app.ui.widget.page.PageView import io.legado.app.ui.widget.page.TextChapter +import io.legado.app.ui.widget.page.delegate.PageDelegate import io.legado.app.utils.* import kotlinx.android.synthetic.main.activity_read_book.* import kotlinx.android.synthetic.main.view_book_page.* @@ -248,10 +249,17 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } KeyEvent.KEYCODE_VOLUME_UP -> { + if (volumeKeyPage(PageDelegate.Direction.PREV)) { + return true + } } KeyEvent.KEYCODE_VOLUME_DOWN -> { + if (volumeKeyPage(PageDelegate.Direction.NEXT)) { + return true + } } KeyEvent.KEYCODE_SPACE -> { + } } return super.onKeyDown(keyCode, event) @@ -260,12 +268,35 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean { when (keyCode) { KeyEvent.KEYCODE_VOLUME_UP, KeyEvent.KEYCODE_VOLUME_DOWN -> { - + if (volumeKeyPage(PageDelegate.Direction.NONE)) { + return true + } } } return super.onKeyUp(keyCode, event) } + private fun volumeKeyPage(direction: PageDelegate.Direction): Boolean { + if (!read_menu.isVisible) { + if (getPrefBoolean("volumeKeyPage", true)) { + if (getPrefBoolean("volumeKeyPageOnPlay") + || readAloudStatus != Status.PLAY + ) { + when (direction) { + PageDelegate.Direction.PREV -> { + + } + PageDelegate.Direction.NEXT -> { + + } + } + return true + } + } + } + return false + } + /** * 加载章节内容 */ diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index f10eeda81..6f211bf0b 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -156,11 +156,11 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att } override fun hasNext(): Boolean { - return true + return pageFactory?.hasNext() == true } override fun hasPrev(): Boolean { - return true + return pageFactory?.hasPrev() == true } fun upStyle() { diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt index 60df9a04a..801f23ea7 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt @@ -26,7 +26,7 @@ data class TextChapter( } fun isLastIndex(index: Int): Boolean { - return index == pages.size - 1 + return index >= pages.size - 1 } fun pageSize(): Int { diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt index 96d646c3d..332537f48 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt @@ -10,11 +10,12 @@ class TextPageFactory private constructor(dataSource: DataSource) : } override fun hasPrev(): Boolean { - return true + return dataSource.hasPrevChapter() || dataSource.pageIndex() > 0 } override fun hasNext(): Boolean { - return true + return dataSource.hasNextChapter() + || dataSource.getCurrentChapter()?.isLastIndex(dataSource.pageIndex()) != true } override fun pageAt(index: Int): TextPage { From 3c0b6a3d2902aeb36a42186f3e05e5108dfb047e Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 1 Sep 2019 18:26:25 +0800 Subject: [PATCH 1208/1997] up --- .../main/java/io/legado/app/ui/widget/page/TextPageFactory.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt index 332537f48..a3cfa8599 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt @@ -19,7 +19,8 @@ class TextPageFactory private constructor(dataSource: DataSource) : } override fun pageAt(index: Int): TextPage { - TODO("todo...") + return dataSource.getCurrentChapter()?.page(index) + ?: TextPage(index = index, title = "index:$index") } override fun moveToFirst() { From 71afa982ba2e555c84843bd0aae42c2942ec3531 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 1 Sep 2019 18:28:12 +0800 Subject: [PATCH 1209/1997] up --- app/src/main/java/io/legado/app/ui/widget/page/PageView.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 6f211bf0b..3a80a2067 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -52,7 +52,7 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att } override fun getChapter(position: Int): TextChapter? { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + return callback?.textChapter(position) } override fun getCurrentChapter(): TextChapter? { From a2de255e4aa8fc068fed82ec2ebd946ad24a25c7 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 1 Sep 2019 18:57:56 +0800 Subject: [PATCH 1210/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 11 +++- .../io/legado/app/ui/widget/page/PageView.kt | 50 +++++++++++++++---- .../page/delegate/NoAnmiPageDelegate.kt | 19 +++++++ .../res/layout/dialog_read_book_style.xml | 12 +++++ 4 files changed, 80 insertions(+), 12 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/widget/page/delegate/NoAnmiPageDelegate.kt diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index efafce804..935f17640 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -309,7 +309,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } /** - * 加载章节内容 + * 加载章节内容, index章节序号 */ override fun loadContent(index: Int) { viewModel.bookData.value?.let { @@ -405,6 +405,9 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea curPageChanged() } + /** + * chapterOnDur: 0为当前页,1为下一页,-1为上一页 + */ override fun textChapter(chapterOnDur: Int): TextChapter? { return when (chapterOnDur) { 0 -> viewModel.curTextChapter @@ -414,6 +417,9 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } + /** + * 下一页 + */ override fun moveToNextChapter() { viewModel.durPageIndex = 0 viewModel.moveToNextChapter() @@ -421,6 +427,9 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea curChapterChanged() } + /** + * 上一页 + */ override fun moveToPrevChapter(last: Boolean) { viewModel.durPageIndex = if (last) viewModel.prevTextChapter?.lastIndex() ?: 0 else 0 viewModel.moveToPrevChapter() diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 3a80a2067..2f27045c9 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -8,11 +8,13 @@ import android.view.MotionEvent import android.widget.FrameLayout import io.legado.app.help.ReadBookConfig import io.legado.app.ui.widget.page.delegate.CoverPageDelegate +import io.legado.app.ui.widget.page.delegate.NoAnmiPageDelegate import io.legado.app.ui.widget.page.delegate.PageDelegate import io.legado.app.ui.widget.page.delegate.SlidePageDelegate import io.legado.app.utils.getPrefInt -class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, attrs), PageDelegate.PageInterface { +class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, attrs), + PageDelegate.PageInterface { var callback: CallBack? = null private var pageDelegate: PageDelegate? = null @@ -44,7 +46,7 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att } override fun isPrepared(): Boolean { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + return true } override fun getChapterPosition(): Int { @@ -123,14 +125,10 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att it.moveToNext() } else -> { - } } - - prevPage?.setContent(it.previousPage()) - curPage?.setContent(it.currentPage()) - nextPage?.setContent(it.nextPage()) } + upContent() } private fun setPageFactory(factory: TextPageFactory) { @@ -143,6 +141,7 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att fun upPageAnim() { pageDelegate = when (context.getPrefInt("pageAnim")) { 1 -> SlidePageDelegate(this) + 2 -> NoAnmiPageDelegate(this) else -> CoverPageDelegate(this) } } @@ -155,12 +154,17 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att } } - override fun hasNext(): Boolean { - return pageFactory?.hasNext() == true + fun moveToPrevPage(noAnim: Boolean = true) { + if (noAnim) { + fillPage(PageDelegate.Direction.PREV) + } + } - override fun hasPrev(): Boolean { - return pageFactory?.hasPrev() == true + fun moveToNextPage(noAnim: Boolean = true) { + if (noAnim) { + fillPage(PageDelegate.Direction.NEXT) + } } fun upStyle() { @@ -190,6 +194,14 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att nextPage?.upBattery(battery) } + override fun hasNext(): Boolean { + return pageFactory?.hasNext() == true + } + + override fun hasPrev(): Boolean { + return pageFactory?.hasPrev() == true + } + override fun clickCenter() { callback?.clickCenter() } @@ -198,10 +210,26 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att fun chapterSize(): Int fun durChapterIndex(): Int fun durChapterPos(): Int + /** + * chapterOnDur: 0为当前页,1为下一页,-1为上一页 + */ fun textChapter(chapterOnDur: Int = 0): TextChapter? + + /** + * 加载章节内容, index章节序号 + */ fun loadContent(index: Int) + + /** + * 下一页 + */ fun moveToNextChapter() + + /** + * 上一页 + */ fun moveToPrevChapter(last: Boolean = true) + fun setPageIndex(pageIndex: Int) fun clickCenter() } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/NoAnmiPageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/NoAnmiPageDelegate.kt new file mode 100644 index 000000000..89e3d9c0a --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/NoAnmiPageDelegate.kt @@ -0,0 +1,19 @@ +package io.legado.app.ui.widget.page.delegate + +import android.graphics.Canvas +import io.legado.app.ui.widget.page.PageView + +class NoAnmiPageDelegate(pageView: PageView) : PageDelegate(pageView) { + override fun onScrollStart() { + startScroll(touchX.toInt(), 0, 0, 0) + } + + override fun onDraw(canvas: Canvas) { + } + + override fun onScrollStop() { + if (!isCancel) { + pageView.fillPage(direction) + } + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_read_book_style.xml b/app/src/main/res/layout/dialog_read_book_style.xml index 599fe7832..6cec496aa 100644 --- a/app/src/main/res/layout/dialog_read_book_style.xml +++ b/app/src/main/res/layout/dialog_read_book_style.xml @@ -261,6 +261,18 @@ android:singleLine="true" android:text="@string/page_anim_slide" /> + + Date: Sun, 1 Sep 2019 19:03:07 +0800 Subject: [PATCH 1211/1997] up --- .../java/io/legado/app/ui/readbook/ReadBookActivity.kt | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 935f17640..ad45d60d2 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -283,12 +283,9 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea || readAloudStatus != Status.PLAY ) { when (direction) { - PageDelegate.Direction.PREV -> { - - } - PageDelegate.Direction.NEXT -> { - - } + PageDelegate.Direction.PREV -> page_view.moveToPrevPage() + PageDelegate.Direction.NEXT -> page_view.moveToNextPage() + else -> return true } return true } From 42592f5d3fe547f04f10f50eecf1c334c02a9f5f Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 1 Sep 2019 19:06:17 +0800 Subject: [PATCH 1212/1997] up --- app/src/main/java/io/legado/app/ui/widget/page/PageView.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 2f27045c9..a2d6e0f81 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -120,12 +120,10 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att PageDelegate.Direction.PREV -> { it.moveToPrevious() } - PageDelegate.Direction.NEXT -> { it.moveToNext() } - else -> { - } + else -> return } } upContent() From 1fea378c617eceec4673d7aeb6f337e1e91ddb63 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 1 Sep 2019 19:13:42 +0800 Subject: [PATCH 1213/1997] up --- app/src/main/java/io/legado/app/ui/widget/page/PageView.kt | 4 ++-- .../delegate/{NoAnmiPageDelegate.kt => NoAnimPageDelegate.kt} | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename app/src/main/java/io/legado/app/ui/widget/page/delegate/{NoAnmiPageDelegate.kt => NoAnimPageDelegate.kt} (85%) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index a2d6e0f81..7aa39bc60 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -8,7 +8,7 @@ import android.view.MotionEvent import android.widget.FrameLayout import io.legado.app.help.ReadBookConfig import io.legado.app.ui.widget.page.delegate.CoverPageDelegate -import io.legado.app.ui.widget.page.delegate.NoAnmiPageDelegate +import io.legado.app.ui.widget.page.delegate.NoAnimPageDelegate import io.legado.app.ui.widget.page.delegate.PageDelegate import io.legado.app.ui.widget.page.delegate.SlidePageDelegate import io.legado.app.utils.getPrefInt @@ -139,7 +139,7 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att fun upPageAnim() { pageDelegate = when (context.getPrefInt("pageAnim")) { 1 -> SlidePageDelegate(this) - 2 -> NoAnmiPageDelegate(this) + 2 -> NoAnimPageDelegate(this) else -> CoverPageDelegate(this) } } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/NoAnmiPageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/NoAnimPageDelegate.kt similarity index 85% rename from app/src/main/java/io/legado/app/ui/widget/page/delegate/NoAnmiPageDelegate.kt rename to app/src/main/java/io/legado/app/ui/widget/page/delegate/NoAnimPageDelegate.kt index 89e3d9c0a..7d19a25ed 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/NoAnmiPageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/NoAnimPageDelegate.kt @@ -3,7 +3,7 @@ package io.legado.app.ui.widget.page.delegate import android.graphics.Canvas import io.legado.app.ui.widget.page.PageView -class NoAnmiPageDelegate(pageView: PageView) : PageDelegate(pageView) { +class NoAnimPageDelegate(pageView: PageView) : PageDelegate(pageView) { override fun onScrollStart() { startScroll(touchX.toInt(), 0, 0, 0) } From 198ea81c9699bf372103e001dce3d408950332ed Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 1 Sep 2019 19:16:38 +0800 Subject: [PATCH 1214/1997] up --- .../main/java/io/legado/app/ui/widget/page/PageView.kt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 7aa39bc60..e05eb8c31 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -156,7 +156,6 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att if (noAnim) { fillPage(PageDelegate.Direction.PREV) } - } fun moveToNextPage(noAnim: Boolean = true) { @@ -228,7 +227,14 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att */ fun moveToPrevChapter(last: Boolean = true) + /** + * 保存页数 + */ fun setPageIndex(pageIndex: Int) + + /** + * 点击屏幕中间 + */ fun clickCenter() } } From dd91e54e384066d2854d38cd3c66ca9f4e5c8446 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 1 Sep 2019 20:58:20 +0800 Subject: [PATCH 1215/1997] up --- .../java/io/legado/app/service/WebService.kt | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/app/src/main/java/io/legado/app/service/WebService.kt b/app/src/main/java/io/legado/app/service/WebService.kt index 99334fd1c..3dcefd09d 100644 --- a/app/src/main/java/io/legado/app/service/WebService.kt +++ b/app/src/main/java/io/legado/app/service/WebService.kt @@ -1,12 +1,44 @@ package io.legado.app.service +import android.content.Context +import android.content.Intent import io.legado.app.base.BaseService +import io.legado.app.constant.Action +import org.jetbrains.anko.startService class WebService : BaseService() { + companion object { + var isRun = false + + fun start(context: Context) { + context.startService() + } + + fun stop(context: Context) { + if (isRun) { + val intent = Intent(context, WebService::class.java) + intent.action = Action.stop + context.startService(intent) + } + } + + } override fun onCreate() { super.onCreate() + isRun = true } + override fun onDestroy() { + super.onDestroy() + isRun = false + } + + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + when (intent?.action) { + Action.stop -> stopSelf() + } + return super.onStartCommand(intent, flags, startId) + } } \ No newline at end of file From 8bdc639246c590a8d8f2770f745ee36852411ef5 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 1 Sep 2019 22:03:17 +0800 Subject: [PATCH 1216/1997] up --- .../main/java/io/legado/app/ui/booksource/BookSourceActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt index eceeb0845..334bc1bcc 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt @@ -121,7 +121,7 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity private fun initDataObserve(searchKey: String = "") { bookSourceLiveDate?.removeObservers(this) val dataFactory = App.db.bookSourceDao().observeSearch("%$searchKey%") - bookSourceLiveDate = LivePagedListBuilder(dataFactory, 2000).build() + bookSourceLiveDate = LivePagedListBuilder(dataFactory, 10000).build() bookSourceLiveDate?.observe(this, Observer { adapter.submitList(it) }) App.db.bookSourceDao().observeGroup().observe(this, Observer { From 0a8fc314b2cbe3cdb9c461874da67bde894d04ea Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 1 Sep 2019 22:22:40 +0800 Subject: [PATCH 1217/1997] up --- .../io/legado/app/data/dao/ReplaceRuleDao.kt | 5 +- .../app/ui/replacerule/ReplaceRuleActivity.kt | 47 +++++++++---------- .../app/ui/replacerule/ReplaceRuleAdapter.kt | 10 ++-- .../ui/replacerule/ReplaceRuleViewModel.kt | 15 ++++++ 4 files changed, 41 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt b/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt index b291ac968..f00be116d 100644 --- a/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt @@ -49,10 +49,7 @@ interface ReplaceRuleDao { fun enableAll(enable: Boolean) @Insert(onConflict = OnConflictStrategy.REPLACE) - fun insert(vararg replaceRules: ReplaceRule): List - - @Insert(onConflict = OnConflictStrategy.REPLACE) - fun insert(replaceRule: ReplaceRule): Long + fun insert(vararg replaceRule: ReplaceRule): List @Update fun update(replaceRules: ReplaceRule) diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt index 0348ef71a..fda735181 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt @@ -23,9 +23,11 @@ import org.jetbrains.anko.doAsync import org.jetbrains.anko.toast -class ReplaceRuleActivity : VMBaseActivity(R.layout.activity_replace_rule) { +class ReplaceRuleActivity : VMBaseActivity(R.layout.activity_replace_rule), + ReplaceRuleAdapter.CallBack { override val viewModel: ReplaceRuleViewModel get() = getViewModel(ReplaceRuleViewModel::class.java) + private lateinit var adapter: ReplaceRuleAdapter private var rulesLiveData: LiveData>? = null private var allEnabled = false @@ -51,31 +53,7 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi private fun initRecyclerView() { ATH.applyEdgeEffectColor(rv_replace_rule) rv_replace_rule.layoutManager = LinearLayoutManager(this) - adapter = ReplaceRuleAdapter(this) - adapter.onClickListener = object : ReplaceRuleAdapter.OnClickListener { - override fun update(rule: ReplaceRule) { - doAsync { - App.db.replaceRuleDao().update(rule) - updateEnableAll() - } - } - - override fun delete(rule: ReplaceRule) { - doAsync { - App.db.replaceRuleDao().delete(rule) - updateEnableAll() - } - } - - override fun edit(rule: ReplaceRule) { - doAsync { - App.db.replaceRuleDao().enableAll(!allEnabled) - allEnabled = !allEnabled - } - - toast("Edit function not implemented!") - } - } + adapter = ReplaceRuleAdapter(this, this) rv_replace_rule.adapter = adapter rv_replace_rule.addItemDecoration( DividerItemDecoration(this, DividerItemDecoration.VERTICAL).apply { @@ -121,4 +99,21 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi }).attachToRecyclerView(rv_replace_rule) } + + override fun update(rule: ReplaceRule) { + viewModel.update(rule) + } + + override fun delete(rule: ReplaceRule) { + viewModel.delete(rule) + } + + override fun edit(rule: ReplaceRule) { + doAsync { + App.db.replaceRuleDao().enableAll(!allEnabled) + allEnabled = !allEnabled + } + + toast("Edit function not implemented!") + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt index 80cc79cce..78587b1a5 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt @@ -14,11 +14,9 @@ import kotlinx.android.synthetic.main.item_relace_rule.view.* import org.jetbrains.anko.sdk27.listeners.onClick -class ReplaceRuleAdapter(context: Context) : +class ReplaceRuleAdapter(context: Context, var callBack: CallBack) : PagedListAdapter(DIFF_CALLBACK) { - var onClickListener: OnClickListener? = null - companion object { @JvmField @@ -45,11 +43,11 @@ class ReplaceRuleAdapter(context: Context) : } override fun onBindViewHolder(holder: MyViewHolder, pos: Int) { - getItem(pos)?.let { holder.bind(it, onClickListener) } + getItem(pos)?.let { holder.bind(it, callBack) } } class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { - fun bind(rule: ReplaceRule, listener: OnClickListener?) = with(itemView) { + fun bind(rule: ReplaceRule, listener: CallBack?) = with(itemView) { tv_name.text = rule.name swt_enabled.isChecked = rule.isEnabled // divider.isGone = hideDivider @@ -64,7 +62,7 @@ class ReplaceRuleAdapter(context: Context) : } } - interface OnClickListener { + interface CallBack { fun update(rule: ReplaceRule) fun delete(rule: ReplaceRule) fun edit(rule: ReplaceRule) diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt index a1f9ca0d6..ac5ce0ca9 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt @@ -1,8 +1,23 @@ package io.legado.app.ui.replacerule import android.app.Application +import io.legado.app.App import io.legado.app.base.BaseViewModel +import io.legado.app.data.entities.ReplaceRule class ReplaceRuleViewModel(application: Application) : BaseViewModel(application) { + + fun update(rule: ReplaceRule) { + execute { + App.db.replaceRuleDao().update(rule) + } + } + + fun delete(rule: ReplaceRule) { + execute { + App.db.replaceRuleDao().delete(rule) + } + } + } From 2e54c2cd0490ef733b35fee3edf9913c681706b1 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 1 Sep 2019 22:36:27 +0800 Subject: [PATCH 1218/1997] up --- .../app/ui/booksource/BookSourceActivity.kt | 5 +-- .../app/ui/booksource/BookSourceAdapter.kt | 45 +++++++++---------- .../app/ui/replacerule/ReplaceRuleActivity.kt | 36 +++------------ .../app/ui/replacerule/ReplaceRuleAdapter.kt | 15 ++++--- 4 files changed, 38 insertions(+), 63 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt index 334bc1bcc..14a947dd3 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt @@ -101,11 +101,10 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity LinearLayoutManager.VERTICAL ) ) - adapter = BookSourceAdapter() - adapter.callBack = this + adapter = BookSourceAdapter(this) recycler_view.adapter = adapter val itemTouchCallback = ItemTouchCallback() - itemTouchCallback.onItemTouchCallbackListener = adapter.itemTouchCallbackListener + itemTouchCallback.onItemTouchCallbackListener = adapter itemTouchCallback.isCanDrag = true ItemTouchHelper(itemTouchCallback).attachToRecyclerView(recycler_view) } diff --git a/app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt b/app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt index f9314073b..0d15be516 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt @@ -14,8 +14,9 @@ import io.legado.app.lib.theme.ThemeStore import kotlinx.android.synthetic.main.item_book_source.view.* import org.jetbrains.anko.sdk27.listeners.onClick -class BookSourceAdapter : - PagedListAdapter(DIFF_CALLBACK) { +class BookSourceAdapter(val callBack: CallBack) : + PagedListAdapter(DIFF_CALLBACK), + OnItemTouchCallbackListener { companion object { @@ -32,27 +33,23 @@ class BookSourceAdapter : } } - var callBack: CallBack? = null + override fun onSwiped(adapterPosition: Int) { - val itemTouchCallbackListener = object : OnItemTouchCallbackListener { - override fun onSwiped(adapterPosition: Int) { - - } + } - override fun onMove(srcPosition: Int, targetPosition: Int): Boolean { - currentList?.let { - val srcSource = it[srcPosition] - val targetSource = it[targetPosition] - srcSource?.let { a -> - targetSource?.let { b -> - a.customOrder = targetPosition - b.customOrder = srcPosition - callBack?.update(a, b) - } + override fun onMove(srcPosition: Int, targetPosition: Int): Boolean { + currentList?.let { + val srcSource = it[srcPosition] + val targetSource = it[targetPosition] + srcSource?.let { a -> + targetSource?.let { b -> + a.customOrder = targetPosition + b.customOrder = srcPosition + callBack.update(a, b) } } - return true } + return true } override fun onCurrentListChanged( @@ -60,7 +57,7 @@ class BookSourceAdapter : currentList: PagedList? ) { super.onCurrentListChanged(previousList, currentList) - callBack?.upCount(itemCount) + callBack.upCount(itemCount) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { @@ -85,7 +82,7 @@ class BookSourceAdapter : itemView.setBackgroundColor(ThemeStore.backgroundColor(itemView.context)) } - fun bind(bookSource: BookSource, callBack: CallBack?) = with(itemView) { + fun bind(bookSource: BookSource, callBack: CallBack) = with(itemView) { if (bookSource.bookSourceGroup.isNullOrEmpty()) { cb_book_source.text = bookSource.bookSourceName } else { @@ -95,11 +92,11 @@ class BookSourceAdapter : cb_book_source.isChecked = bookSource.enabled cb_book_source.setOnClickListener { bookSource.enabled = cb_book_source.isChecked - callBack?.update(bookSource) + callBack.update(bookSource) } - iv_edit_source.onClick { callBack?.edit(bookSource) } - iv_top_source.onClick { callBack?.topSource(bookSource) } - iv_del_source.onClick { callBack?.del(bookSource) } + iv_edit_source.onClick { callBack.edit(bookSource) } + iv_top_source.onClick { callBack.topSource(bookSource) } + iv_del_source.onClick { callBack.del(bookSource) } } } diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt index fda735181..a1854810c 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt @@ -11,16 +11,16 @@ import androidx.paging.PagedList import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView import io.legado.app.App import io.legado.app.R import io.legado.app.base.VMBaseActivity import io.legado.app.data.entities.ReplaceRule +import io.legado.app.help.ItemTouchCallback import io.legado.app.lib.theme.ATH import io.legado.app.utils.getViewModel +import kotlinx.android.synthetic.main.activity_book_source.* import kotlinx.android.synthetic.main.activity_replace_rule.* import org.jetbrains.anko.doAsync -import org.jetbrains.anko.toast class ReplaceRuleActivity : VMBaseActivity(R.layout.activity_replace_rule), @@ -35,7 +35,6 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi override fun onActivityCreated(savedInstanceState: Bundle?) { initRecyclerView() initDataObservers() - initSwipeToDelete() } override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { @@ -61,6 +60,10 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi this.setDrawable(it) } }) + val itemTouchCallback = ItemTouchCallback() + itemTouchCallback.onItemTouchCallbackListener = adapter + itemTouchCallback.isCanDrag = true + ItemTouchHelper(itemTouchCallback).attachToRecyclerView(recycler_view) } @@ -78,28 +81,6 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi } } - private fun initSwipeToDelete() { - ItemTouchHelper(object : ItemTouchHelper.Callback() { - - override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int { - return makeMovementFlags(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) - } - - override fun onMove( - recyclerView: RecyclerView, - viewHolder: RecyclerView.ViewHolder, - target: RecyclerView.ViewHolder - ): Boolean { - return false - } - - override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { - toast("You swiped the item!") - } - }).attachToRecyclerView(rv_replace_rule) - - } - override fun update(rule: ReplaceRule) { viewModel.update(rule) } @@ -109,11 +90,6 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi } override fun edit(rule: ReplaceRule) { - doAsync { - App.db.replaceRuleDao().enableAll(!allEnabled) - allEnabled = !allEnabled - } - toast("Edit function not implemented!") } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt index 78587b1a5..b34f6202f 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt @@ -10,12 +10,14 @@ import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import io.legado.app.R import io.legado.app.data.entities.ReplaceRule +import io.legado.app.help.ItemTouchCallback import kotlinx.android.synthetic.main.item_relace_rule.view.* import org.jetbrains.anko.sdk27.listeners.onClick class ReplaceRuleAdapter(context: Context, var callBack: CallBack) : - PagedListAdapter(DIFF_CALLBACK) { + PagedListAdapter(DIFF_CALLBACK), + ItemTouchCallback.OnItemTouchCallbackListener { companion object { @@ -34,8 +36,12 @@ class ReplaceRuleAdapter(context: Context, var callBack: CallBack) : } } - init { - notifyDataSetChanged() + override fun onMove(srcPosition: Int, targetPosition: Int): Boolean { + return true + } + + override fun onSwiped(adapterPosition: Int) { + } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { @@ -50,11 +56,8 @@ class ReplaceRuleAdapter(context: Context, var callBack: CallBack) : fun bind(rule: ReplaceRule, listener: CallBack?) = with(itemView) { tv_name.text = rule.name swt_enabled.isChecked = rule.isEnabled - // divider.isGone = hideDivider iv_delete.isGone = true iv_edit.isGone = true - // iv_delete.onClick { listener?.delete(rule) } - // iv_edit.onClick { listener?.edit(rule) } swt_enabled.onClick { rule.isEnabled = swt_enabled.isChecked listener?.update(rule) From 9bb61af770279c5d94a37fc82ff730452a93968e Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 1 Sep 2019 22:51:28 +0800 Subject: [PATCH 1219/1997] up --- .../main/java/io/legado/app/data/dao/ReplaceRuleDao.kt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt b/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt index f00be116d..43225b80a 100644 --- a/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt @@ -42,6 +42,15 @@ interface ReplaceRuleDao { ) fun findEnabledByScope(name: String, origin: String): List + @Query("select `group` from replace_rules") + fun observeGroup(): LiveData> + + @Query("select * from replace_rules where `group` like '%' || :group || '%'") + fun getByGroup(group: String): List + + @get:Query("select * from replace_rules where `group` = null or `group` = ''") + val noGroup: List + @get:Query("SELECT COUNT(*) - SUM(isEnabled) FROM replace_rules") val summary: Int From 9aa2735767bf65c3ce282dba8729175acb8917f8 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 1 Sep 2019 22:54:52 +0800 Subject: [PATCH 1220/1997] up --- .../app/ui/replacerule/GroupManageDialog.kt | 143 ++++++++++++++++++ .../ui/replacerule/ReplaceRuleViewModel.kt | 41 +++++ 2 files changed, 184 insertions(+) create mode 100644 app/src/main/java/io/legado/app/ui/replacerule/GroupManageDialog.kt diff --git a/app/src/main/java/io/legado/app/ui/replacerule/GroupManageDialog.kt b/app/src/main/java/io/legado/app/ui/replacerule/GroupManageDialog.kt new file mode 100644 index 000000000..a5a77f95c --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/replacerule/GroupManageDialog.kt @@ -0,0 +1,143 @@ +package io.legado.app.ui.replacerule + +import android.annotation.SuppressLint +import android.content.Context +import android.os.Bundle +import android.util.DisplayMetrics +import android.view.LayoutInflater +import android.view.MenuItem +import android.view.View +import android.view.ViewGroup +import android.widget.EditText +import androidx.appcompat.widget.Toolbar +import androidx.fragment.app.DialogFragment +import androidx.lifecycle.Observer +import androidx.recyclerview.widget.DividerItemDecoration +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import io.legado.app.App +import io.legado.app.R +import io.legado.app.base.adapter.ItemViewHolder +import io.legado.app.base.adapter.SimpleRecyclerAdapter +import io.legado.app.lib.dialogs.alert +import io.legado.app.lib.dialogs.customView +import io.legado.app.lib.dialogs.noButton +import io.legado.app.lib.dialogs.yesButton +import io.legado.app.lib.theme.ATH +import io.legado.app.utils.applyTint +import io.legado.app.utils.getViewModelOfActivity +import io.legado.app.utils.requestInputMethod +import io.legado.app.utils.splitNotBlank +import kotlinx.android.synthetic.main.dialog_edittext.view.* +import kotlinx.android.synthetic.main.dialog_recycler_view.* +import kotlinx.android.synthetic.main.item_book_group.view.tv_group +import kotlinx.android.synthetic.main.item_group_manage.view.* +import org.jetbrains.anko.sdk27.listeners.onClick + +class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { + private lateinit var viewModel: ReplaceRuleViewModel + private lateinit var adapter: GroupAdapter + + override fun onStart() { + super.onStart() + val dm = DisplayMetrics() + activity?.windowManager?.defaultDisplay?.getMetrics(dm) + dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.9).toInt()) + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + viewModel = getViewModelOfActivity(ReplaceRuleViewModel::class.java) + return inflater.inflate(R.layout.dialog_recycler_view, container) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + initData() + } + + private fun initData() { + tool_bar.title = getString(R.string.group_manage) + tool_bar.inflateMenu(R.menu.group_manage) + tool_bar.setOnMenuItemClickListener(this) + adapter = GroupAdapter(requireContext(), this) + recycler_view.layoutManager = LinearLayoutManager(requireContext()) + recycler_view.addItemDecoration( + DividerItemDecoration(requireContext(), RecyclerView.VERTICAL) + ) + recycler_view.adapter = adapter + App.db.bookSourceDao().observeGroup().observe(viewLifecycleOwner, Observer { + val groups = linkedSetOf() + it.map { group -> + groups.addAll(group.splitNotBlank(",", ";")) + } + adapter.setItems(groups.toList()) + }) + } + + override fun onMenuItemClick(item: MenuItem?): Boolean { + when (item?.itemId) { + R.id.menu_add -> addGroup() + } + return true + } + + @SuppressLint("InflateParams") + private fun addGroup() { + alert(title = getString(R.string.add_group)) { + var editText: EditText? = null + customView { + layoutInflater.inflate(R.layout.dialog_edittext, null).apply { + editText = edit_view.apply { + ATH.applyAccentTint(this) + hint = "分组名称" + } + } + } + yesButton { + editText?.text?.toString()?.let { + if (it.isNotBlank()) { + viewModel.addGroup(it) + } + } + } + noButton() + }.show().applyTint().requestInputMethod() + } + + @SuppressLint("InflateParams") + private fun editGroup(group: String) { + alert(title = getString(R.string.group_edit)) { + var editText: EditText? = null + customView { + layoutInflater.inflate(R.layout.dialog_edittext, null).apply { + editText = edit_view.apply { + ATH.applyAccentTint(this) + hint = "分组名称" + setText(group) + } + } + } + yesButton { + viewModel.upGroup(group, editText?.text?.toString()) + } + noButton() + }.show().applyTint().requestInputMethod() + } + + class GroupAdapter(context: Context, val dialog: GroupManageDialog) : + SimpleRecyclerAdapter(context, R.layout.item_group_manage) { + + override fun convert(holder: ItemViewHolder, item: String, payloads: MutableList) { + with(holder.itemView) { + tv_group.text = item + tv_edit.onClick { dialog.editGroup(item) } + tv_del.onClick { dialog.viewModel.delGroup(item) } + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt index ac5ce0ca9..af6648bd5 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt @@ -1,9 +1,11 @@ package io.legado.app.ui.replacerule import android.app.Application +import android.text.TextUtils import io.legado.app.App import io.legado.app.base.BaseViewModel import io.legado.app.data.entities.ReplaceRule +import io.legado.app.utils.splitNotBlank class ReplaceRuleViewModel(application: Application) : BaseViewModel(application) { @@ -20,4 +22,43 @@ class ReplaceRuleViewModel(application: Application) : BaseViewModel(application } } + fun addGroup(group: String) { + execute { + val sources = App.db.replaceRuleDao().noGroup + sources.map { source -> + source.group = group + } + App.db.replaceRuleDao().update(*sources.toTypedArray()) + } + } + + fun upGroup(oldGroup: String, newGroup: String?) { + execute { + val sources = App.db.replaceRuleDao().getByGroup(oldGroup) + sources.map { source -> + source.group?.splitNotBlank(",")?.toHashSet()?.let { + it.remove(oldGroup) + if (!newGroup.isNullOrEmpty()) + it.add(newGroup) + source.group = TextUtils.join(",", it) + } + } + App.db.replaceRuleDao().update(*sources.toTypedArray()) + } + } + + fun delGroup(group: String) { + execute { + execute { + val sources = App.db.replaceRuleDao().getByGroup(group) + sources.map { source -> + source.group?.splitNotBlank(",")?.toHashSet()?.let { + it.remove(group) + source.group = TextUtils.join(",", it) + } + } + App.db.replaceRuleDao().update(*sources.toTypedArray()) + } + } + } } From 9b12555ae8d49f0b373c8cf8a1a65da9837e2151 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 2 Sep 2019 08:25:57 +0800 Subject: [PATCH 1221/1997] up --- .../main/java/io/legado/app/receiver/MediaButtonReceiver.kt | 4 +++- .../main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt index 2e6d33712..54d6ba4e9 100644 --- a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt +++ b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt @@ -48,9 +48,11 @@ class MediaButtonReceiver : BroadcastReceiver() { if (!ActivityHelp.isExist(ReadBookActivity::class.java)) { val intent = Intent(context, ReadBookActivity::class.java) intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + intent.putExtra("readAloud", true) context.startActivity(intent) + } else { + postEvent(Bus.READ_ALOUD_BUTTON, true) } - postEvent(Bus.READ_ALOUD_BUTTON, true) } } diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index ad45d60d2..1d9635ece 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -324,6 +324,10 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea .getTextChapter(content_text_view, bookChapter, content, viewModel.chapterSize) page_view.upContent() curChapterChanged() + if (intent.getBooleanExtra("readAloud", false)) { + intent.removeExtra("readAloud") + readAloud() + } } viewModel.durChapterIndex - 1 -> launch { viewModel.prevTextChapter = ChapterProvider From 215b55784bd983febb81b0b06f99b73204a841c3 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 2 Sep 2019 08:41:37 +0800 Subject: [PATCH 1222/1997] up --- app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt index 54d6ba4e9..b61cbde76 100644 --- a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt +++ b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt @@ -18,7 +18,6 @@ import io.legado.app.utils.postEvent class MediaButtonReceiver : BroadcastReceiver() { companion object { - val TAG = MediaButtonReceiver::class.java.simpleName fun handleIntent(context: Context, intent: Intent): Boolean { val intentAction = intent.action From c22c45fec4156d2357a1aef72fc06d1031800502 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 2 Sep 2019 08:42:59 +0800 Subject: [PATCH 1223/1997] up --- .../java/io/legado/app/receiver/MediaButtonReceiver.kt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt index b61cbde76..da5e22f2b 100644 --- a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt +++ b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt @@ -22,14 +22,19 @@ class MediaButtonReceiver : BroadcastReceiver() { fun handleIntent(context: Context, intent: Intent): Boolean { val intentAction = intent.action if (Intent.ACTION_MEDIA_BUTTON == intentAction) { - val event = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT) ?: return false + val event = + intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT) ?: return false val keycode = event.keyCode val action = event.action var command = false when (keycode) { - KeyEvent.KEYCODE_MEDIA_STOP, KeyEvent.KEYCODE_MEDIA_PAUSE, KeyEvent.KEYCODE_MEDIA_PLAY, KeyEvent.KEYCODE_HEADSETHOOK, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE -> { + KeyEvent.KEYCODE_MEDIA_STOP, + KeyEvent.KEYCODE_MEDIA_PAUSE, + KeyEvent.KEYCODE_MEDIA_PLAY, + KeyEvent.KEYCODE_HEADSETHOOK, + KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE -> { command = true } } From d2c64f98474cca5f0c9ff4da3c8dd84232bb0393 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 2 Sep 2019 08:44:52 +0800 Subject: [PATCH 1224/1997] up --- .../io/legado/app/receiver/MediaButtonReceiver.kt | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt index da5e22f2b..99d838494 100644 --- a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt +++ b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt @@ -28,20 +28,16 @@ class MediaButtonReceiver : BroadcastReceiver() { val keycode = event.keyCode val action = event.action - var command = false when (keycode) { KeyEvent.KEYCODE_MEDIA_STOP, KeyEvent.KEYCODE_MEDIA_PAUSE, KeyEvent.KEYCODE_MEDIA_PLAY, KeyEvent.KEYCODE_HEADSETHOOK, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE -> { - command = true - } - } - if (command) { - if (action == KeyEvent.ACTION_DOWN) { - readAloud(context) - return true + if (action == KeyEvent.ACTION_DOWN) { + readAloud(context) + return true + } } } } From 9a03cbb024446d76a243e8bfbb3cb0a24172d6c0 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 2 Sep 2019 10:00:41 +0800 Subject: [PATCH 1225/1997] up --- .../io/legado/app/ui/config/ThemeConfigFragment.kt | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt index 7d9f4006a..642a57578 100644 --- a/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt @@ -100,11 +100,17 @@ class ThemeConfigFragment : PreferenceFragmentCompat(), SharedPreferences.OnShar .setMessage("是否确认恢复?") .setPositiveButton(R.string.ok) { _, _ -> preferenceManager.sharedPreferences.edit() - .putInt("colorPrimary", getCompatColor(R.color.colorPrimary)) - .putInt("colorAccent", getCompatColor(R.color.colorAccent)) + .putInt("colorPrimary", getCompatColor(R.color.md_light_blue_500)) + .putInt("colorAccent", getCompatColor(R.color.md_pink_800)) .putInt("colorBackground", getCompatColor(R.color.md_grey_100)) - .putInt("colorPrimaryNight", getCompatColor(R.color.colorPrimary)) - .putInt("colorAccentNight", getCompatColor(R.color.colorAccent)) + .putInt( + "colorPrimaryNight", + getCompatColor(R.color.md_blue_grey_600) + ) + .putInt( + "colorAccentNight", + getCompatColor(R.color.md_deep_orange_800) + ) .putInt("colorBackgroundNight", getCompatColor(R.color.md_grey_800)) .apply() App.INSTANCE.applyTheme() From 3f92a05dc3af767da8747835514853363b75f89d Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 2 Sep 2019 10:09:26 +0800 Subject: [PATCH 1226/1997] up --- .../java/io/legado/app/ui/booksource/GroupManageDialog.kt | 1 + app/src/main/java/io/legado/app/utils/MenuExtensions.kt | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt b/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt index ad5643a3a..7ffff5b8f 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt @@ -62,6 +62,7 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { private fun initData() { tool_bar.title = getString(R.string.group_manage) tool_bar.inflateMenu(R.menu.group_manage) + tool_bar.menu.applyTint(requireContext(), false) tool_bar.setOnMenuItemClickListener(this) adapter = GroupAdapter(requireContext(), this) recycler_view.layoutManager = LinearLayoutManager(requireContext()) diff --git a/app/src/main/java/io/legado/app/utils/MenuExtensions.kt b/app/src/main/java/io/legado/app/utils/MenuExtensions.kt index 21eeae968..d4b55caaa 100644 --- a/app/src/main/java/io/legado/app/utils/MenuExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/MenuExtensions.kt @@ -7,10 +7,9 @@ import androidx.appcompat.view.menu.MenuItemImpl import androidx.core.view.forEach import io.legado.app.R import io.legado.app.lib.theme.DrawableUtils -import io.legado.app.lib.theme.getPrimaryTextColor import io.legado.app.lib.theme.primaryTextColor -fun Menu.applyTint(context: Context): Menu = this.let { menu -> +fun Menu.applyTint(context: Context, inPrimary: Boolean = true): Menu = this.let { menu -> if (menu is MenuBuilder) { menu.setOptionalIconsVisible(true) } @@ -21,7 +20,9 @@ fun Menu.applyTint(context: Context): Menu = this.let { menu -> //overflow:展开的item DrawableUtils.setTint( impl.icon, - if (impl.requiresOverflow()) defaultTextColor else primaryTextColor + if (!inPrimary) defaultTextColor + else if (impl.requiresOverflow()) defaultTextColor + else primaryTextColor ) } } From a5838c18123c35c0c23f0a484013663772eac37c Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 2 Sep 2019 10:10:29 +0800 Subject: [PATCH 1227/1997] up --- .../java/io/legado/app/ui/replacerule/GroupManageDialog.kt | 1 + app/src/main/res/xml/pref_config_theme.xml | 7 ------- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/replacerule/GroupManageDialog.kt b/app/src/main/java/io/legado/app/ui/replacerule/GroupManageDialog.kt index a5a77f95c..fc6886bf8 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/GroupManageDialog.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/GroupManageDialog.kt @@ -62,6 +62,7 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { private fun initData() { tool_bar.title = getString(R.string.group_manage) tool_bar.inflateMenu(R.menu.group_manage) + tool_bar.menu.applyTint(requireContext(), false) tool_bar.setOnMenuItemClickListener(this) adapter = GroupAdapter(requireContext(), this) recycler_view.layoutManager = LinearLayoutManager(requireContext()) diff --git a/app/src/main/res/xml/pref_config_theme.xml b/app/src/main/res/xml/pref_config_theme.xml index 35f4f46e4..607359962 100644 --- a/app/src/main/res/xml/pref_config_theme.xml +++ b/app/src/main/res/xml/pref_config_theme.xml @@ -16,13 +16,6 @@ android:title="@string/navigation_bar_color_change" app:iconSpaceReserved="false" /> - - Date: Mon, 2 Sep 2019 10:25:25 +0800 Subject: [PATCH 1228/1997] up --- app/src/main/res/layout/dialog_input.xml | 39 ------------------------ 1 file changed, 39 deletions(-) delete mode 100644 app/src/main/res/layout/dialog_input.xml diff --git a/app/src/main/res/layout/dialog_input.xml b/app/src/main/res/layout/dialog_input.xml deleted file mode 100644 index e867c1792..000000000 --- a/app/src/main/res/layout/dialog_input.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - From 9d5822cff4bf46c466b14811cf8dbbd9db09a643 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 2 Sep 2019 10:42:30 +0800 Subject: [PATCH 1229/1997] up --- .../io/legado/app/ui/main/bookshelf/BookshelfFragment.kt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index 92a405b4c..94b17e6dc 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -1,5 +1,6 @@ package io.legado.app.ui.main.bookshelf +import android.annotation.SuppressLint import android.os.Bundle import android.view.Menu import android.view.MenuItem @@ -130,10 +131,10 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b return false } + @SuppressLint("InflateParams") private fun showGroupInputDialog() { alert(title = "新建分组") { var editText: EditText? = null - customView { layoutInflater.inflate(R.layout.dialog_edittext, null).apply { editText = edit_view.apply { @@ -142,13 +143,10 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b } } } - yesButton { viewModel.saveBookGroup(editText?.text?.toString()) } - noButton() - }.show().applyTint().requestInputMethod() } From 5e1819f788417eed98eaa2b8ebe9ddef1cbca3a1 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 2 Sep 2019 10:47:38 +0800 Subject: [PATCH 1230/1997] up --- app/src/main/res/menu/bookshelf.xml | 12 ++++++------ app/src/main/res/menu/main_bookshelf.xml | 10 +++++----- app/src/main/res/values/strings.xml | 5 +++-- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/app/src/main/res/menu/bookshelf.xml b/app/src/main/res/menu/bookshelf.xml index a3e509913..a913d9925 100644 --- a/app/src/main/res/menu/bookshelf.xml +++ b/app/src/main/res/menu/bookshelf.xml @@ -3,31 +3,31 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> diff --git a/app/src/main/res/menu/main_bookshelf.xml b/app/src/main/res/menu/main_bookshelf.xml index e4bc08efe..6815c9cae 100644 --- a/app/src/main/res/menu/main_bookshelf.xml +++ b/app/src/main/res/menu/main_bookshelf.xml @@ -9,19 +9,19 @@ app:showAsAction="ifRoom" /> @@ -29,11 +29,11 @@ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 574d0e454..b7a9ed8ad 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -44,8 +44,9 @@ 搜索 下载任务 列表视图 - 网格视图 - 列表/网格 + 网格视图三列 + 网格视图四列 + 书架布局 书城 添加本地 书源 From 14f9beec81fbba2409f3a4b13097de55aa399e99 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 2 Sep 2019 10:52:41 +0800 Subject: [PATCH 1231/1997] up --- app/src/main/res/values/arrays.xml | 14 ++++++-------- app/src/main/res/values/strings.xml | 6 +++--- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 01d25293d..399afddd8 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -1,5 +1,11 @@ + + @string/layout_list + @string/layout_grid3 + @string/layout_grid4 + + @string/indent_0 @string/indent_1 @@ -8,14 +14,6 @@ @string/indent_4 - - @string/all_book - @string/pursue_more_book - @string/fattening_book - @string/finish_book - @string/local_book - - .txt .json diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b7a9ed8ad..e1a8371e4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -43,9 +43,9 @@ 书架还空着,先去添加吧! 搜索 下载任务 - 列表视图 - 网格视图三列 - 网格视图四列 + 列表视图 + 网格视图三列 + 网格视图四列 书架布局 书城 添加本地 From 70e6b759adf0c303fc9501db39a0ec58a4ec1935 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 2 Sep 2019 11:52:51 +0800 Subject: [PATCH 1232/1997] up --- .../java/io/legado/app/help/ActivityHelp.kt | 28 ++++++++----------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/ActivityHelp.kt b/app/src/main/java/io/legado/app/help/ActivityHelp.kt index 709bdd305..8c85fe618 100644 --- a/app/src/main/java/io/legado/app/help/ActivityHelp.kt +++ b/app/src/main/java/io/legado/app/help/ActivityHelp.kt @@ -9,10 +9,18 @@ import java.util.* */ object ActivityHelp { - private var activities: MutableList> = arrayListOf() + private val activities: MutableList> = arrayListOf() - fun getActivities(): List> { - return activities + /** + * 判断指定Activity是否存在 + */ + fun isExist(activityClass: Class<*>): Boolean { + for (item in activities) { + if (item.get()?.javaClass == activityClass) { + return true + } + } + return false } /** @@ -74,18 +82,4 @@ object ActivityHelp { } } - /** - * 判断指定Activity是否存在 - */ - fun isExist(activityClass: Class<*>): Boolean { - var result = false - for (item in activities) { - if (item.get()?.javaClass == activityClass) { - result = true - break - } - } - return result - } - } \ No newline at end of file From 1444ee663900e5f29070cc5a67ecbedea08b160c Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 2 Sep 2019 14:51:09 +0800 Subject: [PATCH 1233/1997] up --- app/src/main/java/io/legado/app/help/BookHelp.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/BookHelp.kt b/app/src/main/java/io/legado/app/help/BookHelp.kt index 187064ed8..15e2b5c81 100644 --- a/app/src/main/java/io/legado/app/help/BookHelp.kt +++ b/app/src/main/java/io/legado/app/help/BookHelp.kt @@ -106,8 +106,8 @@ object BookHelp { } var similarity = 0F var newIndex = index - val start = max(index - 10, 0) - val end = min(index + 10, chapters.lastIndex) + val start = max(index - 20, 0) + val end = min(index + 20, chapters.lastIndex) if (start < end) { for (i in start..end) { val s = title.similarity(chapters[i].title) From 59d52551755af759ef8ba092af0765a5a94842c8 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 2 Sep 2019 14:51:51 +0800 Subject: [PATCH 1234/1997] up --- app/src/main/java/io/legado/app/utils/StringExtensions.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/utils/StringExtensions.kt b/app/src/main/java/io/legado/app/utils/StringExtensions.kt index 856a6c2d9..a31dff411 100644 --- a/app/src/main/java/io/legado/app/utils/StringExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/StringExtensions.kt @@ -37,7 +37,9 @@ fun String.startWithIgnoreCase(start: String): Boolean { return if (this.isBlank()) false else startsWith(start, true) } - +/** + * 计算相似度 + */ fun String.similarity(target: String): Float { //计算两个字符串的长度。 val len1 = this.length From 7b4d33e34218447568484198836ce7826cfa8176 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 2 Sep 2019 16:53:30 +0800 Subject: [PATCH 1235/1997] up --- app/src/main/AndroidManifest.xml | 1 + .../app/ui/replacerule/ReplaceEditActivity.kt | 18 ++++++++++++++++++ .../app/ui/replacerule/ReplaceEditViewModel.kt | 9 +++++++++ .../main/res/layout/activity_replace_edit.xml | 7 +++++++ 4 files changed, 35 insertions(+) create mode 100644 app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditActivity.kt create mode 100644 app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditViewModel.kt create mode 100644 app/src/main/res/layout/activity_replace_edit.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index bca5f59fb..a3aa7b7b5 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -61,6 +61,7 @@ + diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditActivity.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditActivity.kt new file mode 100644 index 000000000..3870a752c --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditActivity.kt @@ -0,0 +1,18 @@ +package io.legado.app.ui.replacerule + +import android.os.Bundle +import io.legado.app.R +import io.legado.app.base.VMBaseActivity +import io.legado.app.utils.getViewModel + +class ReplaceEditActivity : + VMBaseActivity(R.layout.activity_replace_edit, false) { + override val viewModel: ReplaceEditViewModel + get() = getViewModel(ReplaceEditViewModel::class.java) + + override fun onActivityCreated(savedInstanceState: Bundle?) { + + } + + +} diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditViewModel.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditViewModel.kt new file mode 100644 index 000000000..5e643727d --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditViewModel.kt @@ -0,0 +1,9 @@ +package io.legado.app.ui.replacerule + +import android.app.Application +import io.legado.app.base.BaseViewModel + +class ReplaceEditViewModel(application: Application) : BaseViewModel(application) { + + +} diff --git a/app/src/main/res/layout/activity_replace_edit.xml b/app/src/main/res/layout/activity_replace_edit.xml new file mode 100644 index 000000000..d829e291c --- /dev/null +++ b/app/src/main/res/layout/activity_replace_edit.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file From 7b722e4bcdc5d9a42aefa4950433f570e81101ec Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 2 Sep 2019 16:58:53 +0800 Subject: [PATCH 1236/1997] up --- app/src/main/java/io/legado/app/web/HttpServer.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/web/HttpServer.kt b/app/src/main/java/io/legado/app/web/HttpServer.kt index 34b196d60..78f1cae11 100644 --- a/app/src/main/java/io/legado/app/web/HttpServer.kt +++ b/app/src/main/java/io/legado/app/web/HttpServer.kt @@ -12,14 +12,14 @@ class HttpServer(port: Int) : NanoHTTPD(port) { private val assetsWeb = AssetsWeb("web") - override fun serve(session: NanoHTTPD.IHTTPSession): NanoHTTPD.Response { + override fun serve(session: IHTTPSession): Response { var returnData: ReturnData? = null var uri = session.uri try { when (session.method.name) { "OPTIONS" -> { - val response = NanoHTTPD.newFixedLengthResponse("") + val response = newFixedLengthResponse("") response.addHeader("Access-Control-Allow-Methods", "POST") response.addHeader("Access-Control-Allow-Headers", "content-type") response.addHeader("Access-Control-Allow-Origin", session.headers["origin"]) @@ -62,12 +62,12 @@ class HttpServer(port: Int) : NanoHTTPD(port) { return assetsWeb.getResponse(uri) } - val response = NanoHTTPD.newFixedLengthResponse(Gson().toJson(returnData)) + val response = newFixedLengthResponse(Gson().toJson(returnData)) response.addHeader("Access-Control-Allow-Methods", "GET, POST") response.addHeader("Access-Control-Allow-Origin", session.headers["origin"]) return response } catch (e: Exception) { - return NanoHTTPD.newFixedLengthResponse(e.message) + return newFixedLengthResponse(e.message) } } From 946c3814a843eafc1b659676d00b411f3f383c48 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 2 Sep 2019 17:01:40 +0800 Subject: [PATCH 1237/1997] up --- app/src/main/java/io/legado/app/web/HttpServer.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/web/HttpServer.kt b/app/src/main/java/io/legado/app/web/HttpServer.kt index 78f1cae11..4f28db10b 100644 --- a/app/src/main/java/io/legado/app/web/HttpServer.kt +++ b/app/src/main/java/io/legado/app/web/HttpServer.kt @@ -56,9 +56,8 @@ class HttpServer(port: Int) : NanoHTTPD(port) { } if (returnData == null) { - if (uri.endsWith("/")) { + if (uri.endsWith("/")) uri += "index.html" - } return assetsWeb.getResponse(uri) } From 32ec555ffe677ea64415d1d4e3a3087932fa55ea Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 2 Sep 2019 17:07:25 +0800 Subject: [PATCH 1238/1997] up --- .../app/ui/bookinfo/edit/BookInfoEditActivity.kt | 2 +- .../app/ui/replacerule/ReplaceEditActivity.kt | 14 ++++++++++++++ .../legado/app/ui/sourceedit/SourceEditActivity.kt | 2 +- app/src/main/res/menu/book_info_edit.xml | 2 +- app/src/main/res/menu/replace_edit.xml | 11 +++++++++++ app/src/main/res/menu/source_edit.xml | 2 +- 6 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 app/src/main/res/menu/replace_edit.xml diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/edit/BookInfoEditActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/edit/BookInfoEditActivity.kt index 5d79d6e1c..6becac683 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/edit/BookInfoEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/edit/BookInfoEditActivity.kt @@ -31,7 +31,7 @@ class BookInfoEditActivity : VMBaseActivity(R.layout.acti override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { - R.id.action_save -> saveData() + R.id.menu_save -> saveData() } return super.onCompatOptionsItemSelected(item) } diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditActivity.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditActivity.kt index 3870a752c..81ed2b297 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditActivity.kt @@ -1,6 +1,8 @@ package io.legado.app.ui.replacerule import android.os.Bundle +import android.view.Menu +import android.view.MenuItem import io.legado.app.R import io.legado.app.base.VMBaseActivity import io.legado.app.utils.getViewModel @@ -14,5 +16,17 @@ class ReplaceEditActivity : } + override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { + menuInflater.inflate(R.menu.replace_edit, menu) + return super.onCompatCreateOptionsMenu(menu) + } + + override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.menu_save -> { + } + } + return super.onCompatOptionsItemSelected(item) + } } diff --git a/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditActivity.kt index 5ad1c0d94..6ae96411f 100644 --- a/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditActivity.kt @@ -67,7 +67,7 @@ class SourceEditActivity : VMBaseActivity(R.layout.activity override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { - R.id.action_save -> { + R.id.menu_save -> { val bookSource = getSource() if (bookSource == null) { toast("书源名称和URL不能为空") diff --git a/app/src/main/res/menu/book_info_edit.xml b/app/src/main/res/menu/book_info_edit.xml index 1c8d3ab8b..652d0076e 100644 --- a/app/src/main/res/menu/book_info_edit.xml +++ b/app/src/main/res/menu/book_info_edit.xml @@ -3,7 +3,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> diff --git a/app/src/main/res/menu/replace_edit.xml b/app/src/main/res/menu/replace_edit.xml new file mode 100644 index 000000000..652d0076e --- /dev/null +++ b/app/src/main/res/menu/replace_edit.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/source_edit.xml b/app/src/main/res/menu/source_edit.xml index ac204a22a..e5cf2d61d 100644 --- a/app/src/main/res/menu/source_edit.xml +++ b/app/src/main/res/menu/source_edit.xml @@ -3,7 +3,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> From 27a2785be40959515b5f1946501f49045b291570 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 2 Sep 2019 17:14:20 +0800 Subject: [PATCH 1239/1997] up --- .../java/io/legado/app/data/entities/ReplaceRule.kt | 6 +++--- app/src/main/java/io/legado/app/help/BookHelp.kt | 13 ++++++++----- .../app/ui/replacerule/ReplaceEditActivity.kt | 1 + 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/ReplaceRule.kt b/app/src/main/java/io/legado/app/data/entities/ReplaceRule.kt index 9235543aa..dcab47e66 100644 --- a/app/src/main/java/io/legado/app/data/entities/ReplaceRule.kt +++ b/app/src/main/java/io/legado/app/data/entities/ReplaceRule.kt @@ -15,10 +15,10 @@ import kotlinx.android.parcel.Parcelize data class ReplaceRule( @PrimaryKey(autoGenerate = true) var id: Int = 0, - var name: String? = null, + var name: String = "", var group: String? = null, - var pattern: String? = null, - var replacement: String? = null, + var pattern: String = "", + var replacement: String = "", var scope: String? = null, var isEnabled: Boolean = true, var isRegex: Boolean = true, diff --git a/app/src/main/java/io/legado/app/help/BookHelp.kt b/app/src/main/java/io/legado/app/help/BookHelp.kt index 15e2b5c81..b3ae92f19 100644 --- a/app/src/main/java/io/legado/app/help/BookHelp.kt +++ b/app/src/main/java/io/legado/app/help/BookHelp.kt @@ -124,8 +124,11 @@ object BookHelp { var bookOrigin: String? = null var replaceRules: List = arrayListOf() - fun disposeContent(name: String, origin: String?, content: String, enableReplace: Boolean) - : String { + fun disposeContent( + name: String, origin: String?, + content: String, + enableReplace: Boolean + ): String { var c = content synchronized(this) { if (enableReplace && (bookName != name || bookOrigin != origin)) { @@ -137,12 +140,12 @@ object BookHelp { } } for (item in replaceRules) { - item.pattern?.let { + item.pattern.let { if (it.isNotEmpty()) { c = if (item.isRegex) { - c.replace(it.toRegex(), item.replacement ?: "") + c.replace(it.toRegex(), item.replacement) } else { - c.replace(it, item.replacement ?: "") + c.replace(it, item.replacement) } } } diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditActivity.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditActivity.kt index 81ed2b297..464fcf9a9 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditActivity.kt @@ -29,4 +29,5 @@ class ReplaceEditActivity : return super.onCompatOptionsItemSelected(item) } + } From 17ca8ad64569a8af369a5a77132923aca1757d8b Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 2 Sep 2019 17:40:00 +0800 Subject: [PATCH 1240/1997] up --- .../java/io/legado/app/data/entities/ReplaceRule.kt | 2 +- .../main/java/io/legado/app/help/storage/Restore.kt | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/ReplaceRule.kt b/app/src/main/java/io/legado/app/data/entities/ReplaceRule.kt index dcab47e66..269325e5d 100644 --- a/app/src/main/java/io/legado/app/data/entities/ReplaceRule.kt +++ b/app/src/main/java/io/legado/app/data/entities/ReplaceRule.kt @@ -14,7 +14,7 @@ import kotlinx.android.parcel.Parcelize ) data class ReplaceRule( @PrimaryKey(autoGenerate = true) - var id: Int = 0, + var id: Long = System.currentTimeMillis(), var name: String = "", var group: String? = null, var pattern: String = "", diff --git a/app/src/main/java/io/legado/app/help/storage/Restore.kt b/app/src/main/java/io/legado/app/help/storage/Restore.kt index 82d256d88..35f5ef0e1 100644 --- a/app/src/main/java/io/legado/app/help/storage/Restore.kt +++ b/app/src/main/java/io/legado/app/help/storage/Restore.kt @@ -175,13 +175,14 @@ object Restore { doAsync { val items: List> = jsonPath.parse(ruleFile.readText()).read("$") val existingRules = App.db.replaceRuleDao().all.map { it.pattern }.toSet() - for (item in items) { + for ((index: Int, item: Map) in items.withIndex()) { val jsonItem = jsonPath.parse(item) val rule = ReplaceRule() - rule.pattern = jsonItem.readString("$.regex") - if (rule.pattern.isNullOrEmpty() || rule.pattern in existingRules) continue - rule.name = jsonItem.readString("$.replaceSummary") - rule.replacement = jsonItem.readString("$.replacement") + rule.id = jsonItem.readLong("$.id") ?: System.currentTimeMillis().plus(index) + rule.pattern = jsonItem.readString("$.regex") ?: "" + if (rule.pattern.isEmpty() || rule.pattern in existingRules) continue + rule.name = jsonItem.readString("$.replaceSummary") ?: "" + rule.replacement = jsonItem.readString("$.replacement") ?: "" rule.isRegex = jsonItem.readBool("$.isRegex") == true rule.scope = jsonItem.readString("$.useTo") rule.isEnabled = jsonItem.readBool("$.enable") == true From 1d61c72515ff9800c45be5ca97aad5b293e0eec2 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 2 Sep 2019 21:05:04 +0800 Subject: [PATCH 1241/1997] up --- app/src/main/AndroidManifest.xml | 1 - .../io/legado/app/data/dao/ReplaceRuleDao.kt | 6 +- .../app/ui/replacerule/ReplaceEditActivity.kt | 33 -------- .../app/ui/replacerule/ReplaceEditDialog.kt | 61 ++++++++++++++ .../ui/replacerule/ReplaceEditViewModel.kt | 26 ++++++ .../app/ui/replacerule/ReplaceRuleActivity.kt | 3 +- .../main/res/layout/activity_replace_edit.xml | 7 -- .../main/res/layout/dialog_replace_edit.xml | 83 +++++++++++++++++++ 8 files changed, 175 insertions(+), 45 deletions(-) delete mode 100644 app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditActivity.kt create mode 100644 app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditDialog.kt delete mode 100644 app/src/main/res/layout/activity_replace_edit.xml create mode 100644 app/src/main/res/layout/dialog_replace_edit.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a3aa7b7b5..bca5f59fb 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -61,7 +61,6 @@ - diff --git a/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt b/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt index 43225b80a..6c0031aa4 100644 --- a/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt @@ -13,7 +13,7 @@ interface ReplaceRuleDao { fun observeAll(): DataSource.Factory @Query("SELECT id FROM replace_rules ORDER BY sortOrder ASC") - fun observeAllIds(): LiveData> + fun observeAllIds(): LiveData> @get:Query("SELECT MAX(sortOrder) FROM replace_rules") val maxOrder: Int @@ -25,10 +25,10 @@ interface ReplaceRuleDao { val allEnabled: List @Query("SELECT * FROM replace_rules WHERE id = :id") - fun findById(id: Int): ReplaceRule? + fun findById(id: Long): ReplaceRule? @Query("SELECT * FROM replace_rules WHERE id in (:ids)") - fun findByIds(vararg ids: Int): List + fun findByIds(vararg ids: Long): List @Query( """SELECT * FROM replace_rules WHERE isEnabled = 1 diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditActivity.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditActivity.kt deleted file mode 100644 index 464fcf9a9..000000000 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditActivity.kt +++ /dev/null @@ -1,33 +0,0 @@ -package io.legado.app.ui.replacerule - -import android.os.Bundle -import android.view.Menu -import android.view.MenuItem -import io.legado.app.R -import io.legado.app.base.VMBaseActivity -import io.legado.app.utils.getViewModel - -class ReplaceEditActivity : - VMBaseActivity(R.layout.activity_replace_edit, false) { - override val viewModel: ReplaceEditViewModel - get() = getViewModel(ReplaceEditViewModel::class.java) - - override fun onActivityCreated(savedInstanceState: Bundle?) { - - } - - override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { - menuInflater.inflate(R.menu.replace_edit, menu) - return super.onCompatCreateOptionsMenu(menu) - } - - override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { - when (item.itemId) { - R.id.menu_save -> { - } - } - return super.onCompatOptionsItemSelected(item) - } - - -} diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditDialog.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditDialog.kt new file mode 100644 index 000000000..b47f0c3a9 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditDialog.kt @@ -0,0 +1,61 @@ +package io.legado.app.ui.replacerule + +import android.os.Bundle +import android.util.DisplayMetrics +import android.view.LayoutInflater +import android.view.MenuItem +import android.view.View +import android.view.ViewGroup +import android.view.ViewGroup.LayoutParams.WRAP_CONTENT +import androidx.appcompat.widget.Toolbar +import androidx.fragment.app.DialogFragment +import androidx.lifecycle.Observer +import io.legado.app.R +import io.legado.app.data.entities.ReplaceRule +import io.legado.app.utils.applyTint +import io.legado.app.utils.getViewModel +import kotlinx.android.synthetic.main.dialog_replace_edit.* + +class ReplaceEditDialog : DialogFragment(), + Toolbar.OnMenuItemClickListener { + private lateinit var viewModel: ReplaceEditViewModel + + override fun onStart() { + super.onStart() + val dm = DisplayMetrics() + activity?.windowManager?.defaultDisplay?.getMetrics(dm) + dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), WRAP_CONTENT) + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + viewModel = getViewModel(ReplaceEditViewModel::class.java) + return inflater.inflate(R.layout.dialog_replace_edit, container) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + tool_bar.inflateMenu(R.menu.replace_edit) + tool_bar.menu.applyTint(requireContext(), false) + tool_bar.setOnMenuItemClickListener(this) + viewModel.replaceRuleData.observe(this, Observer { + upReplaceView(it) + }) + } + + override fun onMenuItemClick(item: MenuItem?): Boolean { + when (item?.itemId) { + R.id.menu_save -> { + } + } + return true + } + + private fun upReplaceView(replaceRule: ReplaceRule) { + + } + +} diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditViewModel.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditViewModel.kt index 5e643727d..aa09b0003 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditViewModel.kt @@ -1,9 +1,35 @@ package io.legado.app.ui.replacerule import android.app.Application +import android.content.Intent +import androidx.lifecycle.MutableLiveData +import io.legado.app.App import io.legado.app.base.BaseViewModel +import io.legado.app.data.entities.ReplaceRule class ReplaceEditViewModel(application: Application) : BaseViewModel(application) { + val replaceRuleData = MutableLiveData() + + fun initData(intent: Intent) { + execute { + replaceRuleData.value ?: let { + val id = intent.getLongExtra("data", -1) + if (id > 0) { + App.db.replaceRuleDao().findById(id)?.let { + replaceRuleData.postValue(it) + } + } + } + } + } + + fun save(replaceRule: ReplaceRule, success: () -> Unit) { + execute { + App.db.replaceRuleDao().insert(replaceRule) + }.onSuccess { + success() + } + } } diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt index a1854810c..41a83d31f 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt @@ -44,7 +44,8 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { - + R.id.menu_add_replace_rule -> + ReplaceEditDialog().show(supportFragmentManager, "replaceNew") } return super.onCompatOptionsItemSelected(item) } diff --git a/app/src/main/res/layout/activity_replace_edit.xml b/app/src/main/res/layout/activity_replace_edit.xml deleted file mode 100644 index d829e291c..000000000 --- a/app/src/main/res/layout/activity_replace_edit.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_replace_edit.xml b/app/src/main/res/layout/dialog_replace_edit.xml new file mode 100644 index 000000000..d68f7dd3e --- /dev/null +++ b/app/src/main/res/layout/dialog_replace_edit.xml @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 58f664f3f47a3d989d758f9cda81fe8b2a3bac7c Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 2 Sep 2019 21:19:46 +0800 Subject: [PATCH 1242/1997] up --- .../app/ui/replacerule/ReplaceEditDialog.kt | 7 +++++- .../main/res/layout/dialog_replace_edit.xml | 24 ++++++++++++++----- app/src/main/res/values/strings.xml | 1 + 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditDialog.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditDialog.kt index b47f0c3a9..1d8843b19 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditDialog.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditDialog.kt @@ -55,7 +55,12 @@ class ReplaceEditDialog : DialogFragment(), } private fun upReplaceView(replaceRule: ReplaceRule) { - + et_name.setText(replaceRule.name) + et_group.setText(replaceRule.group) + et_replace_rule.setText(replaceRule.pattern) + cb_use_regex.isChecked = replaceRule.isRegex + et_replace_to.setText(replaceRule.replacement) + et_scope.setText(replaceRule.scope) } } diff --git a/app/src/main/res/layout/dialog_replace_edit.xml b/app/src/main/res/layout/dialog_replace_edit.xml index d68f7dd3e..4f6a23c6e 100644 --- a/app/src/main/res/layout/dialog_replace_edit.xml +++ b/app/src/main/res/layout/dialog_replace_edit.xml @@ -24,13 +24,25 @@ android:padding="10dp"> + + + + + @@ -42,7 +54,7 @@ android:hint="@string/replace_rule"> @@ -60,19 +72,19 @@ android:hint="@string/replace_to"> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e1a8371e4..076c34dbc 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -495,5 +495,6 @@ 编辑分组 添加分组 新建替换 + 分组 From aa4d7616ed417b8b1d47db24f7a6b17ee279404c Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 2 Sep 2019 22:53:40 +0800 Subject: [PATCH 1243/1997] up --- .../app/ui/bookshelf/BookshelfAdapter.kt | 1 - .../app/ui/main/bookshelf/BookshelfAdapter.kt | 1 - .../app/ui/replacerule/ReplaceEditDialog.kt | 17 ++++ .../ui/replacerule/ReplaceEditViewModel.kt | 6 +- .../app/ui/replacerule/ReplaceRuleActivity.kt | 4 +- .../app/ui/replacerule/ReplaceRuleAdapter.kt | 35 ++++++-- .../main/res/layout/activity_replace_rule.xml | 3 - app/src/main/res/layout/item_relace_rule.xml | 86 ------------------- app/src/main/res/layout/item_replace_rule.xml | 34 ++++++++ 9 files changed, 84 insertions(+), 103 deletions(-) delete mode 100644 app/src/main/res/layout/item_relace_rule.xml create mode 100644 app/src/main/res/layout/item_replace_rule.xml diff --git a/app/src/main/java/io/legado/app/ui/bookshelf/BookshelfAdapter.kt b/app/src/main/java/io/legado/app/ui/bookshelf/BookshelfAdapter.kt index 24822211d..1a8ed67f6 100644 --- a/app/src/main/java/io/legado/app/ui/bookshelf/BookshelfAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/bookshelf/BookshelfAdapter.kt @@ -11,7 +11,6 @@ import io.legado.app.data.entities.Book import io.legado.app.help.ImageLoader import io.legado.app.lib.theme.ATH import kotlinx.android.synthetic.main.item_bookshelf_list.view.* -import kotlinx.android.synthetic.main.item_relace_rule.view.tv_name class BookshelfAdapter : PagedListAdapter(DIFF_CALLBACK) { diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt index f7d9cda78..bfd23569c 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt @@ -14,7 +14,6 @@ import io.legado.app.lib.theme.ThemeStore import io.legado.app.utils.getCompatColor import io.legado.app.utils.invisible import kotlinx.android.synthetic.main.item_bookshelf_list.view.* -import kotlinx.android.synthetic.main.item_relace_rule.view.tv_name import org.jetbrains.anko.sdk27.listeners.onClick import org.jetbrains.anko.sdk27.listeners.onLongClick diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditDialog.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditDialog.kt index 1d8843b19..64a84744f 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditDialog.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditDialog.kt @@ -18,6 +18,20 @@ import kotlinx.android.synthetic.main.dialog_replace_edit.* class ReplaceEditDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { + + companion object { + + fun newInstance(id: Long? = null): ReplaceEditDialog { + val dialog = ReplaceEditDialog() + id?.let { + val bundle = Bundle() + bundle.putLong("data", id) + dialog.arguments = bundle + } + return dialog + } + } + private lateinit var viewModel: ReplaceEditViewModel override fun onStart() { @@ -44,6 +58,9 @@ class ReplaceEditDialog : DialogFragment(), viewModel.replaceRuleData.observe(this, Observer { upReplaceView(it) }) + arguments?.let { + viewModel.initData(it) + } } override fun onMenuItemClick(item: MenuItem?): Boolean { diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditViewModel.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditViewModel.kt index aa09b0003..a13502fa4 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditViewModel.kt @@ -1,7 +1,7 @@ package io.legado.app.ui.replacerule import android.app.Application -import android.content.Intent +import android.os.Bundle import androidx.lifecycle.MutableLiveData import io.legado.app.App import io.legado.app.base.BaseViewModel @@ -11,10 +11,10 @@ class ReplaceEditViewModel(application: Application) : BaseViewModel(application val replaceRuleData = MutableLiveData() - fun initData(intent: Intent) { + fun initData(bundle: Bundle) { execute { replaceRuleData.value ?: let { - val id = intent.getLongExtra("data", -1) + val id = bundle.getLong("data") if (id > 0) { App.db.replaceRuleDao().findById(id)?.let { replaceRuleData.postValue(it) diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt index 41a83d31f..2579cf387 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt @@ -91,6 +91,8 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi } override fun edit(rule: ReplaceRule) { - + ReplaceEditDialog + .newInstance(rule.id) + .show(supportFragmentManager, "editReplace") } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt index b34f6202f..4ab569beb 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt @@ -2,16 +2,17 @@ package io.legado.app.ui.replacerule import android.content.Context import android.view.LayoutInflater +import android.view.Menu import android.view.View import android.view.ViewGroup -import androidx.core.view.isGone +import android.widget.PopupMenu import androidx.paging.PagedListAdapter import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import io.legado.app.R import io.legado.app.data.entities.ReplaceRule import io.legado.app.help.ItemTouchCallback -import kotlinx.android.synthetic.main.item_relace_rule.view.* +import kotlinx.android.synthetic.main.item_replace_rule.view.* import org.jetbrains.anko.sdk27.listeners.onClick @@ -45,7 +46,13 @@ class ReplaceRuleAdapter(context: Context, var callBack: CallBack) : } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { - return MyViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_relace_rule, parent, false)) + return MyViewHolder( + LayoutInflater.from(parent.context).inflate( + R.layout.item_replace_rule, + parent, + false + ) + ) } override fun onBindViewHolder(holder: MyViewHolder, pos: Int) { @@ -53,14 +60,26 @@ class ReplaceRuleAdapter(context: Context, var callBack: CallBack) : } class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { - fun bind(rule: ReplaceRule, listener: CallBack?) = with(itemView) { - tv_name.text = rule.name + + fun bind(rule: ReplaceRule, callBack: CallBack) = with(itemView) { + cb_name.text = rule.name swt_enabled.isChecked = rule.isEnabled - iv_delete.isGone = true - iv_edit.isGone = true swt_enabled.onClick { rule.isEnabled = swt_enabled.isChecked - listener?.update(rule) + callBack.update(rule) + } + iv_menu_more.onClick { + val popupMenu = PopupMenu(context, it) + popupMenu.menu.add(Menu.NONE, R.id.menu_edit, Menu.NONE, R.string.edit) + popupMenu.menu.add(Menu.NONE, R.id.menu_del, Menu.NONE, R.string.delete) + popupMenu.setOnMenuItemClickListener { item -> + when (item.itemId) { + R.id.menu_edit -> callBack.edit(rule) + R.id.menu_del -> callBack.delete(rule) + } + true + } + popupMenu.show() } } } diff --git a/app/src/main/res/layout/activity_replace_rule.xml b/app/src/main/res/layout/activity_replace_rule.xml index b703b0371..24e331018 100644 --- a/app/src/main/res/layout/activity_replace_rule.xml +++ b/app/src/main/res/layout/activity_replace_rule.xml @@ -17,9 +17,6 @@ android:id="@+id/rv_replace_rule" android:layout_width="match_parent" android:layout_height="0dp" - android:paddingStart="16dp" - android:paddingEnd="16dp" - android:layout_marginBottom="8dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@+id/title_bar" diff --git a/app/src/main/res/layout/item_relace_rule.xml b/app/src/main/res/layout/item_relace_rule.xml deleted file mode 100644 index 87d714997..000000000 --- a/app/src/main/res/layout/item_relace_rule.xml +++ /dev/null @@ -1,86 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/item_replace_rule.xml b/app/src/main/res/layout/item_replace_rule.xml new file mode 100644 index 000000000..a2a476dff --- /dev/null +++ b/app/src/main/res/layout/item_replace_rule.xml @@ -0,0 +1,34 @@ + + + + + + + + + From 4cd4baa728980f2abf231f3d9de81df67849c637 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 2 Sep 2019 22:56:54 +0800 Subject: [PATCH 1244/1997] up --- .../io/legado/app/ui/replacerule/ReplaceRuleActivity.kt | 9 ++++----- app/src/main/res/layout/activity_replace_rule.xml | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt index 2579cf387..3242e1e2b 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt @@ -18,7 +18,6 @@ import io.legado.app.data.entities.ReplaceRule import io.legado.app.help.ItemTouchCallback import io.legado.app.lib.theme.ATH import io.legado.app.utils.getViewModel -import kotlinx.android.synthetic.main.activity_book_source.* import kotlinx.android.synthetic.main.activity_replace_rule.* import org.jetbrains.anko.doAsync @@ -51,11 +50,11 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi } private fun initRecyclerView() { - ATH.applyEdgeEffectColor(rv_replace_rule) - rv_replace_rule.layoutManager = LinearLayoutManager(this) + ATH.applyEdgeEffectColor(recycler_view) + recycler_view.layoutManager = LinearLayoutManager(this) adapter = ReplaceRuleAdapter(this, this) - rv_replace_rule.adapter = adapter - rv_replace_rule.addItemDecoration( + recycler_view.adapter = adapter + recycler_view.addItemDecoration( DividerItemDecoration(this, DividerItemDecoration.VERTICAL).apply { ContextCompat.getDrawable(baseContext, R.drawable.ic_divider)?.let { this.setDrawable(it) diff --git a/app/src/main/res/layout/activity_replace_rule.xml b/app/src/main/res/layout/activity_replace_rule.xml index 24e331018..4c3ceff0f 100644 --- a/app/src/main/res/layout/activity_replace_rule.xml +++ b/app/src/main/res/layout/activity_replace_rule.xml @@ -14,7 +14,7 @@ app:title="@string/replace_purify" /> Date: Mon, 2 Sep 2019 22:57:51 +0800 Subject: [PATCH 1245/1997] up --- .../java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt index 4ab569beb..01e14e1a1 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt @@ -12,6 +12,7 @@ import androidx.recyclerview.widget.RecyclerView import io.legado.app.R import io.legado.app.data.entities.ReplaceRule import io.legado.app.help.ItemTouchCallback +import io.legado.app.lib.theme.backgroundColor import kotlinx.android.synthetic.main.item_replace_rule.view.* import org.jetbrains.anko.sdk27.listeners.onClick @@ -62,6 +63,7 @@ class ReplaceRuleAdapter(context: Context, var callBack: CallBack) : class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { fun bind(rule: ReplaceRule, callBack: CallBack) = with(itemView) { + this.setBackgroundColor(context.backgroundColor) cb_name.text = rule.name swt_enabled.isChecked = rule.isEnabled swt_enabled.onClick { From fb69380693c3c1c37834f262c41ca4521bafedcc Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 2 Sep 2019 22:59:31 +0800 Subject: [PATCH 1246/1997] up --- .../java/io/legado/app/ui/booksource/BookSourceAdapter.kt | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt b/app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt index 0d15be516..4faf0de8e 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt @@ -10,7 +10,7 @@ import androidx.recyclerview.widget.RecyclerView import io.legado.app.R import io.legado.app.data.entities.BookSource import io.legado.app.help.ItemTouchCallback.OnItemTouchCallbackListener -import io.legado.app.lib.theme.ThemeStore +import io.legado.app.lib.theme.backgroundColor import kotlinx.android.synthetic.main.item_book_source.view.* import org.jetbrains.anko.sdk27.listeners.onClick @@ -78,11 +78,8 @@ class BookSourceAdapter(val callBack: CallBack) : class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { - init { - itemView.setBackgroundColor(ThemeStore.backgroundColor(itemView.context)) - } - fun bind(bookSource: BookSource, callBack: CallBack) = with(itemView) { + this.setBackgroundColor(context.backgroundColor) if (bookSource.bookSourceGroup.isNullOrEmpty()) { cb_book_source.text = bookSource.bookSourceName } else { From 4c304500d02ceed218d499445cccf8ae11dd47b9 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 3 Sep 2019 09:40:57 +0800 Subject: [PATCH 1247/1997] up --- app/src/main/res/layout/item_replace_rule.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/layout/item_replace_rule.xml b/app/src/main/res/layout/item_replace_rule.xml index a2a476dff..7b14d9375 100644 --- a/app/src/main/res/layout/item_replace_rule.xml +++ b/app/src/main/res/layout/item_replace_rule.xml @@ -3,8 +3,8 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" - android:orientation="horizontal" android:gravity="center" + android:orientation="horizontal" android:padding="8dp"> From b2578d8946bc085c7d6d1ab88b10464a85972b31 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 3 Sep 2019 10:42:00 +0800 Subject: [PATCH 1248/1997] up --- .../app/model/analyzeRule/AnalyzeRule.kt | 52 +++++++++---------- .../app/ui/main/findbook/FindBookFragment.kt | 5 +- app/src/main/res/layout/item_find_book.xml | 41 ++++++++++++--- 3 files changed, 60 insertions(+), 38 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt index 38bda7e0d..94352dfa6 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt @@ -125,14 +125,12 @@ class AnalyzeRule(private var book: BaseBook? = null) { sourceRule.makeUpRule(result) result?.let { if (sourceRule.rule.isNotEmpty()) { - when (sourceRule.mode) { - Mode.Js -> result = evalJS(sourceRule.rule, result) - Mode.Json -> result = - getAnalyzeByJSonPath(it).getStringList(sourceRule.rule) - Mode.XPath -> result = - getAnalyzeByXPath(it).getStringList(sourceRule.rule) - Mode.Default -> result = getAnalyzeByJSoup(it).getStringList(sourceRule.rule) - else -> result = sourceRule.rule + result = when (sourceRule.mode) { + Mode.Js -> evalJS(sourceRule.rule, result) + Mode.Json -> getAnalyzeByJSonPath(it).getStringList(sourceRule.rule) + Mode.XPath -> getAnalyzeByXPath(it).getStringList(sourceRule.rule) + Mode.Default -> getAnalyzeByJSoup(it).getStringList(sourceRule.rule) + else -> sourceRule.rule } } if (sourceRule.replaceRegex.isNotEmpty() && result is List<*>) { @@ -196,16 +194,16 @@ class AnalyzeRule(private var book: BaseBook? = null) { sourceRule.makeUpRule(result) result?.let { if (sourceRule.rule.isNotBlank()) { - when (sourceRule.mode) { - Mode.Js -> result = evalJS(sourceRule.rule, it) - Mode.Json -> result = getAnalyzeByJSonPath(it).getString(sourceRule.rule) - Mode.XPath -> result = getAnalyzeByXPath(it).getString(sourceRule.rule) - Mode.Default -> result = if (isUrl) { + result = when (sourceRule.mode) { + Mode.Js -> evalJS(sourceRule.rule, it) + Mode.Json -> getAnalyzeByJSonPath(it).getString(sourceRule.rule) + Mode.XPath -> getAnalyzeByXPath(it).getString(sourceRule.rule) + Mode.Default -> if (isUrl) { getAnalyzeByJSoup(it).getString0(sourceRule.rule) } else { getAnalyzeByJSoup(it).getString(sourceRule.rule) } - else -> result = sourceRule.rule + else -> sourceRule.rule } } if (sourceRule.replaceRegex.isNotEmpty()) { @@ -236,13 +234,12 @@ class AnalyzeRule(private var book: BaseBook? = null) { for (sourceRule in ruleList) { putRule(sourceRule.putMap) result?.let { - when (sourceRule.mode) { - Mode.Regex -> result = - AnalyzeByRegex.getElement(result.toString(), sourceRule.rule.splitNotBlank("&&")) - Mode.Js -> result = evalJS(sourceRule.rule, it) - Mode.Json -> result = getAnalyzeByJSonPath(it).getObject(sourceRule.rule) - Mode.XPath -> result = getAnalyzeByXPath(it).getElements(sourceRule.rule) - else -> result = getAnalyzeByJSoup(it).getElements(sourceRule.rule) + result = when (sourceRule.mode) { + Mode.Regex -> AnalyzeByRegex.getElement(result.toString(), sourceRule.rule.splitNotBlank("&&")) + Mode.Js -> evalJS(sourceRule.rule, it) + Mode.Json -> getAnalyzeByJSonPath(it).getObject(sourceRule.rule) + Mode.XPath -> getAnalyzeByXPath(it).getElements(sourceRule.rule) + else -> getAnalyzeByJSoup(it).getElements(sourceRule.rule) } if (sourceRule.replaceRegex.isNotEmpty()) { result = replaceRegex(result.toString(), sourceRule) @@ -266,13 +263,12 @@ class AnalyzeRule(private var book: BaseBook? = null) { for (sourceRule in ruleList) { putRule(sourceRule.putMap) result?.let { - when (sourceRule.mode) { - Mode.Regex -> result = - AnalyzeByRegex.getElements(result.toString(), sourceRule.rule.splitNotBlank("&&")) - Mode.Js -> result = evalJS(sourceRule.rule, result) - Mode.Json -> result = getAnalyzeByJSonPath(it).getList(sourceRule.rule) - Mode.XPath -> result = getAnalyzeByXPath(it).getElements(sourceRule.rule) - else -> result = getAnalyzeByJSoup(it).getElements(sourceRule.rule) + result = when (sourceRule.mode) { + Mode.Regex -> AnalyzeByRegex.getElements(result.toString(), sourceRule.rule.splitNotBlank("&&")) + Mode.Js -> evalJS(sourceRule.rule, result) + Mode.Json -> getAnalyzeByJSonPath(it).getList(sourceRule.rule) + Mode.XPath -> getAnalyzeByXPath(it).getElements(sourceRule.rule) + else -> getAnalyzeByJSoup(it).getElements(sourceRule.rule) } if (sourceRule.replaceRegex.isNotEmpty()) { result = replaceRegex(result.toString(), sourceRule) diff --git a/app/src/main/java/io/legado/app/ui/main/findbook/FindBookFragment.kt b/app/src/main/java/io/legado/app/ui/main/findbook/FindBookFragment.kt index c8ef1245d..60e3bef88 100644 --- a/app/src/main/java/io/legado/app/ui/main/findbook/FindBookFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/findbook/FindBookFragment.kt @@ -7,13 +7,12 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.Observer import androidx.paging.LivePagedListBuilder import androidx.paging.PagedList -import com.google.android.flexbox.FlexboxLayoutManager +import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.App import io.legado.app.R import io.legado.app.base.BaseFragment import io.legado.app.data.entities.BookSource import io.legado.app.lib.theme.ATH -import io.legado.app.lib.theme.ThemeStore import kotlinx.android.synthetic.main.fragment_find_book.* import kotlinx.android.synthetic.main.view_title_bar.* @@ -34,7 +33,7 @@ class FindBookFragment : BaseFragment(R.layout.fragment_find_book) { private fun initRecyclerView() { ATH.applyEdgeEffectColor(rv_find) - rv_find.layoutManager = FlexboxLayoutManager(context) + rv_find.layoutManager = LinearLayoutManager(context) adapter = FindBookAdapter() rv_find.adapter = adapter } diff --git a/app/src/main/res/layout/item_find_book.xml b/app/src/main/res/layout/item_find_book.xml index 9ed16650c..021dac0aa 100644 --- a/app/src/main/res/layout/item_find_book.xml +++ b/app/src/main/res/layout/item_find_book.xml @@ -1,10 +1,37 @@ - \ No newline at end of file + android:layout_margin="5dp"> + + + + + + + + + + + + \ No newline at end of file From f9d904eea68bbc589e288116ddb5da8b6acb5a05 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 3 Sep 2019 10:45:53 +0800 Subject: [PATCH 1249/1997] up --- .../java/io/legado/app/model/analyzeRule/AnalyzeByJSonPath.kt | 2 +- .../java/io/legado/app/model/analyzeRule/AnalyzeByXPath.kt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSonPath.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSonPath.kt index 60a3510c2..e6eee96ed 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSonPath.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSonPath.kt @@ -132,7 +132,7 @@ class AnalyzeByJSonPath { } if (results.size > 0) { if ("%" == elementsType) { - for (i in 0 until results[0].size) { + for (i in results[0].indices) { for (temp in results) { if (i < temp.size) { result.add(temp[i]) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByXPath.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByXPath.kt index 42e6bd9f6..4293837c7 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByXPath.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByXPath.kt @@ -63,7 +63,7 @@ class AnalyzeByXPath { } if (results.size > 0) { if ("%" == elementsType) { - for (i in 0 until results[0].size) { + for (i in results[0].indices) { for (temp in results) { if (i < temp.size) { jxNodes.add(temp[i]) @@ -120,7 +120,7 @@ class AnalyzeByXPath { } if (results.size > 0) { if ("%" == elementsType) { - for (i in 0 until results[0].size) { + for (i in results[0].indices) { for (temp in results) { if (i < temp.size) { result.add(temp[i]) From c75156ca2c40725f548bf6df178a5ae866c0866a Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 3 Sep 2019 10:53:29 +0800 Subject: [PATCH 1250/1997] up --- .../legado/app/model/webbook/BookContent.kt | 68 +++++++++---------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookContent.kt b/app/src/main/java/io/legado/app/model/webbook/BookContent.kt index 0f78b9d4a..654e61b02 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookContent.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookContent.kt @@ -18,20 +18,20 @@ object BookContent { @Throws(Exception::class) suspend fun analyzeContent( - coroutineScope: CoroutineScope, - response: Response, - book: Book, - bookChapter: BookChapter, - bookSource: BookSource, - nextChapterUrlF: String? = null + coroutineScope: CoroutineScope, + response: Response, + book: Book, + bookChapter: BookChapter, + bookSource: BookSource, + nextChapterUrlF: String? = null ): String { val baseUrl: String = NetworkUtils.getUrl(response) val body: String? = response.body() body ?: throw Exception( - App.INSTANCE.getString( - R.string.error_get_web_content, - baseUrl - ) + App.INSTANCE.getString( + R.string.error_get_web_content, + baseUrl + ) ) SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取成功:$baseUrl") val content = StringBuilder() @@ -47,21 +47,21 @@ object BookContent { App.db.bookChapterDao().getChapter(book.bookUrl, bookChapter.index + 1)?.url while (nextUrl.isNotEmpty() && !nextUrlList.contains(nextUrl)) { if (!nextChapterUrl.isNullOrEmpty() - && NetworkUtils.getAbsoluteURL(baseUrl, nextUrl) - == NetworkUtils.getAbsoluteURL(baseUrl, nextChapterUrl) + && NetworkUtils.getAbsoluteURL(baseUrl, nextUrl) + == NetworkUtils.getAbsoluteURL(baseUrl, nextChapterUrl) ) break nextUrlList.add(nextUrl) AnalyzeUrl( - ruleUrl = nextUrl, - book = book, - headerMapF = bookSource.getHeaderMap() + ruleUrl = nextUrl, + book = book, + headerMapF = bookSource.getHeaderMap() ).getResponseAsync().await() - .body()?.let { nextBody -> - contentData = analyzeContent(nextBody, contentRule, book, baseUrl) - nextUrl = - if (contentData.nextUrl.isNotEmpty()) contentData.nextUrl[0] else "" - content.append(contentData.content) - } + .body()?.let { nextBody -> + contentData = analyzeContent(nextBody, contentRule, book, baseUrl) + nextUrl = + if (contentData.nextUrl.isNotEmpty()) contentData.nextUrl[0] else "" + content.append(contentData.content) + } } } else if (contentData.nextUrl.size > 1) { val contentDataList = arrayListOf>() @@ -72,15 +72,15 @@ object BookContent { for (item in contentDataList) { withContext(coroutineScope.coroutineContext) { val nextResponse = AnalyzeUrl( - ruleUrl = item.nextUrl, - book = book, - headerMapF = bookSource.getHeaderMap() + ruleUrl = item.nextUrl, + book = book, + headerMapF = bookSource.getHeaderMap() ).getResponseAsync().await() val nextContentData = analyzeContent( - nextResponse.body() ?: "", - contentRule, - book, - item.nextUrl + nextResponse.body() ?: "", + contentRule, + book, + item.nextUrl ) item.content = nextContentData.content } @@ -92,8 +92,8 @@ object BookContent { if (content.isNotEmpty()) { if (!content[0].toString().startsWith(bookChapter.title)) { content - .insert(0, "\n") - .insert(0, bookChapter.title) + .insert(0, "\n") + .insert(0, bookChapter.title) } } return content.toString() @@ -101,10 +101,10 @@ object BookContent { @Throws(Exception::class) private fun analyzeContent( - body: String, - contentRule: ContentRule, - book: Book, - baseUrl: String + body: String, + contentRule: ContentRule, + book: Book, + baseUrl: String ): ContentData> { val nextUrlList = arrayListOf() val analyzeRule = AnalyzeRule(book) From aaad5da0711eb2b1438858f8aa1eb0288cd443c8 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 3 Sep 2019 10:54:08 +0800 Subject: [PATCH 1251/1997] up --- .../java/io/legado/app/model/webbook/BookInfo.kt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt b/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt index 1ad81cf11..533669207 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt @@ -11,17 +11,17 @@ object BookInfo { @Throws(Exception::class) fun analyzeBookInfo( - book: Book, - body: String?, - bookSource: BookSource, - analyzeUrl: AnalyzeUrl + book: Book, + body: String?, + bookSource: BookSource, + analyzeUrl: AnalyzeUrl ) { val baseUrl = analyzeUrl.url body ?: throw Exception( - App.INSTANCE.getString( - R.string.error_get_web_content, - baseUrl - ) + App.INSTANCE.getString( + R.string.error_get_web_content, + baseUrl + ) ) SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取成功:$baseUrl") val infoRule = bookSource.getBookInfoRule() From 10364430f7fc81d721ad62dc2e319f16ec9cdc22 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 3 Sep 2019 10:54:35 +0800 Subject: [PATCH 1252/1997] up --- .../io/legado/app/model/webbook/BookList.kt | 80 ++++++++++--------- 1 file changed, 42 insertions(+), 38 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookList.kt b/app/src/main/java/io/legado/app/model/webbook/BookList.kt index bbdd28766..607677e4d 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookList.kt @@ -14,19 +14,19 @@ object BookList { @Throws(Exception::class) fun analyzeBookList( - response: Response, - bookSource: BookSource, - analyzeUrl: AnalyzeUrl, - isSearch: Boolean = true + response: Response, + bookSource: BookSource, + analyzeUrl: AnalyzeUrl, + isSearch: Boolean = true ): ArrayList { val bookList = ArrayList() val baseUrl: String = NetworkUtils.getUrl(response) val body: String? = response.body() body ?: throw Exception( - App.INSTANCE.getString( - R.string.error_get_web_content, - baseUrl - ) + App.INSTANCE.getString( + R.string.error_get_web_content, + baseUrl + ) ) SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取成功:$baseUrl") val analyzeRule = AnalyzeRule(null) @@ -72,19 +72,19 @@ object BookList { SourceDebug.printLog(bookSource.bookSourceUrl, 1, "列表数为${collections.size}") for ((index, item) in collections.withIndex()) { getSearchItem( - item, - analyzeRule, - bookSource, - baseUrl, - index == 0, - ruleName = ruleName, - ruleBookUrl = ruleBookUrl, - ruleAuthor = ruleAuthor, - ruleCoverUrl = ruleCoverUrl, - ruleIntro = ruleIntro, - ruleKind = ruleKind, - ruleLastChapter = ruleLastChapter, - ruleWordCount = ruleWordCount + item, + analyzeRule, + bookSource, + baseUrl, + index == 0, + ruleName = ruleName, + ruleBookUrl = ruleBookUrl, + ruleAuthor = ruleAuthor, + ruleCoverUrl = ruleCoverUrl, + ruleIntro = ruleIntro, + ruleKind = ruleKind, + ruleLastChapter = ruleLastChapter, + ruleWordCount = ruleWordCount )?.let { searchBook -> if (baseUrl == searchBook.bookUrl) { searchBook.bookInfoHtml = body @@ -125,7 +125,8 @@ object BookList { SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.kind ?: "") SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取简介") searchBook.intro = analyzeRule.getString(intro ?: "") - SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.intro ?: "", isHtml = true) + SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.intro + ?: "", isHtml = true) SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取字数") searchBook.wordCount = analyzeRule.getString(wordCount ?: "") SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.wordCount ?: "") @@ -134,7 +135,8 @@ object BookList { SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.coverUrl ?: "") SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取最新章节") searchBook.latestChapterTitle = analyzeRule.getString(lastChapter ?: "") - SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.latestChapterTitle ?: "") + SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.latestChapterTitle + ?: "") return searchBook } } @@ -142,19 +144,19 @@ object BookList { } private fun getSearchItem( - item: Any, - analyzeRule: AnalyzeRule, - bookSource: BookSource, - baseUrl: String, - printLog: Boolean, - ruleName: List, - ruleBookUrl: List, - ruleAuthor: List, - ruleKind: List, - ruleCoverUrl: List, - ruleWordCount: List, - ruleIntro: List, - ruleLastChapter: List + item: Any, + analyzeRule: AnalyzeRule, + bookSource: BookSource, + baseUrl: String, + printLog: Boolean, + ruleName: List, + ruleBookUrl: List, + ruleAuthor: List, + ruleKind: List, + ruleCoverUrl: List, + ruleWordCount: List, + ruleIntro: List, + ruleLastChapter: List ): SearchBook? { val searchBook = SearchBook() searchBook.origin = bookSource.bookSourceUrl @@ -177,7 +179,8 @@ object BookList { SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.kind ?: "", printLog) SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取简介", printLog) searchBook.intro = analyzeRule.getString(ruleIntro) - SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.intro ?: "", printLog, true) + SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.intro + ?: "", printLog, true) SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取字数", printLog) searchBook.wordCount = analyzeRule.getString(ruleWordCount) SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.wordCount ?: "", printLog) @@ -186,7 +189,8 @@ object BookList { SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.coverUrl ?: "", printLog) SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取最新章节", printLog) searchBook.latestChapterTitle = analyzeRule.getString(ruleLastChapter) - SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.latestChapterTitle ?: "", printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.latestChapterTitle + ?: "", printLog) return searchBook } return null From b51594e418002d1a5f05e0637cb142ce2838aa97 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 3 Sep 2019 10:55:48 +0800 Subject: [PATCH 1253/1997] up --- .../app/model/webbook/BookChapterList.kt | 106 +++++++++--------- 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt b/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt index 63be14066..81b09ef96 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt @@ -17,20 +17,20 @@ import retrofit2.Response object BookChapterList { suspend fun analyzeChapterList( - coroutineScope: CoroutineScope, - book: Book, - response: Response, - bookSource: BookSource, - analyzeUrl: AnalyzeUrl + coroutineScope: CoroutineScope, + book: Book, + response: Response, + bookSource: BookSource, + analyzeUrl: AnalyzeUrl ): List { var chapterList = arrayListOf() val baseUrl: String = NetworkUtils.getUrl(response) val body: String? = response.body() body ?: throw Exception( - App.INSTANCE.getString( - R.string.error_get_web_content, - baseUrl - ) + App.INSTANCE.getString( + R.string.error_get_web_content, + baseUrl + ) ) SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取成功:$baseUrl") val tocRule = bookSource.getTocRule() @@ -45,7 +45,7 @@ object BookChapterList { listRule = listRule.substring(1) } var chapterData = - analyzeChapterList(body, baseUrl, tocRule, listRule, book, bookSource, printLog = true) + analyzeChapterList(body, baseUrl, tocRule, listRule, book, bookSource, printLog = true) chapterData.chapterList?.let { chapterList.addAll(it) } @@ -54,25 +54,25 @@ object BookChapterList { while (nextUrl.isNotEmpty() && !nextUrlList.contains(nextUrl)) { nextUrlList.add(nextUrl) AnalyzeUrl( - ruleUrl = nextUrl, - book = book, - headerMapF = bookSource.getHeaderMap() + ruleUrl = nextUrl, + book = book, + headerMapF = bookSource.getHeaderMap() ).getResponseAsync().await() - .body()?.let { nextBody -> - chapterData = analyzeChapterList( - nextBody, - nextUrl, - tocRule, - listRule, - book, - bookSource - ) - nextUrl = - if (chapterData.nextUrl.isNotEmpty()) chapterData.nextUrl[0] else "" - chapterData.chapterList?.let { - chapterList.addAll(it) + .body()?.let { nextBody -> + chapterData = analyzeChapterList( + nextBody, + nextUrl, + tocRule, + listRule, + book, + bookSource + ) + nextUrl = + if (chapterData.nextUrl.isNotEmpty()) chapterData.nextUrl[0] else "" + chapterData.chapterList?.let { + chapterList.addAll(it) + } } - } } } else if (chapterData.nextUrl.size > 1) { val chapterDataList = arrayListOf>() @@ -83,18 +83,18 @@ object BookChapterList { for (item in chapterDataList) { withContext(coroutineScope.coroutineContext) { val nextResponse = AnalyzeUrl( - ruleUrl = item.nextUrl, - book = book, - headerMapF = bookSource.getHeaderMap() + ruleUrl = item.nextUrl, + book = book, + headerMapF = bookSource.getHeaderMap() ).getResponseAsync().await() val nextChapterData = analyzeChapterList( - nextResponse.body() ?: "", - item.nextUrl, - tocRule, - listRule, - book, - bookSource, - getNextUrl = false + nextResponse.body() ?: "", + item.nextUrl, + tocRule, + listRule, + book, + bookSource, + getNextUrl = false ) item.chapterList = nextChapterData.chapterList } @@ -125,14 +125,14 @@ object BookChapterList { private fun analyzeChapterList( - body: String, - baseUrl: String, - tocRule: TocRule, - listRule: String, - book: Book, - bookSource: BookSource, - getNextUrl: Boolean = true, - printLog: Boolean = false + body: String, + baseUrl: String, + tocRule: TocRule, + listRule: String, + book: Book, + bookSource: BookSource, + getNextUrl: Boolean = true, + printLog: Boolean = false ): ChapterData> { val chapterList = arrayListOf() val nextUrlList = arrayListOf() @@ -148,10 +148,10 @@ object BookChapterList { } } SourceDebug.printLog( - bookSource.bookSourceUrl, - 1, - TextUtils.join(",", nextUrlList), - printLog + bookSource.bookSourceUrl, + 1, + TextUtils.join(",", nextUrlList), + printLog ) } SourceDebug.printLog(bookSource.bookSourceUrl, 1, "解析目录列表", printLog) @@ -173,10 +173,10 @@ object BookChapterList { } } SourceDebug.printLog( - bookSource.bookSourceUrl, - 1, - "${chapterList[0].title}${chapterList[0].url}", - printLog + bookSource.bookSourceUrl, + 1, + "${chapterList[0].title}${chapterList[0].url}", + printLog ) } return ChapterData(chapterList, nextUrlList) From ff8c9983a4f67f42c3a7c060373fff1fb3716671 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 3 Sep 2019 10:59:59 +0800 Subject: [PATCH 1254/1997] up --- .../io/legado/app/model/webbook/BookChapterList.kt | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt b/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt index 81b09ef96..bcd2e8b83 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt @@ -26,12 +26,7 @@ object BookChapterList { var chapterList = arrayListOf() val baseUrl: String = NetworkUtils.getUrl(response) val body: String? = response.body() - body ?: throw Exception( - App.INSTANCE.getString( - R.string.error_get_web_content, - baseUrl - ) - ) + body ?: throw Exception(App.INSTANCE.getString(R.string.error_get_web_content, baseUrl)) SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取成功:$baseUrl") val tocRule = bookSource.getTocRule() val nextUrlList = arrayListOf(baseUrl) @@ -67,8 +62,9 @@ object BookChapterList { book, bookSource ) - nextUrl = - if (chapterData.nextUrl.isNotEmpty()) chapterData.nextUrl[0] else "" + nextUrl = if (chapterData.nextUrl.isNotEmpty()) + chapterData.nextUrl[0] + else "" chapterData.chapterList?.let { chapterList.addAll(it) } From 0270132b161364e08fe647c17d7464db68b5b0ff Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 3 Sep 2019 11:05:01 +0800 Subject: [PATCH 1255/1997] up --- .../java/io/legado/app/model/analyzeRule/AnalyzeRule.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt index 94352dfa6..0469fdc04 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt @@ -61,7 +61,7 @@ class AnalyzeRule(private var book: BaseBook? = null) { private fun getAnalyzeByXPath(): AnalyzeByXPath { if (analyzeByXPath == null || objectChangedXP) { analyzeByXPath = AnalyzeByXPath() - analyzeByXPath!!.parse(content!!) + analyzeByXPath?.parse(content!!) objectChangedXP = false } return analyzeByXPath as AnalyzeByXPath @@ -79,7 +79,7 @@ class AnalyzeRule(private var book: BaseBook? = null) { private fun getAnalyzeByJSoup(): AnalyzeByJSoup { if (analyzeByJSoup == null || objectChangedJS) { analyzeByJSoup = AnalyzeByJSoup() - analyzeByJSoup!!.parse(content!!) + analyzeByJSoup?.parse(content!!) objectChangedJS = false } return analyzeByJSoup as AnalyzeByJSoup @@ -97,7 +97,7 @@ class AnalyzeRule(private var book: BaseBook? = null) { private fun getAnalyzeByJSonPath(): AnalyzeByJSonPath { if (analyzeByJSonPath == null || objectChangedJP) { analyzeByJSonPath = AnalyzeByJSonPath() - analyzeByJSonPath!!.parse(content!!) + analyzeByJSonPath?.parse(content!!) objectChangedJP = false } return analyzeByJSonPath as AnalyzeByJSonPath From dd3201dfc4b152e5c71701dc222dd13404935fd9 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 3 Sep 2019 11:40:01 +0800 Subject: [PATCH 1256/1997] up --- .../app/model/analyzeRule/AnalyzeRule.kt | 46 ++-- .../main/java/io/legado/app/utils/Encoder.kt | 12 + .../java/io/legado/app/utils/StringUtils.kt | 255 ++++++++++++++++++ 3 files changed, 289 insertions(+), 24 deletions(-) create mode 100644 app/src/main/java/io/legado/app/utils/StringUtils.kt diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt index 0469fdc04..19bb80eec 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt @@ -524,38 +524,36 @@ class AnalyzeRule(private var book: BaseBook? = null) { /** * js实现跨域访问,不能删 */ -// fun ajax(urlStr: String): String? { -// try { -// val analyzeUrl = AnalyzeUrl(urlStr) -// val response = BaseModelImpl.getInstance().getResponseO(analyzeUrl) -// .blockingFirst() -// return response.body() -// } catch (e: Exception) { -// return e.localizedMessage -// } -// -// } + suspend fun ajax(urlStr: String): String? { + return try { + val analyzeUrl = AnalyzeUrl(urlStr) + val response = analyzeUrl.getResponseAsync().await() + response.body() + } catch (e: Exception) { + e.localizedMessage + } + } /** * js实现解码,不能删 */ -// fun base64Decoder(base64: String): String { -// return StringUtils.base64Decode(base64) -// } + fun base64Decoder(str: String): String { + return Encoder.base64Decoder(str) + } /** * 章节数转数字 */ -// fun toNumChapter(s: String?): String? { -// if (s == null) { -// return null -// } -// val pattern = Pattern.compile("(第)(.+?)(章)") -// val matcher = pattern.matcher(s) -// return if (matcher.find()) { -// matcher.group(1) + StringUtils.stringToInt(matcher.group(2)) + matcher.group(3) -// } else s -// } + fun toNumChapter(s: String?): String? { + if (s == null) { + return null + } + val pattern = Pattern.compile("(第)(.+?)(章)") + val matcher = pattern.matcher(s) + return if (matcher.find()) { + matcher.group(1) + StringUtils.stringToInt(matcher.group(2)) + matcher.group(3) + } else s + } companion object { private val putPattern = Pattern.compile("@put:(\\{[^}]+?\\})", Pattern.CASE_INSENSITIVE) diff --git a/app/src/main/java/io/legado/app/utils/Encoder.kt b/app/src/main/java/io/legado/app/utils/Encoder.kt index 8f97c4c83..f14785af9 100644 --- a/app/src/main/java/io/legado/app/utils/Encoder.kt +++ b/app/src/main/java/io/legado/app/utils/Encoder.kt @@ -1,5 +1,8 @@ package io.legado.app.utils +import android.util.Base64 +import java.nio.charset.StandardCharsets + object Encoder { fun escape(src: String): String { @@ -20,4 +23,13 @@ object Encoder { } return tmp.toString() } + + fun base64Decoder(str: String): String { + val bytes = Base64.decode(str, Base64.DEFAULT) + return try { + String(bytes, StandardCharsets.UTF_8) + } catch (e: Exception) { + String(bytes) + } + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/utils/StringUtils.kt b/app/src/main/java/io/legado/app/utils/StringUtils.kt new file mode 100644 index 000000000..031e0f705 --- /dev/null +++ b/app/src/main/java/io/legado/app/utils/StringUtils.kt @@ -0,0 +1,255 @@ +package io.legado.app.utils + +import android.annotation.SuppressLint +import android.text.TextUtils +import android.text.TextUtils.isEmpty +import java.text.ParseException +import java.text.SimpleDateFormat +import java.util.* +import java.util.regex.Matcher +import java.util.regex.Pattern + +object StringUtils { + private val TAG = "StringUtils" + private const val HOUR_OF_DAY = 24 + private const val DAY_OF_YESTERDAY = 2 + private const val TIME_UNIT = 60 + private val ChnMap = chnMap + + private val chnMap: HashMap + get() { + val map = HashMap() + var cnStr = "零一二三四五六七八九十" + var c = cnStr.toCharArray() + for (i in 0..10) { + map[c[i]] = i + } + cnStr = "〇壹贰叁肆伍陆柒捌玖拾" + c = cnStr.toCharArray() + for (i in 0..10) { + map[c[i]] = i + } + map['两'] = 2 + map['百'] = 100 + map['佰'] = 100 + map['千'] = 1000 + map['仟'] = 1000 + map['万'] = 10000 + map['亿'] = 100000000 + return map + } + + //将时间转换成日期 + fun dateConvert(time: Long, pattern: String): String { + val date = Date(time) + @SuppressLint("SimpleDateFormat") val format = SimpleDateFormat(pattern) + return format.format(date) + } + + //将日期转换成昨天、今天、明天 + fun dateConvert(source: String, pattern: String): String { + @SuppressLint("SimpleDateFormat") val format = SimpleDateFormat(pattern) + val calendar = Calendar.getInstance() + try { + val date = format.parse(source) + val curTime = calendar.timeInMillis + calendar.time = date + //将MISC 转换成 sec + val difSec = Math.abs((curTime - date.time) / 1000) + val difMin = difSec / 60 + val difHour = difMin / 60 + val difDate = difHour / 60 + val oldHour = calendar.get(Calendar.HOUR) + //如果没有时间 + if (oldHour == 0) { + //比日期:昨天今天和明天 + if (difDate == 0L) { + return "今天" + } else if (difDate < DAY_OF_YESTERDAY) { + return "昨天" + } else { + @SuppressLint("SimpleDateFormat") val convertFormat = SimpleDateFormat("yyyy-MM-dd") + return convertFormat.format(date) + } + } + + return when { + difSec < TIME_UNIT -> difSec.toString() + "秒前" + difMin < TIME_UNIT -> difMin.toString() + "分钟前" + difHour < HOUR_OF_DAY -> difHour.toString() + "小时前" + difDate < DAY_OF_YESTERDAY -> "昨天" + else -> { + @SuppressLint("SimpleDateFormat") val convertFormat = SimpleDateFormat("yyyy-MM-dd") + convertFormat.format(date) + } + } + } catch (e: ParseException) { + e.printStackTrace() + } + + return "" + } + + @SuppressLint("DefaultLocale") + fun toFirstCapital(str: String): String { + return str.substring(0, 1).toUpperCase() + str.substring(1) + } + + /** + * 将文本中的半角字符,转换成全角字符 + */ + fun halfToFull(input: String): String { + val c = input.toCharArray() + for (i in c.indices) { + if (c[i].toInt() == 32) + //半角空格 + { + c[i] = 12288.toChar() + continue + } + //根据实际情况,过滤不需要转换的符号 + //if (c[i] == 46) //半角点号,不转换 + // continue; + + if (c[i].toInt() in 33..126) + //其他符号都转换为全角 + c[i] = (c[i].toInt() + 65248).toChar() + } + return String(c) + } + + //功能:字符串全角转换为半角 + fun fullToHalf(input: String): String { + val c = input.toCharArray() + for (i in c.indices) { + if (c[i].toInt() == 12288) + //全角空格 + { + c[i] = 32.toChar() + continue + } + + if (c[i].toInt() in 65281..65374) + c[i] = (c[i].toInt() - 65248).toChar() + } + return String(c) + } + + fun chineseNumToInt(chNum: String): Int { + var result = 0 + var tmp = 0 + var billion = 0 + val cn = chNum.toCharArray() + + // "一零二五" 形式 + if (cn.size > 1 && chNum.matches("^[〇零一二三四五六七八九壹贰叁肆伍陆柒捌玖]$".toRegex())) { + for (i in cn.indices) { + cn[i] = (48 + ChnMap[cn[i]]!!).toChar() + } + return Integer.parseInt(String(cn)) + } + + // "一千零二十五", "一千二" 形式 + try { + for (i in cn.indices) { + val tmpNum = ChnMap[cn[i]]!! + if (tmpNum == 100000000) { + result += tmp + result *= tmpNum + billion = billion * 100000000 + result + result = 0 + tmp = 0 + } else if (tmpNum == 10000) { + result += tmp + result *= tmpNum + tmp = 0 + } else if (tmpNum >= 10) { + if (tmp == 0) + tmp = 1 + result += tmpNum * tmp + tmp = 0 + } else { + tmp = if (i >= 2 && i == cn.size - 1 && ChnMap[cn[i - 1]]!! > 10) + tmpNum * ChnMap[cn[i - 1]]!! / 10 + else + tmp * 10 + tmpNum + } + } + result += tmp + billion + return result + } catch (e: Exception) { + return -1 + } + + } + + fun stringToInt(str: String?): Int { + if (str != null) { + val num = fullToHalf(str).replace("\\s".toRegex(), "") + return try { + Integer.parseInt(num) + } catch (e: Exception) { + chineseNumToInt(num) + } + + } + return -1 + } + + fun isContainNumber(company: String): Boolean { + val p = Pattern.compile("[0-9]") + val m = p.matcher(company) + return m.find() + } + + fun isNumeric(str: String): Boolean { + val pattern = Pattern.compile("[0-9]*") + val isNum = pattern.matcher(str) + return isNum.matches() + } + + // 移除字符串首尾空字符的高效方法(利用ASCII值判断,包括全角空格) + fun trim(s: String): String { + if (isEmpty(s)) return "" + var start = 0 + val len = s.length + var end = len - 1 + while (start < end && (s[start].toInt() <= 0x20 || s[start] == ' ')) { + ++start + } + while (start < end && (s[end].toInt() <= 0x20 || s[end] == ' ')) { + --end + } + if (end < len) ++end + return if (start > 0 || end < len) s.substring(start, end) else s + } + + fun repeat(str: String, n: Int): String { + val stringBuilder = StringBuilder() + for (i in 0 until n) { + stringBuilder.append(str) + } + return stringBuilder.toString() + } + + fun removeUTFCharacters(data: String?): String? { + if (data == null) return null + val p = Pattern.compile("\\\\u(\\p{XDigit}{4})") + val m = p.matcher(data) + val buf = StringBuffer(data.length) + while (m.find()) { + val ch = Integer.parseInt(m.group(1), 16).toChar().toString() + m.appendReplacement(buf, Matcher.quoteReplacement(ch)) + } + m.appendTail(buf) + return buf.toString() + } + + fun formatHtml(html: String): String { + return if (TextUtils.isEmpty(html)) "" else html.replace("(?i)<(br[\\s/]*|/*p.*?|/*div.*?)>".toRegex(), "\n")// 替换特定标签为换行符 + .replace("<[script>]*.*?>| ".toRegex(), "")// 删除script标签对和空格转义符 + .replace("\\s*\\n+\\s*".toRegex(), "\n  ")// 移除空行,并增加段前缩进2个汉字 + .replace("^[\\n\\s]+".toRegex(), "  ")//移除开头空行,并增加段前缩进2个汉字 + .replace("[\\n\\s]+$".toRegex(), "") //移除尾部空行 + } +} From bf32846a0398f1667e5f3dfd592bba1cecc6241c Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 3 Sep 2019 16:49:56 +0800 Subject: [PATCH 1257/1997] up --- app/src/main/res/layout/item_find_book.xml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/layout/item_find_book.xml b/app/src/main/res/layout/item_find_book.xml index 021dac0aa..0285dc8c5 100644 --- a/app/src/main/res/layout/item_find_book.xml +++ b/app/src/main/res/layout/item_find_book.xml @@ -1,15 +1,17 @@ + android:padding="10dp" + android:orientation="vertical"> @@ -23,6 +25,8 @@ android:id="@+id/iv_status" android:layout_width="24dp" android:layout_height="24dp" + android:src="@drawable/ic_add" + android:tint="@color/tv_text_secondary" tools:ignore="ContentDescription" /> From 3b6add3594bc8773c7735b2867a30aa76cea771b Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 3 Sep 2019 17:36:00 +0800 Subject: [PATCH 1258/1997] up --- .../io/legado/app/data/entities/BookSource.kt | 6 ++++++ .../app/ui/main/bookshelf/BookshelfViewModel.kt | 1 + .../app/ui/main/findbook/FindBookAdapter.kt | 16 ++++++++++++++-- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/BookSource.kt b/app/src/main/java/io/legado/app/data/entities/BookSource.kt index ef652f3e7..8f1d6448c 100644 --- a/app/src/main/java/io/legado/app/data/entities/BookSource.kt +++ b/app/src/main/java/io/legado/app/data/entities/BookSource.kt @@ -111,4 +111,10 @@ data class BookSource( } return contentRuleV!! } + + fun getExploreKind() { + getExploreRule().exploreUrl?.let { + + } + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt index 0accc1813..fae740f80 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt @@ -39,6 +39,7 @@ class BookshelfViewModel(application: Application) : BaseViewModel(application) postEvent(Bus.UP_BOOK, book.bookUrl) WebBook(bookSource).getChapterList(book).onSuccess(IO) { it?.let { + App.db.bookDao().update(book) if (it.size > App.db.bookChapterDao().getChapterCount(book.bookUrl)) { App.db.bookChapterDao().insert(*it.toTypedArray()) } diff --git a/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt b/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt index 41b190618..af0ae836f 100644 --- a/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt @@ -10,10 +10,14 @@ import androidx.recyclerview.widget.RecyclerView import io.legado.app.R import io.legado.app.data.entities.BookSource import io.legado.app.lib.theme.ColorUtils +import io.legado.app.utils.gone +import io.legado.app.utils.invisible import kotlinx.android.synthetic.main.item_find_book.view.* class FindBookAdapter:PagedListAdapter(DIFF_CALLBACK) { + var exIndex = 0 + companion object { var DIFF_CALLBACK = object : DiffUtil.ItemCallback() { override fun areItemsTheSame(oldItem: BookSource, newItem: BookSource): Boolean = @@ -31,16 +35,24 @@ class FindBookAdapter:PagedListAdapter override fun onBindViewHolder(holder: MyViewHolder, position: Int) { currentList?.get(position)?.let { - holder.bind(it) + holder.bind(it, position == exIndex) } } class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { - fun bind(bookSource: BookSource) = with(itemView) { + fun bind(bookSource: BookSource, ex: Boolean) = with(itemView) { val bgShape: GradientDrawable? = tv_name.background as? GradientDrawable bgShape?.setStroke(2, ColorUtils.getRandomColor()) tv_name.text = bookSource.bookSourceName + if (ex) { + gl_child.invisible() + bookSource.getExploreRule().exploreUrl?.let { + + } + } else { + gl_child.gone() + } } } } \ No newline at end of file From 2626205ccd07b57de8901adfa04e89916aafca86 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 3 Sep 2019 17:55:08 +0800 Subject: [PATCH 1259/1997] up --- app/src/main/res/layout/item_find_book.xml | 3 ++- app/src/main/res/values-night/colors.xml | 6 +++--- app/src/main/res/values/colors.xml | 6 +++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/app/src/main/res/layout/item_find_book.xml b/app/src/main/res/layout/item_find_book.xml index 0285dc8c5..0439c293a 100644 --- a/app/src/main/res/layout/item_find_book.xml +++ b/app/src/main/res/layout/item_find_book.xml @@ -3,6 +3,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" + xmlns:app="http://schemas.android.com/apk/res-auto" android:padding="10dp" android:orientation="vertical"> @@ -26,7 +27,7 @@ android:layout_width="24dp" android:layout_height="24dp" android:src="@drawable/ic_add" - android:tint="@color/tv_text_secondary" + app:tint="@color/tv_text_secondary" tools:ignore="ContentDescription" /> diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml index c10a0bfb1..f9c4c4f7c 100644 --- a/app/src/main/res/values-night/colors.xml +++ b/app/src/main/res/values-night/colors.xml @@ -21,9 +21,9 @@ #737373 #565656 - #ffffffff - #e5ffffff - #b3ffffff + #EEEEEE + #D5D5D5 + #B3B3B3 #b7b7b7 diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index d5b3e1f54..8bd010541 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -26,9 +26,9 @@ #737373 #adadad - #de000000 - #b2000000 - #8a000000 + #0E0E0E + #2C2C2C + #8A2C2C2C #dfdfdf #383838 From eb16c0ceaa41fe4853063b6775152f01a0b0c763 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 3 Sep 2019 19:29:36 +0800 Subject: [PATCH 1260/1997] up --- .../java/io/legado/app/ui/widget/BadgeView.kt | 20 +++++++++++------- .../legado/app/ui/widget/KeyboardToolPop.kt | 3 ++- .../java/io/legado/app/ui/widget/TitleBar.kt | 21 ++++++++++++++----- 3 files changed, 30 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/BadgeView.kt b/app/src/main/java/io/legado/app/ui/widget/BadgeView.kt index aad98f5dd..86e7e0629 100644 --- a/app/src/main/java/io/legado/app/ui/widget/BadgeView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/BadgeView.kt @@ -29,12 +29,6 @@ class BadgeView @JvmOverloads constructor( defStyle: Int = android.R.attr.textViewStyle ) : AppCompatTextView(context, attrs, defStyle) { - /** - * @return Returns true if view is hidden on badge value 0 or null; - */ - /** - * @param hideOnNull the hideOnNull to set - */ var isHideOnNull = true set(hideOnNull) { field = hideOnNull @@ -70,7 +64,12 @@ class BadgeView @JvmOverloads constructor( val badgeMargin: IntArray get() { val params = layoutParams as LayoutParams - return intArrayOf(params.leftMargin, params.topMargin, params.rightMargin, params.bottomMargin) + return intArrayOf( + params.leftMargin, + params.topMargin, + params.rightMargin, + params.bottomMargin + ) } init { @@ -154,7 +153,12 @@ class BadgeView @JvmOverloads constructor( setBadgeMargin(dipMargin, dipMargin, dipMargin, dipMargin) } - fun setBadgeMargin(leftDipMargin: Int, topDipMargin: Int, rightDipMargin: Int, bottomDipMargin: Int) { + fun setBadgeMargin( + leftDipMargin: Int, + topDipMargin: Int, + rightDipMargin: Int, + bottomDipMargin: Int + ) { val params = layoutParams as LayoutParams params.leftMargin = dip2Px(leftDipMargin.toFloat()) params.topMargin = dip2Px(topDipMargin.toFloat()) diff --git a/app/src/main/java/io/legado/app/ui/widget/KeyboardToolPop.kt b/app/src/main/java/io/legado/app/ui/widget/KeyboardToolPop.kt index b97e32e97..076fac6b9 100644 --- a/app/src/main/java/io/legado/app/ui/widget/KeyboardToolPop.kt +++ b/app/src/main/java/io/legado/app/ui/widget/KeyboardToolPop.kt @@ -10,7 +10,8 @@ import android.widget.TextView import io.legado.app.R -class KeyboardToolPop(context: Context, onClickListener: OnClickListener?) : PopupWindow(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) { +class KeyboardToolPop(context: Context, onClickListener: OnClickListener?) : + PopupWindow(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) { init { @SuppressLint("InflateParams") diff --git a/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt b/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt index 796e6fcb3..d516601d9 100644 --- a/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt +++ b/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt @@ -60,7 +60,8 @@ class TitleBar(context: Context, attrs: AttributeSet?) : AppBarLayout(context, a displayHomeAsUp = a.getBoolean(R.styleable.TitleBar_displayHomeAsUp, true) val navigationIcon = a.getDrawable(R.styleable.TitleBar_navigationIcon) - val navigationContentDescription = a.getText(R.styleable.TitleBar_navigationContentDescription) + val navigationContentDescription = + a.getText(R.styleable.TitleBar_navigationContentDescription) val titleText = a.getString(R.styleable.TitleBar_title) val subtitleText = a.getString(R.styleable.TitleBar_subtitle) @@ -71,7 +72,10 @@ class TitleBar(context: Context, attrs: AttributeSet?) : AppBarLayout(context, a } if (a.hasValue(R.styleable.TitleBar_titleTextAppearance)) { - this.setTitleTextAppearance(context, a.getResourceId(R.styleable.TitleBar_titleTextAppearance, 0)) + this.setTitleTextAppearance( + context, + a.getResourceId(R.styleable.TitleBar_titleTextAppearance, 0) + ) } if (a.hasValue(R.styleable.TitleBar_titleTextColor)) { @@ -79,7 +83,10 @@ class TitleBar(context: Context, attrs: AttributeSet?) : AppBarLayout(context, a } if (a.hasValue(R.styleable.TitleBar_subtitleTextAppearance)) { - this.setSubtitleTextAppearance(context, a.getResourceId(R.styleable.TitleBar_subtitleTextAppearance, 0)) + this.setSubtitleTextAppearance( + context, + a.getResourceId(R.styleable.TitleBar_subtitleTextAppearance, 0) + ) } if (a.hasValue(R.styleable.TitleBar_subtitleTextColor)) { @@ -177,7 +184,7 @@ class TitleBar(context: Context, attrs: AttributeSet?) : AppBarLayout(context, a } private fun attachToActivity() { - if(attachToActivity) { + if (attachToActivity) { activity?.let { it.setSupportActionBar(toolbar) it.supportActionBar?.setDisplayHomeAsUpEnabled(displayHomeAsUp) @@ -191,7 +198,11 @@ class TitleBar(context: Context, attrs: AttributeSet?) : AppBarLayout(context, a if (navigationIconTint != null) { wrapDrawableTint(toolbar.navigationIcon, navigationIconTint, navigationIconTintMode) } else { - wrapDrawableTint(toolbar.navigationIcon, ColorStateList.valueOf(primaryTextColor), navigationIconTintMode) + wrapDrawableTint( + toolbar.navigationIcon, + ColorStateList.valueOf(primaryTextColor), + navigationIconTintMode + ) } } From 70fe90f20ccf532b9b4216619d7b9163301923dc Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 3 Sep 2019 19:40:08 +0800 Subject: [PATCH 1261/1997] up --- app/src/main/java/io/legado/app/ui/readrss/ReadRssActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/readrss/ReadRssActivity.kt b/app/src/main/java/io/legado/app/ui/readrss/ReadRssActivity.kt index f73e43676..32d14c9ce 100644 --- a/app/src/main/java/io/legado/app/ui/readrss/ReadRssActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readrss/ReadRssActivity.kt @@ -8,7 +8,7 @@ import io.legado.app.base.BaseActivity class ReadRssActivity : BaseActivity(R.layout.activity_read_rss) { override fun onActivityCreated(savedInstanceState: Bundle?) { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } From a15ab83abb83a7fd99edfcd19d7d848598dea086 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 3 Sep 2019 20:02:58 +0800 Subject: [PATCH 1262/1997] up --- app/src/main/java/io/legado/app/data/entities/BookSource.kt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/BookSource.kt b/app/src/main/java/io/legado/app/data/entities/BookSource.kt index 8f1d6448c..27d16566e 100644 --- a/app/src/main/java/io/legado/app/data/entities/BookSource.kt +++ b/app/src/main/java/io/legado/app/data/entities/BookSource.kt @@ -112,9 +112,4 @@ data class BookSource( return contentRuleV!! } - fun getExploreKind() { - getExploreRule().exploreUrl?.let { - - } - } } \ No newline at end of file From 65b1001d1b7eb4f07b5032bb306017e28b34b05b Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 3 Sep 2019 20:06:59 +0800 Subject: [PATCH 1263/1997] up --- .../app/data/entities/rule/ExploreRule.kt | 31 +++--- .../app/model/webbook/BookChapterList.kt | 100 +++++++++--------- .../legado/app/model/webbook/BookContent.kt | 68 ++++++------ .../io/legado/app/model/webbook/BookInfo.kt | 16 +-- .../io/legado/app/model/webbook/BookList.kt | 98 +++++++++-------- 5 files changed, 166 insertions(+), 147 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/rule/ExploreRule.kt b/app/src/main/java/io/legado/app/data/entities/rule/ExploreRule.kt index 12792f7b7..2e4e61a4a 100644 --- a/app/src/main/java/io/legado/app/data/entities/rule/ExploreRule.kt +++ b/app/src/main/java/io/legado/app/data/entities/rule/ExploreRule.kt @@ -1,15 +1,22 @@ package io.legado.app.data.entities.rule data class ExploreRule( - var exploreUrl: String? = null, - override var bookList: String? = null, - override var name: String? = null, - override var author: String? = null, - override var intro: String? = null, - override var kind: String? = null, - override var lastChapter: String? = null, - override var updateTime: String? = null, - override var bookUrl: String? = null, - override var coverUrl: String? = null, - override var wordCount: String? = null -) : BookListRule \ No newline at end of file + var exploreUrl: String? = null, + override var bookList: String? = null, + override var name: String? = null, + override var author: String? = null, + override var intro: String? = null, + override var kind: String? = null, + override var lastChapter: String? = null, + override var updateTime: String? = null, + override var bookUrl: String? = null, + override var coverUrl: String? = null, + override var wordCount: String? = null +) : BookListRule { + + + data class ExploreUrl( + var title: String, + var url: String + ) +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt b/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt index bcd2e8b83..3557ea844 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt @@ -17,11 +17,11 @@ import retrofit2.Response object BookChapterList { suspend fun analyzeChapterList( - coroutineScope: CoroutineScope, - book: Book, - response: Response, - bookSource: BookSource, - analyzeUrl: AnalyzeUrl + coroutineScope: CoroutineScope, + book: Book, + response: Response, + bookSource: BookSource, + analyzeUrl: AnalyzeUrl ): List { var chapterList = arrayListOf() val baseUrl: String = NetworkUtils.getUrl(response) @@ -40,7 +40,7 @@ object BookChapterList { listRule = listRule.substring(1) } var chapterData = - analyzeChapterList(body, baseUrl, tocRule, listRule, book, bookSource, printLog = true) + analyzeChapterList(body, baseUrl, tocRule, listRule, book, bookSource, printLog = true) chapterData.chapterList?.let { chapterList.addAll(it) } @@ -49,26 +49,26 @@ object BookChapterList { while (nextUrl.isNotEmpty() && !nextUrlList.contains(nextUrl)) { nextUrlList.add(nextUrl) AnalyzeUrl( - ruleUrl = nextUrl, - book = book, - headerMapF = bookSource.getHeaderMap() + ruleUrl = nextUrl, + book = book, + headerMapF = bookSource.getHeaderMap() ).getResponseAsync().await() - .body()?.let { nextBody -> - chapterData = analyzeChapterList( - nextBody, - nextUrl, - tocRule, - listRule, - book, - bookSource - ) - nextUrl = if (chapterData.nextUrl.isNotEmpty()) - chapterData.nextUrl[0] - else "" - chapterData.chapterList?.let { - chapterList.addAll(it) - } + .body()?.let { nextBody -> + chapterData = analyzeChapterList( + nextBody, + nextUrl, + tocRule, + listRule, + book, + bookSource + ) + nextUrl = if (chapterData.nextUrl.isNotEmpty()) + chapterData.nextUrl[0] + else "" + chapterData.chapterList?.let { + chapterList.addAll(it) } + } } } else if (chapterData.nextUrl.size > 1) { val chapterDataList = arrayListOf>() @@ -79,18 +79,18 @@ object BookChapterList { for (item in chapterDataList) { withContext(coroutineScope.coroutineContext) { val nextResponse = AnalyzeUrl( - ruleUrl = item.nextUrl, - book = book, - headerMapF = bookSource.getHeaderMap() + ruleUrl = item.nextUrl, + book = book, + headerMapF = bookSource.getHeaderMap() ).getResponseAsync().await() val nextChapterData = analyzeChapterList( - nextResponse.body() ?: "", - item.nextUrl, - tocRule, - listRule, - book, - bookSource, - getNextUrl = false + nextResponse.body() ?: "", + item.nextUrl, + tocRule, + listRule, + book, + bookSource, + getNextUrl = false ) item.chapterList = nextChapterData.chapterList } @@ -121,14 +121,14 @@ object BookChapterList { private fun analyzeChapterList( - body: String, - baseUrl: String, - tocRule: TocRule, - listRule: String, - book: Book, - bookSource: BookSource, - getNextUrl: Boolean = true, - printLog: Boolean = false + body: String, + baseUrl: String, + tocRule: TocRule, + listRule: String, + book: Book, + bookSource: BookSource, + getNextUrl: Boolean = true, + printLog: Boolean = false ): ChapterData> { val chapterList = arrayListOf() val nextUrlList = arrayListOf() @@ -144,10 +144,10 @@ object BookChapterList { } } SourceDebug.printLog( - bookSource.bookSourceUrl, - 1, - TextUtils.join(",", nextUrlList), - printLog + bookSource.bookSourceUrl, + 1, + TextUtils.join(",", nextUrlList), + printLog ) } SourceDebug.printLog(bookSource.bookSourceUrl, 1, "解析目录列表", printLog) @@ -169,10 +169,10 @@ object BookChapterList { } } SourceDebug.printLog( - bookSource.bookSourceUrl, - 1, - "${chapterList[0].title}${chapterList[0].url}", - printLog + bookSource.bookSourceUrl, + 1, + "${chapterList[0].title}${chapterList[0].url}", + printLog ) } return ChapterData(chapterList, nextUrlList) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookContent.kt b/app/src/main/java/io/legado/app/model/webbook/BookContent.kt index 654e61b02..0f78b9d4a 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookContent.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookContent.kt @@ -18,20 +18,20 @@ object BookContent { @Throws(Exception::class) suspend fun analyzeContent( - coroutineScope: CoroutineScope, - response: Response, - book: Book, - bookChapter: BookChapter, - bookSource: BookSource, - nextChapterUrlF: String? = null + coroutineScope: CoroutineScope, + response: Response, + book: Book, + bookChapter: BookChapter, + bookSource: BookSource, + nextChapterUrlF: String? = null ): String { val baseUrl: String = NetworkUtils.getUrl(response) val body: String? = response.body() body ?: throw Exception( - App.INSTANCE.getString( - R.string.error_get_web_content, - baseUrl - ) + App.INSTANCE.getString( + R.string.error_get_web_content, + baseUrl + ) ) SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取成功:$baseUrl") val content = StringBuilder() @@ -47,21 +47,21 @@ object BookContent { App.db.bookChapterDao().getChapter(book.bookUrl, bookChapter.index + 1)?.url while (nextUrl.isNotEmpty() && !nextUrlList.contains(nextUrl)) { if (!nextChapterUrl.isNullOrEmpty() - && NetworkUtils.getAbsoluteURL(baseUrl, nextUrl) - == NetworkUtils.getAbsoluteURL(baseUrl, nextChapterUrl) + && NetworkUtils.getAbsoluteURL(baseUrl, nextUrl) + == NetworkUtils.getAbsoluteURL(baseUrl, nextChapterUrl) ) break nextUrlList.add(nextUrl) AnalyzeUrl( - ruleUrl = nextUrl, - book = book, - headerMapF = bookSource.getHeaderMap() + ruleUrl = nextUrl, + book = book, + headerMapF = bookSource.getHeaderMap() ).getResponseAsync().await() - .body()?.let { nextBody -> - contentData = analyzeContent(nextBody, contentRule, book, baseUrl) - nextUrl = - if (contentData.nextUrl.isNotEmpty()) contentData.nextUrl[0] else "" - content.append(contentData.content) - } + .body()?.let { nextBody -> + contentData = analyzeContent(nextBody, contentRule, book, baseUrl) + nextUrl = + if (contentData.nextUrl.isNotEmpty()) contentData.nextUrl[0] else "" + content.append(contentData.content) + } } } else if (contentData.nextUrl.size > 1) { val contentDataList = arrayListOf>() @@ -72,15 +72,15 @@ object BookContent { for (item in contentDataList) { withContext(coroutineScope.coroutineContext) { val nextResponse = AnalyzeUrl( - ruleUrl = item.nextUrl, - book = book, - headerMapF = bookSource.getHeaderMap() + ruleUrl = item.nextUrl, + book = book, + headerMapF = bookSource.getHeaderMap() ).getResponseAsync().await() val nextContentData = analyzeContent( - nextResponse.body() ?: "", - contentRule, - book, - item.nextUrl + nextResponse.body() ?: "", + contentRule, + book, + item.nextUrl ) item.content = nextContentData.content } @@ -92,8 +92,8 @@ object BookContent { if (content.isNotEmpty()) { if (!content[0].toString().startsWith(bookChapter.title)) { content - .insert(0, "\n") - .insert(0, bookChapter.title) + .insert(0, "\n") + .insert(0, bookChapter.title) } } return content.toString() @@ -101,10 +101,10 @@ object BookContent { @Throws(Exception::class) private fun analyzeContent( - body: String, - contentRule: ContentRule, - book: Book, - baseUrl: String + body: String, + contentRule: ContentRule, + book: Book, + baseUrl: String ): ContentData> { val nextUrlList = arrayListOf() val analyzeRule = AnalyzeRule(book) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt b/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt index 533669207..1ad81cf11 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt @@ -11,17 +11,17 @@ object BookInfo { @Throws(Exception::class) fun analyzeBookInfo( - book: Book, - body: String?, - bookSource: BookSource, - analyzeUrl: AnalyzeUrl + book: Book, + body: String?, + bookSource: BookSource, + analyzeUrl: AnalyzeUrl ) { val baseUrl = analyzeUrl.url body ?: throw Exception( - App.INSTANCE.getString( - R.string.error_get_web_content, - baseUrl - ) + App.INSTANCE.getString( + R.string.error_get_web_content, + baseUrl + ) ) SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取成功:$baseUrl") val infoRule = bookSource.getBookInfoRule() diff --git a/app/src/main/java/io/legado/app/model/webbook/BookList.kt b/app/src/main/java/io/legado/app/model/webbook/BookList.kt index 607677e4d..517ee4ecb 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookList.kt @@ -14,19 +14,19 @@ object BookList { @Throws(Exception::class) fun analyzeBookList( - response: Response, - bookSource: BookSource, - analyzeUrl: AnalyzeUrl, - isSearch: Boolean = true + response: Response, + bookSource: BookSource, + analyzeUrl: AnalyzeUrl, + isSearch: Boolean = true ): ArrayList { val bookList = ArrayList() val baseUrl: String = NetworkUtils.getUrl(response) val body: String? = response.body() body ?: throw Exception( - App.INSTANCE.getString( - R.string.error_get_web_content, - baseUrl - ) + App.INSTANCE.getString( + R.string.error_get_web_content, + baseUrl + ) ) SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取成功:$baseUrl") val analyzeRule = AnalyzeRule(null) @@ -72,19 +72,19 @@ object BookList { SourceDebug.printLog(bookSource.bookSourceUrl, 1, "列表数为${collections.size}") for ((index, item) in collections.withIndex()) { getSearchItem( - item, - analyzeRule, - bookSource, - baseUrl, - index == 0, - ruleName = ruleName, - ruleBookUrl = ruleBookUrl, - ruleAuthor = ruleAuthor, - ruleCoverUrl = ruleCoverUrl, - ruleIntro = ruleIntro, - ruleKind = ruleKind, - ruleLastChapter = ruleLastChapter, - ruleWordCount = ruleWordCount + item, + analyzeRule, + bookSource, + baseUrl, + index == 0, + ruleName = ruleName, + ruleBookUrl = ruleBookUrl, + ruleAuthor = ruleAuthor, + ruleCoverUrl = ruleCoverUrl, + ruleIntro = ruleIntro, + ruleKind = ruleKind, + ruleLastChapter = ruleLastChapter, + ruleWordCount = ruleWordCount )?.let { searchBook -> if (baseUrl == searchBook.bookUrl) { searchBook.bookInfoHtml = body @@ -99,7 +99,11 @@ object BookList { return bookList } - private fun getInfoItem(analyzeRule: AnalyzeRule, bookSource: BookSource, baseUrl: String): SearchBook? { + private fun getInfoItem( + analyzeRule: AnalyzeRule, + bookSource: BookSource, + baseUrl: String + ): SearchBook? { val searchBook = SearchBook() searchBook.bookUrl = baseUrl searchBook.origin = bookSource.bookSourceUrl @@ -125,8 +129,10 @@ object BookList { SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.kind ?: "") SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取简介") searchBook.intro = analyzeRule.getString(intro ?: "") - SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.intro - ?: "", isHtml = true) + SourceDebug.printLog( + bookSource.bookSourceUrl, 1, searchBook.intro + ?: "", isHtml = true + ) SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取字数") searchBook.wordCount = analyzeRule.getString(wordCount ?: "") SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.wordCount ?: "") @@ -135,8 +141,10 @@ object BookList { SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.coverUrl ?: "") SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取最新章节") searchBook.latestChapterTitle = analyzeRule.getString(lastChapter ?: "") - SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.latestChapterTitle - ?: "") + SourceDebug.printLog( + bookSource.bookSourceUrl, 1, searchBook.latestChapterTitle + ?: "" + ) return searchBook } } @@ -144,19 +152,19 @@ object BookList { } private fun getSearchItem( - item: Any, - analyzeRule: AnalyzeRule, - bookSource: BookSource, - baseUrl: String, - printLog: Boolean, - ruleName: List, - ruleBookUrl: List, - ruleAuthor: List, - ruleKind: List, - ruleCoverUrl: List, - ruleWordCount: List, - ruleIntro: List, - ruleLastChapter: List + item: Any, + analyzeRule: AnalyzeRule, + bookSource: BookSource, + baseUrl: String, + printLog: Boolean, + ruleName: List, + ruleBookUrl: List, + ruleAuthor: List, + ruleKind: List, + ruleCoverUrl: List, + ruleWordCount: List, + ruleIntro: List, + ruleLastChapter: List ): SearchBook? { val searchBook = SearchBook() searchBook.origin = bookSource.bookSourceUrl @@ -179,8 +187,10 @@ object BookList { SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.kind ?: "", printLog) SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取简介", printLog) searchBook.intro = analyzeRule.getString(ruleIntro) - SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.intro - ?: "", printLog, true) + SourceDebug.printLog( + bookSource.bookSourceUrl, 1, searchBook.intro + ?: "", printLog, true + ) SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取字数", printLog) searchBook.wordCount = analyzeRule.getString(ruleWordCount) SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.wordCount ?: "", printLog) @@ -189,8 +199,10 @@ object BookList { SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.coverUrl ?: "", printLog) SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取最新章节", printLog) searchBook.latestChapterTitle = analyzeRule.getString(ruleLastChapter) - SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.latestChapterTitle - ?: "", printLog) + SourceDebug.printLog( + bookSource.bookSourceUrl, 1, searchBook.latestChapterTitle + ?: "", printLog + ) return searchBook } return null From 55b8ecf73a15853cc7918d28c41f65e3497dab99 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 3 Sep 2019 22:57:50 +0800 Subject: [PATCH 1264/1997] up --- .../app/data/entities/rule/ExploreRule.kt | 33 ++++++++++++- .../app/ui/main/findbook/FindBookAdapter.kt | 47 +++++++++++-------- 2 files changed, 60 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/rule/ExploreRule.kt b/app/src/main/java/io/legado/app/data/entities/rule/ExploreRule.kt index 2e4e61a4a..921210083 100644 --- a/app/src/main/java/io/legado/app/data/entities/rule/ExploreRule.kt +++ b/app/src/main/java/io/legado/app/data/entities/rule/ExploreRule.kt @@ -1,5 +1,8 @@ package io.legado.app.data.entities.rule +import io.legado.app.constant.AppConst +import javax.script.SimpleBindings + data class ExploreRule( var exploreUrl: String? = null, override var bookList: String? = null, @@ -14,8 +17,36 @@ data class ExploreRule( override var wordCount: String? = null ) : BookListRule { + fun getExploreKinds(baseUrl: String): ArrayList? { + exploreUrl?.let { + var a = it + if (a.isNotBlank()) { + try { + if (it.startsWith("", false)) { + + val bindings = SimpleBindings() + bindings["baseUrl"] = baseUrl + a = AppConst.SCRIPT_ENGINE.eval( + a.substring(4, a.lastIndexOf("<")), + bindings + ).toString() + } + val exploreKinds = arrayListOf() + val b = a.split("(&&|\n)+".toRegex()) + b.map { c -> + val d = c.split("::") + exploreKinds.add(ExploreKind(d[0], d[1])) + } + return exploreKinds + } catch (e: Exception) { + e.printStackTrace() + } + } + } + return null + } - data class ExploreUrl( + data class ExploreKind( var title: String, var url: String ) diff --git a/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt b/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt index af0ae836f..ff89cf48a 100644 --- a/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt @@ -4,6 +4,7 @@ import android.graphics.drawable.GradientDrawable import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.TextView import androidx.paging.PagedListAdapter import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView @@ -13,6 +14,7 @@ import io.legado.app.lib.theme.ColorUtils import io.legado.app.utils.gone import io.legado.app.utils.invisible import kotlinx.android.synthetic.main.item_find_book.view.* +import org.jetbrains.anko.sdk27.listeners.onClick class FindBookAdapter:PagedListAdapter(DIFF_CALLBACK) { @@ -33,26 +35,33 @@ class FindBookAdapter:PagedListAdapter return MyViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_find_book, parent, false)) } - override fun onBindViewHolder(holder: MyViewHolder, position: Int) { - currentList?.get(position)?.let { - holder.bind(it, position == exIndex) - } - } - - class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { - - fun bind(bookSource: BookSource, ex: Boolean) = with(itemView) { - val bgShape: GradientDrawable? = tv_name.background as? GradientDrawable - bgShape?.setStroke(2, ColorUtils.getRandomColor()) - tv_name.text = bookSource.bookSourceName - if (ex) { - gl_child.invisible() - bookSource.getExploreRule().exploreUrl?.let { - + override fun onBindViewHolder(holder: MyViewHolder, position: Int): Unit = + with(holder.itemView) { + currentList?.get(position)?.let { bookSource -> + val bgShape: GradientDrawable? = tv_name.background as? GradientDrawable + bgShape?.setStroke(2, ColorUtils.getRandomColor()) + tv_name.text = bookSource.bookSourceName + ll_title.onClick { + val oldEx = exIndex + exIndex = position + notifyItemChanged(oldEx) + notifyItemChanged(position) + } + if (exIndex == position) { + gl_child.invisible() + bookSource.getExploreRule().getExploreKinds(bookSource.bookSourceUrl)?.let { + it.map { kind -> + val tv = TextView(context) + tv.text = kind.title + tv.onClick { } + gl_child.addView(tv) + } + } + } else { + gl_child.gone() } - } else { - gl_child.gone() - } } } + + class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) } \ No newline at end of file From d824372a2c19a5c98b95e2d0ddc06c39ed606738 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 4 Sep 2019 09:14:13 +0800 Subject: [PATCH 1265/1997] up --- .../app/ui/main/findbook/FindBookAdapter.kt | 36 ++++++++++++++----- app/src/main/res/layout/item_find_book.xml | 2 +- app/src/main/res/layout/item_text.xml | 7 ++++ 3 files changed, 35 insertions(+), 10 deletions(-) create mode 100644 app/src/main/res/layout/item_text.xml diff --git a/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt b/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt index ff89cf48a..c6a217109 100644 --- a/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt @@ -4,7 +4,7 @@ import android.graphics.drawable.GradientDrawable import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.TextView +import android.widget.GridLayout import androidx.paging.PagedListAdapter import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView @@ -12,10 +12,12 @@ import io.legado.app.R import io.legado.app.data.entities.BookSource import io.legado.app.lib.theme.ColorUtils import io.legado.app.utils.gone -import io.legado.app.utils.invisible +import io.legado.app.utils.visible import kotlinx.android.synthetic.main.item_find_book.view.* +import kotlinx.android.synthetic.main.item_text.view.* import org.jetbrains.anko.sdk27.listeners.onClick + class FindBookAdapter:PagedListAdapter(DIFF_CALLBACK) { var exIndex = 0 @@ -43,18 +45,34 @@ class FindBookAdapter:PagedListAdapter tv_name.text = bookSource.bookSourceName ll_title.onClick { val oldEx = exIndex - exIndex = position + if (exIndex == position) { + exIndex = -1 + } else { + exIndex = position + notifyItemChanged(position) + } notifyItemChanged(oldEx) - notifyItemChanged(position) } if (exIndex == position) { - gl_child.invisible() + gl_child.visible() bookSource.getExploreRule().getExploreKinds(bookSource.bookSourceUrl)?.let { + var rowNum = 0 + var columnNum = 0 + gl_child.removeAllViews() it.map { kind -> - val tv = TextView(context) - tv.text = kind.title - tv.onClick { } - gl_child.addView(tv) + val tv = LayoutInflater.from(context) + .inflate(R.layout.item_text, gl_child, false) + tv.text_view.text = kind.title + val rowSpecs = GridLayout.spec(rowNum, 1.0f) + val colSpecs = GridLayout.spec(columnNum, 1.0f) + val params = GridLayout.LayoutParams(rowSpecs, colSpecs) + gl_child.addView(tv, params) + if (columnNum < 2) { + columnNum++ + } else { + columnNum = 0 + rowNum++ + } } } } else { diff --git a/app/src/main/res/layout/item_find_book.xml b/app/src/main/res/layout/item_find_book.xml index 0439c293a..be691c1f6 100644 --- a/app/src/main/res/layout/item_find_book.xml +++ b/app/src/main/res/layout/item_find_book.xml @@ -4,7 +4,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" xmlns:app="http://schemas.android.com/apk/res-auto" - android:padding="10dp" + android:layout_margin="10dp" android:orientation="vertical"> + \ No newline at end of file From fb985a287ce0027a69c7cf50d80096a7d702efd9 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 4 Sep 2019 09:15:55 +0800 Subject: [PATCH 1266/1997] up --- .../java/io/legado/app/ui/main/findbook/FindBookAdapter.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt b/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt index c6a217109..232ee023d 100644 --- a/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt @@ -34,7 +34,10 @@ class FindBookAdapter:PagedListAdapter } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { - return MyViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_find_book, parent, false)) + return MyViewHolder( + LayoutInflater.from(parent.context) + .inflate(R.layout.item_find_book, parent, false) + ) } override fun onBindViewHolder(holder: MyViewHolder, position: Int): Unit = From fafb7d4851951983bbc771d7ea996d4e01cd3118 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 4 Sep 2019 09:50:32 +0800 Subject: [PATCH 1267/1997] up --- app/src/main/res/layout/item_text.xml | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/app/src/main/res/layout/item_text.xml b/app/src/main/res/layout/item_text.xml index 2458ea5a8..8b9aa3eaa 100644 --- a/app/src/main/res/layout/item_text.xml +++ b/app/src/main/res/layout/item_text.xml @@ -1,7 +1,21 @@ - \ No newline at end of file + android:layout_height="wrap_content" + android:padding="3dp"> + + + + From 3a647bf5be4d92e0eaf044aad24f16e3679f9395 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 4 Sep 2019 09:59:38 +0800 Subject: [PATCH 1268/1997] up --- .../java/io/legado/app/ui/main/findbook/FindBookAdapter.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt b/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt index 232ee023d..9dec52302 100644 --- a/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt @@ -76,6 +76,9 @@ class FindBookAdapter:PagedListAdapter columnNum = 0 rowNum++ } + tv.onClick { + + } } } } else { From 60d4d3ade66462c5227678ceee3358be95ede459 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 4 Sep 2019 10:08:01 +0800 Subject: [PATCH 1269/1997] up --- app/src/main/res/layout/item_find_book.xml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/layout/item_find_book.xml b/app/src/main/res/layout/item_find_book.xml index be691c1f6..654ba6c31 100644 --- a/app/src/main/res/layout/item_find_book.xml +++ b/app/src/main/res/layout/item_find_book.xml @@ -1,19 +1,26 @@ From e97951b9e1b4d835397261756d4594ee154b88b0 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 4 Sep 2019 10:41:54 +0800 Subject: [PATCH 1270/1997] up --- .../app/data/entities/rule/ExploreRule.kt | 1 - .../java/io/legado/app/help/JsExtensions.java | 50 +++++++++++++++++++ .../app/model/analyzeRule/AnalyzeRule.kt | 38 ++------------ 3 files changed, 53 insertions(+), 36 deletions(-) create mode 100644 app/src/main/java/io/legado/app/help/JsExtensions.java diff --git a/app/src/main/java/io/legado/app/data/entities/rule/ExploreRule.kt b/app/src/main/java/io/legado/app/data/entities/rule/ExploreRule.kt index 921210083..7337e0245 100644 --- a/app/src/main/java/io/legado/app/data/entities/rule/ExploreRule.kt +++ b/app/src/main/java/io/legado/app/data/entities/rule/ExploreRule.kt @@ -23,7 +23,6 @@ data class ExploreRule( if (a.isNotBlank()) { try { if (it.startsWith("", false)) { - val bindings = SimpleBindings() bindings["baseUrl"] = baseUrl a = AppConst.SCRIPT_ENGINE.eval( diff --git a/app/src/main/java/io/legado/app/help/JsExtensions.java b/app/src/main/java/io/legado/app/help/JsExtensions.java new file mode 100644 index 000000000..93dc3ba92 --- /dev/null +++ b/app/src/main/java/io/legado/app/help/JsExtensions.java @@ -0,0 +1,50 @@ +package io.legado.app.help; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import io.legado.app.model.analyzeRule.AnalyzeUrl; +import io.legado.app.utils.Encoder; +import io.legado.app.utils.StringUtils; + +public class JsExtensions { + + + /** + * js实现跨域访问,不能删 + */ + public String ajax(String urlStr) { + try { + AnalyzeUrl analyzeUrl = new AnalyzeUrl(urlStr, null, null, null, null, null); +/* Response response = analyzeUrl.getResponseAsync().await(); + return response.body().toString();*/ + } catch (Exception e) { + return e.getLocalizedMessage(); + } + return null; + } + + /** + * js实现解码,不能删 + */ + public String base64Decoder(String str) { + return Encoder.INSTANCE.base64Decoder(str); + } + + /** + * 章节数转数字 + */ + public String toNumChapter(String s) { + if (s == null) { + return null; + } + Pattern pattern = Pattern.compile("(第)(.+?)(章)"); + Matcher matcher = pattern.matcher(s); + if (matcher.find()) { + return matcher.group(1) + StringUtils.INSTANCE.stringToInt(matcher.group(2)) + matcher.group(3); + } else { + return s; + } + } + +} diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt index 19bb80eec..c3a5a36fd 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt @@ -5,6 +5,7 @@ import androidx.annotation.Keep import io.legado.app.constant.AppConst.SCRIPT_ENGINE import io.legado.app.constant.Pattern.JS_PATTERN import io.legado.app.data.entities.BaseBook +import io.legado.app.help.JsExtensions import io.legado.app.utils.* import java.util.* import java.util.regex.Pattern @@ -515,46 +516,13 @@ class AnalyzeRule(private var book: BaseBook? = null) { @Throws(Exception::class) private fun evalJS(jsStr: String, result: Any?): Any { val bindings = SimpleBindings() - bindings["java"] = this + bindings["book"] = this + bindings["java"] = JsExtensions() bindings["result"] = result bindings["baseUrl"] = baseUrl return SCRIPT_ENGINE.eval(jsStr, bindings) } - /** - * js实现跨域访问,不能删 - */ - suspend fun ajax(urlStr: String): String? { - return try { - val analyzeUrl = AnalyzeUrl(urlStr) - val response = analyzeUrl.getResponseAsync().await() - response.body() - } catch (e: Exception) { - e.localizedMessage - } - } - - /** - * js实现解码,不能删 - */ - fun base64Decoder(str: String): String { - return Encoder.base64Decoder(str) - } - - /** - * 章节数转数字 - */ - fun toNumChapter(s: String?): String? { - if (s == null) { - return null - } - val pattern = Pattern.compile("(第)(.+?)(章)") - val matcher = pattern.matcher(s) - return if (matcher.find()) { - matcher.group(1) + StringUtils.stringToInt(matcher.group(2)) + matcher.group(3) - } else s - } - companion object { private val putPattern = Pattern.compile("@put:(\\{[^}]+?\\})", Pattern.CASE_INSENSITIVE) private val getPattern = Pattern.compile("@get:\\{([^}]+?)\\}", Pattern.CASE_INSENSITIVE) From d779f11fcc07431eec40a769bedb00f5036582d6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 4 Sep 2019 10:43:27 +0800 Subject: [PATCH 1271/1997] up --- .../main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt index c3a5a36fd..1d1509058 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt @@ -516,7 +516,7 @@ class AnalyzeRule(private var book: BaseBook? = null) { @Throws(Exception::class) private fun evalJS(jsStr: String, result: Any?): Any { val bindings = SimpleBindings() - bindings["book"] = this + bindings["book"] = book bindings["java"] = JsExtensions() bindings["result"] = result bindings["baseUrl"] = baseUrl From 6629ee821b6fb8fa91b723b3a998f595b60c9a8f Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 4 Sep 2019 11:09:33 +0800 Subject: [PATCH 1272/1997] up --- .../io/legado/app/data/api/IHttpGetApi.kt | 13 ++++++++++ .../io/legado/app/data/api/IHttpPostApi.kt | 14 ++++++++++ .../java/io/legado/app/help/JsExtensions.java | 9 +++++-- .../app/model/analyzeRule/AnalyzeUrl.kt | 26 +++++++++++++++++++ 4 files changed, 60 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/api/IHttpGetApi.kt b/app/src/main/java/io/legado/app/data/api/IHttpGetApi.kt index 774cf6c89..a5b0e60c6 100644 --- a/app/src/main/java/io/legado/app/data/api/IHttpGetApi.kt +++ b/app/src/main/java/io/legado/app/data/api/IHttpGetApi.kt @@ -1,6 +1,7 @@ package io.legado.app.data.api import kotlinx.coroutines.Deferred +import retrofit2.Call import retrofit2.Response import retrofit2.http.GET import retrofit2.http.HeaderMap @@ -26,4 +27,16 @@ interface IHttpGetApi { @HeaderMap headers: Map ): Deferred> + @GET + fun get( + @Url url: String, + @HeaderMap headers: Map + ): Call> + + @GET + fun getMap( + @Url url: String, + @QueryMap(encoded = true) queryMap: Map, + @HeaderMap headers: Map + ): Call> } diff --git a/app/src/main/java/io/legado/app/data/api/IHttpPostApi.kt b/app/src/main/java/io/legado/app/data/api/IHttpPostApi.kt index 21fb2622c..113a77291 100644 --- a/app/src/main/java/io/legado/app/data/api/IHttpPostApi.kt +++ b/app/src/main/java/io/legado/app/data/api/IHttpPostApi.kt @@ -28,4 +28,18 @@ interface IHttpPostApi { @HeaderMap headers: Map ): Deferred> + @FormUrlEncoded + @POST + fun postMap( + @Url url: String, + @FieldMap(encoded = true) fieldMap: Map, + @HeaderMap headers: Map + ): Call> + + @POST + fun postBody( + @Url url: String, + @Body body: RequestBody, + @HeaderMap headers: Map + ): Call> } diff --git a/app/src/main/java/io/legado/app/help/JsExtensions.java b/app/src/main/java/io/legado/app/help/JsExtensions.java index 93dc3ba92..7b45b0bc2 100644 --- a/app/src/main/java/io/legado/app/help/JsExtensions.java +++ b/app/src/main/java/io/legado/app/help/JsExtensions.java @@ -6,6 +6,8 @@ import java.util.regex.Pattern; import io.legado.app.model.analyzeRule.AnalyzeUrl; import io.legado.app.utils.Encoder; import io.legado.app.utils.StringUtils; +import retrofit2.Call; +import retrofit2.Response; public class JsExtensions { @@ -16,8 +18,11 @@ public class JsExtensions { public String ajax(String urlStr) { try { AnalyzeUrl analyzeUrl = new AnalyzeUrl(urlStr, null, null, null, null, null); -/* Response response = analyzeUrl.getResponseAsync().await(); - return response.body().toString();*/ + Call call = analyzeUrl.getResponse(); + Response response = call.execute(); + if (response.body() != null) { + return response.body().toString(); + } } catch (Exception e) { return e.getLocalizedMessage(); } diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt index 075c72aca..29b6fe1f4 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt @@ -15,6 +15,7 @@ import okhttp3.FormBody import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.RequestBody import okhttp3.RequestBody.Companion.toRequestBody +import retrofit2.Call import retrofit2.Response import java.net.URLEncoder import java.util.* @@ -199,6 +200,31 @@ class AnalyzeUrl( GET, POST } + fun getResponse(): Call> { + return when { + method == Method.POST -> { + if (fieldMap.isNotEmpty()) { + HttpHelper.getApiService( + baseUrl + ).postMap(url, fieldMap, headerMap) + } else { + HttpHelper.getApiService( + baseUrl + ).postBody( + url, + body, + headerMap + ) + } + } + fieldMap.isEmpty() -> HttpHelper.getApiService( + baseUrl + ).get(url, headerMap) + else -> HttpHelper.getApiService(baseUrl) + .getMap(url, fieldMap, headerMap) + } + } + fun getResponseAsync(): Deferred> { return when { method == Method.POST -> { From 1c9e6846b37b62c2636b10f506d26dc6f18dfb48 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 4 Sep 2019 11:10:44 +0800 Subject: [PATCH 1273/1997] up --- .../main/java/io/legado/app/data/entities/rule/ExploreRule.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/io/legado/app/data/entities/rule/ExploreRule.kt b/app/src/main/java/io/legado/app/data/entities/rule/ExploreRule.kt index 7337e0245..61f7e4e2d 100644 --- a/app/src/main/java/io/legado/app/data/entities/rule/ExploreRule.kt +++ b/app/src/main/java/io/legado/app/data/entities/rule/ExploreRule.kt @@ -1,6 +1,7 @@ package io.legado.app.data.entities.rule import io.legado.app.constant.AppConst +import io.legado.app.help.JsExtensions import javax.script.SimpleBindings data class ExploreRule( @@ -25,6 +26,7 @@ data class ExploreRule( if (it.startsWith("", false)) { val bindings = SimpleBindings() bindings["baseUrl"] = baseUrl + bindings["java"] = JsExtensions() a = AppConst.SCRIPT_ENGINE.eval( a.substring(4, a.lastIndexOf("<")), bindings From b66f578bffd75277c2aaa00be5c403ba4c8ff903 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 4 Sep 2019 11:48:56 +0800 Subject: [PATCH 1274/1997] up --- .../app/data/entities/rule/ExploreRule.kt | 3 +- .../app/ui/main/findbook/FindBookAdapter.kt | 47 +++++++++++-------- .../app/ui/main/findbook/FindBookFragment.kt | 2 +- 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/rule/ExploreRule.kt b/app/src/main/java/io/legado/app/data/entities/rule/ExploreRule.kt index 61f7e4e2d..a20bb60ab 100644 --- a/app/src/main/java/io/legado/app/data/entities/rule/ExploreRule.kt +++ b/app/src/main/java/io/legado/app/data/entities/rule/ExploreRule.kt @@ -36,7 +36,8 @@ data class ExploreRule( val b = a.split("(&&|\n)+".toRegex()) b.map { c -> val d = c.split("::") - exploreKinds.add(ExploreKind(d[0], d[1])) + if (d.size > 1) + exploreKinds.add(ExploreKind(d[0], d[1])) } return exploreKinds } catch (e: Exception) { diff --git a/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt b/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt index 9dec52302..c57b6a36c 100644 --- a/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt @@ -10,15 +10,18 @@ import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import io.legado.app.R import io.legado.app.data.entities.BookSource +import io.legado.app.help.coroutine.Coroutine import io.legado.app.lib.theme.ColorUtils import io.legado.app.utils.gone import io.legado.app.utils.visible import kotlinx.android.synthetic.main.item_find_book.view.* import kotlinx.android.synthetic.main.item_text.view.* +import kotlinx.coroutines.CoroutineScope import org.jetbrains.anko.sdk27.listeners.onClick -class FindBookAdapter:PagedListAdapter(DIFF_CALLBACK) { +class FindBookAdapter(private val scope: CoroutineScope) : + PagedListAdapter(DIFF_CALLBACK) { var exIndex = 0 @@ -58,26 +61,30 @@ class FindBookAdapter:PagedListAdapter } if (exIndex == position) { gl_child.visible() - bookSource.getExploreRule().getExploreKinds(bookSource.bookSourceUrl)?.let { - var rowNum = 0 - var columnNum = 0 - gl_child.removeAllViews() - it.map { kind -> - val tv = LayoutInflater.from(context) - .inflate(R.layout.item_text, gl_child, false) - tv.text_view.text = kind.title - val rowSpecs = GridLayout.spec(rowNum, 1.0f) - val colSpecs = GridLayout.spec(columnNum, 1.0f) - val params = GridLayout.LayoutParams(rowSpecs, colSpecs) - gl_child.addView(tv, params) - if (columnNum < 2) { - columnNum++ - } else { - columnNum = 0 - rowNum++ - } - tv.onClick { + Coroutine.async(scope) { + bookSource.getExploreRule().getExploreKinds(bookSource.bookSourceUrl) + }.onSuccess { + it?.let { + var rowNum = 0 + var columnNum = 0 + gl_child.removeAllViews() + it.map { kind -> + val tv = LayoutInflater.from(context) + .inflate(R.layout.item_text, gl_child, false) + tv.text_view.text = kind.title + val rowSpecs = GridLayout.spec(rowNum, 1.0f) + val colSpecs = GridLayout.spec(columnNum, 1.0f) + val params = GridLayout.LayoutParams(rowSpecs, colSpecs) + gl_child.addView(tv, params) + if (columnNum < 2) { + columnNum++ + } else { + columnNum = 0 + rowNum++ + } + tv.onClick { + } } } } diff --git a/app/src/main/java/io/legado/app/ui/main/findbook/FindBookFragment.kt b/app/src/main/java/io/legado/app/ui/main/findbook/FindBookFragment.kt index 60e3bef88..e991b501a 100644 --- a/app/src/main/java/io/legado/app/ui/main/findbook/FindBookFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/findbook/FindBookFragment.kt @@ -34,7 +34,7 @@ class FindBookFragment : BaseFragment(R.layout.fragment_find_book) { private fun initRecyclerView() { ATH.applyEdgeEffectColor(rv_find) rv_find.layoutManager = LinearLayoutManager(context) - adapter = FindBookAdapter() + adapter = FindBookAdapter(this) rv_find.adapter = adapter } From 4bdc7eb8907d9536c17fd874c16cb7544ce13ef5 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 4 Sep 2019 11:56:23 +0800 Subject: [PATCH 1275/1997] up --- .../java/io/legado/app/ui/main/findbook/FindBookAdapter.kt | 4 +++- app/src/main/res/layout/item_find_book.xml | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt b/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt index c57b6a36c..94c176028 100644 --- a/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt @@ -60,11 +60,13 @@ class FindBookAdapter(private val scope: CoroutineScope) : notifyItemChanged(oldEx) } if (exIndex == position) { - gl_child.visible() + rotate_loading.show() Coroutine.async(scope) { bookSource.getExploreRule().getExploreKinds(bookSource.bookSourceUrl) }.onSuccess { it?.let { + rotate_loading.hide() + gl_child.visible() var rowNum = 0 var columnNum = 0 gl_child.removeAllViews() diff --git a/app/src/main/res/layout/item_find_book.xml b/app/src/main/res/layout/item_find_book.xml index 654ba6c31..1d3fa7c4c 100644 --- a/app/src/main/res/layout/item_find_book.xml +++ b/app/src/main/res/layout/item_find_book.xml @@ -47,4 +47,10 @@ android:columnCount="3" android:visibility="gone" /> + + \ No newline at end of file From 029a73f09b7a51ca05e08a3a8d175a07710e071f Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 4 Sep 2019 12:28:17 +0800 Subject: [PATCH 1276/1997] up --- .../legado/app/ui/main/findbook/FindBookAdapter.kt | 12 ++++++++++-- .../legado/app/ui/main/findbook/FindBookFragment.kt | 11 ++++++++--- app/src/main/res/layout/item_find_book.xml | 4 +++- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt b/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt index 94c176028..144628dc5 100644 --- a/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt @@ -20,7 +20,7 @@ import kotlinx.coroutines.CoroutineScope import org.jetbrains.anko.sdk27.listeners.onClick -class FindBookAdapter(private val scope: CoroutineScope) : +class FindBookAdapter(private val scope: CoroutineScope, val callBack: CallBack) : PagedListAdapter(DIFF_CALLBACK) { var exIndex = 0 @@ -58,6 +58,7 @@ class FindBookAdapter(private val scope: CoroutineScope) : notifyItemChanged(position) } notifyItemChanged(oldEx) + callBack.scrollTo(position) } if (exIndex == position) { rotate_loading.show() @@ -65,7 +66,6 @@ class FindBookAdapter(private val scope: CoroutineScope) : bookSource.getExploreRule().getExploreKinds(bookSource.bookSourceUrl) }.onSuccess { it?.let { - rotate_loading.hide() gl_child.visible() var rowNum = 0 var columnNum = 0 @@ -89,12 +89,20 @@ class FindBookAdapter(private val scope: CoroutineScope) : } } } + }.onFinally { + rotate_loading.hide() } } else { + rotate_loading.hide() gl_child.gone() } } } class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) + + interface CallBack { + + fun scrollTo(pos: Int) + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/findbook/FindBookFragment.kt b/app/src/main/java/io/legado/app/ui/main/findbook/FindBookFragment.kt index e991b501a..97a532801 100644 --- a/app/src/main/java/io/legado/app/ui/main/findbook/FindBookFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/findbook/FindBookFragment.kt @@ -16,10 +16,11 @@ import io.legado.app.lib.theme.ATH import kotlinx.android.synthetic.main.fragment_find_book.* import kotlinx.android.synthetic.main.view_title_bar.* -class FindBookFragment : BaseFragment(R.layout.fragment_find_book) { +class FindBookFragment : BaseFragment(R.layout.fragment_find_book), + FindBookAdapter.CallBack { private lateinit var adapter: FindBookAdapter - private var findLiveData:LiveData>? = null + private var findLiveData: LiveData>? = null override fun onViewCreated(view: View, savedInstanceState: Bundle?) { setSupportToolbar(toolbar) @@ -34,7 +35,7 @@ class FindBookFragment : BaseFragment(R.layout.fragment_find_book) { private fun initRecyclerView() { ATH.applyEdgeEffectColor(rv_find) rv_find.layoutManager = LinearLayoutManager(context) - adapter = FindBookAdapter(this) + adapter = FindBookAdapter(this, this) rv_find.adapter = adapter } @@ -43,4 +44,8 @@ class FindBookFragment : BaseFragment(R.layout.fragment_find_book) { findLiveData = LivePagedListBuilder(App.db.bookSourceDao().observeFind(), 2000).build() findLiveData?.observe(viewLifecycleOwner, Observer { adapter.submitList(it) }) } + + override fun scrollTo(pos: Int) { + rv_find.scrollToPosition(pos) + } } \ No newline at end of file diff --git a/app/src/main/res/layout/item_find_book.xml b/app/src/main/res/layout/item_find_book.xml index 1d3fa7c4c..eef807484 100644 --- a/app/src/main/res/layout/item_find_book.xml +++ b/app/src/main/res/layout/item_find_book.xml @@ -6,6 +6,7 @@ android:layout_height="wrap_content" android:paddingLeft="10dp" android:paddingRight="10dp" + android:gravity="center" android:orientation="vertical"> + android:visibility="gone" + app:loading_width="2dp" /> \ No newline at end of file From 784550853cf6630ea98b158bfbe02eb84ebacb42 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 4 Sep 2019 14:32:03 +0800 Subject: [PATCH 1277/1997] up --- app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt index 1d1509058..c3db2f5ee 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt @@ -516,6 +516,7 @@ class AnalyzeRule(private var book: BaseBook? = null) { @Throws(Exception::class) private fun evalJS(jsStr: String, result: Any?): Any { val bindings = SimpleBindings() + bindings["analyzeRule"] = this bindings["book"] = book bindings["java"] = JsExtensions() bindings["result"] = result From aa329a4667cfdb17695411099b28a16d9cd28bae Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 4 Sep 2019 15:03:56 +0800 Subject: [PATCH 1278/1997] up --- .../io/legado/app/ui/readbook/ReadBookActivity.kt | 2 +- .../io/legado/app/ui/readbook/ReadBookViewModel.kt | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 1d9635ece..7ab90a2f0 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -355,9 +355,9 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea tv_chapter_url.visible() } read_menu.upReadProgress(it.pageSize().minus(1), viewModel.durPageIndex) - curPageChanged() tv_pre.isEnabled = viewModel.durChapterIndex != 0 tv_next.isEnabled = viewModel.durChapterIndex != viewModel.chapterSize - 1 + curPageChanged() } } diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index 5bfac5ea9..fe1a00201 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -114,7 +114,11 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { curTextChapter = nextTextChapter nextTextChapter = null bookData.value?.let { - loadContent(it, durChapterIndex) + if (curTextChapter == null) { + loadContent(it, durChapterIndex) + } else { + callBack?.upContent() + } loadContent(it, durChapterIndex.plus(1)) launch(IO) { for (i in 2..10) { @@ -133,7 +137,11 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { curTextChapter = prevTextChapter prevTextChapter = null bookData.value?.let { - loadContent(it, durChapterIndex) + if (curTextChapter == null) { + loadContent(it, durChapterIndex) + } else { + callBack?.upContent() + } loadContent(it, durChapterIndex.minus(1)) launch(IO) { for (i in -5..-2) { From f68342f21f5b3c40cd34846f8b2ee124d475d123 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 4 Sep 2019 17:00:02 +0800 Subject: [PATCH 1279/1997] Create README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 000000000..d65e3dbdc --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# legado +## 阅读3.0 From 6da676f74e11a2a1496c1b07242818354a4dda49 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 4 Sep 2019 17:25:16 +0800 Subject: [PATCH 1280/1997] up --- app/src/main/AndroidManifest.xml | 1 + .../io/legado/app/data/entities/BaseBook.kt | 17 +++++ .../java/io/legado/app/data/entities/Book.kt | 17 +---- .../io/legado/app/data/entities/SearchBook.kt | 4 +- .../io/legado/app/data/entities/SearchShow.kt | 22 ++---- .../io/legado/app/ui/explore/DiffCallBack.kt | 30 ++++++++ .../app/ui/explore/ExploreShowActivity.kt | 26 +++++++ .../app/ui/explore/ExploreShowAdapter.kt | 75 +++++++++++++++++++ .../io/legado/app/ui/search/SearchActivity.kt | 3 +- .../io/legado/app/ui/search/SearchAdapter.kt | 5 +- .../main/res/layout/activity_explore_show.xml | 34 +++++++++ 11 files changed, 197 insertions(+), 37 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/explore/DiffCallBack.kt create mode 100644 app/src/main/java/io/legado/app/ui/explore/ExploreShowActivity.kt create mode 100644 app/src/main/java/io/legado/app/ui/explore/ExploreShowAdapter.kt create mode 100644 app/src/main/res/layout/activity_explore_show.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index bca5f59fb..86b1d669a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -61,6 +61,7 @@ + diff --git a/app/src/main/java/io/legado/app/data/entities/BaseBook.kt b/app/src/main/java/io/legado/app/data/entities/BaseBook.kt index e3605d6f6..6a7d561ee 100644 --- a/app/src/main/java/io/legado/app/data/entities/BaseBook.kt +++ b/app/src/main/java/io/legado/app/data/entities/BaseBook.kt @@ -1,6 +1,23 @@ package io.legado.app.data.entities +import io.legado.app.utils.splitNotBlank + interface BaseBook { var variableMap: HashMap? + var kind: String? + var wordCount: String? + fun putVariable(key: String, value: String) + + fun getKindList(): List { + val kindList = arrayListOf() + wordCount?.let { + if (it.isNotBlank()) kindList.add(it) + } + kind?.let { + val kinds = it.splitNotBlank(",", "\n") + kindList.addAll(kinds) + } + return kindList + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/data/entities/Book.kt b/app/src/main/java/io/legado/app/data/entities/Book.kt index ebd007a10..118acf35b 100644 --- a/app/src/main/java/io/legado/app/data/entities/Book.kt +++ b/app/src/main/java/io/legado/app/data/entities/Book.kt @@ -9,7 +9,6 @@ import androidx.room.PrimaryKey import io.legado.app.constant.BookType import io.legado.app.utils.GSON import io.legado.app.utils.fromJsonObject -import io.legado.app.utils.splitNotBlank import kotlinx.android.parcel.IgnoredOnParcel import kotlinx.android.parcel.Parcelize import kotlin.math.max @@ -24,7 +23,7 @@ data class Book( var originName: String = "", //书源名称 var name: String = "", // 书籍名称(书源获取) var author: String = "", // 作者名称(书源获取) - var kind: String? = null, // 分类信息(书源获取) + override var kind: String? = null, // 分类信息(书源获取) var customTag: String? = null, // 分类信息(用户修改) var coverUrl: String? = null, // 封面Url(书源获取) var customCoverUrl: String? = null, // 封面Url(用户修改) @@ -42,7 +41,7 @@ data class Book( var durChapterIndex: Int = 0, // 当前章节索引 var durChapterPos: Int = 0, // 当前阅读的进度(首行字符的索引位置) var durChapterTime: Long = System.currentTimeMillis(), // 最近一次阅读书籍的时间(打开正文的时间) - var wordCount: String? = null, + override var wordCount: String? = null, var canUpdate: Boolean = true, // 刷新书架时更新书籍信息 var order: Int = 0, // 手动排序 var originOrder: Int = 0, //书源排序 @@ -79,18 +78,6 @@ data class Book( variable = GSON.toJson(variableMap) } - fun getKindList(): List { - val kindList = arrayListOf() - wordCount?.let { - if (it.isNotBlank()) kindList.add(it) - } - kind?.let { - val kinds = it.splitNotBlank(",", "\n") - kindList.addAll(kinds) - } - return kindList - } - fun toSearchBook(): SearchBook { return SearchBook( name = name, diff --git a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt index 4423ff6f8..00efc0e47 100644 --- a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt +++ b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt @@ -20,10 +20,10 @@ data class SearchBook( var originName: String = "", var name: String = "", var author: String = "", - var kind: String? = null, + override var kind: String? = null, var coverUrl: String? = null, var intro: String? = null, - var wordCount: String? = null, + override var wordCount: String? = null, var latestChapterTitle: String? = null, var tocUrl: String = "", // 目录页Url (toc=table of Contents) var time: Long = System.currentTimeMillis(), diff --git a/app/src/main/java/io/legado/app/data/entities/SearchShow.kt b/app/src/main/java/io/legado/app/data/entities/SearchShow.kt index 1611e04ac..faa7c3575 100644 --- a/app/src/main/java/io/legado/app/data/entities/SearchShow.kt +++ b/app/src/main/java/io/legado/app/data/entities/SearchShow.kt @@ -1,27 +1,19 @@ package io.legado.app.data.entities -import io.legado.app.utils.splitNotBlank - data class SearchShow( var name: String = "", var author: String = "", - var kind: String? = null, + override var kind: String? = null, var coverUrl: String? = null, var intro: String? = null, - var wordCount: String? = null, + override var wordCount: String? = null, var latestChapterTitle: String? = null, var time: Long = 0L, var originCount: Int = 0 -) { - fun getKindList(): List { - val kindList = arrayListOf() - wordCount?.let { - if (it.isNotBlank()) kindList.add(it) - } - kind?.let { - val kinds = it.splitNotBlank(",", "\n") - kindList.addAll(kinds) - } - return kindList +) : BaseBook { + override var variableMap: HashMap? = null + + override fun putVariable(key: String, value: String) { + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/explore/DiffCallBack.kt b/app/src/main/java/io/legado/app/ui/explore/DiffCallBack.kt new file mode 100644 index 000000000..1027dd31d --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/explore/DiffCallBack.kt @@ -0,0 +1,30 @@ +package io.legado.app.ui.explore + +import androidx.recyclerview.widget.DiffUtil +import io.legado.app.data.entities.SearchShow + +class DiffCallBack : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: SearchShow, newItem: SearchShow): Boolean { + return oldItem.name == newItem.name + && oldItem.author == newItem.author + } + + override fun areContentsTheSame(oldItem: SearchShow, newItem: SearchShow): Boolean { + return oldItem.originCount == newItem.originCount + && (oldItem.coverUrl == newItem.coverUrl || !oldItem.coverUrl.isNullOrEmpty()) + && (oldItem.kind == newItem.kind || !oldItem.kind.isNullOrEmpty()) + && (oldItem.latestChapterTitle == newItem.latestChapterTitle || !oldItem.kind.isNullOrEmpty()) + && oldItem.intro?.length ?: 0 > newItem.intro?.length ?: 0 + } + + override fun getChangePayload(oldItem: SearchShow, newItem: SearchShow): Any? { + return when { + oldItem.originCount != newItem.originCount -> 1 + oldItem.coverUrl != newItem.coverUrl -> 2 + oldItem.kind != newItem.kind -> 3 + oldItem.latestChapterTitle != newItem.latestChapterTitle -> 4 + oldItem.intro != newItem.intro -> 5 + else -> null + } + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/explore/ExploreShowActivity.kt b/app/src/main/java/io/legado/app/ui/explore/ExploreShowActivity.kt new file mode 100644 index 000000000..ba9930159 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/explore/ExploreShowActivity.kt @@ -0,0 +1,26 @@ +package io.legado.app.ui.explore + +import android.os.Bundle +import io.legado.app.R +import io.legado.app.base.BaseActivity +import kotlinx.android.synthetic.main.activity_explore_show.* + +class ExploreShowActivity : BaseActivity(R.layout.activity_explore_show) { + + override fun onActivityCreated(savedInstanceState: Bundle?) { + intent.getStringExtra("exploreName")?.let { + title_bar.title = it + } + initRecyclerView() + } + + private fun initRecyclerView() { + + } + + private fun initData() { + val sourceUrl = intent.getStringExtra("sourceUrl") + val exploreUrl = intent.getStringExtra("exploreUrl") + } + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/explore/ExploreShowAdapter.kt b/app/src/main/java/io/legado/app/ui/explore/ExploreShowAdapter.kt new file mode 100644 index 000000000..a9f8bf4d0 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/explore/ExploreShowAdapter.kt @@ -0,0 +1,75 @@ +package io.legado.app.ui.explore + +import android.content.Context +import io.legado.app.R +import io.legado.app.base.adapter.ItemViewHolder +import io.legado.app.base.adapter.SimpleRecyclerAdapter +import io.legado.app.data.entities.SearchBook +import io.legado.app.help.ImageLoader +import io.legado.app.utils.gone +import io.legado.app.utils.visible +import kotlinx.android.synthetic.main.item_bookshelf_list.view.iv_cover +import kotlinx.android.synthetic.main.item_bookshelf_list.view.tv_name +import kotlinx.android.synthetic.main.item_search.view.* +import org.jetbrains.anko.sdk27.listeners.onClick + +class ExploreShowAdapter(context: Context, val callBack: CallBack) : + SimpleRecyclerAdapter(context, R.layout.item_search) { + + override fun convert(holder: ItemViewHolder, item: SearchBook, payloads: MutableList) = + with(holder.itemView) { + tv_name.text = item.name + tv_author.text = context.getString(R.string.author_show, item.author) + if (item.latestChapterTitle.isNullOrEmpty()) { + tv_lasted.gone() + } else { + tv_lasted.text = context.getString(R.string.lasted_show, item.latestChapterTitle) + tv_lasted.visible() + } + tv_introduce.text = context.getString(R.string.intro_show, item.intro) + val kinds = item.getKindList() + if (kinds.isEmpty()) { + ll_kind.gone() + } else { + ll_kind.visible() + for (index in 0..2) { + if (kinds.size > index) { + when (index) { + 0 -> { + tv_kind.text = kinds[index] + tv_kind.visible() + } + 1 -> { + tv_kind_1.text = kinds[index] + tv_kind_1.visible() + } + 2 -> { + tv_kind_2.text = kinds[index] + tv_kind_2.visible() + } + } + } else { + when (index) { + 0 -> tv_kind.gone() + 1 -> tv_kind_1.gone() + 2 -> tv_kind_2.gone() + } + } + } + } + item.coverUrl.let { + ImageLoader.load(context, it)//Glide自动识别http://和file:// + .placeholder(R.drawable.img_cover_default) + .error(R.drawable.img_cover_default) + .centerCrop() + .setAsDrawable(iv_cover) + } + onClick { + callBack.showBookInfo(item.name, item.author) + } + } + + interface CallBack { + fun showBookInfo(name: String, author: String) + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt index c521d56b1..4f0623009 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt @@ -70,8 +70,7 @@ class SearchActivity : VMBaseActivity(R.layout.activity_search) private fun initRecyclerView() { ATH.applyEdgeEffectColor(rv_search_list) - adapter = SearchAdapter() - adapter.callBack = this + adapter = SearchAdapter(this) rv_search_list.layoutManager = LinearLayoutManager(this) rv_search_list.adapter = adapter } diff --git a/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt b/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt index 6ee7337eb..0b40007ff 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt @@ -15,9 +15,8 @@ import kotlinx.android.synthetic.main.item_bookshelf_list.view.tv_name import kotlinx.android.synthetic.main.item_search.view.* import org.jetbrains.anko.sdk27.listeners.onClick -class SearchAdapter : PagedListAdapter(DiffCallBack()) { - - var callBack: CallBack? = null +class SearchAdapter(val callBack: CallBack) : + PagedListAdapter(DiffCallBack()) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { return MyViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_search, parent, false)) diff --git a/app/src/main/res/layout/activity_explore_show.xml b/app/src/main/res/layout/activity_explore_show.xml new file mode 100644 index 000000000..7419b0de8 --- /dev/null +++ b/app/src/main/res/layout/activity_explore_show.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + \ No newline at end of file From 22d2807a9c00cbb1cce3c98aceb0267d4bb57276 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 4 Sep 2019 17:39:12 +0800 Subject: [PATCH 1281/1997] up --- .../io/legado/app/ui/explore/DiffCallBack.kt | 30 ------------------- .../app/ui/explore/ExploreShowActivity.kt | 16 ++++++++-- .../io/legado/app/ui/search/SearchActivity.kt | 6 ++-- .../main/res/layout/activity_explore_show.xml | 2 +- app/src/main/res/layout/activity_search.xml | 2 +- 5 files changed, 19 insertions(+), 37 deletions(-) delete mode 100644 app/src/main/java/io/legado/app/ui/explore/DiffCallBack.kt diff --git a/app/src/main/java/io/legado/app/ui/explore/DiffCallBack.kt b/app/src/main/java/io/legado/app/ui/explore/DiffCallBack.kt deleted file mode 100644 index 1027dd31d..000000000 --- a/app/src/main/java/io/legado/app/ui/explore/DiffCallBack.kt +++ /dev/null @@ -1,30 +0,0 @@ -package io.legado.app.ui.explore - -import androidx.recyclerview.widget.DiffUtil -import io.legado.app.data.entities.SearchShow - -class DiffCallBack : DiffUtil.ItemCallback() { - override fun areItemsTheSame(oldItem: SearchShow, newItem: SearchShow): Boolean { - return oldItem.name == newItem.name - && oldItem.author == newItem.author - } - - override fun areContentsTheSame(oldItem: SearchShow, newItem: SearchShow): Boolean { - return oldItem.originCount == newItem.originCount - && (oldItem.coverUrl == newItem.coverUrl || !oldItem.coverUrl.isNullOrEmpty()) - && (oldItem.kind == newItem.kind || !oldItem.kind.isNullOrEmpty()) - && (oldItem.latestChapterTitle == newItem.latestChapterTitle || !oldItem.kind.isNullOrEmpty()) - && oldItem.intro?.length ?: 0 > newItem.intro?.length ?: 0 - } - - override fun getChangePayload(oldItem: SearchShow, newItem: SearchShow): Any? { - return when { - oldItem.originCount != newItem.originCount -> 1 - oldItem.coverUrl != newItem.coverUrl -> 2 - oldItem.kind != newItem.kind -> 3 - oldItem.latestChapterTitle != newItem.latestChapterTitle -> 4 - oldItem.intro != newItem.intro -> 5 - else -> null - } - } -} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/explore/ExploreShowActivity.kt b/app/src/main/java/io/legado/app/ui/explore/ExploreShowActivity.kt index ba9930159..9b9566f96 100644 --- a/app/src/main/java/io/legado/app/ui/explore/ExploreShowActivity.kt +++ b/app/src/main/java/io/legado/app/ui/explore/ExploreShowActivity.kt @@ -1,11 +1,17 @@ package io.legado.app.ui.explore import android.os.Bundle +import androidx.recyclerview.widget.DividerItemDecoration +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView import io.legado.app.R import io.legado.app.base.BaseActivity import kotlinx.android.synthetic.main.activity_explore_show.* -class ExploreShowActivity : BaseActivity(R.layout.activity_explore_show) { +class ExploreShowActivity : BaseActivity(R.layout.activity_explore_show), + ExploreShowAdapter.CallBack { + + private lateinit var adapter: ExploreShowAdapter override fun onActivityCreated(savedInstanceState: Bundle?) { intent.getStringExtra("exploreName")?.let { @@ -15,7 +21,10 @@ class ExploreShowActivity : BaseActivity(R.layout.activity_explore_show) { } private fun initRecyclerView() { - + adapter = ExploreShowAdapter(this, this) + recycler_view.layoutManager = LinearLayoutManager(this) + recycler_view.addItemDecoration(DividerItemDecoration(this, RecyclerView.VERTICAL)) + recycler_view.adapter = adapter } private fun initData() { @@ -23,4 +32,7 @@ class ExploreShowActivity : BaseActivity(R.layout.activity_explore_show) { val exploreUrl = intent.getStringExtra("exploreUrl") } + override fun showBookInfo(name: String, author: String) { + + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt index 4f0623009..d8b9cdf7e 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt @@ -69,10 +69,10 @@ class SearchActivity : VMBaseActivity(R.layout.activity_search) } private fun initRecyclerView() { - ATH.applyEdgeEffectColor(rv_search_list) + ATH.applyEdgeEffectColor(recycler_view) adapter = SearchAdapter(this) - rv_search_list.layoutManager = LinearLayoutManager(this) - rv_search_list.adapter = adapter + recycler_view.layoutManager = LinearLayoutManager(this) + recycler_view.adapter = adapter } private fun initData() { diff --git a/app/src/main/res/layout/activity_explore_show.xml b/app/src/main/res/layout/activity_explore_show.xml index 7419b0de8..9637cd8b0 100644 --- a/app/src/main/res/layout/activity_explore_show.xml +++ b/app/src/main/res/layout/activity_explore_show.xml @@ -24,7 +24,7 @@ diff --git a/app/src/main/res/layout/activity_search.xml b/app/src/main/res/layout/activity_search.xml index 296dc6b9f..df00899cd 100644 --- a/app/src/main/res/layout/activity_search.xml +++ b/app/src/main/res/layout/activity_search.xml @@ -25,7 +25,7 @@ From 9ce96756b7f973e774f05df24eb4d4966b122a09 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 4 Sep 2019 17:41:18 +0800 Subject: [PATCH 1282/1997] up --- .../java/io/legado/app/ui/explore/ExploreShowActivity.kt | 7 +++++-- .../io/legado/app/ui/explore/ExploreShowViewModel.kt | 9 +++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/explore/ExploreShowViewModel.kt diff --git a/app/src/main/java/io/legado/app/ui/explore/ExploreShowActivity.kt b/app/src/main/java/io/legado/app/ui/explore/ExploreShowActivity.kt index 9b9566f96..25d480633 100644 --- a/app/src/main/java/io/legado/app/ui/explore/ExploreShowActivity.kt +++ b/app/src/main/java/io/legado/app/ui/explore/ExploreShowActivity.kt @@ -5,11 +5,14 @@ import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import io.legado.app.R -import io.legado.app.base.BaseActivity +import io.legado.app.base.VMBaseActivity +import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_explore_show.* -class ExploreShowActivity : BaseActivity(R.layout.activity_explore_show), +class ExploreShowActivity : VMBaseActivity(R.layout.activity_explore_show), ExploreShowAdapter.CallBack { + override val viewModel: ExploreShowViewModel + get() = getViewModel(ExploreShowViewModel::class.java) private lateinit var adapter: ExploreShowAdapter diff --git a/app/src/main/java/io/legado/app/ui/explore/ExploreShowViewModel.kt b/app/src/main/java/io/legado/app/ui/explore/ExploreShowViewModel.kt new file mode 100644 index 000000000..de3efd590 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/explore/ExploreShowViewModel.kt @@ -0,0 +1,9 @@ +package io.legado.app.ui.explore + +import android.app.Application +import io.legado.app.base.BaseViewModel + +class ExploreShowViewModel(application: Application) : BaseViewModel(application) { + + +} \ No newline at end of file From b5a33fd98b4d7e768e0d80abc2c3698a3f209f85 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 4 Sep 2019 19:59:30 +0800 Subject: [PATCH 1283/1997] up --- app/src/main/java/io/legado/app/data/entities/SearchShow.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/SearchShow.kt b/app/src/main/java/io/legado/app/data/entities/SearchShow.kt index faa7c3575..a0e24316a 100644 --- a/app/src/main/java/io/legado/app/data/entities/SearchShow.kt +++ b/app/src/main/java/io/legado/app/data/entities/SearchShow.kt @@ -13,7 +13,5 @@ data class SearchShow( ) : BaseBook { override var variableMap: HashMap? = null - override fun putVariable(key: String, value: String) { - - } + override fun putVariable(key: String, value: String) = Unit } \ No newline at end of file From c56ba47cfbb68770431eba4be9c7b50408c22df3 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 4 Sep 2019 20:32:24 +0800 Subject: [PATCH 1284/1997] up --- .../main/java/io/legado/app/model/WebBook.kt | 39 +++++++++++++++---- .../io/legado/app/model/webbook/BookList.kt | 6 ++- .../app/ui/explore/ExploreShowActivity.kt | 10 +++-- .../app/ui/explore/ExploreShowAdapter.kt | 4 +- .../app/ui/explore/ExploreShowViewModel.kt | 27 +++++++++++++ 5 files changed, 72 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/WebBook.kt b/app/src/main/java/io/legado/app/model/WebBook.kt index 5eaa243c5..0e460edba 100644 --- a/app/src/main/java/io/legado/app/model/WebBook.kt +++ b/app/src/main/java/io/legado/app/model/WebBook.kt @@ -17,12 +17,11 @@ class WebBook(val bookSource: BookSource) { val sourceUrl: String get() = bookSource.bookSourceUrl - fun searchBook( - key: String, - page: Int? = 1, - isSearch: Boolean = true, - scope: CoroutineScope = Coroutine.DEFAULT - ): Coroutine> { + /** + * 搜索 + */ + fun searchBook(key: String, page: Int? = 1, scope: CoroutineScope = Coroutine.DEFAULT) + : Coroutine> { return Coroutine.async(scope) { bookSource.getSearchRule().searchUrl?.let { searchUrl -> val analyzeUrl = AnalyzeUrl( @@ -33,11 +32,31 @@ class WebBook(val bookSource: BookSource) { headerMapF = bookSource.getHeaderMap() ) val response = analyzeUrl.getResponseAsync().await() - BookList.analyzeBookList(response, bookSource, analyzeUrl, isSearch) + BookList.analyzeBookList(response, bookSource, analyzeUrl, true) } ?: arrayListOf() } } + /** + * 发现 + */ + fun exploreBook(url: String, page: Int? = 1, scope: CoroutineScope = Coroutine.DEFAULT) + : Coroutine> { + return Coroutine.async(scope) { + val analyzeUrl = AnalyzeUrl( + ruleUrl = url, + page = page, + baseUrl = sourceUrl, + headerMapF = bookSource.getHeaderMap() + ) + val response = analyzeUrl.getResponseAsync().await() + BookList.analyzeBookList(response, bookSource, analyzeUrl, false) + } + } + + /** + * 书籍信息 + */ fun getBookInfo(book: Book, scope: CoroutineScope = Coroutine.DEFAULT): Coroutine { return Coroutine.async(scope) { val analyzeUrl = AnalyzeUrl( @@ -52,6 +71,9 @@ class WebBook(val bookSource: BookSource) { } } + /** + * 目录 + */ fun getChapterList( book: Book, scope: CoroutineScope = Coroutine.DEFAULT @@ -68,6 +90,9 @@ class WebBook(val bookSource: BookSource) { } } + /** + * 章节内容 + */ fun getContent( book: Book, bookChapter: BookChapter, diff --git a/app/src/main/java/io/legado/app/model/webbook/BookList.kt b/app/src/main/java/io/legado/app/model/webbook/BookList.kt index 517ee4ecb..1e2bfb6c9 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookList.kt @@ -43,7 +43,11 @@ object BookList { } val collections: List var reverse = false - val bookListRule = if (isSearch) bookSource.getSearchRule() else bookSource.getExploreRule() + val bookListRule = when { + isSearch -> bookSource.getSearchRule() + bookSource.getExploreRule().bookList.isNullOrBlank() -> bookSource.getSearchRule() + else -> bookSource.getExploreRule() + } var ruleList = bookListRule.bookList ?: "" if (ruleList.startsWith("-")) { reverse = true diff --git a/app/src/main/java/io/legado/app/ui/explore/ExploreShowActivity.kt b/app/src/main/java/io/legado/app/ui/explore/ExploreShowActivity.kt index 25d480633..695d9ac68 100644 --- a/app/src/main/java/io/legado/app/ui/explore/ExploreShowActivity.kt +++ b/app/src/main/java/io/legado/app/ui/explore/ExploreShowActivity.kt @@ -1,11 +1,13 @@ package io.legado.app.ui.explore import android.os.Bundle +import androidx.lifecycle.Observer import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import io.legado.app.R import io.legado.app.base.VMBaseActivity +import io.legado.app.data.entities.SearchBook import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_explore_show.* @@ -21,6 +23,7 @@ class ExploreShowActivity : VMBaseActivity(R.layout.activi title_bar.title = it } initRecyclerView() + viewModel.booksData.observe(this, Observer { upData(it) }) } private fun initRecyclerView() { @@ -30,12 +33,11 @@ class ExploreShowActivity : VMBaseActivity(R.layout.activi recycler_view.adapter = adapter } - private fun initData() { - val sourceUrl = intent.getStringExtra("sourceUrl") - val exploreUrl = intent.getStringExtra("exploreUrl") + private fun upData(books: List) { + adapter.addItems(books) } - override fun showBookInfo(name: String, author: String) { + override fun showBookInfo(bookUrl: String) { } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/explore/ExploreShowAdapter.kt b/app/src/main/java/io/legado/app/ui/explore/ExploreShowAdapter.kt index a9f8bf4d0..6510735f5 100644 --- a/app/src/main/java/io/legado/app/ui/explore/ExploreShowAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/explore/ExploreShowAdapter.kt @@ -65,11 +65,11 @@ class ExploreShowAdapter(context: Context, val callBack: CallBack) : .setAsDrawable(iv_cover) } onClick { - callBack.showBookInfo(item.name, item.author) + callBack.showBookInfo(item.bookUrl) } } interface CallBack { - fun showBookInfo(name: String, author: String) + fun showBookInfo(bookUrl: String) } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/explore/ExploreShowViewModel.kt b/app/src/main/java/io/legado/app/ui/explore/ExploreShowViewModel.kt index de3efd590..b3d692ca3 100644 --- a/app/src/main/java/io/legado/app/ui/explore/ExploreShowViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/explore/ExploreShowViewModel.kt @@ -1,9 +1,36 @@ package io.legado.app.ui.explore import android.app.Application +import android.content.Intent +import androidx.lifecycle.MutableLiveData +import io.legado.app.App import io.legado.app.base.BaseViewModel +import io.legado.app.data.entities.BookSource +import io.legado.app.data.entities.SearchBook +import io.legado.app.model.WebBook class ExploreShowViewModel(application: Application) : BaseViewModel(application) { + val booksData = MutableLiveData>() + var bookSource: BookSource? = null + var page = 1 + + fun initData(intent: Intent) { + execute { + val sourceUrl = intent.getStringExtra("sourceUrl") + val exploreUrl = intent.getStringExtra("exploreUrl") + if (bookSource == null) { + bookSource = App.db.bookSourceDao().getBookSource(sourceUrl) + } + bookSource?.let { + WebBook(it).exploreBook(exploreUrl, page, this) + .onSuccess { searchBooks -> + searchBooks?.let { + booksData.value = searchBooks + } + } + } + } + } } \ No newline at end of file From eb3bfd4db7ad0dfa6fe551d642044909df932f52 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 4 Sep 2019 20:40:49 +0800 Subject: [PATCH 1285/1997] up --- .../app/ui/explore/ExploreShowActivity.kt | 4 +++- .../app/ui/explore/ExploreShowViewModel.kt | 24 +++++++++++++------ 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/explore/ExploreShowActivity.kt b/app/src/main/java/io/legado/app/ui/explore/ExploreShowActivity.kt index 695d9ac68..577e57682 100644 --- a/app/src/main/java/io/legado/app/ui/explore/ExploreShowActivity.kt +++ b/app/src/main/java/io/legado/app/ui/explore/ExploreShowActivity.kt @@ -8,8 +8,10 @@ import androidx.recyclerview.widget.RecyclerView import io.legado.app.R import io.legado.app.base.VMBaseActivity import io.legado.app.data.entities.SearchBook +import io.legado.app.ui.bookinfo.BookInfoActivity import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_explore_show.* +import org.jetbrains.anko.startActivity class ExploreShowActivity : VMBaseActivity(R.layout.activity_explore_show), ExploreShowAdapter.CallBack { @@ -38,6 +40,6 @@ class ExploreShowActivity : VMBaseActivity(R.layout.activi } override fun showBookInfo(bookUrl: String) { - + startActivity(Pair("searchBookUrl", bookUrl)) } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/explore/ExploreShowViewModel.kt b/app/src/main/java/io/legado/app/ui/explore/ExploreShowViewModel.kt index b3d692ca3..7aa89da91 100644 --- a/app/src/main/java/io/legado/app/ui/explore/ExploreShowViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/explore/ExploreShowViewModel.kt @@ -8,25 +8,35 @@ import io.legado.app.base.BaseViewModel import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.SearchBook import io.legado.app.model.WebBook +import kotlinx.coroutines.Dispatchers.IO class ExploreShowViewModel(application: Application) : BaseViewModel(application) { val booksData = MutableLiveData>() - var bookSource: BookSource? = null - var page = 1 + private var bookSource: BookSource? = null + private var exploreUrl: String? = null + private var page = 1 fun initData(intent: Intent) { execute { val sourceUrl = intent.getStringExtra("sourceUrl") - val exploreUrl = intent.getStringExtra("exploreUrl") + exploreUrl = intent.getStringExtra("exploreUrl") if (bookSource == null) { bookSource = App.db.bookSourceDao().getBookSource(sourceUrl) } - bookSource?.let { - WebBook(it).exploreBook(exploreUrl, page, this) - .onSuccess { searchBooks -> + explore() + } + } + + fun explore() { + bookSource?.let { source -> + exploreUrl?.let { url -> + WebBook(source).exploreBook(url, page, this) + .onSuccess(IO) { searchBooks -> searchBooks?.let { - booksData.value = searchBooks + booksData.postValue(searchBooks) + App.db.searchBookDao().insert(*searchBooks.toTypedArray()) + page++ } } } From f3e1fd0d693a29d5a1d8cfe54e88e3542998e552 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 4 Sep 2019 20:49:38 +0800 Subject: [PATCH 1286/1997] up --- .../io/legado/app/data/entities/SearchShow.kt | 22 ++++++++++++++----- .../app/ui/main/findbook/FindBookAdapter.kt | 10 +++++++-- .../app/ui/main/findbook/FindBookFragment.kt | 10 +++++++++ 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/SearchShow.kt b/app/src/main/java/io/legado/app/data/entities/SearchShow.kt index a0e24316a..a738909ea 100644 --- a/app/src/main/java/io/legado/app/data/entities/SearchShow.kt +++ b/app/src/main/java/io/legado/app/data/entities/SearchShow.kt @@ -1,17 +1,29 @@ package io.legado.app.data.entities +import io.legado.app.utils.splitNotBlank + data class SearchShow( var name: String = "", var author: String = "", - override var kind: String? = null, + var kind: String? = null, var coverUrl: String? = null, var intro: String? = null, - override var wordCount: String? = null, + var wordCount: String? = null, var latestChapterTitle: String? = null, var time: Long = 0L, var originCount: Int = 0 -) : BaseBook { - override var variableMap: HashMap? = null +) { + + fun getKindList(): List { + val kindList = arrayListOf() + wordCount?.let { + if (it.isNotBlank()) kindList.add(it) + } + kind?.let { + val kinds = it.splitNotBlank(",", "\n") + kindList.addAll(kinds) + } + return kindList + } - override fun putVariable(key: String, value: String) = Unit } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt b/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt index 144628dc5..7f44fe28b 100644 --- a/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt @@ -85,7 +85,11 @@ class FindBookAdapter(private val scope: CoroutineScope, val callBack: CallBack) rowNum++ } tv.onClick { - + callBack.openExplore( + bookSource.bookSourceUrl, + kind.title, + kind.url + ) } } } @@ -96,13 +100,15 @@ class FindBookAdapter(private val scope: CoroutineScope, val callBack: CallBack) rotate_loading.hide() gl_child.gone() } + } } - } class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) interface CallBack { fun scrollTo(pos: Int) + + fun openExplore(sourceUrl: String, title: String, exploreUrl: String) } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/findbook/FindBookFragment.kt b/app/src/main/java/io/legado/app/ui/main/findbook/FindBookFragment.kt index 97a532801..75988f74b 100644 --- a/app/src/main/java/io/legado/app/ui/main/findbook/FindBookFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/findbook/FindBookFragment.kt @@ -13,6 +13,8 @@ import io.legado.app.R import io.legado.app.base.BaseFragment import io.legado.app.data.entities.BookSource import io.legado.app.lib.theme.ATH +import io.legado.app.ui.explore.ExploreShowActivity +import io.legado.app.utils.startActivity import kotlinx.android.synthetic.main.fragment_find_book.* import kotlinx.android.synthetic.main.view_title_bar.* @@ -48,4 +50,12 @@ class FindBookFragment : BaseFragment(R.layout.fragment_find_book), override fun scrollTo(pos: Int) { rv_find.scrollToPosition(pos) } + + override fun openExplore(sourceUrl: String, title: String, exploreUrl: String) { + startActivity( + Pair("exploreName", title), + Pair("sourceUrl", sourceUrl), + Pair("exploreUrl", exploreUrl) + ) + } } \ No newline at end of file From 017f94e005bb1f00b57f95e6f21ef33127eacfdc Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 4 Sep 2019 20:55:31 +0800 Subject: [PATCH 1287/1997] up --- app/src/main/res/layout/activity_explore_show.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/res/layout/activity_explore_show.xml b/app/src/main/res/layout/activity_explore_show.xml index 9637cd8b0..8df05cb8c 100644 --- a/app/src/main/res/layout/activity_explore_show.xml +++ b/app/src/main/res/layout/activity_explore_show.xml @@ -10,10 +10,9 @@ android:id="@+id/title_bar" android:layout_width="match_parent" android:layout_height="wrap_content" - app:contentLayout="@layout/view_search" app:contentInsetStartWithNavigation="0dp" app:layout_constraintTop_toTopOf="parent" - app:title="搜索" /> + app:title="@string/find" /> Date: Wed, 4 Sep 2019 20:57:24 +0800 Subject: [PATCH 1288/1997] up --- .../main/java/io/legado/app/ui/explore/ExploreShowActivity.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/explore/ExploreShowActivity.kt b/app/src/main/java/io/legado/app/ui/explore/ExploreShowActivity.kt index 577e57682..9dff24ede 100644 --- a/app/src/main/java/io/legado/app/ui/explore/ExploreShowActivity.kt +++ b/app/src/main/java/io/legado/app/ui/explore/ExploreShowActivity.kt @@ -26,6 +26,7 @@ class ExploreShowActivity : VMBaseActivity(R.layout.activi } initRecyclerView() viewModel.booksData.observe(this, Observer { upData(it) }) + viewModel.initData(intent) } private fun initRecyclerView() { From 5b65702b260364978e9fb5b5375e3149b1cc8390 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 4 Sep 2019 21:02:26 +0800 Subject: [PATCH 1289/1997] up --- .../main/java/io/legado/app/ui/explore/ExploreShowViewModel.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/explore/ExploreShowViewModel.kt b/app/src/main/java/io/legado/app/ui/explore/ExploreShowViewModel.kt index 7aa89da91..275a28631 100644 --- a/app/src/main/java/io/legado/app/ui/explore/ExploreShowViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/explore/ExploreShowViewModel.kt @@ -38,6 +38,8 @@ class ExploreShowViewModel(application: Application) : BaseViewModel(application App.db.searchBookDao().insert(*searchBooks.toTypedArray()) page++ } + }.onError { + it.printStackTrace() } } } From ffdbf91b3cd547a61ef549457cfae8d7c2efb0b5 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 4 Sep 2019 21:52:24 +0800 Subject: [PATCH 1290/1997] up --- .../legado/app/ui/main/findbook/FindBookAdapter.kt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt b/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt index 7f44fe28b..e85f451a9 100644 --- a/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt @@ -74,6 +74,13 @@ class FindBookAdapter(private val scope: CoroutineScope, val callBack: CallBack) val tv = LayoutInflater.from(context) .inflate(R.layout.item_text, gl_child, false) tv.text_view.text = kind.title + tv.text_view.onClick { + callBack.openExplore( + bookSource.bookSourceUrl, + kind.title, + kind.url + ) + } val rowSpecs = GridLayout.spec(rowNum, 1.0f) val colSpecs = GridLayout.spec(columnNum, 1.0f) val params = GridLayout.LayoutParams(rowSpecs, colSpecs) @@ -84,13 +91,6 @@ class FindBookAdapter(private val scope: CoroutineScope, val callBack: CallBack) columnNum = 0 rowNum++ } - tv.onClick { - callBack.openExplore( - bookSource.bookSourceUrl, - kind.title, - kind.url - ) - } } } }.onFinally { From eda339e599c85966ebc6ae3815db3c0668156838 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 4 Sep 2019 22:11:33 +0800 Subject: [PATCH 1291/1997] up --- .../main/java/io/legado/app/ui/explore/ExploreShowViewModel.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/explore/ExploreShowViewModel.kt b/app/src/main/java/io/legado/app/ui/explore/ExploreShowViewModel.kt index 275a28631..f36a5fc69 100644 --- a/app/src/main/java/io/legado/app/ui/explore/ExploreShowViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/explore/ExploreShowViewModel.kt @@ -32,6 +32,7 @@ class ExploreShowViewModel(application: Application) : BaseViewModel(application bookSource?.let { source -> exploreUrl?.let { url -> WebBook(source).exploreBook(url, page, this) + .timeout(30000L) .onSuccess(IO) { searchBooks -> searchBooks?.let { booksData.postValue(searchBooks) From bce9c17fad1ce777f485ff47ca97ff984d5b3332 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 5 Sep 2019 08:15:05 +0800 Subject: [PATCH 1292/1997] up --- .../io/legado/app/data/dao/BookSourceDao.kt | 5 +- .../app/ui/booksource/BookSourceActivity.kt | 2 +- .../app/ui/booksource/GroupManageDialog.kt | 2 +- .../io/legado/app/ui/main/MainActivity.kt | 7 +- .../app/ui/main/explore/FindBookAdapter.kt | 91 ++++++++++++++ .../{findbook => explore}/FindBookFragment.kt | 15 +-- .../app/ui/main/findbook/FindBookAdapter.kt | 114 ------------------ .../app/ui/replacerule/GroupManageDialog.kt | 2 +- 8 files changed, 108 insertions(+), 130 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/main/explore/FindBookAdapter.kt rename app/src/main/java/io/legado/app/ui/main/{findbook => explore}/FindBookFragment.kt (72%) delete mode 100644 app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt diff --git a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt index b616d1733..920be8a00 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt @@ -14,8 +14,11 @@ interface BookSourceDao { @Query("select * from book_sources where bookSourceName like :searchKey or `bookSourceGroup` like :searchKey or bookSourceUrl like :searchKey order by customOrder asc") fun observeSearch(searchKey: String = ""): DataSource.Factory + @Query("select * from book_sources where enabledExplore = 1 order by customOrder asc") + fun liveExplore(): LiveData> + @Query("select bookSourceGroup from book_sources") - fun observeGroup(): LiveData> + fun liveGroup(): LiveData> @Query("select distinct enabled from book_sources where bookSourceName like :searchKey or `bookSourceGroup` like :searchKey or bookSourceUrl like :searchKey") fun searchIsEnable(searchKey: String = ""): List diff --git a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt index 14a947dd3..0e815e15b 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt @@ -123,7 +123,7 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity bookSourceLiveDate = LivePagedListBuilder(dataFactory, 10000).build() bookSourceLiveDate?.observe(this, Observer { adapter.submitList(it) }) - App.db.bookSourceDao().observeGroup().observe(this, Observer { + App.db.bookSourceDao().liveGroup().observe(this, Observer { groups.clear() it.map { group -> groups.addAll(group.splitNotBlank(",", ";")) diff --git a/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt b/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt index 7ffff5b8f..5d4996fb0 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt @@ -70,7 +70,7 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { DividerItemDecoration(requireContext(), RecyclerView.VERTICAL) ) recycler_view.adapter = adapter - App.db.bookSourceDao().observeGroup().observe(viewLifecycleOwner, Observer { + App.db.bookSourceDao().liveGroup().observe(viewLifecycleOwner, Observer { val groups = linkedSetOf() it.map { group -> groups.addAll(group.splitNotBlank(",", ";")) diff --git a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt index db04c42f2..6fc769e01 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt @@ -15,10 +15,13 @@ import io.legado.app.help.permission.Permissions import io.legado.app.help.permission.PermissionsCompat import io.legado.app.lib.theme.ATH import io.legado.app.ui.main.bookshelf.BookshelfFragment -import io.legado.app.ui.main.findbook.FindBookFragment +import io.legado.app.ui.main.explore.FindBookFragment import io.legado.app.ui.main.my.MyFragment import io.legado.app.ui.main.rss.RssFragment -import io.legado.app.utils.* +import io.legado.app.utils.getPrefInt +import io.legado.app.utils.getViewModel +import io.legado.app.utils.observeEvent +import io.legado.app.utils.putPrefInt import kotlinx.android.synthetic.main.activity_main.* import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.launch diff --git a/app/src/main/java/io/legado/app/ui/main/explore/FindBookAdapter.kt b/app/src/main/java/io/legado/app/ui/main/explore/FindBookAdapter.kt new file mode 100644 index 000000000..0148b88f9 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/main/explore/FindBookAdapter.kt @@ -0,0 +1,91 @@ +package io.legado.app.ui.main.explore + +import android.content.Context +import android.graphics.drawable.GradientDrawable +import android.view.LayoutInflater +import android.widget.GridLayout +import io.legado.app.R +import io.legado.app.base.adapter.ItemViewHolder +import io.legado.app.base.adapter.SimpleRecyclerAdapter +import io.legado.app.data.entities.BookSource +import io.legado.app.help.coroutine.Coroutine +import io.legado.app.lib.theme.ColorUtils +import io.legado.app.lib.theme.accentColor +import io.legado.app.utils.gone +import io.legado.app.utils.visible +import kotlinx.android.synthetic.main.item_find_book.view.* +import kotlinx.android.synthetic.main.item_text.view.* +import kotlinx.coroutines.CoroutineScope +import org.jetbrains.anko.sdk27.listeners.onClick + + +class FindBookAdapter(context: Context, private val scope: CoroutineScope, val callBack: CallBack) : + SimpleRecyclerAdapter(context, R.layout.item_find_book) { + + var exIndex = 0 + + override fun convert(holder: ItemViewHolder, item: BookSource, payloads: MutableList) { + with(holder.itemView) { + val bgShape: GradientDrawable? = tv_name.background as? GradientDrawable + bgShape?.setStroke(2, ColorUtils.getRandomColor()) + tv_name.text = item.bookSourceName + ll_title.onClick { + val oldEx = exIndex + if (exIndex == holder.layoutPosition) { + exIndex = -1 + } else { + exIndex = holder.layoutPosition + notifyItemChanged(holder.layoutPosition) + } + notifyItemChanged(oldEx) + callBack.scrollTo(holder.layoutPosition) + } + if (exIndex == holder.layoutPosition) { + rotate_loading.loadingColor = context.accentColor + rotate_loading.show() + Coroutine.async(scope) { + item.getExploreRule().getExploreKinds(item.bookSourceUrl) + }.onSuccess { + it?.let { + gl_child.visible() + var rowNum = 0 + var columnNum = 0 + gl_child.removeAllViews() + it.map { kind -> + val tv = LayoutInflater.from(context) + .inflate(R.layout.item_text, gl_child, false) + tv.text_view.text = kind.title + tv.text_view.onClick { + callBack.openExplore( + item.bookSourceUrl, + kind.title, + kind.url + ) + } + val rowSpecs = GridLayout.spec(rowNum, 1.0f) + val colSpecs = GridLayout.spec(columnNum, 1.0f) + val params = GridLayout.LayoutParams(rowSpecs, colSpecs) + gl_child.addView(tv, params) + if (columnNum < 2) { + columnNum++ + } else { + columnNum = 0 + rowNum++ + } + } + } + }.onFinally { + rotate_loading.hide() + } + } else { + rotate_loading.hide() + gl_child.gone() + } + } + } + + interface CallBack { + fun scrollTo(pos: Int) + fun openExplore(sourceUrl: String, title: String, exploreUrl: String) + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/findbook/FindBookFragment.kt b/app/src/main/java/io/legado/app/ui/main/explore/FindBookFragment.kt similarity index 72% rename from app/src/main/java/io/legado/app/ui/main/findbook/FindBookFragment.kt rename to app/src/main/java/io/legado/app/ui/main/explore/FindBookFragment.kt index 75988f74b..76ed36885 100644 --- a/app/src/main/java/io/legado/app/ui/main/findbook/FindBookFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/explore/FindBookFragment.kt @@ -1,17 +1,13 @@ -package io.legado.app.ui.main.findbook +package io.legado.app.ui.main.explore import android.os.Bundle import android.view.Menu import android.view.View -import androidx.lifecycle.LiveData import androidx.lifecycle.Observer -import androidx.paging.LivePagedListBuilder -import androidx.paging.PagedList import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.App import io.legado.app.R import io.legado.app.base.BaseFragment -import io.legado.app.data.entities.BookSource import io.legado.app.lib.theme.ATH import io.legado.app.ui.explore.ExploreShowActivity import io.legado.app.utils.startActivity @@ -22,7 +18,6 @@ class FindBookFragment : BaseFragment(R.layout.fragment_find_book), FindBookAdapter.CallBack { private lateinit var adapter: FindBookAdapter - private var findLiveData: LiveData>? = null override fun onViewCreated(view: View, savedInstanceState: Bundle?) { setSupportToolbar(toolbar) @@ -37,14 +32,14 @@ class FindBookFragment : BaseFragment(R.layout.fragment_find_book), private fun initRecyclerView() { ATH.applyEdgeEffectColor(rv_find) rv_find.layoutManager = LinearLayoutManager(context) - adapter = FindBookAdapter(this, this) + adapter = FindBookAdapter(requireContext(), this, this) rv_find.adapter = adapter } private fun initData() { - findLiveData?.removeObservers(viewLifecycleOwner) - findLiveData = LivePagedListBuilder(App.db.bookSourceDao().observeFind(), 2000).build() - findLiveData?.observe(viewLifecycleOwner, Observer { adapter.submitList(it) }) + App.db.bookSourceDao().liveExplore().observe(viewLifecycleOwner, Observer { + adapter.setItems(it) + }) } override fun scrollTo(pos: Int) { diff --git a/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt b/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt deleted file mode 100644 index e85f451a9..000000000 --- a/app/src/main/java/io/legado/app/ui/main/findbook/FindBookAdapter.kt +++ /dev/null @@ -1,114 +0,0 @@ -package io.legado.app.ui.main.findbook - -import android.graphics.drawable.GradientDrawable -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.GridLayout -import androidx.paging.PagedListAdapter -import androidx.recyclerview.widget.DiffUtil -import androidx.recyclerview.widget.RecyclerView -import io.legado.app.R -import io.legado.app.data.entities.BookSource -import io.legado.app.help.coroutine.Coroutine -import io.legado.app.lib.theme.ColorUtils -import io.legado.app.utils.gone -import io.legado.app.utils.visible -import kotlinx.android.synthetic.main.item_find_book.view.* -import kotlinx.android.synthetic.main.item_text.view.* -import kotlinx.coroutines.CoroutineScope -import org.jetbrains.anko.sdk27.listeners.onClick - - -class FindBookAdapter(private val scope: CoroutineScope, val callBack: CallBack) : - PagedListAdapter(DIFF_CALLBACK) { - - var exIndex = 0 - - companion object { - var DIFF_CALLBACK = object : DiffUtil.ItemCallback() { - override fun areItemsTheSame(oldItem: BookSource, newItem: BookSource): Boolean = - oldItem.bookSourceUrl == newItem.bookSourceUrl - - override fun areContentsTheSame(oldItem: BookSource, newItem: BookSource): Boolean = - oldItem.bookSourceUrl == newItem.bookSourceUrl - && oldItem.bookSourceName == newItem.bookSourceName - } - } - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { - return MyViewHolder( - LayoutInflater.from(parent.context) - .inflate(R.layout.item_find_book, parent, false) - ) - } - - override fun onBindViewHolder(holder: MyViewHolder, position: Int): Unit = - with(holder.itemView) { - currentList?.get(position)?.let { bookSource -> - val bgShape: GradientDrawable? = tv_name.background as? GradientDrawable - bgShape?.setStroke(2, ColorUtils.getRandomColor()) - tv_name.text = bookSource.bookSourceName - ll_title.onClick { - val oldEx = exIndex - if (exIndex == position) { - exIndex = -1 - } else { - exIndex = position - notifyItemChanged(position) - } - notifyItemChanged(oldEx) - callBack.scrollTo(position) - } - if (exIndex == position) { - rotate_loading.show() - Coroutine.async(scope) { - bookSource.getExploreRule().getExploreKinds(bookSource.bookSourceUrl) - }.onSuccess { - it?.let { - gl_child.visible() - var rowNum = 0 - var columnNum = 0 - gl_child.removeAllViews() - it.map { kind -> - val tv = LayoutInflater.from(context) - .inflate(R.layout.item_text, gl_child, false) - tv.text_view.text = kind.title - tv.text_view.onClick { - callBack.openExplore( - bookSource.bookSourceUrl, - kind.title, - kind.url - ) - } - val rowSpecs = GridLayout.spec(rowNum, 1.0f) - val colSpecs = GridLayout.spec(columnNum, 1.0f) - val params = GridLayout.LayoutParams(rowSpecs, colSpecs) - gl_child.addView(tv, params) - if (columnNum < 2) { - columnNum++ - } else { - columnNum = 0 - rowNum++ - } - } - } - }.onFinally { - rotate_loading.hide() - } - } else { - rotate_loading.hide() - gl_child.gone() - } - } - } - - class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) - - interface CallBack { - - fun scrollTo(pos: Int) - - fun openExplore(sourceUrl: String, title: String, exploreUrl: String) - } -} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/replacerule/GroupManageDialog.kt b/app/src/main/java/io/legado/app/ui/replacerule/GroupManageDialog.kt index fc6886bf8..03e76b6c6 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/GroupManageDialog.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/GroupManageDialog.kt @@ -70,7 +70,7 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { DividerItemDecoration(requireContext(), RecyclerView.VERTICAL) ) recycler_view.adapter = adapter - App.db.bookSourceDao().observeGroup().observe(viewLifecycleOwner, Observer { + App.db.bookSourceDao().liveGroup().observe(viewLifecycleOwner, Observer { val groups = linkedSetOf() it.map { group -> groups.addAll(group.splitNotBlank(",", ";")) From a692416bbf413b9c72c2c5ce6955a69585137d83 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 5 Sep 2019 08:25:49 +0800 Subject: [PATCH 1293/1997] up --- .../app/ui/main/explore/FindBookAdapter.kt | 28 +++++++++---------- app/src/main/res/layout/item_find_book.xml | 4 +-- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/main/explore/FindBookAdapter.kt b/app/src/main/java/io/legado/app/ui/main/explore/FindBookAdapter.kt index 0148b88f9..6af95b0f8 100644 --- a/app/src/main/java/io/legado/app/ui/main/explore/FindBookAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/explore/FindBookAdapter.kt @@ -1,7 +1,6 @@ package io.legado.app.ui.main.explore import android.content.Context -import android.graphics.drawable.GradientDrawable import android.view.LayoutInflater import android.widget.GridLayout import io.legado.app.R @@ -9,7 +8,6 @@ import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.data.entities.BookSource import io.legado.app.help.coroutine.Coroutine -import io.legado.app.lib.theme.ColorUtils import io.legado.app.lib.theme.accentColor import io.legado.app.utils.gone import io.legado.app.utils.visible @@ -26,21 +24,22 @@ class FindBookAdapter(context: Context, private val scope: CoroutineScope, val c override fun convert(holder: ItemViewHolder, item: BookSource, payloads: MutableList) { with(holder.itemView) { - val bgShape: GradientDrawable? = tv_name.background as? GradientDrawable - bgShape?.setStroke(2, ColorUtils.getRandomColor()) - tv_name.text = item.bookSourceName - ll_title.onClick { - val oldEx = exIndex - if (exIndex == holder.layoutPosition) { - exIndex = -1 - } else { - exIndex = holder.layoutPosition - notifyItemChanged(holder.layoutPosition) + if (payloads.isEmpty()) { + tv_name.text = item.bookSourceName + ll_title.onClick { + val oldEx = exIndex + if (exIndex == holder.layoutPosition) { + exIndex = -1 + } else { + exIndex = holder.layoutPosition + notifyItemChanged(holder.layoutPosition, false) + } + notifyItemChanged(oldEx, false) + callBack.scrollTo(holder.layoutPosition) } - notifyItemChanged(oldEx) - callBack.scrollTo(holder.layoutPosition) } if (exIndex == holder.layoutPosition) { + iv_status.setImageResource(R.drawable.ic_remove) rotate_loading.loadingColor = context.accentColor rotate_loading.show() Coroutine.async(scope) { @@ -78,6 +77,7 @@ class FindBookAdapter(context: Context, private val scope: CoroutineScope, val c rotate_loading.hide() } } else { + iv_status.setImageResource(R.drawable.ic_add) rotate_loading.hide() gl_child.gone() } diff --git a/app/src/main/res/layout/item_find_book.xml b/app/src/main/res/layout/item_find_book.xml index eef807484..9fa766c19 100644 --- a/app/src/main/res/layout/item_find_book.xml +++ b/app/src/main/res/layout/item_find_book.xml @@ -32,8 +32,8 @@ From 4a34a78816d20952e3ec126123fff26694b609b7 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 5 Sep 2019 08:57:41 +0800 Subject: [PATCH 1294/1997] up --- .../io/legado/app/data/dao/BookSourceDao.kt | 2 +- .../io/legado/app/data/entities/BookSource.kt | 73 ++++++++++++++----- .../app/data/entities/rule/ExploreRule.kt | 43 +---------- .../app/data/entities/rule/SearchRule.kt | 1 - .../io/legado/app/help/storage/Restore.kt | 7 +- .../main/java/io/legado/app/model/WebBook.kt | 2 +- .../app/ui/main/explore/FindBookAdapter.kt | 2 +- .../app/ui/sourceedit/SourceEditActivity.kt | 20 ++++- 8 files changed, 81 insertions(+), 69 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt index 920be8a00..a8d13edaa 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt @@ -14,7 +14,7 @@ interface BookSourceDao { @Query("select * from book_sources where bookSourceName like :searchKey or `bookSourceGroup` like :searchKey or bookSourceUrl like :searchKey order by customOrder asc") fun observeSearch(searchKey: String = ""): DataSource.Factory - @Query("select * from book_sources where enabledExplore = 1 order by customOrder asc") + @Query("select * from book_sources where enabledExplore = 1 and exploreUrl is not null order by customOrder asc") fun liveExplore(): LiveData> @Query("select bookSourceGroup from book_sources") diff --git a/app/src/main/java/io/legado/app/data/entities/BookSource.kt b/app/src/main/java/io/legado/app/data/entities/BookSource.kt index 27d16566e..b972cefe8 100644 --- a/app/src/main/java/io/legado/app/data/entities/BookSource.kt +++ b/app/src/main/java/io/legado/app/data/entities/BookSource.kt @@ -6,14 +6,17 @@ import androidx.room.Ignore import androidx.room.Index import androidx.room.PrimaryKey import io.legado.app.App +import io.legado.app.constant.AppConst import io.legado.app.constant.AppConst.userAgent import io.legado.app.data.entities.rule.* +import io.legado.app.help.JsExtensions import io.legado.app.utils.GSON import io.legado.app.utils.fromJsonObject import io.legado.app.utils.getPrefString import kotlinx.android.parcel.IgnoredOnParcel import kotlinx.android.parcel.Parcelize import java.util.* +import javax.script.SimpleBindings @Parcelize @Entity( @@ -21,24 +24,26 @@ import java.util.* indices = [(Index(value = ["bookSourceUrl"], unique = false))] ) data class BookSource( - var bookSourceName: String = "", // 名称 - var bookSourceGroup: String? = null, // 分组 - @PrimaryKey + var bookSourceName: String = "", // 名称 + var bookSourceGroup: String? = null, // 分组 + @PrimaryKey var bookSourceUrl: String = "", // 地址,包括 http/https - var bookSourceType: Int = 0, // 类型,0 文本,1 音频 - var bookUrlPattern: String? = null, - var customOrder: Int = 0, // 手动排序编号 - var enabled: Boolean = true, // 是否启用 - var enabledExplore: Boolean = true, //启用发现 - var header: String? = null, // header - var loginUrl: String? = null, // 登录地址 - var lastUpdateTime: Long = 0, // 最后更新时间,用于排序 - var weight: Int = 0, // 智能排序的权重 - var ruleExplore: String? = null, // 发现规则 - var ruleSearch: String? = null, // 搜索规则 - var ruleBookInfo: String? = null, // 书籍信息页规则 - var ruleToc: String? = null, // 目录页规则 - var ruleContent: String? = null // 正文页规则 + var bookSourceType: Int = 0, // 类型,0 文本,1 音频 + var bookUrlPattern: String? = null, + var customOrder: Int = 0, // 手动排序编号 + var enabled: Boolean = true, // 是否启用 + var enabledExplore: Boolean = true, //启用发现 + var header: String? = null, // header + var loginUrl: String? = null, // 登录地址 + var lastUpdateTime: Long = 0, // 最后更新时间,用于排序 + var weight: Int = 0, // 智能排序的权重 + var exploreUrl: String? = null, //发现url + var ruleExplore: String? = null, // 发现规则 + var searchUrl: String? = null, //搜索url + var ruleSearch: String? = null, // 搜索规则 + var ruleBookInfo: String? = null, // 书籍信息页规则 + var ruleToc: String? = null, // 目录页规则 + var ruleContent: String? = null // 正文页规则 ) : Parcelable { @Ignore @IgnoredOnParcel @@ -112,4 +117,38 @@ data class BookSource( return contentRuleV!! } + fun getExploreKinds(): ArrayList? { + exploreUrl?.let { + var a = it + if (a.isNotBlank()) { + try { + if (it.startsWith("", false)) { + val bindings = SimpleBindings() + bindings["baseUrl"] = bookSourceUrl + bindings["java"] = JsExtensions() + a = AppConst.SCRIPT_ENGINE.eval( + a.substring(4, a.lastIndexOf("<")), + bindings + ).toString() + } + val exploreKinds = arrayListOf() + val b = a.split("(&&|\n)+".toRegex()) + b.map { c -> + val d = c.split("::") + if (d.size > 1) + exploreKinds.add(ExploreKind(d[0], d[1])) + } + return exploreKinds + } catch (e: Exception) { + e.printStackTrace() + } + } + } + return null + } + + data class ExploreKind( + var title: String, + var url: String + ) } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/data/entities/rule/ExploreRule.kt b/app/src/main/java/io/legado/app/data/entities/rule/ExploreRule.kt index a20bb60ab..22b267ed3 100644 --- a/app/src/main/java/io/legado/app/data/entities/rule/ExploreRule.kt +++ b/app/src/main/java/io/legado/app/data/entities/rule/ExploreRule.kt @@ -1,11 +1,6 @@ package io.legado.app.data.entities.rule -import io.legado.app.constant.AppConst -import io.legado.app.help.JsExtensions -import javax.script.SimpleBindings - data class ExploreRule( - var exploreUrl: String? = null, override var bookList: String? = null, override var name: String? = null, override var author: String? = null, @@ -16,40 +11,4 @@ data class ExploreRule( override var bookUrl: String? = null, override var coverUrl: String? = null, override var wordCount: String? = null -) : BookListRule { - - fun getExploreKinds(baseUrl: String): ArrayList? { - exploreUrl?.let { - var a = it - if (a.isNotBlank()) { - try { - if (it.startsWith("", false)) { - val bindings = SimpleBindings() - bindings["baseUrl"] = baseUrl - bindings["java"] = JsExtensions() - a = AppConst.SCRIPT_ENGINE.eval( - a.substring(4, a.lastIndexOf("<")), - bindings - ).toString() - } - val exploreKinds = arrayListOf() - val b = a.split("(&&|\n)+".toRegex()) - b.map { c -> - val d = c.split("::") - if (d.size > 1) - exploreKinds.add(ExploreKind(d[0], d[1])) - } - return exploreKinds - } catch (e: Exception) { - e.printStackTrace() - } - } - } - return null - } - - data class ExploreKind( - var title: String, - var url: String - ) -} \ No newline at end of file +) : BookListRule \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/data/entities/rule/SearchRule.kt b/app/src/main/java/io/legado/app/data/entities/rule/SearchRule.kt index bef943962..83921e56d 100644 --- a/app/src/main/java/io/legado/app/data/entities/rule/SearchRule.kt +++ b/app/src/main/java/io/legado/app/data/entities/rule/SearchRule.kt @@ -1,7 +1,6 @@ package io.legado.app.data.entities.rule data class SearchRule( - var searchUrl: String? = null, override var bookList: String? = null, override var name: String? = null, override var author: String? = null, diff --git a/app/src/main/java/io/legado/app/help/storage/Restore.kt b/app/src/main/java/io/legado/app/help/storage/Restore.kt index 35f5ef0e1..0ae35a208 100644 --- a/app/src/main/java/io/legado/app/help/storage/Restore.kt +++ b/app/src/main/java/io/legado/app/help/storage/Restore.kt @@ -110,8 +110,12 @@ object Restore { source.bookUrlPattern = jsonItem.readString("ruleBookUrlPattern") source.customOrder = jsonItem.readInt("serialNumber") ?: 0 source.header = OldRule.uaToHeader(jsonItem.readString("httpUserAgent")) + source.searchUrl = OldRule.toNewUrl(jsonItem.readString("ruleSearchUrl")) + source.exploreUrl = OldRule.toNewUrl(jsonItem.readString("ruleFindUrl")) + if (source.exploreUrl.isNullOrBlank()) { + source.enabledExplore = false + } val searchRule = SearchRule( - searchUrl = OldRule.toNewUrl(jsonItem.readString("ruleSearchUrl")), bookList = jsonItem.readString("ruleSearchList"), name = jsonItem.readString("ruleSearchName"), author = jsonItem.readString("ruleSearchAuthor"), @@ -123,7 +127,6 @@ object Restore { ) source.ruleSearch = GSON.toJson(searchRule) val exploreRule = ExploreRule( - exploreUrl = OldRule.toNewUrl(jsonItem.readString("ruleFindUrl")), bookList = jsonItem.readString("ruleFindList"), name = jsonItem.readString("ruleFindName"), author = jsonItem.readString("ruleFindAuthor"), diff --git a/app/src/main/java/io/legado/app/model/WebBook.kt b/app/src/main/java/io/legado/app/model/WebBook.kt index 0e460edba..6e00a80bc 100644 --- a/app/src/main/java/io/legado/app/model/WebBook.kt +++ b/app/src/main/java/io/legado/app/model/WebBook.kt @@ -23,7 +23,7 @@ class WebBook(val bookSource: BookSource) { fun searchBook(key: String, page: Int? = 1, scope: CoroutineScope = Coroutine.DEFAULT) : Coroutine> { return Coroutine.async(scope) { - bookSource.getSearchRule().searchUrl?.let { searchUrl -> + bookSource.searchUrl?.let { searchUrl -> val analyzeUrl = AnalyzeUrl( ruleUrl = searchUrl, key = key, diff --git a/app/src/main/java/io/legado/app/ui/main/explore/FindBookAdapter.kt b/app/src/main/java/io/legado/app/ui/main/explore/FindBookAdapter.kt index 6af95b0f8..2b04d0d5b 100644 --- a/app/src/main/java/io/legado/app/ui/main/explore/FindBookAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/explore/FindBookAdapter.kt @@ -43,7 +43,7 @@ class FindBookAdapter(context: Context, private val scope: CoroutineScope, val c rotate_loading.loadingColor = context.accentColor rotate_loading.show() Coroutine.async(scope) { - item.getExploreRule().getExploreKinds(item.bookSourceUrl) + item.getExploreKinds() }.onSuccess { it?.let { gl_child.visible() diff --git a/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditActivity.kt index 6ae96411f..c915b139a 100644 --- a/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditActivity.kt @@ -140,7 +140,13 @@ class SourceEditActivity : VMBaseActivity(R.layout.activity //搜索 with(bookSource?.getSearchRule()) { searchEditList.clear() - searchEditList.add(EditEntity("searchUrl", this?.searchUrl, R.string.rule_search_url)) + searchEditList.add( + EditEntity( + "searchUrl", + bookSource?.searchUrl, + R.string.rule_search_url + ) + ) searchEditList.add(EditEntity("bookList", this?.bookList, R.string.rule_book_list)) searchEditList.add(EditEntity("name", this?.name, R.string.rule_book_name)) searchEditList.add(EditEntity("author", this?.author, R.string.rule_book_author)) @@ -182,7 +188,13 @@ class SourceEditActivity : VMBaseActivity(R.layout.activity //发现 with(bookSource?.getExploreRule()) { findEditList.clear() - findEditList.add(EditEntity("exploreUrl", this?.exploreUrl, R.string.rule_find_url)) + findEditList.add( + EditEntity( + "exploreUrl", + bookSource?.exploreUrl, + R.string.rule_find_url + ) + ) findEditList.add(EditEntity("bookList", this?.bookList, R.string.rule_book_list)) findEditList.add(EditEntity("name", this?.name, R.string.rule_book_name)) findEditList.add(EditEntity("author", this?.author, R.string.rule_book_author)) @@ -224,7 +236,7 @@ class SourceEditActivity : VMBaseActivity(R.layout.activity for (entity in searchEditList) { with(entity) { when (key) { - "searchUrl" -> searchRule.searchUrl = value + "searchUrl" -> source.searchUrl = value "bookList" -> searchRule.bookList = value "name" -> searchRule.name = value "author" -> searchRule.author = value @@ -241,7 +253,7 @@ class SourceEditActivity : VMBaseActivity(R.layout.activity for (entity in findEditList) { with(entity) { when (key) { - "exploreUrl" -> exploreRule.exploreUrl = value + "exploreUrl" -> source.exploreUrl = value "bookList" -> exploreRule.bookList = value "name" -> exploreRule.name = value "author" -> exploreRule.author = value From b58d9de2242c9cd195272d235e92af983a8f705e Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 5 Sep 2019 09:12:40 +0800 Subject: [PATCH 1295/1997] up --- .../java/io/legado/app/ui/main/explore/FindBookAdapter.kt | 8 +++----- .../io/legado/app/ui/main/explore/FindBookFragment.kt | 4 +++- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/main/explore/FindBookAdapter.kt b/app/src/main/java/io/legado/app/ui/main/explore/FindBookAdapter.kt index 2b04d0d5b..06bc23c1b 100644 --- a/app/src/main/java/io/legado/app/ui/main/explore/FindBookAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/explore/FindBookAdapter.kt @@ -28,13 +28,11 @@ class FindBookAdapter(context: Context, private val scope: CoroutineScope, val c tv_name.text = item.bookSourceName ll_title.onClick { val oldEx = exIndex - if (exIndex == holder.layoutPosition) { - exIndex = -1 - } else { - exIndex = holder.layoutPosition + exIndex = if (exIndex == holder.layoutPosition) -1 else holder.layoutPosition + notifyItemChanged(oldEx, false) + if (exIndex != -1) { notifyItemChanged(holder.layoutPosition, false) } - notifyItemChanged(oldEx, false) callBack.scrollTo(holder.layoutPosition) } } diff --git a/app/src/main/java/io/legado/app/ui/main/explore/FindBookFragment.kt b/app/src/main/java/io/legado/app/ui/main/explore/FindBookFragment.kt index 76ed36885..4268bb719 100644 --- a/app/src/main/java/io/legado/app/ui/main/explore/FindBookFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/explore/FindBookFragment.kt @@ -18,6 +18,7 @@ class FindBookFragment : BaseFragment(R.layout.fragment_find_book), FindBookAdapter.CallBack { private lateinit var adapter: FindBookAdapter + private lateinit var linearLayoutManager: LinearLayoutManager override fun onViewCreated(view: View, savedInstanceState: Bundle?) { setSupportToolbar(toolbar) @@ -31,7 +32,8 @@ class FindBookFragment : BaseFragment(R.layout.fragment_find_book), private fun initRecyclerView() { ATH.applyEdgeEffectColor(rv_find) - rv_find.layoutManager = LinearLayoutManager(context) + linearLayoutManager = LinearLayoutManager(context) + rv_find.layoutManager = linearLayoutManager adapter = FindBookAdapter(requireContext(), this, this) rv_find.adapter = adapter } From fd054211f5c0f76024f2b218160bce1a43897410 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 5 Sep 2019 09:24:44 +0800 Subject: [PATCH 1296/1997] up --- .../app/ui/main/explore/FindBookAdapter.kt | 16 ++++++++++++++++ .../app/ui/main/explore/FindBookFragment.kt | 5 +++++ 2 files changed, 21 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/main/explore/FindBookAdapter.kt b/app/src/main/java/io/legado/app/ui/main/explore/FindBookAdapter.kt index 06bc23c1b..c43c4bf6e 100644 --- a/app/src/main/java/io/legado/app/ui/main/explore/FindBookAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/explore/FindBookAdapter.kt @@ -2,7 +2,9 @@ package io.legado.app.ui.main.explore import android.content.Context import android.view.LayoutInflater +import android.view.Menu import android.widget.GridLayout +import android.widget.PopupMenu import io.legado.app.R import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter @@ -15,6 +17,7 @@ import kotlinx.android.synthetic.main.item_find_book.view.* import kotlinx.android.synthetic.main.item_text.view.* import kotlinx.coroutines.CoroutineScope import org.jetbrains.anko.sdk27.listeners.onClick +import org.jetbrains.anko.sdk27.listeners.onLongClick class FindBookAdapter(context: Context, private val scope: CoroutineScope, val callBack: CallBack) : @@ -35,6 +38,18 @@ class FindBookAdapter(context: Context, private val scope: CoroutineScope, val c } callBack.scrollTo(holder.layoutPosition) } + ll_title.onLongClick { + val popupMenu = PopupMenu(context, ll_title) + popupMenu.menu.add(Menu.NONE, R.id.menu_edit, Menu.NONE, R.string.edit) + popupMenu.setOnMenuItemClickListener { + when (it.itemId) { + R.id.menu_edit -> callBack.editSource(item.bookSourceUrl) + } + true + } + popupMenu.show() + true + } } if (exIndex == holder.layoutPosition) { iv_status.setImageResource(R.drawable.ic_remove) @@ -85,5 +100,6 @@ class FindBookAdapter(context: Context, private val scope: CoroutineScope, val c interface CallBack { fun scrollTo(pos: Int) fun openExplore(sourceUrl: String, title: String, exploreUrl: String) + fun editSource(sourceUrl: String) } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/explore/FindBookFragment.kt b/app/src/main/java/io/legado/app/ui/main/explore/FindBookFragment.kt index 4268bb719..cb456d3ff 100644 --- a/app/src/main/java/io/legado/app/ui/main/explore/FindBookFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/explore/FindBookFragment.kt @@ -10,6 +10,7 @@ import io.legado.app.R import io.legado.app.base.BaseFragment import io.legado.app.lib.theme.ATH import io.legado.app.ui.explore.ExploreShowActivity +import io.legado.app.ui.sourceedit.SourceEditActivity import io.legado.app.utils.startActivity import kotlinx.android.synthetic.main.fragment_find_book.* import kotlinx.android.synthetic.main.view_title_bar.* @@ -55,4 +56,8 @@ class FindBookFragment : BaseFragment(R.layout.fragment_find_book), Pair("exploreUrl", exploreUrl) ) } + + override fun editSource(sourceUrl: String) { + startActivity(Pair("data", sourceUrl)) + } } \ No newline at end of file From ed5a83e8601bb6ae94f7f7abb507beb4f671726d Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 5 Sep 2019 10:21:21 +0800 Subject: [PATCH 1297/1997] up --- .../app/ui/main/explore/FindBookAdapter.kt | 14 +------- app/src/main/res/layout/item_find_book.xml | 11 +++++-- app/src/main/res/layout/item_text.xml | 32 ++++++++----------- 3 files changed, 22 insertions(+), 35 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/main/explore/FindBookAdapter.kt b/app/src/main/java/io/legado/app/ui/main/explore/FindBookAdapter.kt index c43c4bf6e..20c625bfa 100644 --- a/app/src/main/java/io/legado/app/ui/main/explore/FindBookAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/explore/FindBookAdapter.kt @@ -3,7 +3,6 @@ package io.legado.app.ui.main.explore import android.content.Context import android.view.LayoutInflater import android.view.Menu -import android.widget.GridLayout import android.widget.PopupMenu import io.legado.app.R import io.legado.app.base.adapter.ItemViewHolder @@ -60,8 +59,6 @@ class FindBookAdapter(context: Context, private val scope: CoroutineScope, val c }.onSuccess { it?.let { gl_child.visible() - var rowNum = 0 - var columnNum = 0 gl_child.removeAllViews() it.map { kind -> val tv = LayoutInflater.from(context) @@ -74,16 +71,7 @@ class FindBookAdapter(context: Context, private val scope: CoroutineScope, val c kind.url ) } - val rowSpecs = GridLayout.spec(rowNum, 1.0f) - val colSpecs = GridLayout.spec(columnNum, 1.0f) - val params = GridLayout.LayoutParams(rowSpecs, colSpecs) - gl_child.addView(tv, params) - if (columnNum < 2) { - columnNum++ - } else { - columnNum = 0 - rowNum++ - } + gl_child.addView(tv) } } }.onFinally { diff --git a/app/src/main/res/layout/item_find_book.xml b/app/src/main/res/layout/item_find_book.xml index 9fa766c19..e5911c942 100644 --- a/app/src/main/res/layout/item_find_book.xml +++ b/app/src/main/res/layout/item_find_book.xml @@ -40,13 +40,18 @@ - + android:visibility="gone" + app:dividerDrawable="@drawable/shape_space_divider" + app:flexDirection="row" + app:flexWrap="wrap" + app:showDivider="middle" /> - - - - - + android:layout_margin="3dp" + android:background="@drawable/shape_card_view" + android:clickable="true" + android:ellipsize="end" + android:focusable="true" + android:gravity="center" + android:padding="5dp" + android:singleLine="true" + android:textColor="@color/tv_text_default" + android:textSize="14sp" /> From 065cbfc447501739540c6918b3d9761da3f9994f Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 5 Sep 2019 10:23:44 +0800 Subject: [PATCH 1298/1997] up --- .../main/java/io/legado/app/ui/main/explore/FindBookFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/main/explore/FindBookFragment.kt b/app/src/main/java/io/legado/app/ui/main/explore/FindBookFragment.kt index cb456d3ff..66ed92289 100644 --- a/app/src/main/java/io/legado/app/ui/main/explore/FindBookFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/explore/FindBookFragment.kt @@ -46,7 +46,7 @@ class FindBookFragment : BaseFragment(R.layout.fragment_find_book), } override fun scrollTo(pos: Int) { - rv_find.scrollToPosition(pos) + rv_find.smoothScrollToPosition(pos) } override fun openExplore(sourceUrl: String, title: String, exploreUrl: String) { From 4a1c9a2cad3e12d50db1b81d2c64e1f46fecaf0d Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 5 Sep 2019 10:26:19 +0800 Subject: [PATCH 1299/1997] up --- app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt index a8d13edaa..7d47afa6f 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt @@ -14,7 +14,7 @@ interface BookSourceDao { @Query("select * from book_sources where bookSourceName like :searchKey or `bookSourceGroup` like :searchKey or bookSourceUrl like :searchKey order by customOrder asc") fun observeSearch(searchKey: String = ""): DataSource.Factory - @Query("select * from book_sources where enabledExplore = 1 and exploreUrl is not null order by customOrder asc") + @Query("select * from book_sources where enabledExplore = 1 and exploreUrl is not null and exploreUrl <> '' order by customOrder asc") fun liveExplore(): LiveData> @Query("select bookSourceGroup from book_sources") From 76bd70d23a476c66a90faa36eedbf81390fa2b28 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 5 Sep 2019 10:32:29 +0800 Subject: [PATCH 1300/1997] up --- app/src/main/res/layout/item_find_book.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/res/layout/item_find_book.xml b/app/src/main/res/layout/item_find_book.xml index e5911c942..4cb1f620a 100644 --- a/app/src/main/res/layout/item_find_book.xml +++ b/app/src/main/res/layout/item_find_book.xml @@ -13,11 +13,11 @@ android:id="@+id/ll_title" android:layout_width="match_parent" android:layout_height="wrap_content" - android:paddingLeft="6dp" - android:paddingRight="6dp" - android:paddingTop="3dp" - android:paddingBottom="3dp" - android:layout_margin="3dp" + android:paddingLeft="10dp" + android:paddingRight="10dp" + android:paddingTop="6dp" + android:paddingBottom="6dp" + android:layout_margin="4dp" android:background="@color/background" android:elevation="3dp" android:orientation="horizontal" From 44f5b600e3191316e76e5d4c501ec079df17943a Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 5 Sep 2019 11:07:00 +0800 Subject: [PATCH 1301/1997] up --- app/src/main/res/menu/find_book.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/menu/find_book.xml b/app/src/main/res/menu/find_book.xml index 49e83ef13..72f4f570a 100644 --- a/app/src/main/res/menu/find_book.xml +++ b/app/src/main/res/menu/find_book.xml @@ -3,9 +3,9 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> + android:id="@+id/menu_search" + android:title="@string/search" + app:showAsAction="always" /> From 3cb9754052fd46c2f39baede92a57e52a7931ff8 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 5 Sep 2019 11:18:06 +0800 Subject: [PATCH 1302/1997] up --- app/src/main/res/layout/item_find_book.xml | 42 +++++++++++++--------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/app/src/main/res/layout/item_find_book.xml b/app/src/main/res/layout/item_find_book.xml index 4cb1f620a..6a2b53f3a 100644 --- a/app/src/main/res/layout/item_find_book.xml +++ b/app/src/main/res/layout/item_find_book.xml @@ -40,24 +40,32 @@ - - - + android:layout_gravity="center"> + + + + + + \ No newline at end of file From 3a2adca2536e6879aae9abd54c22038a92af33f4 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 5 Sep 2019 11:25:31 +0800 Subject: [PATCH 1303/1997] up --- app/src/main/assets/readConfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/assets/readConfig.json b/app/src/main/assets/readConfig.json index 2dc96caa8..21cea9f69 100644 --- a/app/src/main/assets/readConfig.json +++ b/app/src/main/assets/readConfig.json @@ -43,7 +43,7 @@ }, { "bgStr": "宁静夜色", - "bgType": 0, + "bgType": 1, "darkStatusIcon": false, "textColor": "#adadad", "textSize": 22, From c874c6e816b7741a3ac12dcfe8e00b25ee873004 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 5 Sep 2019 14:01:46 +0800 Subject: [PATCH 1304/1997] up --- .../io/legado/app/help/storage/OldRule.kt | 84 ++++++++++++++++++- .../io/legado/app/help/storage/Restore.kt | 71 +--------------- .../app/ui/booksource/BookSourceActivity.kt | 2 + 3 files changed, 88 insertions(+), 69 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/storage/OldRule.kt b/app/src/main/java/io/legado/app/help/storage/OldRule.kt index 361fd1402..df2a389cc 100644 --- a/app/src/main/java/io/legado/app/help/storage/OldRule.kt +++ b/app/src/main/java/io/legado/app/help/storage/OldRule.kt @@ -1,13 +1,92 @@ package io.legado.app.help.storage +import com.jayway.jsonpath.JsonPath +import io.legado.app.data.entities.BookSource +import io.legado.app.data.entities.rule.* import io.legado.app.utils.GSON +import io.legado.app.utils.fromJsonObject +import io.legado.app.utils.readInt +import io.legado.app.utils.readString import java.util.regex.Pattern object OldRule { private val headerPattern = Pattern.compile("@Header:\\{.+?\\}", Pattern.CASE_INSENSITIVE) private val jsPattern = Pattern.compile("\\{\\{.+?\\}\\}", Pattern.CASE_INSENSITIVE) - fun toNewUrl(oldUrl: String?): String? { + + fun jsonToBookSource(json: String): BookSource? { + var source: BookSource? = null + runCatching { + source = GSON.fromJsonObject(json) + } + runCatching { + source ?: let { + source = BookSource().apply { + val jsonItem = JsonPath.parse(json) + bookSourceUrl = jsonItem.readString("bookSourceUrl") ?: "" + bookSourceName = jsonItem.readString("bookSourceName") ?: "" + bookSourceGroup = jsonItem.readString("bookSourceGroup") ?: "" + loginUrl = jsonItem.readString("loginUrl") + bookUrlPattern = jsonItem.readString("ruleBookUrlPattern") + customOrder = jsonItem.readInt("serialNumber") ?: 0 + header = uaToHeader(jsonItem.readString("httpUserAgent")) + searchUrl = toNewUrl(jsonItem.readString("ruleSearchUrl")) + exploreUrl = toNewUrl(jsonItem.readString("ruleFindUrl")) + if (exploreUrl.isNullOrBlank()) { + enabledExplore = false + } + val searchRule = SearchRule( + bookList = jsonItem.readString("ruleSearchList"), + name = jsonItem.readString("ruleSearchName"), + author = jsonItem.readString("ruleSearchAuthor"), + intro = jsonItem.readString("ruleSearchIntroduce"), + kind = jsonItem.readString("ruleSearchKind"), + bookUrl = jsonItem.readString("ruleSearchNoteUrl"), + coverUrl = jsonItem.readString("ruleSearchCoverUrl"), + lastChapter = jsonItem.readString("ruleSearchLastChapter") + ) + ruleSearch = GSON.toJson(searchRule) + val exploreRule = ExploreRule( + bookList = jsonItem.readString("ruleFindList"), + name = jsonItem.readString("ruleFindName"), + author = jsonItem.readString("ruleFindAuthor"), + intro = jsonItem.readString("ruleFindIntroduce"), + kind = jsonItem.readString("ruleFindKind"), + bookUrl = jsonItem.readString("ruleFindNoteUrl"), + coverUrl = jsonItem.readString("ruleFindCoverUrl"), + lastChapter = jsonItem.readString("ruleFindLastChapter") + ) + ruleExplore = GSON.toJson(exploreRule) + val bookInfoRule = BookInfoRule( + init = jsonItem.readString("ruleBookInfoInit"), + name = jsonItem.readString("ruleBookName"), + author = jsonItem.readString("ruleBookAuthor"), + intro = jsonItem.readString("ruleIntroduce"), + kind = jsonItem.readString("ruleBookKind"), + coverUrl = jsonItem.readString("ruleCoverUrl"), + lastChapter = jsonItem.readString("ruleBookLastChapter"), + tocUrl = jsonItem.readString("ruleChapterUrl") + ) + ruleBookInfo = GSON.toJson(bookInfoRule) + val chapterRule = TocRule( + chapterList = jsonItem.readString("ruleChapterList"), + chapterName = jsonItem.readString("ruleChapterName"), + chapterUrl = jsonItem.readString("ruleContentUrl"), + nextTocUrl = jsonItem.readString("ruleChapterUrlNext") + ) + ruleToc = GSON.toJson(chapterRule) + val contentRule = ContentRule( + content = jsonItem.readString("ruleBookContent"), + nextContentUrl = jsonItem.readString("ruleContentUrlNext") + ) + ruleContent = GSON.toJson(contentRule) + } + } + } + return source + } + + private fun toNewUrl(oldUrl: String?): String? { if (oldUrl == null) return null val map = HashMap() var url: String = oldUrl @@ -46,9 +125,10 @@ object OldRule { return url } - fun uaToHeader(ua: String?): String? { + private fun uaToHeader(ua: String?): String? { if (ua.isNullOrEmpty()) return null val map = mapOf(Pair("user_agent", ua)) return GSON.toJson(map) } + } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/help/storage/Restore.kt b/app/src/main/java/io/legado/app/help/storage/Restore.kt index 0ae35a208..714b751cc 100644 --- a/app/src/main/java/io/legado/app/help/storage/Restore.kt +++ b/app/src/main/java/io/legado/app/help/storage/Restore.kt @@ -10,7 +10,6 @@ import io.legado.app.constant.AppConst import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.ReplaceRule -import io.legado.app.data.entities.rule.* import io.legado.app.utils.* import org.jetbrains.anko.doAsync import org.jetbrains.anko.toast @@ -93,81 +92,19 @@ object Restore { // Book source val sourceFile = File(yuedu, "myBookSource.json") val bookSources = mutableListOf() - if (shelfFile.exists()) try { + if (sourceFile.exists()) try { doAsync { val items: List> = jsonPath.parse(sourceFile.readText()).read("$") - val existingSources = App.db.bookSourceDao().all.map { it.bookSourceUrl }.toSet() for (item in items) { val jsonItem = jsonPath.parse(item) - val source = BookSource() - source.bookSourceUrl = jsonItem.readString("bookSourceUrl") ?: "" - if (source.bookSourceUrl.isBlank()) continue - if (source.bookSourceUrl in existingSources) continue - runCatching { - source.bookSourceName = jsonItem.readString("bookSourceName") ?: "" - source.bookSourceGroup = jsonItem.readString("bookSourceGroup") ?: "" - source.loginUrl = jsonItem.readString("loginUrl") - source.bookUrlPattern = jsonItem.readString("ruleBookUrlPattern") - source.customOrder = jsonItem.readInt("serialNumber") ?: 0 - source.header = OldRule.uaToHeader(jsonItem.readString("httpUserAgent")) - source.searchUrl = OldRule.toNewUrl(jsonItem.readString("ruleSearchUrl")) - source.exploreUrl = OldRule.toNewUrl(jsonItem.readString("ruleFindUrl")) - if (source.exploreUrl.isNullOrBlank()) { - source.enabledExplore = false - } - val searchRule = SearchRule( - bookList = jsonItem.readString("ruleSearchList"), - name = jsonItem.readString("ruleSearchName"), - author = jsonItem.readString("ruleSearchAuthor"), - intro = jsonItem.readString("ruleSearchIntroduce"), - kind = jsonItem.readString("ruleSearchKind"), - bookUrl = jsonItem.readString("ruleSearchNoteUrl"), - coverUrl = jsonItem.readString("ruleSearchCoverUrl"), - lastChapter = jsonItem.readString("ruleSearchLastChapter") - ) - source.ruleSearch = GSON.toJson(searchRule) - val exploreRule = ExploreRule( - bookList = jsonItem.readString("ruleFindList"), - name = jsonItem.readString("ruleFindName"), - author = jsonItem.readString("ruleFindAuthor"), - intro = jsonItem.readString("ruleFindIntroduce"), - kind = jsonItem.readString("ruleFindKind"), - bookUrl = jsonItem.readString("ruleFindNoteUrl"), - coverUrl = jsonItem.readString("ruleFindCoverUrl"), - lastChapter = jsonItem.readString("ruleFindLastChapter") - ) - source.ruleExplore = GSON.toJson(exploreRule) - val bookInfoRule = BookInfoRule( - init = jsonItem.readString("ruleBookInfoInit"), - name = jsonItem.readString("ruleBookName"), - author = jsonItem.readString("ruleBookAuthor"), - intro = jsonItem.readString("ruleIntroduce"), - kind = jsonItem.readString("ruleBookKind"), - coverUrl = jsonItem.readString("ruleCoverUrl"), - lastChapter = jsonItem.readString("ruleBookLastChapter"), - tocUrl = jsonItem.readString("ruleChapterUrl") - ) - source.ruleBookInfo = GSON.toJson(bookInfoRule) - val chapterRule = TocRule( - chapterList = jsonItem.readString("ruleChapterList"), - chapterName = jsonItem.readString("ruleChapterName"), - chapterUrl = jsonItem.readString("ruleContentUrl"), - nextTocUrl = jsonItem.readString("ruleChapterUrlNext") - ) - source.ruleToc = GSON.toJson(chapterRule) - val contentRule = ContentRule( - content = jsonItem.readString("ruleBookContent"), - nextContentUrl = jsonItem.readString("ruleContentUrlNext") - ) - source.ruleContent = GSON.toJson(contentRule) + OldRule.jsonToBookSource(jsonItem.jsonString())?.let { + bookSources.add(it) } - - bookSources.add(source) } App.db.bookSourceDao().insert(*bookSources.toTypedArray()) } } catch (e: Exception) { - error(e.localizedMessage) + e.printStackTrace() } diff --git a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt index 0e815e15b..73646f3ff 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt @@ -18,6 +18,7 @@ import io.legado.app.R import io.legado.app.base.VMBaseActivity import io.legado.app.data.entities.BookSource import io.legado.app.help.ItemTouchCallback +import io.legado.app.help.storage.Restore import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.primaryTextColor import io.legado.app.ui.qrcode.QrCodeActivity @@ -85,6 +86,7 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity supportFragmentManager, "groupManage" ) + R.id.menu_import_book_source_local -> Restore.importYueDuData(this) } if (item.groupId == R.id.source_group) { search_view.setQuery(item.title, true) From e47a8602e702b98e52e921ad93d617b3b9ccee5d Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 5 Sep 2019 15:00:33 +0800 Subject: [PATCH 1305/1997] up --- .../main/java/io/legado/app/help/storage/OldRule.kt | 11 +++++++++-- .../main/java/io/legado/app/help/storage/Restore.kt | 10 +++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/storage/OldRule.kt b/app/src/main/java/io/legado/app/help/storage/OldRule.kt index df2a389cc..52d1deb0e 100644 --- a/app/src/main/java/io/legado/app/help/storage/OldRule.kt +++ b/app/src/main/java/io/legado/app/help/storage/OldRule.kt @@ -1,6 +1,8 @@ package io.legado.app.help.storage +import com.jayway.jsonpath.Configuration import com.jayway.jsonpath.JsonPath +import com.jayway.jsonpath.Option import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.rule.* import io.legado.app.utils.GSON @@ -12,7 +14,11 @@ import java.util.regex.Pattern object OldRule { private val headerPattern = Pattern.compile("@Header:\\{.+?\\}", Pattern.CASE_INSENSITIVE) private val jsPattern = Pattern.compile("\\{\\{.+?\\}\\}", Pattern.CASE_INSENSITIVE) - + private val jsonPath = JsonPath.using( + Configuration.builder() + .options(Option.SUPPRESS_EXCEPTIONS) + .build() + ) fun jsonToBookSource(json: String): BookSource? { var source: BookSource? = null @@ -22,7 +28,7 @@ object OldRule { runCatching { source ?: let { source = BookSource().apply { - val jsonItem = JsonPath.parse(json) + val jsonItem = jsonPath.parse(json) bookSourceUrl = jsonItem.readString("bookSourceUrl") ?: "" bookSourceName = jsonItem.readString("bookSourceName") ?: "" bookSourceGroup = jsonItem.readString("bookSourceGroup") ?: "" @@ -88,6 +94,7 @@ object OldRule { private fun toNewUrl(oldUrl: String?): String? { if (oldUrl == null) return null + if (oldUrl.startsWith("", true)) return oldUrl val map = HashMap() var url: String = oldUrl var mather = headerPattern.matcher(url) diff --git a/app/src/main/java/io/legado/app/help/storage/Restore.kt b/app/src/main/java/io/legado/app/help/storage/Restore.kt index 714b751cc..124e74303 100644 --- a/app/src/main/java/io/legado/app/help/storage/Restore.kt +++ b/app/src/main/java/io/legado/app/help/storage/Restore.kt @@ -17,6 +17,11 @@ import org.jetbrains.anko.uiThread import java.io.File object Restore { + private val jsonPath = JsonPath.using( + Configuration.builder() + .options(Option.SUPPRESS_EXCEPTIONS) + .build() + ) fun restore() { @@ -28,11 +33,6 @@ object Restore { fun importYueDuData(context: Context) { val yuedu = File(FileUtils.getSdPath(), "YueDu") - val jsonPath = JsonPath.using( - Configuration.builder() - .options(Option.SUPPRESS_EXCEPTIONS) - .build() - ) // 导入书架 val shelfFile = File(yuedu, "myBookShelf.json") From 8d85662aa1d3598622e0bb2a710a2982af3329f5 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 5 Sep 2019 16:15:53 +0800 Subject: [PATCH 1306/1997] up --- .../main/java/io/legado/app/help/BookHelp.kt | 10 +++++++--- .../io/legado/app/ui/config/ConfigFragment.kt | 19 ++++++++++++++++--- app/src/main/res/xml/pref_config.xml | 5 +++++ 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/BookHelp.kt b/app/src/main/java/io/legado/app/help/BookHelp.kt index b3ae92f19..d32e4d077 100644 --- a/app/src/main/java/io/legado/app/help/BookHelp.kt +++ b/app/src/main/java/io/legado/app/help/BookHelp.kt @@ -16,12 +16,16 @@ import kotlin.math.min object BookHelp { - private var downloadPath = - App.INSTANCE.getPrefString("downloadPath") ?: App.INSTANCE.getExternalFilesDir(null) + private var downloadPath: String = + App.INSTANCE.getPrefString("downloadPath") + ?: App.INSTANCE.getExternalFilesDir(null)?.absolutePath + ?: App.INSTANCE.cacheDir.absolutePath fun upDownloadPath() { downloadPath = - App.INSTANCE.getPrefString("downloadPath") ?: App.INSTANCE.getExternalFilesDir(null) + App.INSTANCE.getPrefString("downloadPath") + ?: App.INSTANCE.getExternalFilesDir(null)?.absolutePath + ?: App.INSTANCE.cacheDir.absolutePath } fun saveContent(book: Book, bookChapter: BookChapter, content: String) { diff --git a/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt index 2885572ae..c3b0ae799 100644 --- a/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt @@ -6,7 +6,9 @@ import android.view.View import androidx.preference.ListPreference import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat +import io.legado.app.App import io.legado.app.R +import io.legado.app.help.BookHelp import io.legado.app.lib.theme.ATH import io.legado.app.utils.getPrefString @@ -16,6 +18,7 @@ class ConfigFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChange override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { addPreferencesFromResource(R.xml.pref_config) + bindPreferenceSummaryToValue(findPreference("downloadPath")) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -34,8 +37,9 @@ class ConfigFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChange } override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { - - + when (key) { + "downloadPath" -> BookHelp.upDownloadPath() + } } override fun onPreferenceChange(preference: Preference?, newValue: Any?): Boolean { @@ -57,9 +61,18 @@ class ConfigFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChange preference.onPreferenceChangeListener = this onPreferenceChange( preference, - preference.context.getPrefString(preference.key, "") + getPreferenceString(preference.key) ) } } + private fun getPreferenceString(key: String): String { + return when (key) { + "downloadPath" -> getPrefString("downloadPath") + ?: App.INSTANCE.getExternalFilesDir(null)?.absolutePath + ?: App.INSTANCE.cacheDir.absolutePath + else -> getPrefString(key, "") + } + } + } \ No newline at end of file diff --git a/app/src/main/res/xml/pref_config.xml b/app/src/main/res/xml/pref_config.xml index 043eb7cbc..a682044d0 100644 --- a/app/src/main/res/xml/pref_config.xml +++ b/app/src/main/res/xml/pref_config.xml @@ -24,4 +24,9 @@ android:title="文字操作显示搜索" app:iconSpaceReserved="false" /> + + \ No newline at end of file From fd74bcedcf9d12779010c095179e89b53d704d29 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 5 Sep 2019 16:38:28 +0800 Subject: [PATCH 1307/1997] up --- .../io/legado/app/data/entities/BookSource.kt | 9 ++++----- .../app/ui/main/explore/FindBookAdapter.kt | 18 ++++++++++-------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/BookSource.kt b/app/src/main/java/io/legado/app/data/entities/BookSource.kt index b972cefe8..10c420ba0 100644 --- a/app/src/main/java/io/legado/app/data/entities/BookSource.kt +++ b/app/src/main/java/io/legado/app/data/entities/BookSource.kt @@ -118,6 +118,7 @@ data class BookSource( } fun getExploreKinds(): ArrayList? { + val exploreKinds = arrayListOf() exploreUrl?.let { var a = it if (a.isNotBlank()) { @@ -131,24 +132,22 @@ data class BookSource( bindings ).toString() } - val exploreKinds = arrayListOf() val b = a.split("(&&|\n)+".toRegex()) b.map { c -> val d = c.split("::") if (d.size > 1) exploreKinds.add(ExploreKind(d[0], d[1])) } - return exploreKinds } catch (e: Exception) { - e.printStackTrace() + exploreKinds.add(ExploreKind(e.localizedMessage)) } } } - return null + return exploreKinds } data class ExploreKind( var title: String, - var url: String + var url: String? = null ) } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/explore/FindBookAdapter.kt b/app/src/main/java/io/legado/app/ui/main/explore/FindBookAdapter.kt index 20c625bfa..a7f786bfe 100644 --- a/app/src/main/java/io/legado/app/ui/main/explore/FindBookAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/explore/FindBookAdapter.kt @@ -56,20 +56,22 @@ class FindBookAdapter(context: Context, private val scope: CoroutineScope, val c rotate_loading.show() Coroutine.async(scope) { item.getExploreKinds() - }.onSuccess { - it?.let { + }.onSuccess { kindList -> + if (!kindList.isNullOrEmpty()) { gl_child.visible() gl_child.removeAllViews() - it.map { kind -> + kindList.map { kind -> val tv = LayoutInflater.from(context) .inflate(R.layout.item_text, gl_child, false) tv.text_view.text = kind.title tv.text_view.onClick { - callBack.openExplore( - item.bookSourceUrl, - kind.title, - kind.url - ) + kind.url?.let { kindUrl -> + callBack.openExplore( + item.bookSourceUrl, + kind.title, + kindUrl + ) + } } gl_child.addView(tv) } From b5dbc04032c5ab1466fbb71356f94a6725d8c07d Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 5 Sep 2019 17:21:17 +0800 Subject: [PATCH 1308/1997] up --- .../io/legado/app/data/entities/BaseBook.kt | 2 +- .../java/io/legado/app/data/entities/Book.kt | 20 ++----------------- .../io/legado/app/data/entities/SearchBook.kt | 20 ++----------------- 3 files changed, 5 insertions(+), 37 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/BaseBook.kt b/app/src/main/java/io/legado/app/data/entities/BaseBook.kt index 6a7d561ee..144f59ec4 100644 --- a/app/src/main/java/io/legado/app/data/entities/BaseBook.kt +++ b/app/src/main/java/io/legado/app/data/entities/BaseBook.kt @@ -3,7 +3,7 @@ package io.legado.app.data.entities import io.legado.app.utils.splitNotBlank interface BaseBook { - var variableMap: HashMap? + var variableMap: HashMap var kind: String? var wordCount: String? diff --git a/app/src/main/java/io/legado/app/data/entities/Book.kt b/app/src/main/java/io/legado/app/data/entities/Book.kt index 118acf35b..0ab5a9879 100644 --- a/app/src/main/java/io/legado/app/data/entities/Book.kt +++ b/app/src/main/java/io/legado/app/data/entities/Book.kt @@ -1,7 +1,6 @@ package io.legado.app.data.entities import android.os.Parcelable -import android.text.TextUtils.isEmpty import androidx.room.Entity import androidx.room.Ignore import androidx.room.Index @@ -50,11 +49,7 @@ data class Book( ) : Parcelable, BaseBook { @IgnoredOnParcel @Ignore - override var variableMap: HashMap? = null - get() = run { - initVariableMap() - return field - } + override var variableMap: HashMap = GSON.fromJsonObject(variable) ?: HashMap() fun getUnreadChapterNum() = max(totalChapterNum - durChapterIndex - 1, 0) @@ -62,19 +57,8 @@ data class Book( fun getDisplayIntro() = if (customIntro.isNullOrEmpty()) intro else customIntro - private fun initVariableMap() { - if (variableMap == null) { - variableMap = if (isEmpty(variable)) { - HashMap() - } else { - GSON.fromJsonObject(variable) - } - } - } - override fun putVariable(key: String, value: String) { - initVariableMap() - variableMap?.put(key, value) + variableMap[key] = value variable = GSON.toJson(variableMap) } diff --git a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt index 00efc0e47..69caf7c6c 100644 --- a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt +++ b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt @@ -1,7 +1,6 @@ package io.legado.app.data.entities import android.os.Parcelable -import android.text.TextUtils import androidx.room.Entity import androidx.room.Ignore import androidx.room.Index @@ -51,25 +50,10 @@ data class SearchBook( @IgnoredOnParcel @Ignore - override var variableMap: HashMap? = null - get() = run { - initVariableMap() - return field - } - - private fun initVariableMap() { - variableMap?.let { - variableMap = if (TextUtils.isEmpty(variable)) { - HashMap() - } else { - GSON.fromJsonObject(variable) - } - } - } + override var variableMap: HashMap = GSON.fromJsonObject(variable) ?: HashMap() override fun putVariable(key: String, value: String) { - initVariableMap() - variableMap?.put(key, value) + variableMap[key] = value variable = GSON.toJson(variableMap) } From b5a198e8871ea4c8d7d836917deba548487efa59 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 5 Sep 2019 17:23:45 +0800 Subject: [PATCH 1309/1997] up --- .../app/model/analyzeRule/AnalyzeRule.kt | 44 +++++++++++++++++-- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt index c3db2f5ee..cb4ff8a80 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt @@ -5,7 +5,6 @@ import androidx.annotation.Keep import io.legado.app.constant.AppConst.SCRIPT_ENGINE import io.legado.app.constant.Pattern.JS_PATTERN import io.legado.app.data.entities.BaseBook -import io.legado.app.help.JsExtensions import io.legado.app.utils.* import java.util.* import java.util.regex.Pattern @@ -516,9 +515,8 @@ class AnalyzeRule(private var book: BaseBook? = null) { @Throws(Exception::class) private fun evalJS(jsStr: String, result: Any?): Any { val bindings = SimpleBindings() - bindings["analyzeRule"] = this + bindings["java"] = this bindings["book"] = book - bindings["java"] = JsExtensions() bindings["result"] = result bindings["baseUrl"] = baseUrl return SCRIPT_ENGINE.eval(jsStr, bindings) @@ -529,4 +527,44 @@ class AnalyzeRule(private var book: BaseBook? = null) { private val getPattern = Pattern.compile("@get:\\{([^}]+?)\\}", Pattern.CASE_INSENSITIVE) } + /** + * js实现跨域访问,不能删 + */ + fun ajax(urlStr: String): String? { + try { + val analyzeUrl = AnalyzeUrl(urlStr, null, null, null, null, null) + val call = analyzeUrl.getResponse() + val response = call.execute() + if (response.body() != null) { + return response.body()!!.toString() + } + } catch (e: Exception) { + return e.localizedMessage + } + + return null + } + + /** + * js实现解码,不能删 + */ + fun base64Decoder(str: String): String { + return Encoder.base64Decoder(str) + } + + /** + * 章节数转数字 + */ + fun toNumChapter(s: String?): String? { + if (s == null) { + return null + } + val pattern = Pattern.compile("(第)(.+?)(章)") + val matcher = pattern.matcher(s) + return if (matcher.find()) { + matcher.group(1) + StringUtils.stringToInt(matcher.group(2)) + matcher.group(3) + } else { + s + } + } } From 12e19d41ffe48c1e718e10f76071092f782f2788 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 5 Sep 2019 17:25:00 +0800 Subject: [PATCH 1310/1997] up --- .../java/io/legado/app/help/JsExtensions.java | 55 ------------------- .../java/io/legado/app/help/JsExtensions.kt | 53 ++++++++++++++++++ 2 files changed, 53 insertions(+), 55 deletions(-) delete mode 100644 app/src/main/java/io/legado/app/help/JsExtensions.java create mode 100644 app/src/main/java/io/legado/app/help/JsExtensions.kt diff --git a/app/src/main/java/io/legado/app/help/JsExtensions.java b/app/src/main/java/io/legado/app/help/JsExtensions.java deleted file mode 100644 index 7b45b0bc2..000000000 --- a/app/src/main/java/io/legado/app/help/JsExtensions.java +++ /dev/null @@ -1,55 +0,0 @@ -package io.legado.app.help; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import io.legado.app.model.analyzeRule.AnalyzeUrl; -import io.legado.app.utils.Encoder; -import io.legado.app.utils.StringUtils; -import retrofit2.Call; -import retrofit2.Response; - -public class JsExtensions { - - - /** - * js实现跨域访问,不能删 - */ - public String ajax(String urlStr) { - try { - AnalyzeUrl analyzeUrl = new AnalyzeUrl(urlStr, null, null, null, null, null); - Call call = analyzeUrl.getResponse(); - Response response = call.execute(); - if (response.body() != null) { - return response.body().toString(); - } - } catch (Exception e) { - return e.getLocalizedMessage(); - } - return null; - } - - /** - * js实现解码,不能删 - */ - public String base64Decoder(String str) { - return Encoder.INSTANCE.base64Decoder(str); - } - - /** - * 章节数转数字 - */ - public String toNumChapter(String s) { - if (s == null) { - return null; - } - Pattern pattern = Pattern.compile("(第)(.+?)(章)"); - Matcher matcher = pattern.matcher(s); - if (matcher.find()) { - return matcher.group(1) + StringUtils.INSTANCE.stringToInt(matcher.group(2)) + matcher.group(3); - } else { - return s; - } - } - -} diff --git a/app/src/main/java/io/legado/app/help/JsExtensions.kt b/app/src/main/java/io/legado/app/help/JsExtensions.kt new file mode 100644 index 000000000..238996a5a --- /dev/null +++ b/app/src/main/java/io/legado/app/help/JsExtensions.kt @@ -0,0 +1,53 @@ +package io.legado.app.help + +import io.legado.app.model.analyzeRule.AnalyzeUrl +import io.legado.app.utils.Encoder +import io.legado.app.utils.StringUtils +import java.util.regex.Pattern + + +@Suppress("unused") +class JsExtensions { + + /** + * js实现跨域访问,不能删 + */ + fun ajax(urlStr: String): String? { + try { + val analyzeUrl = AnalyzeUrl(urlStr, null, null, null, null, null) + val call = analyzeUrl.getResponse() + val response = call.execute() + if (response.body() != null) { + return response.body()!!.toString() + } + } catch (e: Exception) { + return e.localizedMessage + } + + return null + } + + /** + * js实现解码,不能删 + */ + fun base64Decoder(str: String): String { + return Encoder.base64Decoder(str) + } + + /** + * 章节数转数字 + */ + fun toNumChapter(s: String?): String? { + if (s == null) { + return null + } + val pattern = Pattern.compile("(第)(.+?)(章)") + val matcher = pattern.matcher(s) + return if (matcher.find()) { + matcher.group(1) + StringUtils.stringToInt(matcher.group(2)) + matcher.group(3) + } else { + s + } + } + +} From c0110d128207812a420f3d29cd15edbda650f0e1 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 5 Sep 2019 17:36:44 +0800 Subject: [PATCH 1311/1997] up --- .../java/io/legado/app/ui/sourceedit/SourceEditActivity.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditActivity.kt index c915b139a..dba47e57d 100644 --- a/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditActivity.kt @@ -60,6 +60,11 @@ class SourceEditActivity : VMBaseActivity(R.layout.activity } } + override fun onDestroy() { + super.onDestroy() + mSoftKeyboardTool?.dismiss() + } + override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { menuInflater.inflate(R.menu.source_edit, menu) return super.onCompatCreateOptionsMenu(menu) From d907623069162c06ad462e61d47efc8f9e3c1dec Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 5 Sep 2019 17:51:52 +0800 Subject: [PATCH 1312/1997] up --- app/src/main/java/io/legado/app/data/entities/Book.kt | 3 ++- app/src/main/java/io/legado/app/data/entities/SearchBook.kt | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/Book.kt b/app/src/main/java/io/legado/app/data/entities/Book.kt index 0ab5a9879..15dd497a8 100644 --- a/app/src/main/java/io/legado/app/data/entities/Book.kt +++ b/app/src/main/java/io/legado/app/data/entities/Book.kt @@ -75,7 +75,8 @@ data class Book( coverUrl = coverUrl, intro = intro, tocUrl = tocUrl, - originOrder = originOrder + originOrder = originOrder, + variable = variable ) } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt index 69caf7c6c..ec107ef77 100644 --- a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt +++ b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt @@ -70,7 +70,8 @@ data class SearchBook( coverUrl = coverUrl, intro = intro, tocUrl = tocUrl, - originOrder = originOrder + originOrder = originOrder, + variable = variable ) } } \ No newline at end of file From 701932c55594c3fb5696160d1d10f673641dff92 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 5 Sep 2019 18:58:11 +0800 Subject: [PATCH 1313/1997] up --- .../java/io/legado/app/model/analyzeRule/AnalyzeRule.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt index cb4ff8a80..668ab0b79 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt @@ -474,9 +474,11 @@ class AnalyzeRule(private var book: BaseBook? = null) { val regType = ruleType[j] if (regType > 0) { @Suppress("UNCHECKED_CAST") - val resultList = result as List + val resultList = result as List if (resultList.size > regType) { - infoVal.insert(0, resultList[regType]) + resultList[regType]?.let { + infoVal.insert(0, resultList[regType]) + } } } else if (regType < 0) { val jsEval: Any = evalJS(ruleParam[j], result) From 03d567c12e7f43a5b910c01050442477a732e14d Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 5 Sep 2019 19:01:26 +0800 Subject: [PATCH 1314/1997] up --- app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt index 21a1b83ca..5b99563e8 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt @@ -59,6 +59,7 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { WebBook(bookSource).getBookInfo(book, this) .onSuccess(IO) { it?.let { + bookData.postValue(book) if (inBookshelf) { App.db.bookDao().update(book) } From e39461b90e0d04b536abd77d453476598dc7657a Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 5 Sep 2019 19:04:11 +0800 Subject: [PATCH 1315/1997] up --- app/src/main/java/io/legado/app/model/webbook/BookInfo.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt b/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt index 1ad81cf11..1a7c5051c 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt @@ -6,6 +6,7 @@ import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookSource import io.legado.app.model.analyzeRule.AnalyzeRule import io.legado.app.model.analyzeRule.AnalyzeUrl +import io.legado.app.utils.htmlFormat object BookInfo { @@ -50,7 +51,7 @@ object BookInfo { SourceDebug.printLog(bookSource.bookSourceUrl, 1, book.kind ?: "") SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取简介") analyzeRule.getString(infoRule.intro ?: "")?.let { - if (it.isNotEmpty()) book.intro = it + if (it.isNotEmpty()) book.intro = it.htmlFormat() } SourceDebug.printLog(bookSource.bookSourceUrl, 1, book.intro ?: "", isHtml = true) SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取字数") From 92f0bb4dee80db09b86562821eb04ec529576887 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 5 Sep 2019 19:25:27 +0800 Subject: [PATCH 1316/1997] up --- .../app/model/analyzeRule/AnalyzeByXPath.kt | 51 ++++++++++++------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByXPath.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByXPath.kt index 4293837c7..7cba03083 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByXPath.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByXPath.kt @@ -3,30 +3,50 @@ package io.legado.app.model.analyzeRule import android.text.TextUtils import io.legado.app.utils.splitNotBlank import org.jsoup.nodes.Document +import org.jsoup.nodes.Element +import org.jsoup.select.Elements import org.seimicrawler.xpath.JXDocument import org.seimicrawler.xpath.JXNode import java.util.* class AnalyzeByXPath { private var jxDocument: JXDocument? = null + private var jxNode: JXNode? = null fun parse(doc: Any): AnalyzeByXPath { - if (doc is Document) { + if (doc is JXNode) { + jxNode = doc + if (jxNode?.isElement == false) { + jxDocument = strToJXDocument(doc.toString()) + jxNode = null + } + } else if (doc is Document) { + jxDocument = JXDocument.create(doc) + jxNode = null + } else if (doc is Element) { + jxDocument = JXDocument.create(Elements(doc)) + jxNode = null + } else if (doc is Elements) { jxDocument = JXDocument.create(doc) + jxNode = null } else { - var html = doc.toString() - // 给表格标签添加完整的框架结构,否则会丢失表格标签;html标准不允许表格标签独立在table之外 - if (html.endsWith("")) { - html = String.format("%s", html) - } - if (html.endsWith("") || html.endsWith("")) { - html = String.format("%s
    ", html) - } - jxDocument = JXDocument.create(html) + jxDocument = strToJXDocument(doc.toString()) + jxNode = null } return this } + private fun strToJXDocument(html: String): JXDocument { + var html1 = html + if (html1.endsWith("")) { + html1 = String.format("%s", html1) + } + if (html1.endsWith("") || html1.endsWith("")) { + html1 = String.format("%s
    ", html1) + } + return JXDocument.create(html1) + } + internal fun getElements(xPath: String): List? { if (TextUtils.isEmpty(xPath)) { return null @@ -49,7 +69,7 @@ class AnalyzeByXPath { } } if (rules.size == 1) { - return jxDocument?.selN(rules[0]) + return jxNode?.sel(rules[0]) ?: jxDocument?.selN(rules[0]) } else { val results = ArrayList>() for (rl in rules) { @@ -99,11 +119,8 @@ class AnalyzeByXPath { } } if (rules.size == 1) { - val jxNodes = jxDocument!!.selN(xPath) - for (jxNode in jxNodes) { - /*if(jxNode.isString()){ - result.add(String.valueOf(jxNode)); - }*/ + val jxNodes = jxNode?.sel(xPath) ?: jxDocument?.selN(xPath) + jxNodes?.map { result.add(jxNode.toString()) } return result @@ -148,7 +165,7 @@ class AnalyzeByXPath { elementsType = "|" } if (rules.size == 1) { - val jxNodes = jxDocument?.selN(rule) + val jxNodes = jxNode?.sel(rule) ?: jxDocument?.selN(rule) jxNodes?.let { return TextUtils.join(",", jxNodes) } From b2add1b84f24d317d26d54bf9843feb899ac4ac9 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 5 Sep 2019 20:46:42 +0800 Subject: [PATCH 1317/1997] up --- .../io/legado/app/data/entities/BookSource.kt | 20 +- .../main/java/io/legado/app/utils/ACache.java | 846 ++++++++++++++++++ 2 files changed, 859 insertions(+), 7 deletions(-) create mode 100644 app/src/main/java/io/legado/app/utils/ACache.java diff --git a/app/src/main/java/io/legado/app/data/entities/BookSource.kt b/app/src/main/java/io/legado/app/data/entities/BookSource.kt index 10c420ba0..a8a88e4cb 100644 --- a/app/src/main/java/io/legado/app/data/entities/BookSource.kt +++ b/app/src/main/java/io/legado/app/data/entities/BookSource.kt @@ -10,6 +10,7 @@ import io.legado.app.constant.AppConst import io.legado.app.constant.AppConst.userAgent import io.legado.app.data.entities.rule.* import io.legado.app.help.JsExtensions +import io.legado.app.utils.ACache import io.legado.app.utils.GSON import io.legado.app.utils.fromJsonObject import io.legado.app.utils.getPrefString @@ -124,13 +125,18 @@ data class BookSource( if (a.isNotBlank()) { try { if (it.startsWith("", false)) { - val bindings = SimpleBindings() - bindings["baseUrl"] = bookSourceUrl - bindings["java"] = JsExtensions() - a = AppConst.SCRIPT_ENGINE.eval( - a.substring(4, a.lastIndexOf("<")), - bindings - ).toString() + val aCache = ACache.get(App.INSTANCE, "explore") + a = aCache.getAsString(bookSourceUrl) ?: "" + if (a.isBlank()) { + val bindings = SimpleBindings() + bindings["baseUrl"] = bookSourceUrl + bindings["java"] = JsExtensions() + a = AppConst.SCRIPT_ENGINE.eval( + it.substring(4, it.lastIndexOf("<")), + bindings + ).toString() + aCache.put(bookSourceUrl, a) + } } val b = a.split("(&&|\n)+".toRegex()) b.map { c -> diff --git a/app/src/main/java/io/legado/app/utils/ACache.java b/app/src/main/java/io/legado/app/utils/ACache.java new file mode 100644 index 000000000..381c093b6 --- /dev/null +++ b/app/src/main/java/io/legado/app/utils/ACache.java @@ -0,0 +1,846 @@ +//Copyright (c) 2017. 章钦豪. All rights reserved. +package io.legado.app.utils; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.PixelFormat; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.util.Log; + +import androidx.annotation.Nullable; + +import org.json.JSONArray; +import org.json.JSONObject; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.RandomAccessFile; +import java.io.Serializable; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + + +/** + * 本地缓存 + */ +@SuppressWarnings({"unused", "ResultOfMethodCallIgnored", "WeakerAccess"}) +public class ACache { + public static final int TIME_HOUR = 60 * 60; + public static final int TIME_DAY = TIME_HOUR * 24; + private static final int MAX_SIZE = 1000 * 1000 * 50; // 50 mb + private static final int MAX_COUNT = Integer.MAX_VALUE; // 不限制存放数据的数量 + private static Map mInstanceMap = new HashMap<>(); + private ACacheManager mCache; + + private ACache(File cacheDir, long max_size, int max_count) { + try { + if (!cacheDir.exists() && !cacheDir.mkdirs()) { + Log.i("ACache", "can't make dirs in %s" + cacheDir.getAbsolutePath()); + } + mCache = new ACacheManager(cacheDir, max_size, max_count); + } catch (Exception ignored) { + } + } + + public static ACache get(Context ctx) { + return get(ctx, "ACache"); + } + + public static ACache get(Context ctx, String cacheName) { + File f = new File(ctx.getCacheDir(), cacheName); + return get(f, MAX_SIZE, MAX_COUNT); + } + + public static ACache get(File cacheDir) { + return get(cacheDir, MAX_SIZE, MAX_COUNT); + } + + public static ACache get(Context ctx, long max_zise, int max_count) { + try { + File f = new File(ctx.getCacheDir(), "ACache"); + return get(f, max_zise, max_count); + } catch (Exception ignored) { + } + + return null; + } + + public static ACache get(File cacheDir, long max_zise, int max_count) { + try { + ACache manager = mInstanceMap.get(cacheDir.getAbsoluteFile() + myPid()); + if (manager == null) { + manager = new ACache(cacheDir, max_zise, max_count); + mInstanceMap.put(cacheDir.getAbsolutePath() + myPid(), manager); + } + return manager; + } catch (Exception ignored) { + } + + return null; + } + + private static String myPid() { + return "_" + android.os.Process.myPid(); + } + + // ======================================= + // ============ String数据 读写 ============== + // ======================================= + + /** + * 保存 String数据 到 缓存中 + * + * @param key 保存的key + * @param value 保存的String数据 + */ + public void put(String key, String value) { + try { + File file = mCache.newFile(key); + BufferedWriter out = null; + try { + out = new BufferedWriter(new FileWriter(file), 1024); + out.write(value); + } catch (IOException ignored) { + } finally { + if (out != null) { + try { + out.flush(); + out.close(); + } catch (IOException ignored) { + } + } + mCache.put(file); + } + } catch (Exception ignored) { + } + + } + + /** + * 保存 String数据 到 缓存中 + * + * @param key 保存的key + * @param value 保存的String数据 + * @param saveTime 保存的时间,单位:秒 + */ + public void put(String key, String value, int saveTime) { + put(key, Utils.newStringWithDateInfo(saveTime, value)); + } + + /** + * 读取 String数据 + * + * @return String 数据 + */ + @Nullable + public String getAsString(String key) { + File file = mCache.get(key); + if (!file.exists()) + return null; + boolean removeFile = false; + try (BufferedReader in = new BufferedReader(new FileReader(file))) { + StringBuilder readString = new StringBuilder(); + String currentLine; + while ((currentLine = in.readLine()) != null) { + readString.append(currentLine); + } + if (!Utils.isDue(readString.toString())) { + return Utils.clearDateInfo(readString.toString()); + } else { + removeFile = true; + return null; + } + } catch (IOException e) { + return null; + } finally { + if (removeFile) + remove(key); + } + } + + // ======================================= + // ========== JSONObject 数据 读写 ========= + // ======================================= + + /** + * 保存 JSONObject数据 到 缓存中 + * + * @param key 保存的key + * @param value 保存的JSON数据 + */ + public void put(String key, JSONObject value) { + put(key, value.toString()); + } + + /** + * 保存 JSONObject数据 到 缓存中 + * + * @param key 保存的key + * @param value 保存的JSONObject数据 + * @param saveTime 保存的时间,单位:秒 + */ + public void put(String key, JSONObject value, int saveTime) { + put(key, value.toString(), saveTime); + } + + /** + * 读取JSONObject数据 + * + * @return JSONObject数据 + */ + public JSONObject getAsJSONObject(String key) { + String JSONString = getAsString(key); + try { + return new JSONObject(JSONString); + } catch (Exception e) { + return null; + } + } + + // ======================================= + // ============ JSONArray 数据 读写 ============= + // ======================================= + + /** + * 保存 JSONArray数据 到 缓存中 + * + * @param key 保存的key + * @param value 保存的JSONArray数据 + */ + public void put(String key, JSONArray value) { + put(key, value.toString()); + } + + /** + * 保存 JSONArray数据 到 缓存中 + * + * @param key 保存的key + * @param value 保存的JSONArray数据 + * @param saveTime 保存的时间,单位:秒 + */ + public void put(String key, JSONArray value, int saveTime) { + put(key, value.toString(), saveTime); + } + + /** + * 读取JSONArray数据 + * + * @return JSONArray数据 + */ + public JSONArray getAsJSONArray(String key) { + String JSONString = getAsString(key); + try { + return new JSONArray(JSONString); + } catch (Exception e) { + return null; + } + } + + // ======================================= + // ============== byte 数据 读写 ============= + // ======================================= + + /** + * 保存 byte数据 到 缓存中 + * + * @param key 保存的key + * @param value 保存的数据 + */ + public void put(String key, byte[] value) { + File file = mCache.newFile(key); + FileOutputStream out = null; + try { + out = new FileOutputStream(file); + out.write(value); + } catch (Exception ignored) { + } finally { + if (out != null) { + try { + out.flush(); + out.close(); + } catch (IOException ignored) { + } + } + mCache.put(file); + } + } + + /** + * 保存 byte数据 到 缓存中 + * + * @param key 保存的key + * @param value 保存的数据 + * @param saveTime 保存的时间,单位:秒 + */ + public void put(String key, byte[] value, int saveTime) { + put(key, Utils.newByteArrayWithDateInfo(saveTime, value)); + } + + /** + * 获取 byte 数据 + * + * @return byte 数据 + */ + public byte[] getAsBinary(String key) { + RandomAccessFile RAFile = null; + boolean removeFile = false; + try { + File file = mCache.get(key); + if (!file.exists()) + return null; + RAFile = new RandomAccessFile(file, "r"); + byte[] byteArray = new byte[(int) RAFile.length()]; + RAFile.read(byteArray); + if (!Utils.isDue(byteArray)) { + return Utils.clearDateInfo(byteArray); + } else { + removeFile = true; + return null; + } + } catch (Exception e) { + e.printStackTrace(); + return null; + } finally { + if (RAFile != null) { + try { + RAFile.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if (removeFile) + remove(key); + } + } + + // ======================================= + // ============= 序列化 数据 读写 =============== + // ======================================= + + /** + * 保存 Serializable数据 到 缓存中 + * + * @param key 保存的key + * @param value 保存的value + */ + public void put(String key, Serializable value) { + put(key, value, -1); + } + + /** + * 保存 Serializable数据到 缓存中 + * + * @param key 保存的key + * @param value 保存的value + * @param saveTime 保存的时间,单位:秒 + */ + public void put(String key, Serializable value, int saveTime) { + ByteArrayOutputStream baos; + baos = new ByteArrayOutputStream(); + try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { + oos.writeObject(value); + byte[] data = baos.toByteArray(); + if (saveTime != -1) { + put(key, data, saveTime); + } else { + put(key, data); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 读取 Serializable数据 + * + * @return Serializable 数据 + */ + public Object getAsObject(String key) { + byte[] data = getAsBinary(key); + if (data != null) { + ByteArrayInputStream bais = null; + ObjectInputStream ois = null; + try { + bais = new ByteArrayInputStream(data); + ois = new ObjectInputStream(bais); + return ois.readObject(); + } catch (Exception e) { + e.printStackTrace(); + return null; + } finally { + try { + if (bais != null) + bais.close(); + } catch (IOException e) { + e.printStackTrace(); + } + try { + if (ois != null) + ois.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + return null; + + } + + // ======================================= + // ============== bitmap 数据 读写 ============= + // ======================================= + + /** + * 保存 bitmap 到 缓存中 + * + * @param key 保存的key + * @param value 保存的bitmap数据 + */ + public void put(String key, Bitmap value) { + put(key, Utils.Bitmap2Bytes(value)); + } + + /** + * 保存 bitmap 到 缓存中 + * + * @param key 保存的key + * @param value 保存的 bitmap 数据 + * @param saveTime 保存的时间,单位:秒 + */ + public void put(String key, Bitmap value, int saveTime) { + put(key, Utils.Bitmap2Bytes(value), saveTime); + } + + /** + * 读取 bitmap 数据 + * + * @return bitmap 数据 + */ + public Bitmap getAsBitmap(String key) { + if (getAsBinary(key) == null) { + return null; + } + return Utils.Bytes2Bimap(getAsBinary(key)); + } + + // ======================================= + // ============= drawable 数据 读写 ============= + // ======================================= + + /** + * 保存 drawable 到 缓存中 + * + * @param key 保存的key + * @param value 保存的drawable数据 + */ + public void put(String key, Drawable value) { + put(key, Utils.drawable2Bitmap(value)); + } + + /** + * 保存 drawable 到 缓存中 + * + * @param key 保存的key + * @param value 保存的 drawable 数据 + * @param saveTime 保存的时间,单位:秒 + */ + public void put(String key, Drawable value, int saveTime) { + put(key, Utils.drawable2Bitmap(value), saveTime); + } + + /** + * 读取 Drawable 数据 + * + * @return Drawable 数据 + */ + public Drawable getAsDrawable(String key) { + if (getAsBinary(key) == null) { + return null; + } + return Utils.bitmap2Drawable(Utils.Bytes2Bimap(getAsBinary(key))); + } + + /** + * 获取缓存文件 + * + * @return value 缓存的文件 + */ + public File file(String key) { + try { + File f = mCache.newFile(key); + if (f.exists()) { + return f; + } + } catch (Exception e) { + e.printStackTrace(); + } + + return null; + } + + /** + * 移除某个key + * + * @return 是否移除成功 + */ + public boolean remove(String key) { + return mCache.remove(key); + } + + /** + * 清除所有数据 + */ + public void clear() { + mCache.clear(); + } + + /** + * @author 杨福海(michael) www.yangfuhai.com + * @version 1.0 + * @title 时间计算工具类 + */ + private static class Utils { + + private static final char mSeparator = ' '; + + /** + * 判断缓存的String数据是否到期 + * + * @return true:到期了 false:还没有到期 + */ + private static boolean isDue(String str) { + return isDue(str.getBytes()); + } + + /** + * 判断缓存的byte数据是否到期 + * + * @return true:到期了 false:还没有到期 + */ + private static boolean isDue(byte[] data) { + try { + String[] strs = getDateInfoFromDate(data); + if (strs != null && strs.length == 2) { + String saveTimeStr = strs[0]; + while (saveTimeStr.startsWith("0")) { + saveTimeStr = saveTimeStr + .substring(1); + } + long saveTime = Long.valueOf(saveTimeStr); + long deleteAfter = Long.valueOf(strs[1]); + if (System.currentTimeMillis() > saveTime + deleteAfter * 1000) { + return true; + } + } + } catch (Exception e) { + e.printStackTrace(); + } + + return false; + } + + private static String newStringWithDateInfo(int second, String strInfo) { + return createDateInfo(second) + strInfo; + } + + private static byte[] newByteArrayWithDateInfo(int second, byte[] data2) { + byte[] data1 = createDateInfo(second).getBytes(); + byte[] retdata = new byte[data1.length + data2.length]; + System.arraycopy(data1, 0, retdata, 0, data1.length); + System.arraycopy(data2, 0, retdata, data1.length, data2.length); + return retdata; + } + + private static String clearDateInfo(String strInfo) { + if (strInfo != null && hasDateInfo(strInfo.getBytes())) { + strInfo = strInfo.substring(strInfo.indexOf(mSeparator) + 1); + } + return strInfo; + } + + private static byte[] clearDateInfo(byte[] data) { + if (hasDateInfo(data)) { + return copyOfRange(data, indexOf(data, mSeparator) + 1, + data.length); + } + return data; + } + + private static boolean hasDateInfo(byte[] data) { + return data != null && data.length > 15 && data[13] == '-' + && indexOf(data, mSeparator) > 14; + } + + private static String[] getDateInfoFromDate(byte[] data) { + if (hasDateInfo(data)) { + String saveDate = new String(copyOfRange(data, 0, 13)); + String deleteAfter = new String(copyOfRange(data, 14, + indexOf(data, mSeparator))); + return new String[]{saveDate, deleteAfter}; + } + return null; + } + + private static int indexOf(byte[] data, char c) { + for (int i = 0; i < data.length; i++) { + if (data[i] == c) { + return i; + } + } + return -1; + } + + private static byte[] copyOfRange(byte[] original, int from, int to) { + int newLength = to - from; + if (newLength < 0) + throw new IllegalArgumentException(from + " > " + to); + byte[] copy = new byte[newLength]; + System.arraycopy(original, from, copy, 0, + Math.min(original.length - from, newLength)); + return copy; + } + + private static String createDateInfo(int second) { + StringBuilder currentTime = new StringBuilder(System.currentTimeMillis() + ""); + while (currentTime.length() < 13) { + currentTime.insert(0, "0"); + } + return currentTime + "-" + second + mSeparator; + } + + /* + * Bitmap → byte[] + */ + private static byte[] Bitmap2Bytes(Bitmap bm) { + if (bm == null) { + return null; + } + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + bm.compress(Bitmap.CompressFormat.PNG, 100, baos); + return baos.toByteArray(); + } + + /* + * byte[] → Bitmap + */ + private static Bitmap Bytes2Bimap(byte[] b) { + if (b.length == 0) { + return null; + } + return BitmapFactory.decodeByteArray(b, 0, b.length); + } + + /* + * Drawable → Bitmap + */ + private static Bitmap drawable2Bitmap(Drawable drawable) { + if (drawable == null) { + return null; + } + // 取 drawable 的长宽 + int w = drawable.getIntrinsicWidth(); + int h = drawable.getIntrinsicHeight(); + // 取 drawable 的颜色格式 + Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 + : Bitmap.Config.RGB_565; + // 建立对应 bitmap + Bitmap bitmap = Bitmap.createBitmap(w, h, config); + // 建立对应 bitmap 的画布 + Canvas canvas = new Canvas(bitmap); + drawable.setBounds(0, 0, w, h); + // 把 drawable 内容画到画布中 + drawable.draw(canvas); + return bitmap; + } + + /* + * Bitmap → Drawable + */ + @SuppressWarnings("deprecation") + private static Drawable bitmap2Drawable(Bitmap bm) { + if (bm == null) { + return null; + } + return new BitmapDrawable(bm); + } + } + + /** + * @author 杨福海(michael) www.yangfuhai.com + * @version 1.0 + * @title 缓存管理器 + */ + public class ACacheManager { + private final AtomicLong cacheSize; + private final AtomicInteger cacheCount; + private final long sizeLimit; + private final int countLimit; + private final Map lastUsageDates = Collections + .synchronizedMap(new HashMap<>()); + protected File cacheDir; + + private ACacheManager(File cacheDir, long sizeLimit, int countLimit) { + this.cacheDir = cacheDir; + this.sizeLimit = sizeLimit; + this.countLimit = countLimit; + cacheSize = new AtomicLong(); + cacheCount = new AtomicInteger(); + calculateCacheSizeAndCacheCount(); + } + + /** + * 计算 cacheSize和cacheCount + */ + private void calculateCacheSizeAndCacheCount() { + new Thread(() -> { + + try { + int size = 0; + int count = 0; + File[] cachedFiles = cacheDir.listFiles(); + if (cachedFiles != null) { + for (File cachedFile : cachedFiles) { + size += calculateSize(cachedFile); + count += 1; + lastUsageDates.put(cachedFile, + cachedFile.lastModified()); + } + cacheSize.set(size); + cacheCount.set(count); + } + } catch (Exception e) { + e.printStackTrace(); + } + + }).start(); + } + + private void put(File file) { + + try { + int curCacheCount = cacheCount.get(); + while (curCacheCount + 1 > countLimit) { + long freedSize = removeNext(); + cacheSize.addAndGet(-freedSize); + + curCacheCount = cacheCount.addAndGet(-1); + } + cacheCount.addAndGet(1); + + long valueSize = calculateSize(file); + long curCacheSize = cacheSize.get(); + while (curCacheSize + valueSize > sizeLimit) { + long freedSize = removeNext(); + curCacheSize = cacheSize.addAndGet(-freedSize); + } + cacheSize.addAndGet(valueSize); + + long currentTime = System.currentTimeMillis(); + file.setLastModified(currentTime); + lastUsageDates.put(file, currentTime); + } catch (Exception e) { + e.printStackTrace(); + } + + } + + private File get(String key) { + File file = newFile(key); + long currentTime = System.currentTimeMillis(); + file.setLastModified(currentTime); + lastUsageDates.put(file, currentTime); + + return file; + } + + private File newFile(String key) { + return new File(cacheDir, key.hashCode() + ""); + } + + private boolean remove(String key) { + File image = get(key); + return image.delete(); + } + + private void clear() { + try { + lastUsageDates.clear(); + cacheSize.set(0); + File[] files = cacheDir.listFiles(); + if (files != null) { + for (File f : files) { + f.delete(); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + + } + + /** + * 移除旧的文件 + */ + private long removeNext() { + try { + if (lastUsageDates.isEmpty()) { + return 0; + } + + Long oldestUsage = null; + File mostLongUsedFile = null; + Set> entries = lastUsageDates.entrySet(); + synchronized (lastUsageDates) { + for (Entry entry : entries) { + if (mostLongUsedFile == null) { + mostLongUsedFile = entry.getKey(); + oldestUsage = entry.getValue(); + } else { + Long lastValueUsage = entry.getValue(); + if (lastValueUsage < oldestUsage) { + oldestUsage = lastValueUsage; + mostLongUsedFile = entry.getKey(); + } + } + } + } + + long fileSize = 0; + if (mostLongUsedFile != null) { + fileSize = calculateSize(mostLongUsedFile); + if (mostLongUsedFile.delete()) { + lastUsageDates.remove(mostLongUsedFile); + } + } + return fileSize; + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + + + } + + private long calculateSize(File file) { + return file.length(); + } + } + +} From 7933563e95c8054278090b0f4ad27bbea5f63256 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 5 Sep 2019 21:02:55 +0800 Subject: [PATCH 1318/1997] up --- .../java/io/legado/app/ui/main/MainActivity.kt | 4 ++-- .../{FindBookAdapter.kt => ExploreAdapter.kt} | 12 +++++++++++- ...{FindBookFragment.kt => ExploreFragment.kt} | 18 +++++++++++++----- .../app/ui/main/explore/ExploreViewModel.kt | 18 ++++++++++++++++++ app/src/main/res/values/strings.xml | 2 +- 5 files changed, 45 insertions(+), 9 deletions(-) rename app/src/main/java/io/legado/app/ui/main/explore/{FindBookAdapter.kt => ExploreAdapter.kt} (84%) rename app/src/main/java/io/legado/app/ui/main/explore/{FindBookFragment.kt => ExploreFragment.kt} (76%) create mode 100644 app/src/main/java/io/legado/app/ui/main/explore/ExploreViewModel.kt diff --git a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt index 6fc769e01..eea51eb6e 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt @@ -15,7 +15,7 @@ import io.legado.app.help.permission.Permissions import io.legado.app.help.permission.PermissionsCompat import io.legado.app.lib.theme.ATH import io.legado.app.ui.main.bookshelf.BookshelfFragment -import io.legado.app.ui.main.explore.FindBookFragment +import io.legado.app.ui.main.explore.ExploreFragment import io.legado.app.ui.main.my.MyFragment import io.legado.app.ui.main.rss.RssFragment import io.legado.app.utils.getPrefInt @@ -83,7 +83,7 @@ class MainActivity : VMBaseActivity(R.layout.activity_main), override fun getItem(position: Int): Fragment { return when (position) { 0 -> BookshelfFragment() - 1 -> FindBookFragment() + 1 -> ExploreFragment() 2 -> RssFragment() else -> MyFragment() } diff --git a/app/src/main/java/io/legado/app/ui/main/explore/FindBookAdapter.kt b/app/src/main/java/io/legado/app/ui/main/explore/ExploreAdapter.kt similarity index 84% rename from app/src/main/java/io/legado/app/ui/main/explore/FindBookAdapter.kt rename to app/src/main/java/io/legado/app/ui/main/explore/ExploreAdapter.kt index a7f786bfe..369bafdcf 100644 --- a/app/src/main/java/io/legado/app/ui/main/explore/FindBookAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/explore/ExploreAdapter.kt @@ -10,6 +10,7 @@ import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.data.entities.BookSource import io.legado.app.help.coroutine.Coroutine import io.legado.app.lib.theme.accentColor +import io.legado.app.utils.ACache import io.legado.app.utils.gone import io.legado.app.utils.visible import kotlinx.android.synthetic.main.item_find_book.view.* @@ -19,7 +20,7 @@ import org.jetbrains.anko.sdk27.listeners.onClick import org.jetbrains.anko.sdk27.listeners.onLongClick -class FindBookAdapter(context: Context, private val scope: CoroutineScope, val callBack: CallBack) : +class ExploreAdapter(context: Context, private val scope: CoroutineScope, val callBack: CallBack) : SimpleRecyclerAdapter(context, R.layout.item_find_book) { var exIndex = 0 @@ -40,9 +41,17 @@ class FindBookAdapter(context: Context, private val scope: CoroutineScope, val c ll_title.onLongClick { val popupMenu = PopupMenu(context, ll_title) popupMenu.menu.add(Menu.NONE, R.id.menu_edit, Menu.NONE, R.string.edit) + popupMenu.menu.add(Menu.NONE, R.id.menu_top, Menu.NONE, R.string.to_top) + popupMenu.menu.add(Menu.NONE, R.id.menu_refresh, Menu.NONE, R.string.refresh) popupMenu.setOnMenuItemClickListener { when (it.itemId) { R.id.menu_edit -> callBack.editSource(item.bookSourceUrl) + R.id.menu_top -> { + } + R.id.menu_refresh -> { + ACache.get(context, "explore").remove(item.bookSourceUrl) + notifyItemChanged(holder.layoutPosition) + } } true } @@ -91,5 +100,6 @@ class FindBookAdapter(context: Context, private val scope: CoroutineScope, val c fun scrollTo(pos: Int) fun openExplore(sourceUrl: String, title: String, exploreUrl: String) fun editSource(sourceUrl: String) + fun toTop(source: BookSource) } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/explore/FindBookFragment.kt b/app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt similarity index 76% rename from app/src/main/java/io/legado/app/ui/main/explore/FindBookFragment.kt rename to app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt index 66ed92289..5c7d78e72 100644 --- a/app/src/main/java/io/legado/app/ui/main/explore/FindBookFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt @@ -7,18 +7,22 @@ import androidx.lifecycle.Observer import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.App import io.legado.app.R -import io.legado.app.base.BaseFragment +import io.legado.app.base.VMBaseFragment +import io.legado.app.data.entities.BookSource import io.legado.app.lib.theme.ATH import io.legado.app.ui.explore.ExploreShowActivity import io.legado.app.ui.sourceedit.SourceEditActivity +import io.legado.app.utils.getViewModel import io.legado.app.utils.startActivity import kotlinx.android.synthetic.main.fragment_find_book.* import kotlinx.android.synthetic.main.view_title_bar.* -class FindBookFragment : BaseFragment(R.layout.fragment_find_book), - FindBookAdapter.CallBack { +class ExploreFragment : VMBaseFragment(R.layout.fragment_find_book), + ExploreAdapter.CallBack { + override val viewModel: ExploreViewModel + get() = getViewModel(ExploreViewModel::class.java) - private lateinit var adapter: FindBookAdapter + private lateinit var adapter: ExploreAdapter private lateinit var linearLayoutManager: LinearLayoutManager override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -35,7 +39,7 @@ class FindBookFragment : BaseFragment(R.layout.fragment_find_book), ATH.applyEdgeEffectColor(rv_find) linearLayoutManager = LinearLayoutManager(context) rv_find.layoutManager = linearLayoutManager - adapter = FindBookAdapter(requireContext(), this, this) + adapter = ExploreAdapter(requireContext(), this, this) rv_find.adapter = adapter } @@ -60,4 +64,8 @@ class FindBookFragment : BaseFragment(R.layout.fragment_find_book), override fun editSource(sourceUrl: String) { startActivity(Pair("data", sourceUrl)) } + + override fun toTop(source: BookSource) { + viewModel.topSource(source) + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/explore/ExploreViewModel.kt b/app/src/main/java/io/legado/app/ui/main/explore/ExploreViewModel.kt new file mode 100644 index 000000000..a3716b592 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/main/explore/ExploreViewModel.kt @@ -0,0 +1,18 @@ +package io.legado.app.ui.main.explore + +import android.app.Application +import io.legado.app.App +import io.legado.app.base.BaseViewModel +import io.legado.app.data.entities.BookSource + +class ExploreViewModel(application: Application) : BaseViewModel(application) { + + fun topSource(bookSource: BookSource) { + execute { + val minXh = App.db.bookSourceDao().minOrder + bookSource.customOrder = minXh - 1 + App.db.bookSourceDao().insert(bookSource) + } + } + +} \ 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 076c34dbc..2c849417a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -119,7 +119,7 @@ 正在朗读 点击打开阅读界面 返回 - 重新加载 + 刷新 开始 停止 暂停 From ee88472077f6ab8c732d2bd352d0e6c14edfed8c Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 5 Sep 2019 21:04:51 +0800 Subject: [PATCH 1319/1997] up --- .../main/java/io/legado/app/ui/main/explore/ExploreAdapter.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/main/explore/ExploreAdapter.kt b/app/src/main/java/io/legado/app/ui/main/explore/ExploreAdapter.kt index 369bafdcf..0bc6c0891 100644 --- a/app/src/main/java/io/legado/app/ui/main/explore/ExploreAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/explore/ExploreAdapter.kt @@ -46,8 +46,7 @@ class ExploreAdapter(context: Context, private val scope: CoroutineScope, val ca popupMenu.setOnMenuItemClickListener { when (it.itemId) { R.id.menu_edit -> callBack.editSource(item.bookSourceUrl) - R.id.menu_top -> { - } + R.id.menu_top -> callBack.toTop(item) R.id.menu_refresh -> { ACache.get(context, "explore").remove(item.bookSourceUrl) notifyItemChanged(holder.layoutPosition) From 29c03d799a88a0eb35e9c13f0d17c32b94a2dc4f Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 5 Sep 2019 21:58:38 +0800 Subject: [PATCH 1320/1997] up --- .../app/ui/sourceedit/SourceEditActivity.kt | 179 ++++++++++-------- .../app/ui/sourceedit/SourceEditViewModel.kt | 24 ++- app/src/main/res/menu/source_edit.xml | 12 +- 3 files changed, 124 insertions(+), 91 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditActivity.kt index dba47e57d..2bea174be 100644 --- a/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditActivity.kt @@ -1,6 +1,9 @@ package io.legado.app.ui.sourceedit import android.app.Activity +import android.content.ClipData +import android.content.ClipboardManager +import android.content.Context import android.graphics.Rect import android.os.Bundle import android.view.Gravity @@ -27,18 +30,19 @@ import org.jetbrains.anko.startActivity import org.jetbrains.anko.toast import kotlin.math.abs -class SourceEditActivity : VMBaseActivity(R.layout.activity_source_edit, false), +class SourceEditActivity : + VMBaseActivity(R.layout.activity_source_edit, false), KeyboardToolPop.OnClickListener { override val viewModel: SourceEditViewModel get() = getViewModel(SourceEditViewModel::class.java) private val adapter = SourceEditAdapter() - private val sourceEditList: ArrayList = ArrayList() - private val searchEditList: ArrayList = ArrayList() - private val findEditList: ArrayList = ArrayList() - private val infoEditList: ArrayList = ArrayList() - private val tocEditList: ArrayList = ArrayList() - private val contentEditList: ArrayList = ArrayList() + private val sourceEntities: ArrayList = ArrayList() + private val searchEntities: ArrayList = ArrayList() + private val findEntities: ArrayList = ArrayList() + private val infoEntities: ArrayList = ArrayList() + private val tocEntities: ArrayList = ArrayList() + private val contentEntities: ArrayList = ArrayList() private var mSoftKeyboardTool: PopupWindow? = null private var mIsSoftKeyBoardShowing = false @@ -80,7 +84,7 @@ class SourceEditActivity : VMBaseActivity(R.layout.activity viewModel.save(bookSource) { setResult(Activity.RESULT_OK); finish() } } } - R.id.action_debug_source -> { + R.id.menu_debug_source -> { val bookSource = getSource() if (bookSource == null) { toast("书源名称和URL不能为空") @@ -90,6 +94,13 @@ class SourceEditActivity : VMBaseActivity(R.layout.activity } } } + R.id.menu_copy_source -> { + GSON.toJson(getSource())?.let { sourceStr -> + val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager? + clipboard?.primaryClip = ClipData.newPlainText(null, sourceStr) + } + } + R.id.menu_paste_source -> viewModel.pasteSource() } return super.onCompatOptionsItemSelected(item) } @@ -117,12 +128,12 @@ class SourceEditActivity : VMBaseActivity(R.layout.activity private fun setEditEntities(tabPosition: Int?) { when (tabPosition) { - 1 -> adapter.editEntities = searchEditList - 2 -> adapter.editEntities = findEditList - 3 -> adapter.editEntities = infoEditList - 4 -> adapter.editEntities = tocEditList - 5 -> adapter.editEntities = contentEditList - else -> adapter.editEntities = sourceEditList + 1 -> adapter.editEntities = searchEntities + 2 -> adapter.editEntities = findEntities + 3 -> adapter.editEntities = infoEntities + 4 -> adapter.editEntities = tocEntities + 5 -> adapter.editEntities = contentEntities + else -> adapter.editEntities = sourceEntities } recycler_view.scrollToPosition(0) } @@ -134,81 +145,89 @@ class SourceEditActivity : VMBaseActivity(R.layout.activity } //基本信息 with(bookSource) { - sourceEditList.clear() - sourceEditList.add(EditEntity("bookSourceUrl", this?.bookSourceUrl, R.string.book_source_url)) - sourceEditList.add(EditEntity("bookSourceName", this?.bookSourceName, R.string.book_source_name)) - sourceEditList.add(EditEntity("bookSourceGroup", this?.bookSourceGroup, R.string.book_source_group)) - sourceEditList.add(EditEntity("loginUrl", this?.loginUrl, R.string.book_source_login_url)) - sourceEditList.add(EditEntity("bookUrlPattern", this?.bookUrlPattern, R.string.book_url_pattern)) - sourceEditList.add(EditEntity("header", this?.header, R.string.source_http_header)) + sourceEntities.clear() + sourceEntities + .add(EditEntity("bookSourceUrl", this?.bookSourceUrl, R.string.book_source_url)) + sourceEntities + .add(EditEntity("bookSourceName", this?.bookSourceName, R.string.book_source_name)) + sourceEntities.add( + EditEntity("bookSourceGroup", this?.bookSourceGroup, R.string.book_source_group) + ) + sourceEntities + .add(EditEntity("loginUrl", this?.loginUrl, R.string.book_source_login_url)) + sourceEntities + .add(EditEntity("bookUrlPattern", this?.bookUrlPattern, R.string.book_url_pattern)) + sourceEntities.add(EditEntity("header", this?.header, R.string.source_http_header)) } //搜索 with(bookSource?.getSearchRule()) { - searchEditList.clear() - searchEditList.add( - EditEntity( - "searchUrl", - bookSource?.searchUrl, - R.string.rule_search_url - ) - ) - searchEditList.add(EditEntity("bookList", this?.bookList, R.string.rule_book_list)) - searchEditList.add(EditEntity("name", this?.name, R.string.rule_book_name)) - searchEditList.add(EditEntity("author", this?.author, R.string.rule_book_author)) - searchEditList.add(EditEntity("kind", this?.kind, R.string.rule_book_kind)) - searchEditList.add(EditEntity("wordCount", this?.wordCount, R.string.rule_word_count)) - searchEditList.add(EditEntity("lastChapter", this?.lastChapter, R.string.rule_last_chapter)) - searchEditList.add(EditEntity("intro", this?.intro, R.string.rule_book_intro)) - searchEditList.add(EditEntity("coverUrl", this?.coverUrl, R.string.rule_cover_url)) - searchEditList.add(EditEntity("bookUrl", this?.bookUrl, R.string.rule_book_url)) + searchEntities.clear() + searchEntities + .add(EditEntity("searchUrl", bookSource?.searchUrl, R.string.rule_search_url)) + searchEntities.add(EditEntity("bookList", this?.bookList, R.string.rule_book_list)) + searchEntities.add(EditEntity("name", this?.name, R.string.rule_book_name)) + searchEntities.add(EditEntity("author", this?.author, R.string.rule_book_author)) + searchEntities.add(EditEntity("kind", this?.kind, R.string.rule_book_kind)) + searchEntities.add(EditEntity("wordCount", this?.wordCount, R.string.rule_word_count)) + searchEntities + .add(EditEntity("lastChapter", this?.lastChapter, R.string.rule_last_chapter)) + searchEntities.add(EditEntity("intro", this?.intro, R.string.rule_book_intro)) + searchEntities.add(EditEntity("coverUrl", this?.coverUrl, R.string.rule_cover_url)) + searchEntities.add(EditEntity("bookUrl", this?.bookUrl, R.string.rule_book_url)) } //详情页 with(bookSource?.getBookInfoRule()) { - infoEditList.clear() - infoEditList.add(EditEntity("init", this?.init, R.string.rule_book_info_init)) - infoEditList.add(EditEntity("name", this?.name, R.string.rule_book_name)) - infoEditList.add(EditEntity("author", this?.author, R.string.rule_book_author)) - infoEditList.add(EditEntity("coverUrl", this?.coverUrl, R.string.rule_cover_url)) - infoEditList.add(EditEntity("intro", this?.intro, R.string.rule_book_intro)) - infoEditList.add(EditEntity("kind", this?.kind, R.string.rule_book_kind)) - infoEditList.add(EditEntity("wordCount", this?.wordCount, R.string.rule_word_count)) - infoEditList.add(EditEntity("lastChapter", this?.lastChapter, R.string.rule_last_chapter)) - infoEditList.add(EditEntity("tocUrl", this?.tocUrl, R.string.rule_toc_url)) + infoEntities.clear() + infoEntities.add(EditEntity("init", this?.init, R.string.rule_book_info_init)) + infoEntities.add(EditEntity("name", this?.name, R.string.rule_book_name)) + infoEntities.add(EditEntity("author", this?.author, R.string.rule_book_author)) + infoEntities.add(EditEntity("coverUrl", this?.coverUrl, R.string.rule_cover_url)) + infoEntities.add(EditEntity("intro", this?.intro, R.string.rule_book_intro)) + infoEntities.add(EditEntity("kind", this?.kind, R.string.rule_book_kind)) + infoEntities.add(EditEntity("wordCount", this?.wordCount, R.string.rule_word_count)) + infoEntities.add( + EditEntity("lastChapter", this?.lastChapter, R.string.rule_last_chapter) + ) + infoEntities.add(EditEntity("tocUrl", this?.tocUrl, R.string.rule_toc_url)) } //目录页 with(bookSource?.getTocRule()) { - tocEditList.clear() - tocEditList.add(EditEntity("chapterList", this?.chapterList, R.string.rule_chapter_list)) - tocEditList.add(EditEntity("chapterName", this?.chapterName, R.string.rule_chapter_name)) - tocEditList.add(EditEntity("chapterUrl", this?.chapterUrl, R.string.rule_chapter_url)) - tocEditList.add(EditEntity("nextTocUrl", this?.nextTocUrl, R.string.rule_next_toc_url)) + tocEntities.clear() + tocEntities.add( + EditEntity("chapterList", this?.chapterList, R.string.rule_chapter_list) + ) + tocEntities.add( + EditEntity("chapterName", this?.chapterName, R.string.rule_chapter_name) + ) + tocEntities.add(EditEntity("chapterUrl", this?.chapterUrl, R.string.rule_chapter_url)) + tocEntities.add(EditEntity("nextTocUrl", this?.nextTocUrl, R.string.rule_next_toc_url)) } //正文页 with(bookSource?.getContentRule()) { - contentEditList.clear() - contentEditList.add(EditEntity("content", this?.content, R.string.rule_book_content)) - contentEditList.add(EditEntity("nextContentUrl", this?.nextContentUrl, R.string.rule_content_url_next)) + contentEntities.clear() + contentEntities.add(EditEntity("content", this?.content, R.string.rule_book_content)) + contentEntities.add( + EditEntity("nextContentUrl", this?.nextContentUrl, R.string.rule_content_url_next) + ) } //发现 with(bookSource?.getExploreRule()) { - findEditList.clear() - findEditList.add( - EditEntity( - "exploreUrl", - bookSource?.exploreUrl, - R.string.rule_find_url - ) + findEntities.clear() + findEntities.add( + EditEntity("exploreUrl", bookSource?.exploreUrl, R.string.rule_find_url) + ) + findEntities.add(EditEntity("bookList", this?.bookList, R.string.rule_book_list)) + findEntities.add(EditEntity("name", this?.name, R.string.rule_book_name)) + findEntities.add(EditEntity("author", this?.author, R.string.rule_book_author)) + findEntities.add(EditEntity("kind", this?.kind, R.string.rule_book_kind)) + findEntities.add(EditEntity("wordCount", this?.wordCount, R.string.rule_word_count)) + findEntities.add(EditEntity("intro", this?.intro, R.string.rule_book_intro)) + findEntities.add( + EditEntity("lastChapter", this?.lastChapter, R.string.rule_last_chapter) ) - findEditList.add(EditEntity("bookList", this?.bookList, R.string.rule_book_list)) - findEditList.add(EditEntity("name", this?.name, R.string.rule_book_name)) - findEditList.add(EditEntity("author", this?.author, R.string.rule_book_author)) - findEditList.add(EditEntity("kind", this?.kind, R.string.rule_book_kind)) - findEditList.add(EditEntity("wordCount", this?.wordCount, R.string.rule_word_count)) - findEditList.add(EditEntity("intro", this?.intro, R.string.rule_book_intro)) - findEditList.add(EditEntity("lastChapter", this?.lastChapter, R.string.rule_last_chapter)) - findEditList.add(EditEntity("coverUrl", this?.coverUrl, R.string.rule_cover_url)) - findEditList.add(EditEntity("bookUrl", this?.bookUrl, R.string.rule_book_url)) + findEntities.add(EditEntity("coverUrl", this?.coverUrl, R.string.rule_cover_url)) + findEntities.add(EditEntity("bookUrl", this?.bookUrl, R.string.rule_book_url)) } setEditEntities(0) } @@ -226,11 +245,11 @@ class SourceEditActivity : VMBaseActivity(R.layout.activity val bookInfoRule = BookInfoRule() val tocRule = TocRule() val contentRule = ContentRule() - for (entity in sourceEditList) { + for (entity in sourceEntities) { with(entity) { when (key) { - "bookSourceUrl" -> if (value != null) source.bookSourceUrl = value!! else return null - "bookSourceName" -> if (value != null) source.bookSourceName = value!! else return null + "bookSourceUrl" -> value?.let { source.bookSourceUrl = it } ?: return null + "bookSourceName" -> value?.let { source.bookSourceName = it } ?: return null "bookSourceGroup" -> source.bookSourceGroup = value "loginUrl" -> source.loginUrl = value "bookUrlPattern" -> source.bookUrlPattern = value @@ -238,7 +257,7 @@ class SourceEditActivity : VMBaseActivity(R.layout.activity } } } - for (entity in searchEditList) { + for (entity in searchEntities) { with(entity) { when (key) { "searchUrl" -> source.searchUrl = value @@ -255,7 +274,7 @@ class SourceEditActivity : VMBaseActivity(R.layout.activity } } } - for (entity in findEditList) { + for (entity in findEntities) { with(entity) { when (key) { "exploreUrl" -> source.exploreUrl = value @@ -272,7 +291,7 @@ class SourceEditActivity : VMBaseActivity(R.layout.activity } } } - for (entity in infoEditList) { + for (entity in infoEntities) { with(entity) { when (key) { "init" -> bookInfoRule.init = value @@ -288,7 +307,7 @@ class SourceEditActivity : VMBaseActivity(R.layout.activity } } } - for (entity in tocEditList) { + for (entity in tocEntities) { with(entity) { when (key) { "chapterList" -> tocRule.chapterList = value @@ -298,7 +317,7 @@ class SourceEditActivity : VMBaseActivity(R.layout.activity } } } - for (entity in contentEditList) { + for (entity in contentEntities) { with(entity) { when (key) { "content" -> contentRule.content = value diff --git a/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditViewModel.kt b/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditViewModel.kt index 90b72305c..c7edc615d 100644 --- a/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditViewModel.kt @@ -1,19 +1,20 @@ package io.legado.app.ui.sourceedit import android.app.Application +import android.content.ClipboardManager +import android.content.Context import androidx.lifecycle.MutableLiveData import io.legado.app.App import io.legado.app.base.BaseViewModel import io.legado.app.data.entities.BookSource -import kotlinx.coroutines.Dispatchers.IO -import kotlinx.coroutines.launch +import io.legado.app.help.storage.OldRule class SourceEditViewModel(application: Application) : BaseViewModel(application) { val sourceLiveData: MutableLiveData = MutableLiveData() fun setBookSource(key: String) { - launch(IO) { + execute { App.db.bookSourceDao().getBookSource(key)?.let { sourceLiveData.postValue(it) } ?: sourceLiveData.postValue(BookSource()) @@ -21,14 +22,27 @@ class SourceEditViewModel(application: Application) : BaseViewModel(application) } fun save(bookSource: BookSource, finally: (() -> Unit)? = null) { - launch(IO) { + execute { if (bookSource.customOrder == 0) { bookSource.customOrder = App.db.bookSourceDao().allCount() } App.db.bookSourceDao().insert(bookSource) + }.onFinally { finally?.let { it() } } } - + fun pasteSource() { + execute { + val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager? + clipboard?.primaryClip?.let { + if (it.itemCount > 0) { + val json = it.getItemAt(0).text.toString() + OldRule.jsonToBookSource(json)?.let { source -> + sourceLiveData.postValue(source) + } ?: toast("格式不对") + } + } + } + } } \ No newline at end of file diff --git a/app/src/main/res/menu/source_edit.xml b/app/src/main/res/menu/source_edit.xml index e5cf2d61d..ef909ad3b 100644 --- a/app/src/main/res/menu/source_edit.xml +++ b/app/src/main/res/menu/source_edit.xml @@ -9,7 +9,7 @@ app:showAsAction="ifRoom" /> @@ -20,22 +20,22 @@ app:showAsAction="never" /> @@ -45,7 +45,7 @@ app:showAsAction="never" /> From 4e56935cf94f6a89823f56f408938996166b6d10 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 6 Sep 2019 07:53:41 +0800 Subject: [PATCH 1321/1997] up --- .../java/io/legado/app/ui/sourceedit/SourceEditViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditViewModel.kt b/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditViewModel.kt index c7edc615d..ef8d75740 100644 --- a/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditViewModel.kt @@ -29,7 +29,7 @@ class SourceEditViewModel(application: Application) : BaseViewModel(application) App.db.bookSourceDao().insert(bookSource) }.onFinally { finally?.let { it() } - } + } } fun pasteSource() { From 6db32b4501c0aed52e16d62953b71a5f621e05e1 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 6 Sep 2019 08:24:23 +0800 Subject: [PATCH 1322/1997] up --- app/src/main/java/io/legado/app/help/JsExtensions.kt | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/JsExtensions.kt b/app/src/main/java/io/legado/app/help/JsExtensions.kt index 238996a5a..a09d338c3 100644 --- a/app/src/main/java/io/legado/app/help/JsExtensions.kt +++ b/app/src/main/java/io/legado/app/help/JsExtensions.kt @@ -13,18 +13,14 @@ class JsExtensions { * js实现跨域访问,不能删 */ fun ajax(urlStr: String): String? { - try { + return try { val analyzeUrl = AnalyzeUrl(urlStr, null, null, null, null, null) val call = analyzeUrl.getResponse() val response = call.execute() - if (response.body() != null) { - return response.body()!!.toString() - } + response.body()?.toString() } catch (e: Exception) { - return e.localizedMessage + e.localizedMessage } - - return null } /** From e0453a55471891b8475b09adbc3b206aa2749d97 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 6 Sep 2019 08:34:20 +0800 Subject: [PATCH 1323/1997] up --- .../java/io/legado/app/help/coroutine/CompositeCoroutine.kt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/coroutine/CompositeCoroutine.kt b/app/src/main/java/io/legado/app/help/coroutine/CompositeCoroutine.kt index c832b475d..3f76acbe6 100644 --- a/app/src/main/java/io/legado/app/help/coroutine/CompositeCoroutine.kt +++ b/app/src/main/java/io/legado/app/help/coroutine/CompositeCoroutine.kt @@ -1,7 +1,5 @@ package io.legado.app.help.coroutine -import android.util.Log - class CompositeCoroutine : CoroutineContainer { private var resources: HashSet>? = null @@ -78,10 +76,7 @@ class CompositeCoroutine : CoroutineContainer { resources = null } - Log.e("TAG", "size: ${set?.size}") - set?.forEachIndexed { index, coroutine -> - Log.e("TAG", "index: $index") coroutine.cancel() } } From dd4fa27856d700b71a82ff6612db8f5854b0e451 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 6 Sep 2019 08:37:16 +0800 Subject: [PATCH 1324/1997] up --- app/src/main/java/io/legado/app/data/api/IHttpGetApi.kt | 4 ++-- app/src/main/java/io/legado/app/data/api/IHttpPostApi.kt | 4 ++-- app/src/main/java/io/legado/app/help/JsExtensions.kt | 2 +- .../main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/api/IHttpGetApi.kt b/app/src/main/java/io/legado/app/data/api/IHttpGetApi.kt index a5b0e60c6..e4180fa59 100644 --- a/app/src/main/java/io/legado/app/data/api/IHttpGetApi.kt +++ b/app/src/main/java/io/legado/app/data/api/IHttpGetApi.kt @@ -31,12 +31,12 @@ interface IHttpGetApi { fun get( @Url url: String, @HeaderMap headers: Map - ): Call> + ): Call @GET fun getMap( @Url url: String, @QueryMap(encoded = true) queryMap: Map, @HeaderMap headers: Map - ): Call> + ): Call } diff --git a/app/src/main/java/io/legado/app/data/api/IHttpPostApi.kt b/app/src/main/java/io/legado/app/data/api/IHttpPostApi.kt index 113a77291..0aa3ef3db 100644 --- a/app/src/main/java/io/legado/app/data/api/IHttpPostApi.kt +++ b/app/src/main/java/io/legado/app/data/api/IHttpPostApi.kt @@ -34,12 +34,12 @@ interface IHttpPostApi { @Url url: String, @FieldMap(encoded = true) fieldMap: Map, @HeaderMap headers: Map - ): Call> + ): Call @POST fun postBody( @Url url: String, @Body body: RequestBody, @HeaderMap headers: Map - ): Call> + ): Call } diff --git a/app/src/main/java/io/legado/app/help/JsExtensions.kt b/app/src/main/java/io/legado/app/help/JsExtensions.kt index a09d338c3..643630121 100644 --- a/app/src/main/java/io/legado/app/help/JsExtensions.kt +++ b/app/src/main/java/io/legado/app/help/JsExtensions.kt @@ -17,7 +17,7 @@ class JsExtensions { val analyzeUrl = AnalyzeUrl(urlStr, null, null, null, null, null) val call = analyzeUrl.getResponse() val response = call.execute() - response.body()?.toString() + response.body() } catch (e: Exception) { e.localizedMessage } diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt index 29b6fe1f4..bdd18608c 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt @@ -200,7 +200,7 @@ class AnalyzeUrl( GET, POST } - fun getResponse(): Call> { + fun getResponse(): Call { return when { method == Method.POST -> { if (fieldMap.isNotEmpty()) { From 721989d721ee250ba8eb6c59605baf2174e16900 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 6 Sep 2019 08:38:39 +0800 Subject: [PATCH 1325/1997] up --- .../io/legado/app/model/analyzeRule/AnalyzeRule.kt | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt index 668ab0b79..bc38b8571 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt @@ -533,18 +533,14 @@ class AnalyzeRule(private var book: BaseBook? = null) { * js实现跨域访问,不能删 */ fun ajax(urlStr: String): String? { - try { + return try { val analyzeUrl = AnalyzeUrl(urlStr, null, null, null, null, null) val call = analyzeUrl.getResponse() val response = call.execute() - if (response.body() != null) { - return response.body()!!.toString() - } + response.body() } catch (e: Exception) { - return e.localizedMessage + e.localizedMessage } - - return null } /** From 1789d04034f2abe02d917e858c90fcf0dd804267 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 6 Sep 2019 10:16:17 +0800 Subject: [PATCH 1326/1997] up --- app/src/main/java/io/legado/app/help/ReadBookConfig.kt | 5 ++--- app/src/main/java/io/legado/app/utils/IntExtensions.kt | 5 ++++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index 48c9bc27b..915ea9f5a 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -9,7 +9,6 @@ import io.legado.app.utils.* import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch -import okhttp3.internal.toHexString import java.io.BufferedWriter import java.io.File import java.io.FileWriter @@ -126,9 +125,9 @@ object ReadBookConfig { fun setTextColor(color: Int) { if (App.INSTANCE.isNightTheme) { - textColorNight = "#${color.toHexString()}" + textColorNight = "#${color.hexString}" } else { - textColor = "#${color.toHexString()}" + textColor = "#${color.hexString}" } } diff --git a/app/src/main/java/io/legado/app/utils/IntExtensions.kt b/app/src/main/java/io/legado/app/utils/IntExtensions.kt index 11946c14a..2354a6a78 100644 --- a/app/src/main/java/io/legado/app/utils/IntExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/IntExtensions.kt @@ -10,4 +10,7 @@ val Int.dp: Int val Int.sp: Int get() = android.util.TypedValue.applyDimension( android.util.TypedValue.COMPLEX_UNIT_SP, this.toFloat(), Resources.getSystem().displayMetrics - ).toInt() \ No newline at end of file + ).toInt() + +val Int.hexString: String + get() = Integer.toHexString(this) \ No newline at end of file From d2a8e5d9e7ec72cf2e8604ec04bf3010f2887a09 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 6 Sep 2019 10:17:49 +0800 Subject: [PATCH 1327/1997] up --- .../main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 7ab90a2f0..899074477 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -47,7 +47,6 @@ import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import okhttp3.internal.toHexString import org.jetbrains.anko.sdk27.listeners.onClick import org.jetbrains.anko.startActivity import org.jetbrains.anko.startActivityForResult @@ -499,7 +498,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea postEvent(Bus.UP_CONFIG, false) } BG_COLOR -> { - setBg(0, "#${color.toHexString()}") + setBg(0, "#${color.hexString}") ReadBookConfig.upBg() postEvent(Bus.UP_CONFIG, false) } From a292844219ca4316aab10a218845e0837d59d016 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 6 Sep 2019 10:22:36 +0800 Subject: [PATCH 1328/1997] up --- app/src/main/java/io/legado/app/help/storage/OldRule.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/storage/OldRule.kt b/app/src/main/java/io/legado/app/help/storage/OldRule.kt index 52d1deb0e..086c67d9f 100644 --- a/app/src/main/java/io/legado/app/help/storage/OldRule.kt +++ b/app/src/main/java/io/legado/app/help/storage/OldRule.kt @@ -94,9 +94,13 @@ object OldRule { private fun toNewUrl(oldUrl: String?): String? { if (oldUrl == null) return null - if (oldUrl.startsWith("", true)) return oldUrl - val map = HashMap() var url: String = oldUrl + if (oldUrl.startsWith("", true)) { + url = url.replace("=searchKey", "={{key}}") + .replace("=searchPage", "={{page}}") + return url + } + val map = HashMap() var mather = headerPattern.matcher(url) if (mather.find()) { val header = mather.group() From 0a3dcc7f064e371ec0d6e2aa67585811d98e95a7 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 6 Sep 2019 10:55:49 +0800 Subject: [PATCH 1329/1997] up --- .../java/io/legado/app/help/http/SSLHelper.kt | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/http/SSLHelper.kt b/app/src/main/java/io/legado/app/help/http/SSLHelper.kt index 8fc40d27c..ef70ac1b5 100644 --- a/app/src/main/java/io/legado/app/help/http/SSLHelper.kt +++ b/app/src/main/java/io/legado/app/help/http/SSLHelper.kt @@ -1,5 +1,6 @@ package io.legado.app.help.http +import android.annotation.SuppressLint import java.io.IOException import java.io.InputStream import java.security.KeyManagementException @@ -21,10 +22,12 @@ object SSLHelper { * 这是一种有很大安全漏洞的办法 */ val unsafeTrustManager: X509TrustManager = object : X509TrustManager { + @SuppressLint("TrustAllX509TrustManager") @Throws(CertificateException::class) override fun checkClientTrusted(chain: Array, authType: String) { } + @SuppressLint("TrustAllX509TrustManager") @Throws(CertificateException::class) override fun checkServerTrusted(chain: Array, authType: String) { } @@ -34,16 +37,15 @@ object SSLHelper { } } - val unsafeSSLSocketFactory: SSLSocketFactory - get() { - try { - val sslContext = SSLContext.getInstance("SSL") - sslContext.init(null, arrayOf(unsafeTrustManager), SecureRandom()) - return sslContext.socketFactory - } catch (e: Exception) { - throw RuntimeException(e) - } + val unsafeSSLSocketFactory: SSLSocketFactory by lazy { + try { + val sslContext = SSLContext.getInstance("SSL") + sslContext.init(null, arrayOf(unsafeTrustManager), SecureRandom()) + sslContext.socketFactory + } catch (e: Exception) { + throw RuntimeException(e) } + } /** * 此类是用于主机名验证的基接口。 在握手期间,如果 URL 的主机名和服务器的标识主机名不匹配, From 09320bd133b4d3ed4a380c716fb79d46b4723517 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 6 Sep 2019 11:25:05 +0800 Subject: [PATCH 1330/1997] up --- app/src/main/java/io/legado/app/help/storage/OldRule.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/help/storage/OldRule.kt b/app/src/main/java/io/legado/app/help/storage/OldRule.kt index 086c67d9f..3c49817a8 100644 --- a/app/src/main/java/io/legado/app/help/storage/OldRule.kt +++ b/app/src/main/java/io/legado/app/help/storage/OldRule.kt @@ -26,7 +26,7 @@ object OldRule { source = GSON.fromJsonObject(json) } runCatching { - source ?: let { + if (source == null || source?.searchUrl.isNullOrBlank()) { source = BookSource().apply { val jsonItem = jsonPath.parse(json) bookSourceUrl = jsonItem.readString("bookSourceUrl") ?: "" From b67ed8dee98ffcb2c5d75a2efe35ea9b6b3192a8 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 6 Sep 2019 11:28:59 +0800 Subject: [PATCH 1331/1997] up --- .../io/legado/app/help/http/HttpHelper.kt | 42 +++++++++---------- .../java/io/legado/app/lib/webdav/WebDav.kt | 9 ++-- .../io/legado/app/lib/webdav/http/OkHttp.kt | 7 ---- 3 files changed, 26 insertions(+), 32 deletions(-) delete mode 100644 app/src/main/java/io/legado/app/lib/webdav/http/OkHttp.kt diff --git a/app/src/main/java/io/legado/app/help/http/HttpHelper.kt b/app/src/main/java/io/legado/app/help/http/HttpHelper.kt index 342d0a1e3..5ae7c286e 100644 --- a/app/src/main/java/io/legado/app/help/http/HttpHelper.kt +++ b/app/src/main/java/io/legado/app/help/http/HttpHelper.kt @@ -7,27 +7,7 @@ import java.util.concurrent.TimeUnit object HttpHelper { - val client: OkHttpClient = getOkHttpClient() - - inline fun getApiService(baseUrl: String): T { - return getRetrofit(baseUrl).create(T::class.java) - } - - inline fun getApiService(baseUrl: String, encode: String): T { - return getRetrofit(baseUrl, encode).create(T::class.java) - } - - fun getRetrofit(baseUrl: String, encode: String? = null): Retrofit { - return Retrofit.Builder().baseUrl(baseUrl) - //增加返回值为字符串的支持(以实体类返回) - .addConverterFactory(EncodeConverter.create(encode)) - //增加返回值为Observable的支持 - .addCallAdapterFactory(CoroutinesCallAdapterFactory.create()) - .client(client) - .build() - } - - private fun getOkHttpClient(): OkHttpClient { + val client: OkHttpClient by lazy { val default = ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) .tlsVersions(TlsVersion.TLS_1_2) .build() @@ -50,7 +30,25 @@ object HttpHelper { .protocols(listOf(Protocol.HTTP_1_1)) .addInterceptor(getHeaderInterceptor()) - return builder.build() + builder.build() + } + + inline fun getApiService(baseUrl: String): T { + return getRetrofit(baseUrl).create(T::class.java) + } + + inline fun getApiService(baseUrl: String, encode: String): T { + return getRetrofit(baseUrl, encode).create(T::class.java) + } + + fun getRetrofit(baseUrl: String, encode: String? = null): Retrofit { + return Retrofit.Builder().baseUrl(baseUrl) + //增加返回值为字符串的支持(以实体类返回) + .addConverterFactory(EncodeConverter.create(encode)) + //增加返回值为Observable的支持 + .addCallAdapterFactory(CoroutinesCallAdapterFactory.create()) + .client(client) + .build() } private fun getHeaderInterceptor(): Interceptor { diff --git a/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt b/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt index f35e41db3..ec1dc573e 100644 --- a/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt +++ b/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt @@ -1,10 +1,13 @@ package io.legado.app.lib.webdav +import io.legado.app.help.http.HttpHelper import io.legado.app.lib.webdav.http.Handler import io.legado.app.lib.webdav.http.HttpAuth -import io.legado.app.lib.webdav.http.OkHttp -import okhttp3.* +import okhttp3.Credentials import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.Request +import okhttp3.RequestBody +import okhttp3.Response import org.jsoup.Jsoup import java.io.File import java.io.IOException @@ -32,7 +35,7 @@ constructor(url: String) { return field } - private val okHttpClient: OkHttpClient = OkHttp.okHttpClient + private val okHttpClient = HttpHelper.client val path: String get() = url.toString() diff --git a/app/src/main/java/io/legado/app/lib/webdav/http/OkHttp.kt b/app/src/main/java/io/legado/app/lib/webdav/http/OkHttp.kt deleted file mode 100644 index 6861deb62..000000000 --- a/app/src/main/java/io/legado/app/lib/webdav/http/OkHttp.kt +++ /dev/null @@ -1,7 +0,0 @@ -package io.legado.app.lib.webdav.http - -import okhttp3.OkHttpClient - -object OkHttp { - val okHttpClient: OkHttpClient = OkHttpClient.Builder().build() -} \ No newline at end of file From 6ec36d848af593023819b9cd549a8eeb3c7797ec Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 6 Sep 2019 11:31:29 +0800 Subject: [PATCH 1332/1997] up --- .../java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt index 20851e59f..a36693ddc 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt @@ -135,7 +135,7 @@ class ReadStyleDialog : DialogFragment() { tv_text_size.text = textSize.toString() postEvent(Bus.UP_CONFIG, true) } - iv_line_size_remove.onClick { + iv_text_size_remove.onClick { textSize-- if (textSize < 5) textSize = 5 seek_text_size.progress = textSize - 5 From bd09590d36fed68e4307c49c2948547ec4af2b12 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 6 Sep 2019 11:45:48 +0800 Subject: [PATCH 1333/1997] up --- .../legado/app/model/webbook/SourceDebug.kt | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt index cd599f54b..97008b566 100644 --- a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt +++ b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt @@ -60,17 +60,15 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { fun startDebug(key: String) { cancelDebug() startTime = System.currentTimeMillis() - with(webBook) { - if (key.isAbsUrl()) { - val book = Book() - book.origin = sourceUrl - book.bookUrl = key - printLog(sourceUrl, 1, "开始访问$key") - infoDebug(book) - } else { - printLog(sourceUrl, 1, "开始搜索关键字$key") - searchDebug(key) - } + if (key.isAbsUrl()) { + val book = Book() + book.origin = webBook.sourceUrl + book.bookUrl = key + printLog(webBook.sourceUrl, 1, "开始访问$key") + infoDebug(book) + } else { + printLog(webBook.sourceUrl, 1, "开始搜索关键字$key") + searchDebug(key) } } From fdfbc65df68e7226efeda631d5418a5d9a764519 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 6 Sep 2019 12:37:27 +0800 Subject: [PATCH 1334/1997] up --- app/src/main/java/io/legado/app/constant/AppConst.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/constant/AppConst.kt b/app/src/main/java/io/legado/app/constant/AppConst.kt index 3d86a738b..158e1e4b4 100644 --- a/app/src/main/java/io/legado/app/constant/AppConst.kt +++ b/app/src/main/java/io/legado/app/constant/AppConst.kt @@ -18,7 +18,8 @@ object AppConst { const val APP_TAG = "Legado" const val RC_IMPORT_YUEDU_DATA = 100 - const val userAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.2357.134 Safari/537.36" + const val userAgent = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36" val SCRIPT_ENGINE: ScriptEngine = ScriptEngineManager().getEngineByName("rhino") From e37b94fcfc270d79a18138c2f5816207322c58a8 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 6 Sep 2019 15:13:27 +0800 Subject: [PATCH 1335/1997] up --- app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt index bdd18608c..4a958caa1 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt @@ -68,7 +68,7 @@ class AnalyzeUrl( init { baseUrl?.let { - this.baseUrl = it.split(",\n*".toRegex(), 1)[0] + this.baseUrl = it.split(",[^\\{]*".toRegex(), 1)[0] } headerMapF?.let { headerMap.putAll(it) } //替换参数 From 658cbe9995b0003bc5193e48ec8dc4abda46bdb2 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 6 Sep 2019 15:17:37 +0800 Subject: [PATCH 1336/1997] up --- app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt index 4a958caa1..49c4f92b3 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt @@ -90,7 +90,7 @@ class AnalyzeUrl( ruleUrl = if (page <= pages.size) { ruleUrl.replace(matcher.group(), pages[page - 1].trim { it <= ' ' }) } else { - ruleUrl.replace(matcher.group(), pages[pages.size - 1].trim { it <= ' ' }) + ruleUrl.replace(matcher.group(), pages.last().trim { it <= ' ' }) } } } From 627ce6c164295df78bd1b9492dcbf05ad9c2a296 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 6 Sep 2019 15:53:15 +0800 Subject: [PATCH 1337/1997] up --- .../java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt index 49c4f92b3..080345ab1 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt @@ -186,16 +186,6 @@ class AnalyzeUrl( } } - /** - * 执行JS - */ - @Throws(Exception::class) - private fun evalJS(jsStr: String, result: Any): Any { - val bindings = SimpleBindings() - bindings["result"] = result - return SCRIPT_ENGINE.eval(jsStr, bindings) - } - enum class Method { GET, POST } From 2e405256790f2724f6c5ea927c5aaf0c48530ace Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 6 Sep 2019 15:58:16 +0800 Subject: [PATCH 1338/1997] up --- .../main/java/io/legado/app/help/http/EncodeConverter.kt | 8 +------- app/src/main/java/io/legado/app/help/http/HttpHelper.kt | 2 +- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/http/EncodeConverter.kt b/app/src/main/java/io/legado/app/help/http/EncodeConverter.kt index a371135d0..b17f50ef8 100644 --- a/app/src/main/java/io/legado/app/help/http/EncodeConverter.kt +++ b/app/src/main/java/io/legado/app/help/http/EncodeConverter.kt @@ -6,7 +6,7 @@ import retrofit2.Retrofit import java.lang.reflect.Type import java.nio.charset.Charset -class EncodeConverter private constructor(private val encode: String? = null) : Converter.Factory() { +class EncodeConverter(private val encode: String? = null) : Converter.Factory() { override fun responseBodyConverter( type: Type?, @@ -33,10 +33,4 @@ class EncodeConverter private constructor(private val encode: String? = null) : } } - companion object { - - fun create(encode: String? = null): EncodeConverter { - return EncodeConverter(encode) - } - } } diff --git a/app/src/main/java/io/legado/app/help/http/HttpHelper.kt b/app/src/main/java/io/legado/app/help/http/HttpHelper.kt index 5ae7c286e..2945d2882 100644 --- a/app/src/main/java/io/legado/app/help/http/HttpHelper.kt +++ b/app/src/main/java/io/legado/app/help/http/HttpHelper.kt @@ -44,7 +44,7 @@ object HttpHelper { fun getRetrofit(baseUrl: String, encode: String? = null): Retrofit { return Retrofit.Builder().baseUrl(baseUrl) //增加返回值为字符串的支持(以实体类返回) - .addConverterFactory(EncodeConverter.create(encode)) + .addConverterFactory(EncodeConverter(encode)) //增加返回值为Observable的支持 .addCallAdapterFactory(CoroutinesCallAdapterFactory.create()) .client(client) From bbc18cf1bded24e7d686b6518fddd5bbf6e267c3 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 6 Sep 2019 17:52:12 +0800 Subject: [PATCH 1339/1997] up --- .../main/java/io/legado/app/constant/Bus.kt | 2 +- .../io/legado/app/service/ReadAloudService.kt | 4 +-- .../app/ui/readbook/ReadBookActivity.kt | 25 +++++++++++++------ .../app/ui/readbook/config/ReadAloudDialog.kt | 3 +++ 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/io/legado/app/constant/Bus.kt b/app/src/main/java/io/legado/app/constant/Bus.kt index eb2783a8f..d81f8f224 100644 --- a/app/src/main/java/io/legado/app/constant/Bus.kt +++ b/app/src/main/java/io/legado/app/constant/Bus.kt @@ -5,7 +5,7 @@ object Bus { const val UP_BOOK = "sourceDebugLog" const val ALOUD_STATE = "aloud_state" const val TTS_START = "ttsStart" - const val TTS_NEXT = "ttsNextPage" + const val TTS_TURN_PAGE = "ttsTurnPage" const val TTS_DS = "ttsDs" const val BATTERY_CHANGED = "batteryChanged" const val TIME_CHANGED = "timeChanged" diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index bb138ad9f..e6b62b68f 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -416,7 +416,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, readAloudNumber += contentList[nowSpeak].length + 1 nowSpeak += 1 if (nowSpeak >= contentList.size) { - postEvent(Bus.TTS_NEXT, true) + postEvent(Bus.TTS_TURN_PAGE, 2) } } @@ -425,7 +425,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, textChapter?.let { if (readAloudNumber + start > it.getReadLength(pageIndex + 1)) { pageIndex++ - postEvent(Bus.TTS_NEXT, false) + postEvent(Bus.TTS_TURN_PAGE, 1) postEvent(Bus.TTS_START, readAloudNumber + start) } } diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 899074477..a913c90ef 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -581,13 +581,24 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } } - observeEvent(Bus.TTS_NEXT) { - if (it) { - moveToNextChapter() - } else { - viewModel.durPageIndex = viewModel.durPageIndex + 1 - page_view.upContent() - viewModel.saveRead() + observeEvent(Bus.TTS_TURN_PAGE) { + when (it) { + 1 -> { + viewModel.durPageIndex = viewModel.durPageIndex + 1 + page_view.upContent() + viewModel.saveRead() + } + 2 -> moveToNextChapter() + -1 -> { + if (viewModel.durPageIndex > 0) { + viewModel.durPageIndex = viewModel.durPageIndex - 1 + page_view.upContent() + viewModel.saveRead() + } else { + moveToPrevChapter() + } + } + -2 -> moveToPrevChapter() } } observeEvent(Bus.REPLACE) { diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt index 0069e748d..e3f26e37c 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt @@ -18,6 +18,7 @@ import io.legado.app.utils.* import kotlinx.android.synthetic.main.activity_read_book.* import kotlinx.android.synthetic.main.dialog_read_aloud.* import org.jetbrains.anko.sdk27.listeners.onClick +import org.jetbrains.anko.sdk27.listeners.onLongClick class ReadAloudDialog : DialogFragment() { @@ -119,7 +120,9 @@ class ReadAloudDialog : DialogFragment() { iv_stop.onClick { ReadAloudService.stop(requireContext()); dismiss() } iv_play_pause.onClick { postEvent(Bus.READ_ALOUD_BUTTON, true) } iv_play_prev.onClick { ReadAloudService.prevParagraph(requireContext()) } + iv_play_prev.onLongClick { postEvent(Bus.TTS_TURN_PAGE, -2); true } iv_play_next.onClick { ReadAloudService.nextParagraph(requireContext()) } + iv_play_next.onLongClick { postEvent(Bus.TTS_TURN_PAGE, 2); true } } private fun upPlayState(state: Int) { From 40e74961477730238a5b1c6fc8e10bfe2f2e1c6e Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 6 Sep 2019 17:56:28 +0800 Subject: [PATCH 1340/1997] up --- app/src/main/java/io/legado/app/service/ReadAloudService.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index e6b62b68f..de01ff154 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -295,6 +295,11 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, nowSpeak-- readAloudNumber -= contentList[nowSpeak].length.minus(1) playTTS() + textChapter?.let { + if (readAloudNumber < it.getReadLength(pageIndex)) { + postEvent(Bus.TTS_TURN_PAGE, -1) + } + } } } From 9f38e08253d377a190a32a2fcb1cc2717cbb774f Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 6 Sep 2019 17:58:46 +0800 Subject: [PATCH 1341/1997] up --- app/src/main/java/io/legado/app/service/ReadAloudService.kt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index de01ff154..e6b62b68f 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -295,11 +295,6 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, nowSpeak-- readAloudNumber -= contentList[nowSpeak].length.minus(1) playTTS() - textChapter?.let { - if (readAloudNumber < it.getReadLength(pageIndex)) { - postEvent(Bus.TTS_TURN_PAGE, -1) - } - } } } From 2d1ef9fd6a27fd891dc7b6da25e6229a96667f34 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 6 Sep 2019 18:00:21 +0800 Subject: [PATCH 1342/1997] up --- app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index a913c90ef..0d549f183 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -598,7 +598,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea moveToPrevChapter() } } - -2 -> moveToPrevChapter() + -2 -> moveToPrevChapter(false) } } observeEvent(Bus.REPLACE) { From 54333ffc4f99e2b261c6d06f2eb1b0ed555680af Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 6 Sep 2019 20:57:14 +0800 Subject: [PATCH 1343/1997] up --- .../app/ui/main/bookshelf/BookshelfViewModel.kt | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt index fae740f80..463c0b015 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt @@ -35,8 +35,10 @@ class BookshelfViewModel(application: Application) : BaseViewModel(application) if (book.origin != BookType.local) { val bookSource = App.db.bookSourceDao().getBookSource(book.origin) bookSource?.let { - updateList.add(book.bookUrl) - postEvent(Bus.UP_BOOK, book.bookUrl) + synchronized(this) { + updateList.add(book.bookUrl) + postEvent(Bus.UP_BOOK, book.bookUrl) + } WebBook(bookSource).getChapterList(book).onSuccess(IO) { it?.let { App.db.bookDao().update(book) @@ -45,8 +47,10 @@ class BookshelfViewModel(application: Application) : BaseViewModel(application) } } }.onFinally { - updateList.remove(book.bookUrl) - postEvent(Bus.UP_BOOK, book.bookUrl) + synchronized(this) { + updateList.remove(book.bookUrl) + postEvent(Bus.UP_BOOK, book.bookUrl) + } } } } From b71d317eebe5d18dc658d5e5de6871350d2f4e1f Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 6 Sep 2019 21:05:23 +0800 Subject: [PATCH 1344/1997] up --- .../java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt index bfd23569c..213a325e6 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt @@ -48,7 +48,10 @@ class BookshelfAdapter : PagedListAdapter(D } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { - return MyViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_bookshelf_list, parent, false)) + return MyViewHolder( + LayoutInflater.from(parent.context) + .inflate(R.layout.item_bookshelf_list, parent, false) + ) } override fun onBindViewHolder(holder: MyViewHolder, position: Int) { From 128a1b6a0ba7596739ec4700987aa11aa952cc9a Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 6 Sep 2019 21:32:57 +0800 Subject: [PATCH 1345/1997] up --- .../legado/app/ui/changesource/ChangeSourceDialog.kt | 10 ++++++++-- .../app/ui/changesource/ChangeSourceViewModel.kt | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt index b4ff6b8ba..dcb1398cd 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt @@ -37,7 +37,11 @@ class ChangeSourceDialog : DialogFragment(), private lateinit var viewModel: ChangeSourceViewModel private lateinit var changeSourceAdapter: ChangeSourceAdapter - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { viewModel = getViewModel(ChangeSourceViewModel::class.java) return inflater.inflate(R.layout.dialog_change_source, container) } @@ -75,7 +79,9 @@ class ChangeSourceDialog : DialogFragment(), private fun initRecyclerView() { changeSourceAdapter = ChangeSourceAdapter(requireContext(), this) recycler_view.layoutManager = LinearLayoutManager(context) - recycler_view.addItemDecoration(DividerItemDecoration(requireContext(), LinearLayout.VERTICAL)) + recycler_view.addItemDecoration( + DividerItemDecoration(requireContext(), LinearLayout.VERTICAL) + ) recycler_view.adapter = changeSourceAdapter viewModel.callBack = this } diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt index df0caee90..533813a73 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt @@ -35,7 +35,7 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio callBack?.adapter()?.let { val books = searchBooks.toList() books.sorted() - val diffResult = DiffUtil.calculateDiff(DiffCallBack(it.getItems(), searchBooks.toList())) + val diffResult = DiffUtil.calculateDiff(DiffCallBack(it.getItems(), books)) withContext(Main) { synchronized(this) { it.setItemsNoNotify(books) From b0492a2138486a66f66033b19aad7e3f24b94c77 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 6 Sep 2019 21:47:00 +0800 Subject: [PATCH 1346/1997] up --- .../app/ui/changesource/ChangeSourceViewModel.kt | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt index 533813a73..5d7410b5b 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt @@ -54,16 +54,14 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio WebBook(item).searchBook(name, scope = this@execute) .timeout(30000L) .onSuccess(IO) { - it?.let { list -> - for (searchBook in list) { - if (searchBook.name == name && searchBook.author == author) { - if (searchBook.tocUrl.isEmpty()) { - loadBookInfo(searchBook.toBook()) - } else { - loadChapter(searchBook.toBook()) - } - break + it?.forEach { searchBook -> + if (searchBook.name == name && searchBook.author == author) { + if (searchBook.tocUrl.isEmpty()) { + loadBookInfo(searchBook.toBook()) + } else { + loadChapter(searchBook.toBook()) } + return@onSuccess } } } From 3c791686979928a7fc35d87403ba2451f336e8a5 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 6 Sep 2019 22:13:23 +0800 Subject: [PATCH 1347/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 94 ++++++++----------- .../io/legado/app/ui/readbook/ReadMenu.kt | 25 ++--- 2 files changed, 48 insertions(+), 71 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 0d549f183..d381e410b 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -54,6 +54,7 @@ import org.jetbrains.anko.toast class ReadBookActivity : VMBaseActivity(R.layout.activity_read_book), PageView.CallBack, + ReadMenu.Callback, ChangeSourceDialog.CallBack, ReadBookViewModel.CallBack, ColorPickerDialogListener { @@ -87,12 +88,12 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea override fun onWindowFocusChanged(hasFocus: Boolean) { super.onWindowFocusChanged(hasFocus) - Help.upSystemUiVisibility(window, !read_menu.isVisible) + upSystemUiVisibility() } override fun onResume() { super.onResume() - Help.upSystemUiVisibility(window, !read_menu.isVisible) + upSystemUiVisibility() timeElectricityReceiver = TimeElectricityReceiver.register(this) } @@ -102,7 +103,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea unregisterReceiver(it) timeElectricityReceiver = null } - Help.upSystemUiVisibility(window, !read_menu.isVisible) + upSystemUiVisibility() } /** @@ -125,57 +126,6 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea startActivity(intent) } } - read_menu.setListener(object : ReadMenu.Callback { - override fun setScreenBrightness(value: Int) { - this@ReadBookActivity.setScreenBrightness(value) - } - - override fun autoPage() { - - } - - override fun skipToPage(page: Int) { - viewModel.durPageIndex = page - page_view.upContent() - curPageChanged() - } - - override fun skipPreChapter() { - moveToPrevChapter(false) - page_view.upContent() - } - - override fun skipNextChapter() { - moveToNextChapter() - page_view.upContent() - } - - override fun openReplaceRule() { - startActivity() - } - - override fun openChapterList() { - viewModel.bookData.value?.let { - startActivity(Pair("bookUrl", it.bookUrl)) - } - } - - override fun showReadStyle() { - ReadStyleDialog().show(supportFragmentManager, "readStyle") - } - - override fun showMoreSetting() { - MoreConfigDialog().show(supportFragmentManager, "moreConfig") - } - - override fun menuShow() { - Help.upSystemUiVisibility(window, !read_menu.isVisible) - } - - override fun menuHide() { - Help.upSystemUiVisibility(window, !read_menu.isVisible) - } - }) } fun showPaddingConfig() { @@ -445,6 +395,38 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } + override fun autoPage() { + + } + + override fun skipToPage(page: Int) { + viewModel.durPageIndex = page + page_view.upContent() + curPageChanged() + } + + override fun openReplaceRule() { + startActivity() + } + + override fun openChapterList() { + viewModel.bookData.value?.let { + startActivity(Pair("bookUrl", it.bookUrl)) + } + } + + override fun showReadStyle() { + ReadStyleDialog().show(supportFragmentManager, "readStyle") + } + + override fun showMoreSetting() { + MoreConfigDialog().show(supportFragmentManager, "moreConfig") + } + + override fun upSystemUiVisibility() { + Help.upSystemUiVisibility(window, !read_menu.isVisible) + } + /** * 朗读按钮 */ @@ -479,7 +461,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea /** * 设置屏幕亮度 */ - private fun setScreenBrightness(value: Int) { + override fun setScreenBrightness(value: Int) { var brightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE if (this.getPrefBoolean("brightnessAuto").not()) { brightness = value.toFloat() @@ -560,7 +542,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } observeEvent(Bus.UP_CONFIG) { - Help.upSystemUiVisibility(window, !read_menu.isVisible) + upSystemUiVisibility() page_view.upBg() content_view.upStyle() page_view.upStyle() diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt index 630735701..362059afc 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt @@ -17,9 +17,8 @@ import kotlinx.android.synthetic.main.view_read_menu.view.* import org.jetbrains.anko.sdk27.listeners.onClick class ReadMenu : FrameLayout { - - private var callback: Callback? = null var cnaShowMenu: Boolean = false + private var callback: Callback? = null private lateinit var menuTopIn: Animation private lateinit var menuTopOut: Animation private lateinit var menuBottomIn: Animation @@ -37,6 +36,7 @@ class ReadMenu : FrameLayout { ) init { + callback = activity as? Callback inflate(context, R.layout.view_read_menu, this) if (context.isNightTheme) { fabNightTheme.setImageResource(R.drawable.ic_daytime) @@ -48,6 +48,7 @@ class ReadMenu : FrameLayout { vwNavigationBar.onClick { } seek_brightness.progress = context.getPrefInt("brightness", 100) upBrightness() + bindEvent() } private fun upBrightness() { @@ -61,11 +62,6 @@ class ReadMenu : FrameLayout { callback?.setScreenBrightness(context.getPrefInt("brightness", 100)) } - fun setListener(callback: Callback) { - this.callback = callback - bindEvent() - } - fun runMenuIn() { this.visible() title_bar.visible() @@ -138,10 +134,10 @@ class ReadMenu : FrameLayout { } //上一章 - tv_pre.onClick { callback?.skipPreChapter() } + tv_pre.onClick { callback?.moveToPrevChapter(false) } //下一章 - tv_next.onClick { callback?.skipNextChapter() } + tv_next.onClick { callback?.moveToNextChapter() } //目录 ll_catalog.onClick { @@ -177,7 +173,7 @@ class ReadMenu : FrameLayout { menuBottomIn = AnimationUtils.loadAnimation(context, R.anim.anim_readbook_bottom_in) menuTopIn.setAnimationListener(object : Animation.AnimationListener { override fun onAnimationStart(animation: Animation) { - callback?.menuShow() + callback?.upSystemUiVisibility() } override fun onAnimationEnd(animation: Animation) { @@ -211,7 +207,7 @@ class ReadMenu : FrameLayout { bottom_menu.invisible() cnaShowMenu = false onMenuOutEnd?.invoke() - callback?.menuHide() + callback?.upSystemUiVisibility() } override fun onAnimationRepeat(animation: Animation) { @@ -234,14 +230,13 @@ class ReadMenu : FrameLayout { fun setScreenBrightness(value: Int) fun autoPage() fun skipToPage(page: Int) - fun skipPreChapter() - fun skipNextChapter() + fun moveToPrevChapter(last: Boolean) + fun moveToNextChapter() fun openReplaceRule() fun openChapterList() fun showReadStyle() fun showMoreSetting() - fun menuShow() - fun menuHide() + fun upSystemUiVisibility() } } From 4ca744791ebb7add5058048cdc7d6016a3a232d8 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 6 Sep 2019 22:18:08 +0800 Subject: [PATCH 1348/1997] up --- .../java/io/legado/app/ui/readbook/ReadBookActivity.kt | 2 +- app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index d381e410b..d9a1cdd26 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -463,7 +463,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea */ override fun setScreenBrightness(value: Int) { var brightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE - if (this.getPrefBoolean("brightnessAuto").not()) { + if (!read_menu.brightnessAuto()) { brightness = value.toFloat() if (brightness < 1f) brightness = 1f brightness /= 255f diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt index 362059afc..4afcfda10 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt @@ -52,7 +52,7 @@ class ReadMenu : FrameLayout { } private fun upBrightness() { - if (context.getPrefBoolean("brightnessAuto", true)) { + if (brightnessAuto()) { iv_brightness_auto.setColorFilter(context.accentColor) seek_brightness.isEnabled = false } else { @@ -83,11 +83,15 @@ class ReadMenu : FrameLayout { seek_read_page.progress = dur } + fun brightnessAuto(): Boolean { + return context.getPrefBoolean("brightnessAuto", true) + } + private fun bindEvent() { iv_brightness_auto.onClick { context.putPrefBoolean( "brightnessAuto", - !context.getPrefBoolean("brightnessAuto", true) + !brightnessAuto() ) upBrightness() } From 2f659ac47a5ffd6299fffaa4d9ed981673ad7642 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 6 Sep 2019 22:20:14 +0800 Subject: [PATCH 1349/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 2 +- .../io/legado/app/ui/readbook/ReadMenu.kt | 30 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index d9a1cdd26..c219b2430 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -54,7 +54,7 @@ import org.jetbrains.anko.toast class ReadBookActivity : VMBaseActivity(R.layout.activity_read_book), PageView.CallBack, - ReadMenu.Callback, + ReadMenu.CallBack, ChangeSourceDialog.CallBack, ReadBookViewModel.CallBack, ColorPickerDialogListener { diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt index 4afcfda10..d5a8a97a1 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt @@ -18,7 +18,7 @@ import org.jetbrains.anko.sdk27.listeners.onClick class ReadMenu : FrameLayout { var cnaShowMenu: Boolean = false - private var callback: Callback? = null + private var callBack: CallBack? = null private lateinit var menuTopIn: Animation private lateinit var menuTopOut: Animation private lateinit var menuBottomIn: Animation @@ -36,7 +36,7 @@ class ReadMenu : FrameLayout { ) init { - callback = activity as? Callback + callBack = activity as? CallBack inflate(context, R.layout.view_read_menu, this) if (context.isNightTheme) { fabNightTheme.setImageResource(R.drawable.ic_daytime) @@ -59,7 +59,7 @@ class ReadMenu : FrameLayout { iv_brightness_auto.setColorFilter(context.buttonDisabledColor) seek_brightness.isEnabled = true } - callback?.setScreenBrightness(context.getPrefInt("brightness", 100)) + callBack?.setScreenBrightness(context.getPrefInt("brightness", 100)) } fun runMenuIn() { @@ -97,7 +97,7 @@ class ReadMenu : FrameLayout { } seek_brightness.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { - callback?.setScreenBrightness(progress) + callBack?.setScreenBrightness(progress) } override fun onStartTrackingTouch(seekBar: SeekBar?) { @@ -121,15 +121,15 @@ class ReadMenu : FrameLayout { } override fun onStopTrackingTouch(seekBar: SeekBar) { - callback?.skipToPage(seekBar.progress) + callBack?.skipToPage(seekBar.progress) } }) //自动翻页 - fabAutoPage.onClick { callback?.autoPage() } + fabAutoPage.onClick { callBack?.autoPage() } //替换 - fabReplaceRule.onClick { callback?.openReplaceRule() } + fabReplaceRule.onClick { callBack?.openReplaceRule() } //夜间模式 fabNightTheme.onClick { @@ -138,15 +138,15 @@ class ReadMenu : FrameLayout { } //上一章 - tv_pre.onClick { callback?.moveToPrevChapter(false) } + tv_pre.onClick { callBack?.moveToPrevChapter(false) } //下一章 - tv_next.onClick { callback?.moveToNextChapter() } + tv_next.onClick { callBack?.moveToNextChapter() } //目录 ll_catalog.onClick { runMenuOut { - callback?.openChapterList() + callBack?.openChapterList() } } @@ -160,14 +160,14 @@ class ReadMenu : FrameLayout { //界面 ll_font.onClick { runMenuOut { - callback?.showReadStyle() + callBack?.showReadStyle() } } //设置 ll_setting.onClick { runMenuOut { - callback?.showMoreSetting() + callBack?.showMoreSetting() } } } @@ -177,7 +177,7 @@ class ReadMenu : FrameLayout { menuBottomIn = AnimationUtils.loadAnimation(context, R.anim.anim_readbook_bottom_in) menuTopIn.setAnimationListener(object : Animation.AnimationListener { override fun onAnimationStart(animation: Animation) { - callback?.upSystemUiVisibility() + callBack?.upSystemUiVisibility() } override fun onAnimationEnd(animation: Animation) { @@ -211,7 +211,7 @@ class ReadMenu : FrameLayout { bottom_menu.invisible() cnaShowMenu = false onMenuOutEnd?.invoke() - callback?.upSystemUiVisibility() + callBack?.upSystemUiVisibility() } override fun onAnimationRepeat(animation: Animation) { @@ -230,7 +230,7 @@ class ReadMenu : FrameLayout { } } - interface Callback { + interface CallBack { fun setScreenBrightness(value: Int) fun autoPage() fun skipToPage(page: Int) From 31d1872b7628d1660c71f63f9417178ae2a5fbdd Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 6 Sep 2019 22:27:12 +0800 Subject: [PATCH 1350/1997] up --- app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt index d5a8a97a1..62a8a834e 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt @@ -47,11 +47,11 @@ class ReadMenu : FrameLayout { vw_bg.onClick { } vwNavigationBar.onClick { } seek_brightness.progress = context.getPrefInt("brightness", 100) - upBrightness() + upBrightnessState() bindEvent() } - private fun upBrightness() { + private fun upBrightnessState() { if (brightnessAuto()) { iv_brightness_auto.setColorFilter(context.accentColor) seek_brightness.isEnabled = false @@ -59,7 +59,6 @@ class ReadMenu : FrameLayout { iv_brightness_auto.setColorFilter(context.buttonDisabledColor) seek_brightness.isEnabled = true } - callBack?.setScreenBrightness(context.getPrefInt("brightness", 100)) } fun runMenuIn() { @@ -93,7 +92,8 @@ class ReadMenu : FrameLayout { "brightnessAuto", !brightnessAuto() ) - upBrightness() + upBrightnessState() + callBack?.setScreenBrightness(context.getPrefInt("brightness", 100)) } seek_brightness.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { From fe310524e70119e475f56d31791aa35121401957 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 6 Sep 2019 22:36:36 +0800 Subject: [PATCH 1351/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 17 --------------- .../io/legado/app/ui/readbook/ReadMenu.kt | 21 ++++++++++++++++--- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index c219b2430..3bec6c67e 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -9,7 +9,6 @@ import android.text.SpannableStringBuilder import android.view.KeyEvent import android.view.Menu import android.view.MenuItem -import android.view.WindowManager import android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES import androidx.core.view.isVisible import androidx.lifecycle.Observer @@ -83,7 +82,6 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea changeSourceDialog = supportFragmentManager.findFragmentByTag(ChangeSourceDialog.tag) as? ChangeSourceDialog } - setScreenBrightness(getPrefInt("brightness", 100)) } override fun onWindowFocusChanged(hasFocus: Boolean) { @@ -458,21 +456,6 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } - /** - * 设置屏幕亮度 - */ - override fun setScreenBrightness(value: Int) { - var brightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE - if (!read_menu.brightnessAuto()) { - brightness = value.toFloat() - if (brightness < 1f) brightness = 1f - brightness /= 255f - } - val params = window.attributes - params.screenBrightness = brightness - window.attributes = params - } - override fun onColorSelected(dialogId: Int, color: Int) = with(ReadBookConfig.getConfig()) { when (dialogId) { TEXT_COLOR -> { diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt index 62a8a834e..45442dc66 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt @@ -2,6 +2,7 @@ package io.legado.app.ui.readbook import android.content.Context import android.util.AttributeSet +import android.view.WindowManager import android.view.animation.Animation import android.view.animation.AnimationUtils import android.widget.FrameLayout @@ -59,6 +60,22 @@ class ReadMenu : FrameLayout { iv_brightness_auto.setColorFilter(context.buttonDisabledColor) seek_brightness.isEnabled = true } + setScreenBrightness(context.getPrefInt("brightness", 100)) + } + + /** + * 设置屏幕亮度 + */ + private fun setScreenBrightness(value: Int) { + var brightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE + if (!brightnessAuto()) { + brightness = value.toFloat() + if (brightness < 1f) brightness = 1f + brightness /= 255f + } + val params = activity?.window?.attributes + params?.screenBrightness = brightness + activity?.window?.attributes = params } fun runMenuIn() { @@ -93,11 +110,10 @@ class ReadMenu : FrameLayout { !brightnessAuto() ) upBrightnessState() - callBack?.setScreenBrightness(context.getPrefInt("brightness", 100)) } seek_brightness.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { - callBack?.setScreenBrightness(progress) + setScreenBrightness(progress) } override fun onStartTrackingTouch(seekBar: SeekBar?) { @@ -231,7 +247,6 @@ class ReadMenu : FrameLayout { } interface CallBack { - fun setScreenBrightness(value: Int) fun autoPage() fun skipToPage(page: Int) fun moveToPrevChapter(last: Boolean) From 693522f2dfcd8190f386c4f90f8b026b6eaf362d Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 6 Sep 2019 22:37:19 +0800 Subject: [PATCH 1352/1997] up --- app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt index 45442dc66..b15272816 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt @@ -99,7 +99,7 @@ class ReadMenu : FrameLayout { seek_read_page.progress = dur } - fun brightnessAuto(): Boolean { + private fun brightnessAuto(): Boolean { return context.getPrefBoolean("brightnessAuto", true) } From f409d502f77935668df967e3a589848884da4cef Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 6 Sep 2019 23:03:05 +0800 Subject: [PATCH 1353/1997] up --- .../io/legado/app/data/dao/ReplaceRuleDao.kt | 9 +++----- .../app/ui/booksource/BookSourceActivity.kt | 11 +++++----- .../app/ui/replacerule/ReplaceRuleActivity.kt | 4 ++++ .../app/ui/replacerule/ReplaceRuleAdapter.kt | 8 +++++-- .../ui/replacerule/ReplaceRuleViewModel.kt | 7 ++++++ app/src/main/res/layout/item_book_source.xml | 22 +++++++++---------- app/src/main/res/layout/item_replace_rule.xml | 19 ++++++++++++---- 7 files changed, 52 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt b/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt index 6c0031aa4..3b75e9555 100644 --- a/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt @@ -15,6 +15,9 @@ interface ReplaceRuleDao { @Query("SELECT id FROM replace_rules ORDER BY sortOrder ASC") fun observeAllIds(): LiveData> + @get:Query("SELECT MIN(sortOrder) FROM replace_rules") + val minOrder: Int + @get:Query("SELECT MAX(sortOrder) FROM replace_rules") val maxOrder: Int @@ -60,15 +63,9 @@ interface ReplaceRuleDao { @Insert(onConflict = OnConflictStrategy.REPLACE) fun insert(vararg replaceRule: ReplaceRule): List - @Update - fun update(replaceRules: ReplaceRule) - @Update fun update(vararg replaceRules: ReplaceRule) - @Delete - fun delete(replaceRules: ReplaceRule) - @Delete fun delete(vararg replaceRules: ReplaceRule) } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt index 73646f3ff..b98a8bf2f 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt @@ -6,6 +6,7 @@ import android.view.Menu import android.view.MenuItem import android.view.SubMenu import androidx.appcompat.widget.SearchView +import androidx.core.content.ContextCompat import androidx.lifecycle.LiveData import androidx.lifecycle.Observer import androidx.paging.LivePagedListBuilder @@ -98,11 +99,11 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity ATH.applyEdgeEffectColor(recycler_view) recycler_view.layoutManager = LinearLayoutManager(this) recycler_view.addItemDecoration( - DividerItemDecoration( - this, - LinearLayoutManager.VERTICAL - ) - ) + DividerItemDecoration(this, DividerItemDecoration.VERTICAL).apply { + ContextCompat.getDrawable(baseContext, R.drawable.ic_divider)?.let { + this.setDrawable(it) + } + }) adapter = BookSourceAdapter(this) recycler_view.adapter = adapter val itemTouchCallback = ItemTouchCallback() diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt index 3242e1e2b..5c0796169 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt @@ -94,4 +94,8 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi .newInstance(rule.id) .show(supportFragmentManager, "editReplace") } + + override fun toTop(rule: ReplaceRule) { + viewModel.toTop(rule) + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt index 01e14e1a1..55b9d6c3c 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt @@ -70,13 +70,16 @@ class ReplaceRuleAdapter(context: Context, var callBack: CallBack) : rule.isEnabled = swt_enabled.isChecked callBack.update(rule) } + iv_edit.onClick { + callBack.edit(rule) + } iv_menu_more.onClick { val popupMenu = PopupMenu(context, it) - popupMenu.menu.add(Menu.NONE, R.id.menu_edit, Menu.NONE, R.string.edit) + popupMenu.menu.add(Menu.NONE, R.id.menu_top, Menu.NONE, R.string.to_top) popupMenu.menu.add(Menu.NONE, R.id.menu_del, Menu.NONE, R.string.delete) popupMenu.setOnMenuItemClickListener { item -> when (item.itemId) { - R.id.menu_edit -> callBack.edit(rule) + R.id.menu_top -> callBack.toTop(rule) R.id.menu_del -> callBack.delete(rule) } true @@ -90,5 +93,6 @@ class ReplaceRuleAdapter(context: Context, var callBack: CallBack) : fun update(rule: ReplaceRule) fun delete(rule: ReplaceRule) fun edit(rule: ReplaceRule) + fun toTop(rule: ReplaceRule) } } diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt index af6648bd5..85f7cf430 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt @@ -22,6 +22,13 @@ class ReplaceRuleViewModel(application: Application) : BaseViewModel(application } } + fun toTop(rule: ReplaceRule) { + execute { + rule.order = App.db.replaceRuleDao().minOrder - 1 + App.db.replaceRuleDao().update(rule) + } + } + fun addGroup(group: String) { execute { val sources = App.db.replaceRuleDao().noGroup diff --git a/app/src/main/res/layout/item_book_source.xml b/app/src/main/res/layout/item_book_source.xml index fb6263705..a95216088 100644 --- a/app/src/main/res/layout/item_book_source.xml +++ b/app/src/main/res/layout/item_book_source.xml @@ -20,34 +20,34 @@ - - diff --git a/app/src/main/res/layout/item_replace_rule.xml b/app/src/main/res/layout/item_replace_rule.xml index 7b14d9375..ef3f211c0 100644 --- a/app/src/main/res/layout/item_replace_rule.xml +++ b/app/src/main/res/layout/item_replace_rule.xml @@ -14,7 +14,7 @@ android:layout_weight="1" tools:ignore="RtlSymmetry" /> - + + Date: Sat, 7 Sep 2019 11:19:52 +0800 Subject: [PATCH 1354/1997] up --- .../java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt index 5c0796169..b10b14762 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt @@ -45,6 +45,8 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi when (item.itemId) { R.id.menu_add_replace_rule -> ReplaceEditDialog().show(supportFragmentManager, "replaceNew") + R.id.menu_group_manage -> + GroupManageDialog().show(supportFragmentManager, "groupManage") } return super.onCompatOptionsItemSelected(item) } From 78cdea0b1b46418229cb6f4040c59542329464f1 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 7 Sep 2019 11:55:55 +0800 Subject: [PATCH 1355/1997] up --- .../io/legado/app/data/dao/ReplaceRuleDao.kt | 2 +- .../app/ui/replacerule/GroupManageDialog.kt | 2 +- .../app/ui/replacerule/ReplaceRuleActivity.kt | 26 ++++++++++++++++++- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt b/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt index 3b75e9555..e5ee321e3 100644 --- a/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt @@ -46,7 +46,7 @@ interface ReplaceRuleDao { fun findEnabledByScope(name: String, origin: String): List @Query("select `group` from replace_rules") - fun observeGroup(): LiveData> + fun liveGroup(): LiveData> @Query("select * from replace_rules where `group` like '%' || :group || '%'") fun getByGroup(group: String): List diff --git a/app/src/main/java/io/legado/app/ui/replacerule/GroupManageDialog.kt b/app/src/main/java/io/legado/app/ui/replacerule/GroupManageDialog.kt index 03e76b6c6..a7799cc87 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/GroupManageDialog.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/GroupManageDialog.kt @@ -70,7 +70,7 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { DividerItemDecoration(requireContext(), RecyclerView.VERTICAL) ) recycler_view.adapter = adapter - App.db.bookSourceDao().liveGroup().observe(viewLifecycleOwner, Observer { + App.db.replaceRuleDao().liveGroup().observe(viewLifecycleOwner, Observer { val groups = linkedSetOf() it.map { group -> groups.addAll(group.splitNotBlank(",", ";")) diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt index b10b14762..b2b9b0b8c 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt @@ -3,6 +3,7 @@ package io.legado.app.ui.replacerule import android.os.Bundle import android.view.Menu import android.view.MenuItem +import android.view.SubMenu import androidx.core.content.ContextCompat import androidx.lifecycle.LiveData import androidx.lifecycle.Observer @@ -18,6 +19,7 @@ import io.legado.app.data.entities.ReplaceRule import io.legado.app.help.ItemTouchCallback import io.legado.app.lib.theme.ATH import io.legado.app.utils.getViewModel +import io.legado.app.utils.splitNotBlank import kotlinx.android.synthetic.main.activity_replace_rule.* import org.jetbrains.anko.doAsync @@ -30,6 +32,8 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi private lateinit var adapter: ReplaceRuleAdapter private var rulesLiveData: LiveData>? = null private var allEnabled = false + private var groups = hashSetOf() + private var groupMenu: SubMenu? = null override fun onActivityCreated(savedInstanceState: Bundle?) { initRecyclerView() @@ -41,6 +45,12 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi return super.onCompatCreateOptionsMenu(menu) } + override fun onPrepareOptionsMenu(menu: Menu?): Boolean { + groupMenu = menu?.findItem(R.id.menu_group)?.subMenu + upGroupMenu() + return super.onPrepareOptionsMenu(menu) + } + override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { R.id.menu_add_replace_rule -> @@ -68,11 +78,25 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi ItemTouchHelper(itemTouchCallback).attachToRecyclerView(recycler_view) } - private fun initDataObservers() { rulesLiveData?.removeObservers(this) rulesLiveData = LivePagedListBuilder(App.db.replaceRuleDao().observeAll(), 30).build() rulesLiveData?.observe(this, Observer> { adapter.submitList(it) }) + + App.db.replaceRuleDao().liveGroup().observe(this, Observer { + groups.clear() + it.map { group -> + groups.addAll(group.splitNotBlank(",", ";")) + } + upGroupMenu() + }) + } + + private fun upGroupMenu() { + groupMenu?.removeGroup(R.id.source_group) + groups.map { + groupMenu?.add(R.id.source_group, Menu.NONE, Menu.NONE, it) + } } private fun updateEnableAll() { From f9b2e7f7a806a636849e52a42098795de470cdb7 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 7 Sep 2019 12:04:36 +0800 Subject: [PATCH 1356/1997] up --- app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt b/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt index e5ee321e3..b3488d8b3 100644 --- a/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt @@ -45,7 +45,7 @@ interface ReplaceRuleDao { ) fun findEnabledByScope(name: String, origin: String): List - @Query("select `group` from replace_rules") + @Query("select `group` from replace_rules where `group` is not null and `group` <> ''") fun liveGroup(): LiveData> @Query("select * from replace_rules where `group` like '%' || :group || '%'") From 6bafe1dacd63e1a37c794ef5d10df2b66eb68c0b Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 7 Sep 2019 12:05:20 +0800 Subject: [PATCH 1357/1997] up --- app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt index 7d47afa6f..97f7da559 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt @@ -17,7 +17,7 @@ interface BookSourceDao { @Query("select * from book_sources where enabledExplore = 1 and exploreUrl is not null and exploreUrl <> '' order by customOrder asc") fun liveExplore(): LiveData> - @Query("select bookSourceGroup from book_sources") + @Query("select bookSourceGroup from book_sources where bookSourceGroup is not null and bookSourceGroup <> ''") fun liveGroup(): LiveData> @Query("select distinct enabled from book_sources where bookSourceName like :searchKey or `bookSourceGroup` like :searchKey or bookSourceUrl like :searchKey") From 47d93aea7e8b7691d2c65d19a7d38b25a95c3bac Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 7 Sep 2019 12:06:04 +0800 Subject: [PATCH 1358/1997] up --- app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt | 2 +- app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt index 97f7da559..ef66a2372 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt @@ -32,7 +32,7 @@ interface BookSourceDao { @Query("select * from book_sources where bookSourceGroup like '%' || :group || '%'") fun getByGroup(group: String): List - @get:Query("select * from book_sources where bookSourceGroup = null or bookSourceGroup = ''") + @get:Query("select * from book_sources where bookSourceGroup is null or bookSourceGroup = ''") val noGroup: List @get:Query("select * from book_sources order by customOrder asc") diff --git a/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt b/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt index b3488d8b3..907b96d71 100644 --- a/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt @@ -51,7 +51,7 @@ interface ReplaceRuleDao { @Query("select * from replace_rules where `group` like '%' || :group || '%'") fun getByGroup(group: String): List - @get:Query("select * from replace_rules where `group` = null or `group` = ''") + @get:Query("select * from replace_rules where `group` is null or `group` = ''") val noGroup: List @get:Query("SELECT COUNT(*) - SUM(isEnabled) FROM replace_rules") From 01f953ccaaaf9cf76c3fce3add420dc36da76ee2 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 7 Sep 2019 12:47:26 +0800 Subject: [PATCH 1359/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 7 ++++- .../app/ui/readbook/config/ReadAloudDialog.kt | 26 ++++++++++--------- .../app/ui/replacerule/ReplaceRuleActivity.kt | 21 +++++++++++++++ .../main/res/layout/activity_replace_rule.xml | 1 + app/src/main/res/values/strings.xml | 2 +- 5 files changed, 43 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 3bec6c67e..8cbab8ce6 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -54,6 +54,7 @@ import org.jetbrains.anko.toast class ReadBookActivity : VMBaseActivity(R.layout.activity_read_book), PageView.CallBack, ReadMenu.CallBack, + ReadAloudDialog.CallBack, ChangeSourceDialog.CallBack, ReadBookViewModel.CallBack, ColorPickerDialogListener { @@ -63,7 +64,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea private val requestCodeEditSource = 111 private var changeSourceDialog: ChangeSourceDialog? = null private var timeElectricityReceiver: TimeElectricityReceiver? = null - var readAloudStatus = Status.STOP + override var readAloudStatus = Status.STOP override fun onActivityCreated(savedInstanceState: Bundle?) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { @@ -317,6 +318,10 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } + override fun showMenu() { + read_menu.runMenuIn() + } + override fun chapterSize(): Int { return viewModel.chapterSize } diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt index e3f26e37c..a48544363 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt @@ -15,18 +15,19 @@ import io.legado.app.service.ReadAloudService import io.legado.app.ui.readbook.Help import io.legado.app.ui.readbook.ReadBookActivity import io.legado.app.utils.* -import kotlinx.android.synthetic.main.activity_read_book.* import kotlinx.android.synthetic.main.dialog_read_aloud.* import org.jetbrains.anko.sdk27.listeners.onClick import org.jetbrains.anko.sdk27.listeners.onLongClick class ReadAloudDialog : DialogFragment() { + var callBack: CallBack? = null override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { + callBack = activity as? CallBack return inflater.inflate(R.layout.dialog_read_aloud, container) } @@ -111,12 +112,10 @@ class ReadAloudDialog : DialogFragment() { private fun initOnClick() { iv_menu.onClick { - val activity = activity - if (activity is ReadBookActivity) { - activity.read_menu.runMenuIn() - dismiss() - } + callBack?.showMenu() + dismiss() } + iv_menu.onLongClick { callBack?.openChapterList(); true } iv_stop.onClick { ReadAloudService.stop(requireContext()); dismiss() } iv_play_pause.onClick { postEvent(Bus.READ_ALOUD_BUTTON, true) } iv_play_prev.onClick { ReadAloudService.prevParagraph(requireContext()) } @@ -134,13 +133,16 @@ class ReadAloudDialog : DialogFragment() { } private fun upTtsSpeechRate() { - val activity = activity ReadAloudService.upTtsSpeechRate(requireContext()) - if (activity is ReadBookActivity) { - if (activity.readAloudStatus == Status.PLAY) { - ReadAloudService.pause(requireContext()) - ReadAloudService.resume(requireContext()) - } + if (callBack?.readAloudStatus == Status.PLAY) { + ReadAloudService.pause(requireContext()) + ReadAloudService.resume(requireContext()) } } + + interface CallBack { + fun showMenu() + fun openChapterList() + var readAloudStatus: Int + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt index b2b9b0b8c..c839da8bf 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt @@ -4,6 +4,7 @@ import android.os.Bundle import android.view.Menu import android.view.MenuItem import android.view.SubMenu +import androidx.appcompat.widget.SearchView import androidx.core.content.ContextCompat import androidx.lifecycle.LiveData import androidx.lifecycle.Observer @@ -18,13 +19,16 @@ import io.legado.app.base.VMBaseActivity import io.legado.app.data.entities.ReplaceRule import io.legado.app.help.ItemTouchCallback import io.legado.app.lib.theme.ATH +import io.legado.app.lib.theme.primaryTextColor import io.legado.app.utils.getViewModel import io.legado.app.utils.splitNotBlank import kotlinx.android.synthetic.main.activity_replace_rule.* +import kotlinx.android.synthetic.main.view_search.* import org.jetbrains.anko.doAsync class ReplaceRuleActivity : VMBaseActivity(R.layout.activity_replace_rule), + SearchView.OnQueryTextListener, ReplaceRuleAdapter.CallBack { override val viewModel: ReplaceRuleViewModel get() = getViewModel(ReplaceRuleViewModel::class.java) @@ -37,6 +41,7 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi override fun onActivityCreated(savedInstanceState: Bundle?) { initRecyclerView() + initSearchView() initDataObservers() } @@ -78,6 +83,14 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi ItemTouchHelper(itemTouchCallback).attachToRecyclerView(recycler_view) } + private fun initSearchView() { + ATH.setTint(search_view, primaryTextColor) + search_view.onActionViewExpanded() + search_view.queryHint = getString(R.string.replace_purify_search) + search_view.clearFocus() + search_view.setOnQueryTextListener(this) + } + private fun initDataObservers() { rulesLiveData?.removeObservers(this) rulesLiveData = LivePagedListBuilder(App.db.replaceRuleDao().observeAll(), 30).build() @@ -107,6 +120,14 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi } } + override fun onQueryTextChange(newText: String?): Boolean { + return false + } + + override fun onQueryTextSubmit(query: String?): Boolean { + return false + } + override fun update(rule: ReplaceRule) { viewModel.update(rule) } diff --git a/app/src/main/res/layout/activity_replace_rule.xml b/app/src/main/res/layout/activity_replace_rule.xml index 4c3ceff0f..cefeba9d0 100644 --- a/app/src/main/res/layout/activity_replace_rule.xml +++ b/app/src/main/res/layout/activity_replace_rule.xml @@ -10,6 +10,7 @@ android:id="@+id/title_bar" android:layout_width="match_parent" android:layout_height="wrap_content" + app:contentLayout="@layout/view_search" app:layout_constraintTop_toTopOf="parent" app:title="@string/replace_purify" /> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2c849417a..8799447c5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -32,7 +32,7 @@ 替换净化 暂无 启用 - + 替换净化-搜索 书架 订阅 最近阅读 From 67edd4172fccb82aff7e957c8911800806308b0f Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 7 Sep 2019 12:50:18 +0800 Subject: [PATCH 1360/1997] up --- .../legado/app/ui/readbook/config/ReadAloudDialog.kt | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt index a48544363..62f7829aa 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt @@ -13,7 +13,6 @@ import io.legado.app.constant.Bus import io.legado.app.constant.Status import io.legado.app.service.ReadAloudService import io.legado.app.ui.readbook.Help -import io.legado.app.ui.readbook.ReadBookActivity import io.legado.app.utils.* import kotlinx.android.synthetic.main.dialog_read_aloud.* import org.jetbrains.anko.sdk27.listeners.onClick @@ -57,9 +56,8 @@ class ReadAloudDialog : DialogFragment() { private fun initData() { observeEvent(Bus.ALOUD_STATE) { upPlayState(it) } observeEvent(Bus.TTS_DS) { seek_timer.progress = it } - val activity = activity - if (activity is ReadBookActivity) { - upPlayState(activity.readAloudStatus) + callBack?.readAloudStatus?.let { + upPlayState(it) } seek_timer.progress = ReadAloudService.timeMinute tv_timer.text = requireContext().getString(R.string.timer_m, ReadAloudService.timeMinute) @@ -111,10 +109,7 @@ class ReadAloudDialog : DialogFragment() { } private fun initOnClick() { - iv_menu.onClick { - callBack?.showMenu() - dismiss() - } + iv_menu.onClick { callBack?.showMenu(); dismiss() } iv_menu.onLongClick { callBack?.openChapterList(); true } iv_stop.onClick { ReadAloudService.stop(requireContext()); dismiss() } iv_play_pause.onClick { postEvent(Bus.READ_ALOUD_BUTTON, true) } From 3dfc060d64af63b97a385b68b7abbcdb7dcdb3ea Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 7 Sep 2019 16:48:39 +0800 Subject: [PATCH 1361/1997] up --- .../io/legado/app/ui/readbook/config/BgTextConfigDialog.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt index bd67d8352..9ecde4b0e 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt @@ -30,6 +30,7 @@ import io.legado.app.utils.getCompatColor import io.legado.app.utils.postEvent import kotlinx.android.synthetic.main.dialog_read_bg_text.* import kotlinx.android.synthetic.main.item_bg_image.view.* +import org.jetbrains.anko.sdk27.listeners.onCheckedChange import org.jetbrains.anko.sdk27.listeners.onClick class BgTextConfigDialog : DialogFragment() { @@ -97,6 +98,11 @@ class BgTextConfigDialog : DialogFragment() { } private fun initView() = with(ReadBookConfig.getConfig()) { + sw_dark_status_icon.onCheckedChange { buttonView, isChecked -> + if (buttonView?.isPressed == true) { + setStatusIconDark(isChecked) + } + } tv_text_color.onClick { ColorPickerDialog.newBuilder() .setColor(textColor()) From 84f179fc002916be57bd011c6501601886068607 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 7 Sep 2019 17:29:22 +0800 Subject: [PATCH 1362/1997] up --- .../java/io/legado/app/base/BaseActivity.kt | 17 +++++------- .../main/java/io/legado/app/lib/theme/ATH.kt | 26 +++++++++++++------ .../java/io/legado/app/ui/readbook/Help.kt | 3 +-- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/io/legado/app/base/BaseActivity.kt b/app/src/main/java/io/legado/app/base/BaseActivity.kt index 96d3d21d5..513e367af 100644 --- a/app/src/main/java/io/legado/app/base/BaseActivity.kt +++ b/app/src/main/java/io/legado/app/base/BaseActivity.kt @@ -1,6 +1,5 @@ package io.legado.app.base -import android.graphics.Color import android.os.Bundle import android.view.Menu import android.view.MenuItem @@ -10,15 +9,17 @@ import androidx.appcompat.app.AppCompatActivity import io.legado.app.R import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.ColorUtils -import io.legado.app.lib.theme.ThemeStore import io.legado.app.lib.theme.primaryColor -import io.legado.app.utils.* +import io.legado.app.utils.applyTint +import io.legado.app.utils.disableAutoFill +import io.legado.app.utils.hideSoftInput import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.MainScope import kotlinx.coroutines.cancel -abstract class BaseActivity(private val layoutID: Int, private val fullScreen: Boolean = true) : AppCompatActivity(), +abstract class BaseActivity(private val layoutID: Int, private val fullScreen: Boolean = true) : + AppCompatActivity(), CoroutineScope by MainScope() { override fun onCreate(savedInstanceState: Bundle?) { @@ -80,14 +81,8 @@ abstract class BaseActivity(private val layoutID: Int, private val fullScreen: B window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_STABLE window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) - if (isTransparentStatusBar) { - window.statusBarColor = Color.TRANSPARENT - } else { - window.statusBarColor = getCompatColor(R.color.status_bar_bag) - } - } else { - window.statusBarColor = ThemeStore.statusBarColor(this, isTransparentStatusBar) } + ATH.setStatusbarColorAuto(this, fullScreen) } open fun observeLiveBus() { diff --git a/app/src/main/java/io/legado/app/lib/theme/ATH.kt b/app/src/main/java/io/legado/app/lib/theme/ATH.kt index c5d284064..53de3a488 100644 --- a/app/src/main/java/io/legado/app/lib/theme/ATH.kt +++ b/app/src/main/java/io/legado/app/lib/theme/ATH.kt @@ -4,6 +4,7 @@ import android.annotation.SuppressLint import android.app.Activity import android.app.ActivityManager import android.content.Context +import android.graphics.Color import android.os.Build import android.view.View import android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR @@ -34,18 +35,27 @@ object ATH { ) > since } - fun setStatusbarColorAuto(activity: Activity) { + fun setStatusbarColorAuto(activity: Activity, fullScreen: Boolean) { + val isTransparentStatusBar = activity.isTransparentStatusBar setStatusbarColor( activity, - ThemeStore.statusBarColor(activity, activity.isTransparentStatusBar) + ThemeStore.statusBarColor(activity, isTransparentStatusBar), + isTransparentStatusBar, fullScreen ) } - fun setStatusbarColor(activity: Activity, color: Int) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + fun setStatusbarColor( + activity: Activity, + color: Int, + isTransparentStatusBar: Boolean, + fullScreen: Boolean + ) { + if (fullScreen && isTransparentStatusBar) { + activity.window.statusBarColor = Color.TRANSPARENT + } else { activity.window.statusBarColor = color - setLightStatusbarAuto(activity, color) } + setLightStatusbarAuto(activity, color) } fun setLightStatusbarAuto(activity: Activity, bgColor: Int) { @@ -68,10 +78,10 @@ object ATH { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val decorView = activity.window.decorView var systemUiVisibility = decorView.systemUiVisibility - if (enabled) { - systemUiVisibility = systemUiVisibility or SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR + systemUiVisibility = if (enabled) { + systemUiVisibility or SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR } else { - systemUiVisibility = systemUiVisibility and SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR.inv() + systemUiVisibility and SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR.inv() } decorView.systemUiVisibility = systemUiVisibility } diff --git a/app/src/main/java/io/legado/app/ui/readbook/Help.kt b/app/src/main/java/io/legado/app/ui/readbook/Help.kt index c6226d3a8..2828c9f05 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/Help.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/Help.kt @@ -20,8 +20,7 @@ object Help { or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) val hideNavigationBar = App.INSTANCE.getPrefBoolean("hideNavigationBar") if (hideNavigationBar) { - flag = - flag or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + flag = flag or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION } if (hide) { if (App.INSTANCE.getPrefBoolean("hideStatusBar")) { From ca2ca0caa5d0a612ef291081a6e7dfa83febd5f3 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 7 Sep 2019 17:31:05 +0800 Subject: [PATCH 1363/1997] up --- app/src/main/java/io/legado/app/base/BaseActivity.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/base/BaseActivity.kt b/app/src/main/java/io/legado/app/base/BaseActivity.kt index 513e367af..094ec93c0 100644 --- a/app/src/main/java/io/legado/app/base/BaseActivity.kt +++ b/app/src/main/java/io/legado/app/base/BaseActivity.kt @@ -77,10 +77,13 @@ abstract class BaseActivity(private val layoutID: Int, private val fullScreen: B private fun setupSystemBar() { if (fullScreen) { - window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS or WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) + window.clearFlags( + WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS + or WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION + ) + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_STABLE - window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) } ATH.setStatusbarColorAuto(this, fullScreen) } From a137fcb03637960dfecd6776437f8040251371f0 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 7 Sep 2019 17:59:09 +0800 Subject: [PATCH 1364/1997] up --- .../java/io/legado/app/base/BaseActivity.kt | 2 +- .../main/java/io/legado/app/lib/theme/ATH.kt | 28 +++++++++---------- .../java/io/legado/app/ui/readbook/Help.kt | 19 ++++++++++--- .../app/ui/readbook/ReadBookActivity.kt | 2 +- .../ui/readbook/config/BgTextConfigDialog.kt | 6 ++-- .../ui/readbook/config/MoreConfigDialog.kt | 6 ++-- .../ui/readbook/config/PaddingConfigDialog.kt | 6 ++-- .../app/ui/readbook/config/ReadAloudDialog.kt | 6 ++-- .../app/ui/readbook/config/ReadStyleDialog.kt | 6 ++-- 9 files changed, 51 insertions(+), 30 deletions(-) diff --git a/app/src/main/java/io/legado/app/base/BaseActivity.kt b/app/src/main/java/io/legado/app/base/BaseActivity.kt index 094ec93c0..c02f4731a 100644 --- a/app/src/main/java/io/legado/app/base/BaseActivity.kt +++ b/app/src/main/java/io/legado/app/base/BaseActivity.kt @@ -85,7 +85,7 @@ abstract class BaseActivity(private val layoutID: Int, private val fullScreen: B window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_STABLE } - ATH.setStatusbarColorAuto(this, fullScreen) + ATH.setStatusBarColorAuto(this, fullScreen) } open fun observeLiveBus() { diff --git a/app/src/main/java/io/legado/app/lib/theme/ATH.kt b/app/src/main/java/io/legado/app/lib/theme/ATH.kt index 53de3a488..a09750b2a 100644 --- a/app/src/main/java/io/legado/app/lib/theme/ATH.kt +++ b/app/src/main/java/io/legado/app/lib/theme/ATH.kt @@ -35,16 +35,16 @@ object ATH { ) > since } - fun setStatusbarColorAuto(activity: Activity, fullScreen: Boolean) { + fun setStatusBarColorAuto(activity: Activity, fullScreen: Boolean) { val isTransparentStatusBar = activity.isTransparentStatusBar - setStatusbarColor( + setStatusBarColor( activity, ThemeStore.statusBarColor(activity, isTransparentStatusBar), isTransparentStatusBar, fullScreen ) } - fun setStatusbarColor( + fun setStatusBarColor( activity: Activity, color: Int, isTransparentStatusBar: Boolean, @@ -55,14 +55,14 @@ object ATH { } else { activity.window.statusBarColor = color } - setLightStatusbarAuto(activity, color) + setLightStatusBarAuto(activity, color) } - fun setLightStatusbarAuto(activity: Activity, bgColor: Int) { - setLightStatusbar(activity, ColorUtils.isColorLight(bgColor)) + fun setLightStatusBarAuto(activity: Activity, bgColor: Int) { + setLightStatusBar(activity, ColorUtils.isColorLight(bgColor)) } - fun setLightStatusbar(activity: Activity, enabled: Boolean) { + fun setLightStatusBar(activity: Activity, enabled: Boolean) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { val decorView = activity.window.decorView val systemUiVisibility = decorView.systemUiVisibility @@ -74,7 +74,7 @@ object ATH { } } - fun setLightNavigationbar(activity: Activity, enabled: Boolean) { + fun setLightNavigationBar(activity: Activity, enabled: Boolean) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val decorView = activity.window.decorView var systemUiVisibility = decorView.systemUiVisibility @@ -87,18 +87,18 @@ object ATH { } } - fun setLightNavigationbarAuto(activity: Activity, bgColor: Int) { - setLightNavigationbar(activity, ColorUtils.isColorLight(bgColor)) + fun setLightNavigationBarAuto(activity: Activity, bgColor: Int) { + setLightNavigationBar(activity, ColorUtils.isColorLight(bgColor)) } - fun setNavigationbarColorAuto(activity: Activity) { - setNavigationbarColor(activity, ThemeStore.navigationBarColor(activity)) + fun setNavigationBarColorAuto(activity: Activity) { + setNavigationBarColor(activity, ThemeStore.navigationBarColor(activity)) } - fun setNavigationbarColor(activity: Activity, color: Int) { + fun setNavigationBarColor(activity: Activity, color: Int) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { activity.window.navigationBarColor = color - setLightNavigationbarAuto(activity, color) + setLightNavigationBarAuto(activity, color) } } diff --git a/app/src/main/java/io/legado/app/ui/readbook/Help.kt b/app/src/main/java/io/legado/app/ui/readbook/Help.kt index 2828c9f05..eaf448006 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/Help.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/Help.kt @@ -4,16 +4,19 @@ import android.app.Activity import android.view.View import android.view.View.NO_ID import android.view.ViewGroup -import android.view.Window import io.legado.app.App +import io.legado.app.help.ReadBookConfig +import io.legado.app.lib.theme.ATH +import io.legado.app.lib.theme.ThemeStore import io.legado.app.utils.getPrefBoolean +import io.legado.app.utils.isTransparentStatusBar object Help { private const val NAVIGATION = "navigationBarBackground" - fun upSystemUiVisibility(window: Window, hide: Boolean = true) { + fun upSystemUiVisibility(activity: Activity, toolBarHide: Boolean = true) { var flag = (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_IMMERSIVE @@ -22,7 +25,7 @@ object Help { if (hideNavigationBar) { flag = flag or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION } - if (hide) { + if (toolBarHide) { if (App.INSTANCE.getPrefBoolean("hideStatusBar")) { flag = flag or View.SYSTEM_UI_FLAG_FULLSCREEN } @@ -30,7 +33,15 @@ object Help { flag = flag or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION } } - window.decorView.systemUiVisibility = flag + activity.window.decorView.systemUiVisibility = flag + if (toolBarHide) { + ATH.setLightStatusBar(activity, ReadBookConfig.getConfig().statusIconDark()) + } else { + ATH.setLightStatusBarAuto( + activity, + ThemeStore.statusBarColor(activity, activity.isTransparentStatusBar) + ) + } } /** diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 8cbab8ce6..19fd69675 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -427,7 +427,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } override fun upSystemUiVisibility() { - Help.upSystemUiVisibility(window, !read_menu.isVisible) + Help.upSystemUiVisibility(this, !read_menu.isVisible) } /** diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt index 9ecde4b0e..529654ae2 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt @@ -54,7 +54,10 @@ class BgTextConfigDialog : DialogFragment() { override fun onStart() { super.onStart() val dm = DisplayMetrics() - activity?.windowManager?.defaultDisplay?.getMetrics(dm) + activity?.let { + Help.upSystemUiVisibility(it) + it.windowManager?.defaultDisplay?.getMetrics(dm) + } dialog?.window?.let { it.setBackgroundDrawableResource(R.color.transparent) it.decorView.setPadding(0, 0, 0, 0) @@ -63,7 +66,6 @@ class BgTextConfigDialog : DialogFragment() { attr.gravity = Gravity.BOTTOM it.attributes = attr it.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) - Help.upSystemUiVisibility(it) } } diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt index 02dff931e..3e1652645 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt @@ -30,7 +30,10 @@ class MoreConfigDialog : DialogFragment() { override fun onStart() { super.onStart() val dm = DisplayMetrics() - activity?.windowManager?.defaultDisplay?.getMetrics(dm) + activity?.let { + Help.upSystemUiVisibility(it) + it.windowManager?.defaultDisplay?.getMetrics(dm) + } dialog?.window?.let { it.setBackgroundDrawableResource(R.color.transparent) it.decorView.setPadding(0, 0, 0, 0) @@ -39,7 +42,6 @@ class MoreConfigDialog : DialogFragment() { attr.gravity = Gravity.BOTTOM it.attributes = attr it.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) - Help.upSystemUiVisibility(it) } } diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.kt index a814ef6d0..779ba3dab 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.kt @@ -28,7 +28,10 @@ class PaddingConfigDialog : DialogFragment() { override fun onStart() { super.onStart() val dm = DisplayMetrics() - activity?.windowManager?.defaultDisplay?.getMetrics(dm) + activity?.let { + Help.upSystemUiVisibility(it) + it.windowManager?.defaultDisplay?.getMetrics(dm) + } dialog?.window?.let { it.setBackgroundDrawableResource(R.color.transparent) it.decorView.setPadding(0, 0, 0, 0) @@ -36,7 +39,6 @@ class PaddingConfigDialog : DialogFragment() { attr.dimAmount = 0.0f it.attributes = attr it.setLayout((dm.widthPixels * 0.9).toInt(), ViewGroup.LayoutParams.WRAP_CONTENT) - Help.upSystemUiVisibility(it) } } diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt index 62f7829aa..3922ee122 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt @@ -33,7 +33,10 @@ class ReadAloudDialog : DialogFragment() { override fun onStart() { super.onStart() val dm = DisplayMetrics() - activity?.windowManager?.defaultDisplay?.getMetrics(dm) + activity?.let { + Help.upSystemUiVisibility(it) + it.windowManager?.defaultDisplay?.getMetrics(dm) + } dialog?.window?.let { it.setBackgroundDrawableResource(R.color.transparent) it.decorView.setPadding(0, 0, 0, 0) @@ -42,7 +45,6 @@ class ReadAloudDialog : DialogFragment() { attr.gravity = Gravity.BOTTOM it.attributes = attr it.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) - Help.upSystemUiVisibility(it) } } diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt index a36693ddc..15fa51590 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt @@ -45,7 +45,10 @@ class ReadStyleDialog : DialogFragment() { override fun onStart() { super.onStart() val dm = DisplayMetrics() - activity?.windowManager?.defaultDisplay?.getMetrics(dm) + activity?.let { + Help.upSystemUiVisibility(it) + it.windowManager?.defaultDisplay?.getMetrics(dm) + } dialog?.window?.let { it.setBackgroundDrawableResource(R.color.transparent) it.decorView.setPadding(0, 0, 0, 0) @@ -54,7 +57,6 @@ class ReadStyleDialog : DialogFragment() { attr.gravity = Gravity.BOTTOM it.attributes = attr it.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) - Help.upSystemUiVisibility(it) } } From 316b7bbd5950636e7badc5c025adbc75f48d3084 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 7 Sep 2019 19:41:49 +0800 Subject: [PATCH 1365/1997] up --- .../main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 1 - app/src/main/java/io/legado/app/ui/widget/page/PageView.kt | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 19fd69675..b47f6001a 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -74,7 +74,6 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } setSupportActionBar(toolbar) initView() - page_view.callback = this viewModel.callBack = this viewModel.bookData.observe(this, Observer { title_bar.title = it.name }) viewModel.chapterListFinish.observe(this, Observer { loadContent() }) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index e05eb8c31..db51ab9e0 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -11,12 +11,13 @@ import io.legado.app.ui.widget.page.delegate.CoverPageDelegate import io.legado.app.ui.widget.page.delegate.NoAnimPageDelegate import io.legado.app.ui.widget.page.delegate.PageDelegate import io.legado.app.ui.widget.page.delegate.SlidePageDelegate +import io.legado.app.utils.activity import io.legado.app.utils.getPrefInt class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, attrs), PageDelegate.PageInterface { - var callback: CallBack? = null + private var callback: CallBack? = null private var pageDelegate: PageDelegate? = null private var pageFactory: TextPageFactory? = null @@ -25,6 +26,7 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att var nextPage: ContentView? = null init { + callback = activity as? CallBack prevPage = ContentView(context) addView(prevPage) nextPage = ContentView(context) From 8fdf876456ea6da458e7c0fce1ba05da8ec09b03 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 7 Sep 2019 21:26:27 +0800 Subject: [PATCH 1366/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 32 ++++++++++++------- .../io/legado/app/ui/readbook/ReadMenu.kt | 4 +-- .../io/legado/app/ui/widget/page/PageView.kt | 8 ++--- 3 files changed, 27 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index b47f6001a..e070950d6 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -372,21 +372,31 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea /** * 下一页 */ - override fun moveToNextChapter() { - viewModel.durPageIndex = 0 - viewModel.moveToNextChapter() - viewModel.saveRead() - curChapterChanged() + override fun moveToNextChapter(): Boolean { + return if (viewModel.durChapterIndex < viewModel.chapterSize - 1) { + viewModel.durPageIndex = 0 + viewModel.moveToNextChapter() + viewModel.saveRead() + curChapterChanged() + true + } else { + false + } } /** * 上一页 */ - override fun moveToPrevChapter(last: Boolean) { - viewModel.durPageIndex = if (last) viewModel.prevTextChapter?.lastIndex() ?: 0 else 0 - viewModel.moveToPrevChapter() - viewModel.saveRead() - curChapterChanged() + override fun moveToPrevChapter(last: Boolean): Boolean { + return if (viewModel.durChapterIndex > 0) { + viewModel.durPageIndex = if (last) viewModel.prevTextChapter?.lastIndex() ?: 0 else 0 + viewModel.moveToPrevChapter() + viewModel.saveRead() + curChapterChanged() + true + } else { + false + } } override fun clickCenter() { @@ -557,7 +567,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea page_view.upContent() viewModel.saveRead() } - 2 -> moveToNextChapter() + 2 -> if (moveToNextChapter()) ReadAloudService.stop(this) -1 -> { if (viewModel.durPageIndex > 0) { viewModel.durPageIndex = viewModel.durPageIndex - 1 diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt index b15272816..c9b15348a 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt @@ -249,8 +249,8 @@ class ReadMenu : FrameLayout { interface CallBack { fun autoPage() fun skipToPage(page: Int) - fun moveToPrevChapter(last: Boolean) - fun moveToNextChapter() + fun moveToPrevChapter(last: Boolean): Boolean + fun moveToNextChapter(): Boolean fun openReplaceRule() fun openChapterList() fun showReadStyle() diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index db51ab9e0..e64df6781 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -220,14 +220,14 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att fun loadContent(index: Int) /** - * 下一页 + * 下一章 */ - fun moveToNextChapter() + fun moveToNextChapter(): Boolean /** - * 上一页 + * 上一章 */ - fun moveToPrevChapter(last: Boolean = true) + fun moveToPrevChapter(last: Boolean = true): Boolean /** * 保存页数 From 966af854d8bb36f22a76823c60195c498d4cd532 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 7 Sep 2019 21:54:59 +0800 Subject: [PATCH 1367/1997] up --- .../main/java/io/legado/app/ui/readbook/ReadBookActivity.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index e070950d6..3e45d65d2 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -415,6 +415,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea viewModel.durPageIndex = page page_view.upContent() curPageChanged() + viewModel.saveRead() } override fun openReplaceRule() { @@ -567,7 +568,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea page_view.upContent() viewModel.saveRead() } - 2 -> if (moveToNextChapter()) ReadAloudService.stop(this) + 2 -> if (!moveToNextChapter()) ReadAloudService.stop(this) -1 -> { if (viewModel.durPageIndex > 0) { viewModel.durPageIndex = viewModel.durPageIndex - 1 From c9099b5b5acc5ed469f406f8d25dbd16733bb18a Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 7 Sep 2019 22:20:51 +0800 Subject: [PATCH 1368/1997] up --- .../main/java/io/legado/app/ui/readbook/ReadMenu.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt index c9b15348a..eb6d67b29 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt @@ -111,6 +111,7 @@ class ReadMenu : FrameLayout { ) upBrightnessState() } + //亮度调节 seek_brightness.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { setScreenBrightness(progress) @@ -200,11 +201,10 @@ class ReadMenu : FrameLayout { vw_menu_bg.onClick { runMenuOut() } val lp = vwNavigationBar.layoutParams lp.height = - if (context.getPrefBoolean("hideNavigationBar") and Help.isNavigationBarExist( - activity - ) - ) - context.getNavigationBarHeight() else 0 + if (context.getPrefBoolean("hideNavigationBar") + && Help.isNavigationBarExist(activity) + ) context.getNavigationBarHeight() + else 0 vwNavigationBar.layoutParams = lp } From 337d393f71f149c002669ec2c397f64edc8bdfa7 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 7 Sep 2019 22:23:05 +0800 Subject: [PATCH 1369/1997] up --- .../java/io/legado/app/ui/readbook/ReadMenu.kt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt index eb6d67b29..dccdce01e 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt @@ -199,13 +199,13 @@ class ReadMenu : FrameLayout { override fun onAnimationEnd(animation: Animation) { vw_menu_bg.onClick { runMenuOut() } - val lp = vwNavigationBar.layoutParams - lp.height = - if (context.getPrefBoolean("hideNavigationBar") - && Help.isNavigationBarExist(activity) - ) context.getNavigationBarHeight() - else 0 - vwNavigationBar.layoutParams = lp + vwNavigationBar.layoutParams = vwNavigationBar.layoutParams.apply { + height = + if (context.getPrefBoolean("hideNavigationBar") + && Help.isNavigationBarExist(activity) + ) context.getNavigationBarHeight() + else 0 + } } override fun onAnimationRepeat(animation: Animation) { From f6e28c60367f516ae9196a3764449c00f7b42d60 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 7 Sep 2019 22:28:12 +0800 Subject: [PATCH 1370/1997] up --- app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt index dccdce01e..2d42e0d70 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt @@ -105,10 +105,7 @@ class ReadMenu : FrameLayout { private fun bindEvent() { iv_brightness_auto.onClick { - context.putPrefBoolean( - "brightnessAuto", - !brightnessAuto() - ) + context.putPrefBoolean("brightnessAuto", !brightnessAuto()) upBrightnessState() } //亮度调节 From ab83e12c0ff417b5e1269ef928475bd9b43ffe86 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 7 Sep 2019 22:58:11 +0800 Subject: [PATCH 1371/1997] up --- .../io/legado/app/data/dao/ReplaceRuleDao.kt | 6 +- .../legado/app/ui/replacerule/DiffCallBack.kt | 32 +++++++ .../app/ui/replacerule/ReplaceRuleActivity.kt | 17 ++-- .../app/ui/replacerule/ReplaceRuleAdapter.kt | 90 +++++++------------ .../ui/replacerule/ReplaceRuleViewModel.kt | 4 +- 5 files changed, 74 insertions(+), 75 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/replacerule/DiffCallBack.kt diff --git a/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt b/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt index 907b96d71..30e2522e9 100644 --- a/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt @@ -1,7 +1,6 @@ package io.legado.app.data.dao import androidx.lifecycle.LiveData -import androidx.paging.DataSource import androidx.room.* import io.legado.app.data.entities.ReplaceRule @@ -10,10 +9,7 @@ import io.legado.app.data.entities.ReplaceRule interface ReplaceRuleDao { @Query("SELECT * FROM replace_rules ORDER BY sortOrder ASC") - fun observeAll(): DataSource.Factory - - @Query("SELECT id FROM replace_rules ORDER BY sortOrder ASC") - fun observeAllIds(): LiveData> + fun liveDataAll(): LiveData> @get:Query("SELECT MIN(sortOrder) FROM replace_rules") val minOrder: Int diff --git a/app/src/main/java/io/legado/app/ui/replacerule/DiffCallBack.kt b/app/src/main/java/io/legado/app/ui/replacerule/DiffCallBack.kt new file mode 100644 index 000000000..fc1f33b11 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/replacerule/DiffCallBack.kt @@ -0,0 +1,32 @@ +package io.legado.app.ui.replacerule + +import androidx.recyclerview.widget.DiffUtil +import io.legado.app.data.entities.ReplaceRule + +class DiffCallBack( + private val oldItems: List, + private val newItems: List +) : DiffUtil.Callback() { + override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { + val oldItem = oldItems[oldItemPosition] + val newItem = newItems[newItemPosition] + return oldItem.id == newItem.id + } + + override fun getOldListSize(): Int { + return oldItems.size + } + + override fun getNewListSize(): Int { + return newItems.size + } + + override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { + val oldItem = oldItems[oldItemPosition] + val newItem = newItems[newItemPosition] + return oldItem.name == newItem.name + && oldItem.isEnabled == newItem.isEnabled + } + + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt index c839da8bf..8515aa180 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt @@ -6,10 +6,8 @@ import android.view.MenuItem import android.view.SubMenu import androidx.appcompat.widget.SearchView import androidx.core.content.ContextCompat -import androidx.lifecycle.LiveData import androidx.lifecycle.Observer -import androidx.paging.LivePagedListBuilder -import androidx.paging.PagedList +import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager @@ -34,7 +32,6 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi get() = getViewModel(ReplaceRuleViewModel::class.java) private lateinit var adapter: ReplaceRuleAdapter - private var rulesLiveData: LiveData>? = null private var allEnabled = false private var groups = hashSetOf() private var groupMenu: SubMenu? = null @@ -92,9 +89,11 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi } private fun initDataObservers() { - rulesLiveData?.removeObservers(this) - rulesLiveData = LivePagedListBuilder(App.db.replaceRuleDao().observeAll(), 30).build() - rulesLiveData?.observe(this, Observer> { adapter.submitList(it) }) + App.db.replaceRuleDao().liveDataAll().observe(this, Observer { + val diffResult = DiffUtil.calculateDiff(DiffCallBack(adapter.getItems(), it)) + adapter.setItemsNoNotify(it) + diffResult.dispatchUpdatesTo(adapter) + }) App.db.replaceRuleDao().liveGroup().observe(this, Observer { groups.clear() @@ -128,8 +127,8 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi return false } - override fun update(rule: ReplaceRule) { - viewModel.update(rule) + override fun update(vararg rule: ReplaceRule) { + viewModel.update(*rule) } override fun delete(rule: ReplaceRule) { diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt index 55b9d6c3c..92483c7d8 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt @@ -1,15 +1,11 @@ package io.legado.app.ui.replacerule import android.content.Context -import android.view.LayoutInflater import android.view.Menu -import android.view.View -import android.view.ViewGroup import android.widget.PopupMenu -import androidx.paging.PagedListAdapter -import androidx.recyclerview.widget.DiffUtil -import androidx.recyclerview.widget.RecyclerView import io.legado.app.R +import io.legado.app.base.adapter.ItemViewHolder +import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.data.entities.ReplaceRule import io.legado.app.help.ItemTouchCallback import io.legado.app.lib.theme.backgroundColor @@ -18,69 +14,29 @@ import org.jetbrains.anko.sdk27.listeners.onClick class ReplaceRuleAdapter(context: Context, var callBack: CallBack) : - PagedListAdapter(DIFF_CALLBACK), + SimpleRecyclerAdapter(context, R.layout.item_replace_rule), ItemTouchCallback.OnItemTouchCallbackListener { - companion object { - - @JvmField - val DIFF_CALLBACK = object : DiffUtil.ItemCallback() { - override fun areItemsTheSame(oldItem: ReplaceRule, newItem: ReplaceRule): Boolean = - oldItem.id == newItem.id - - override fun areContentsTheSame(oldItem: ReplaceRule, newItem: ReplaceRule): Boolean = - oldItem.id == newItem.id - && oldItem.pattern == newItem.pattern - && oldItem.replacement == newItem.replacement - && oldItem.isRegex == newItem.isRegex - && oldItem.isEnabled == newItem.isEnabled - && oldItem.scope == newItem.scope - } - } - - override fun onMove(srcPosition: Int, targetPosition: Int): Boolean { - return true - } - - override fun onSwiped(adapterPosition: Int) { - - } - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { - return MyViewHolder( - LayoutInflater.from(parent.context).inflate( - R.layout.item_replace_rule, - parent, - false - ) - ) - } - - override fun onBindViewHolder(holder: MyViewHolder, pos: Int) { - getItem(pos)?.let { holder.bind(it, callBack) } - } - - class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { - - fun bind(rule: ReplaceRule, callBack: CallBack) = with(itemView) { + override fun convert(holder: ItemViewHolder, item: ReplaceRule, payloads: MutableList) { + with(holder.itemView) { this.setBackgroundColor(context.backgroundColor) - cb_name.text = rule.name - swt_enabled.isChecked = rule.isEnabled + cb_name.text = item.name + swt_enabled.isChecked = item.isEnabled swt_enabled.onClick { - rule.isEnabled = swt_enabled.isChecked - callBack.update(rule) + item.isEnabled = swt_enabled.isChecked + callBack.update(item) } iv_edit.onClick { - callBack.edit(rule) + callBack.edit(item) } iv_menu_more.onClick { val popupMenu = PopupMenu(context, it) popupMenu.menu.add(Menu.NONE, R.id.menu_top, Menu.NONE, R.string.to_top) popupMenu.menu.add(Menu.NONE, R.id.menu_del, Menu.NONE, R.string.delete) - popupMenu.setOnMenuItemClickListener { item -> - when (item.itemId) { - R.id.menu_top -> callBack.toTop(rule) - R.id.menu_del -> callBack.delete(rule) + popupMenu.setOnMenuItemClickListener { menuItem -> + when (menuItem.itemId) { + R.id.menu_top -> callBack.toTop(item) + R.id.menu_del -> callBack.delete(item) } true } @@ -89,8 +45,24 @@ class ReplaceRuleAdapter(context: Context, var callBack: CallBack) : } } + override fun onMove(srcPosition: Int, targetPosition: Int): Boolean { + val srcItem = getItem(srcPosition) + val targetItem = getItem(targetPosition) + if (srcItem != null && targetItem != null) { + val srcOrder = srcItem.order + srcItem.order = targetItem.order + targetItem.order = srcOrder + callBack.update(srcItem, targetItem) + } + return true + } + + override fun onSwiped(adapterPosition: Int) { + + } + interface CallBack { - fun update(rule: ReplaceRule) + fun update(vararg rule: ReplaceRule) fun delete(rule: ReplaceRule) fun edit(rule: ReplaceRule) fun toTop(rule: ReplaceRule) diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt index 85f7cf430..4674ab415 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt @@ -10,9 +10,9 @@ import io.legado.app.utils.splitNotBlank class ReplaceRuleViewModel(application: Application) : BaseViewModel(application) { - fun update(rule: ReplaceRule) { + fun update(vararg rule: ReplaceRule) { execute { - App.db.replaceRuleDao().update(rule) + App.db.replaceRuleDao().update(*rule) } } From e6f66f23c3f8830e71837867a49713501b93663f Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 7 Sep 2019 22:59:38 +0800 Subject: [PATCH 1372/1997] up --- app/src/main/java/io/legado/app/help/storage/Restore.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/help/storage/Restore.kt b/app/src/main/java/io/legado/app/help/storage/Restore.kt index 124e74303..335dd2497 100644 --- a/app/src/main/java/io/legado/app/help/storage/Restore.kt +++ b/app/src/main/java/io/legado/app/help/storage/Restore.kt @@ -126,7 +126,7 @@ object Restore { rule.isRegex = jsonItem.readBool("$.isRegex") == true rule.scope = jsonItem.readString("$.useTo") rule.isEnabled = jsonItem.readBool("$.enable") == true - rule.order = jsonItem.readInt("$.serialNumber") ?: 0 + rule.order = jsonItem.readInt("$.serialNumber") ?: index replaceRules.add(rule) } App.db.replaceRuleDao().insert(*replaceRules.toTypedArray()) From ded07def0eee956ef4163fa31090ff11ac13e25f Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 7 Sep 2019 23:27:00 +0800 Subject: [PATCH 1373/1997] up --- .../app/ui/replacerule/ReplaceEditDialog.kt | 13 +++++++++++++ .../app/ui/replacerule/ReplaceEditViewModel.kt | 3 +++ .../app/ui/replacerule/ReplaceRuleAdapter.kt | 17 +++++++++++++---- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditDialog.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditDialog.kt index 64a84744f..0759f0a2a 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditDialog.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditDialog.kt @@ -66,6 +66,9 @@ class ReplaceEditDialog : DialogFragment(), override fun onMenuItemClick(item: MenuItem?): Boolean { when (item?.itemId) { R.id.menu_save -> { + viewModel.save(getReplaceRule()) { + dismiss() + } } } return true @@ -80,4 +83,14 @@ class ReplaceEditDialog : DialogFragment(), et_scope.setText(replaceRule.scope) } + private fun getReplaceRule(): ReplaceRule { + val replaceRule: ReplaceRule = viewModel.replaceRuleData.value ?: ReplaceRule() + replaceRule.name = et_name.text.toString() + replaceRule.group = et_group.text.toString() + replaceRule.pattern = et_group.text.toString() + replaceRule.isRegex = cb_use_regex.isChecked + replaceRule.replacement = et_replace_to.text.toString() + replaceRule.scope = et_scope.text.toString() + return replaceRule + } } diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditViewModel.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditViewModel.kt index a13502fa4..79ab10c0c 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditViewModel.kt @@ -26,6 +26,9 @@ class ReplaceEditViewModel(application: Application) : BaseViewModel(application fun save(replaceRule: ReplaceRule, success: () -> Unit) { execute { + if (replaceRule.order == 0) { + replaceRule.order = App.db.replaceRuleDao().maxOrder + 1 + } App.db.replaceRuleDao().insert(replaceRule) }.onSuccess { success() diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt index 92483c7d8..9d251fb01 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt @@ -49,10 +49,19 @@ class ReplaceRuleAdapter(context: Context, var callBack: CallBack) : val srcItem = getItem(srcPosition) val targetItem = getItem(targetPosition) if (srcItem != null && targetItem != null) { - val srcOrder = srcItem.order - srcItem.order = targetItem.order - targetItem.order = srcOrder - callBack.update(srcItem, targetItem) + if (srcItem.order == targetItem.order) { + if (targetPosition > srcPosition) { + srcItem.order = srcItem.order + 1 + } else { + srcItem.order = srcItem.order - 1 + } + callBack.update(srcItem) + } else { + val srcOrder = srcItem.order + srcItem.order = targetItem.order + targetItem.order = srcOrder + callBack.update(srcItem, targetItem) + } } return true } From fa73b91d1db0d502d3ea99fc1e97358d3236e1b6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 7 Sep 2019 23:45:52 +0800 Subject: [PATCH 1374/1997] up --- .../io/legado/app/ui/replacerule/ReplaceRuleActivity.kt | 4 ++++ .../io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt | 8 ++------ .../io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt | 9 +++++++++ 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt index 8515aa180..bf942b36d 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt @@ -144,4 +144,8 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi override fun toTop(rule: ReplaceRule) { viewModel.toTop(rule) } + + override fun upOrder(rules: List) { + viewModel.upOrder(rules) + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt index 9d251fb01..6f41abc5a 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt @@ -50,12 +50,7 @@ class ReplaceRuleAdapter(context: Context, var callBack: CallBack) : val targetItem = getItem(targetPosition) if (srcItem != null && targetItem != null) { if (srcItem.order == targetItem.order) { - if (targetPosition > srcPosition) { - srcItem.order = srcItem.order + 1 - } else { - srcItem.order = srcItem.order - 1 - } - callBack.update(srcItem) + callBack.upOrder(getItems()) } else { val srcOrder = srcItem.order srcItem.order = targetItem.order @@ -75,5 +70,6 @@ class ReplaceRuleAdapter(context: Context, var callBack: CallBack) : fun delete(rule: ReplaceRule) fun edit(rule: ReplaceRule) fun toTop(rule: ReplaceRule) + fun upOrder(rules: List) } } diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt index 4674ab415..755befb75 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt @@ -29,6 +29,15 @@ class ReplaceRuleViewModel(application: Application) : BaseViewModel(application } } + fun upOrder(rules: List) { + execute { + for ((index: Int, rule: ReplaceRule) in rules.withIndex()) { + rule.order = index + 1 + } + App.db.replaceRuleDao().update(*rules.toTypedArray()) + } + } + fun addGroup(group: String) { execute { val sources = App.db.replaceRuleDao().noGroup From 518353117eb8812201c1089f31209dd7114b1d0a Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 8 Sep 2019 06:55:34 +0800 Subject: [PATCH 1375/1997] up --- .../java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt | 4 ++-- .../java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt | 4 ++-- .../java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt index bf942b36d..4f45f4b23 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt @@ -145,7 +145,7 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi viewModel.toTop(rule) } - override fun upOrder(rules: List) { - viewModel.upOrder(rules) + override fun upOrder() { + viewModel.upOrder() } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt index 6f41abc5a..4386996f9 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt @@ -50,7 +50,7 @@ class ReplaceRuleAdapter(context: Context, var callBack: CallBack) : val targetItem = getItem(targetPosition) if (srcItem != null && targetItem != null) { if (srcItem.order == targetItem.order) { - callBack.upOrder(getItems()) + callBack.upOrder() } else { val srcOrder = srcItem.order srcItem.order = targetItem.order @@ -70,6 +70,6 @@ class ReplaceRuleAdapter(context: Context, var callBack: CallBack) : fun delete(rule: ReplaceRule) fun edit(rule: ReplaceRule) fun toTop(rule: ReplaceRule) - fun upOrder(rules: List) + fun upOrder() } } diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt index 755befb75..ed566ab14 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt @@ -29,8 +29,9 @@ class ReplaceRuleViewModel(application: Application) : BaseViewModel(application } } - fun upOrder(rules: List) { + fun upOrder() { execute { + val rules = App.db.replaceRuleDao().all for ((index: Int, rule: ReplaceRule) in rules.withIndex()) { rule.order = index + 1 } From 0897c9f592f8627876b371c1df60b7f326a79f88 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 8 Sep 2019 07:10:06 +0800 Subject: [PATCH 1376/1997] up --- .../io/legado/app/data/dao/ReplaceRuleDao.kt | 3 +++ .../app/ui/replacerule/ReplaceRuleActivity.kt | 17 ++++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt b/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt index 30e2522e9..e57a2251b 100644 --- a/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt @@ -11,6 +11,9 @@ interface ReplaceRuleDao { @Query("SELECT * FROM replace_rules ORDER BY sortOrder ASC") fun liveDataAll(): LiveData> + @Query("SELECT * FROM replace_rules where `group` like :key or name like :key ORDER BY sortOrder ASC") + fun liveDataSearch(key: String): LiveData> + @get:Query("SELECT MIN(sortOrder) FROM replace_rules") val minOrder: Int diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt index 4f45f4b23..f39ffd797 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt @@ -6,6 +6,7 @@ import android.view.MenuItem import android.view.SubMenu import androidx.appcompat.widget.SearchView import androidx.core.content.ContextCompat +import androidx.lifecycle.LiveData import androidx.lifecycle.Observer import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DividerItemDecoration @@ -35,11 +36,13 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi private var allEnabled = false private var groups = hashSetOf() private var groupMenu: SubMenu? = null + private var replaceRuleLiveData: LiveData>? = null override fun onActivityCreated(savedInstanceState: Bundle?) { initRecyclerView() initSearchView() - initDataObservers() + observeReplaceRuleData() + observeGroupData() } override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { @@ -88,13 +91,21 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi search_view.setOnQueryTextListener(this) } - private fun initDataObservers() { - App.db.replaceRuleDao().liveDataAll().observe(this, Observer { + private fun observeReplaceRuleData(key: String? = null) { + replaceRuleLiveData?.removeObservers(this) + replaceRuleLiveData = if (key.isNullOrEmpty()) { + App.db.replaceRuleDao().liveDataAll() + } else { + App.db.replaceRuleDao().liveDataSearch(key) + } + replaceRuleLiveData?.observe(this, Observer { val diffResult = DiffUtil.calculateDiff(DiffCallBack(adapter.getItems(), it)) adapter.setItemsNoNotify(it) diffResult.dispatchUpdatesTo(adapter) }) + } + private fun observeGroupData() { App.db.replaceRuleDao().liveGroup().observe(this, Observer { groups.clear() it.map { group -> From 8b310b96dd6a1bbae2d876f1433358d763b7ab57 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 8 Sep 2019 07:16:10 +0800 Subject: [PATCH 1377/1997] up --- .../java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt index f39ffd797..6895039aa 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt @@ -131,6 +131,7 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi } override fun onQueryTextChange(newText: String?): Boolean { + observeReplaceRuleData("%$newText%") return false } From 579863ca7c761be14f73453b24e540aa5a914349 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 8 Sep 2019 08:54:21 +0800 Subject: [PATCH 1378/1997] up --- .../java/io/legado/app/data/dao/BookChapterDao.kt | 4 ++++ .../app/ui/main/bookshelf/BookshelfViewModel.kt | 14 +++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/BookChapterDao.kt b/app/src/main/java/io/legado/app/data/dao/BookChapterDao.kt index fdbff2bf1..8ed58cadf 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookChapterDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookChapterDao.kt @@ -25,4 +25,8 @@ interface BookChapterDao { @Insert(onConflict = OnConflictStrategy.REPLACE) fun insert(vararg bookChapter: BookChapter) + + @Query("delete from chapters where bookUrl = :bookUrl") + fun delByBook(bookUrl: String) + } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt index 463c0b015..b1fd24966 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt @@ -39,14 +39,18 @@ class BookshelfViewModel(application: Application) : BaseViewModel(application) updateList.add(book.bookUrl) postEvent(Bus.UP_BOOK, book.bookUrl) } - WebBook(bookSource).getChapterList(book).onSuccess(IO) { + WebBook(bookSource).getChapterList(book) + .onSuccess(IO) { it?.let { App.db.bookDao().update(book) - if (it.size > App.db.bookChapterDao().getChapterCount(book.bookUrl)) { - App.db.bookChapterDao().insert(*it.toTypedArray()) - } + App.db.bookChapterDao().delByBook(book.bookUrl) + App.db.bookChapterDao().insert(*it.toTypedArray()) } - }.onFinally { + } + .onError { + it.printStackTrace() + } + .onFinally { synchronized(this) { updateList.remove(book.bookUrl) postEvent(Bus.UP_BOOK, book.bookUrl) From 6a71f87c6f4e6460363a5b150f4544d78498dde4 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 8 Sep 2019 08:56:18 +0800 Subject: [PATCH 1379/1997] up --- app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index 1709391b2..599a26acc 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -133,6 +133,7 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo adapter.clearItems() adapter.addItems(chapterList) rv_chapter_list.scrollToPosition(viewModel.durChapterIndex) + upLoading(false) } private fun upLoading(isLoading: Boolean) { From bc31589bdf2f5ee7509280ffb38a1efb03555239 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 8 Sep 2019 09:39:01 +0800 Subject: [PATCH 1380/1997] up --- .../app/ui/replacerule/ReplaceRuleActivity.kt | 11 +--- .../app/ui/replacerule/ReplaceRuleAdapter.kt | 66 +++++++++++++------ 2 files changed, 48 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt index 6895039aa..1082ebd3c 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt @@ -23,7 +23,6 @@ import io.legado.app.utils.getViewModel import io.legado.app.utils.splitNotBlank import kotlinx.android.synthetic.main.activity_replace_rule.* import kotlinx.android.synthetic.main.view_search.* -import org.jetbrains.anko.doAsync class ReplaceRuleActivity : VMBaseActivity(R.layout.activity_replace_rule), @@ -33,7 +32,6 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi get() = getViewModel(ReplaceRuleViewModel::class.java) private lateinit var adapter: ReplaceRuleAdapter - private var allEnabled = false private var groups = hashSetOf() private var groupMenu: SubMenu? = null private var replaceRuleLiveData: LiveData>? = null @@ -62,6 +60,7 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi ReplaceEditDialog().show(supportFragmentManager, "replaceNew") R.id.menu_group_manage -> GroupManageDialog().show(supportFragmentManager, "groupManage") + R.id.menu_select_all -> adapter.selectAll() } return super.onCompatOptionsItemSelected(item) } @@ -100,6 +99,7 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi } replaceRuleLiveData?.observe(this, Observer { val diffResult = DiffUtil.calculateDiff(DiffCallBack(adapter.getItems(), it)) + adapter.selectedIds.clear() adapter.setItemsNoNotify(it) diffResult.dispatchUpdatesTo(adapter) }) @@ -122,13 +122,6 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi } } - private fun updateEnableAll() { - doAsync { - App.db.replaceRuleDao().summary.let { - allEnabled = it == 0 - } - } - } override fun onQueryTextChange(newText: String?): Boolean { observeReplaceRuleData("%$newText%") diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt index 4386996f9..5057500f5 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt @@ -17,30 +17,56 @@ class ReplaceRuleAdapter(context: Context, var callBack: CallBack) : SimpleRecyclerAdapter(context, R.layout.item_replace_rule), ItemTouchCallback.OnItemTouchCallbackListener { + val selectedIds = linkedSetOf() + + fun selectAll() { + if (selectedIds.size == itemCount) { + selectedIds.clear() + notifyItemRangeChanged(0, itemCount, 1) + } else { + getItems().forEach { selectedIds.add(it.id) } + notifyItemRangeChanged(0, itemCount, 1) + } + } + override fun convert(holder: ItemViewHolder, item: ReplaceRule, payloads: MutableList) { with(holder.itemView) { - this.setBackgroundColor(context.backgroundColor) - cb_name.text = item.name - swt_enabled.isChecked = item.isEnabled - swt_enabled.onClick { - item.isEnabled = swt_enabled.isChecked - callBack.update(item) - } - iv_edit.onClick { - callBack.edit(item) - } - iv_menu_more.onClick { - val popupMenu = PopupMenu(context, it) - popupMenu.menu.add(Menu.NONE, R.id.menu_top, Menu.NONE, R.string.to_top) - popupMenu.menu.add(Menu.NONE, R.id.menu_del, Menu.NONE, R.string.delete) - popupMenu.setOnMenuItemClickListener { menuItem -> - when (menuItem.itemId) { - R.id.menu_top -> callBack.toTop(item) - R.id.menu_del -> callBack.delete(item) + if (payloads.isEmpty()) { + this.setBackgroundColor(context.backgroundColor) + cb_name.text = item.name + swt_enabled.isChecked = item.isEnabled + swt_enabled.onClick { + item.isEnabled = swt_enabled.isChecked + callBack.update(item) + } + iv_edit.onClick { + callBack.edit(item) + } + iv_menu_more.onClick { + val popupMenu = PopupMenu(context, it) + popupMenu.menu.add(Menu.NONE, R.id.menu_top, Menu.NONE, R.string.to_top) + popupMenu.menu.add(Menu.NONE, R.id.menu_del, Menu.NONE, R.string.delete) + popupMenu.setOnMenuItemClickListener { menuItem -> + when (menuItem.itemId) { + R.id.menu_top -> callBack.toTop(item) + R.id.menu_del -> callBack.delete(item) + } + true + } + popupMenu.show() + } + cb_name.onClick { + if (cb_name.isChecked) { + selectedIds.add(item.id) + } else { + selectedIds.remove(item.id) } - true } - popupMenu.show() + cb_name.isChecked = selectedIds.contains(item.id) + } else { + when (payloads[0]) { + 1 -> cb_name.isChecked = selectedIds.contains(item.id) + } } } } From 2414f38afcbb10a9b548e0feacf7235ddafe636c Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 8 Sep 2019 10:22:28 +0800 Subject: [PATCH 1381/1997] up --- .../io/legado/app/data/dao/ReplaceRuleDao.kt | 3 ++ .../legado/app/ui/replacerule/DiffCallBack.kt | 12 ++++- .../app/ui/replacerule/ReplaceRuleActivity.kt | 2 + .../app/ui/replacerule/ReplaceRuleAdapter.kt | 28 ++++++++--- .../ui/replacerule/ReplaceRuleViewModel.kt | 6 +++ app/src/main/res/menu/replace_rule.xml | 49 +++++++++++++------ app/src/main/res/values/strings.xml | 3 ++ 7 files changed, 79 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt b/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt index e57a2251b..e8a2be048 100644 --- a/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt @@ -32,6 +32,9 @@ interface ReplaceRuleDao { @Query("SELECT * FROM replace_rules WHERE id in (:ids)") fun findByIds(vararg ids: Long): List + @Query("update replace_rules set isEnabled = 1 where id in (:ids)") + fun enableSection(vararg ids: Long) + @Query( """SELECT * FROM replace_rules WHERE isEnabled = 1 AND (scope LIKE '%' || :scope || '%' or scope = null or scope = '')""" diff --git a/app/src/main/java/io/legado/app/ui/replacerule/DiffCallBack.kt b/app/src/main/java/io/legado/app/ui/replacerule/DiffCallBack.kt index fc1f33b11..1824313b3 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/DiffCallBack.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/DiffCallBack.kt @@ -25,8 +25,18 @@ class DiffCallBack( val oldItem = oldItems[oldItemPosition] val newItem = newItems[newItemPosition] return oldItem.name == newItem.name + && oldItem.group == newItem.group && oldItem.isEnabled == newItem.isEnabled } - + override fun getChangePayload(oldItemPosition: Int, newItemPosition: Int): Any? { + val oldItem = oldItems[oldItemPosition] + val newItem = newItems[newItemPosition] + return when { + oldItem.name == newItem.name + && oldItem.group == newItem.group + && oldItem.isEnabled != newItem.isEnabled -> 2 + else -> null + } + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt index 1082ebd3c..7ef6eea0e 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt @@ -61,6 +61,8 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi R.id.menu_group_manage -> GroupManageDialog().show(supportFragmentManager, "groupManage") R.id.menu_select_all -> adapter.selectAll() + R.id.menu_revert_selection -> adapter.revertSelection() + R.id.menu_enable_selection -> viewModel.enableSelection(adapter.selectedIds) } return super.onCompatOptionsItemSelected(item) } diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt index 5057500f5..e32b509ef 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt @@ -29,6 +29,17 @@ class ReplaceRuleAdapter(context: Context, var callBack: CallBack) : } } + fun revertSelection() { + getItems().forEach { + if (selectedIds.contains(it.id)) { + selectedIds.remove(it.id) + } else { + selectedIds.add(it.id) + } + } + notifyItemRangeChanged(0, itemCount, 1) + } + override fun convert(holder: ItemViewHolder, item: ReplaceRule, payloads: MutableList) { with(holder.itemView) { if (payloads.isEmpty()) { @@ -42,6 +53,14 @@ class ReplaceRuleAdapter(context: Context, var callBack: CallBack) : iv_edit.onClick { callBack.edit(item) } + cb_name.isChecked = selectedIds.contains(item.id) + cb_name.onClick { + if (cb_name.isChecked) { + selectedIds.add(item.id) + } else { + selectedIds.remove(item.id) + } + } iv_menu_more.onClick { val popupMenu = PopupMenu(context, it) popupMenu.menu.add(Menu.NONE, R.id.menu_top, Menu.NONE, R.string.to_top) @@ -55,17 +74,10 @@ class ReplaceRuleAdapter(context: Context, var callBack: CallBack) : } popupMenu.show() } - cb_name.onClick { - if (cb_name.isChecked) { - selectedIds.add(item.id) - } else { - selectedIds.remove(item.id) - } - } - cb_name.isChecked = selectedIds.contains(item.id) } else { when (payloads[0]) { 1 -> cb_name.isChecked = selectedIds.contains(item.id) + 2 -> swt_enabled.isChecked = item.isEnabled } } } diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt index ed566ab14..d6c874649 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt @@ -39,6 +39,12 @@ class ReplaceRuleViewModel(application: Application) : BaseViewModel(application } } + fun enableSelection(ids: LinkedHashSet) { + execute { + App.db.replaceRuleDao().enableSection(*ids.toLongArray()) + } + } + fun addGroup(group: String) { execute { val sources = App.db.replaceRuleDao().noGroup diff --git a/app/src/main/res/menu/replace_rule.xml b/app/src/main/res/menu/replace_rule.xml index b0551eee4..29b21845d 100644 --- a/app/src/main/res/menu/replace_rule.xml +++ b/app/src/main/res/menu/replace_rule.xml @@ -4,11 +4,42 @@ xmlns:tools="http://schemas.android.com/tools"> + tools:ignore="AlwaysShowAction"> + + + + + + + + + + + + + + + + - - - - diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8799447c5..b4a44b681 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -180,6 +180,7 @@ 清除缓存会删除所有已保存章节,是否确认删除? 书源共享 替换规则名称 + 选择操作 全选 夜间模式 启动页 @@ -496,5 +497,7 @@ 添加分组 新建替换 分组 + 启用所选 + 禁用所选 From b9aab125131b1cb13b8e45d9ede66779b20842fa Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 8 Sep 2019 10:36:52 +0800 Subject: [PATCH 1382/1997] up --- app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt | 3 +++ .../io/legado/app/ui/replacerule/ReplaceRuleActivity.kt | 1 + .../io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt | 6 ++++++ 3 files changed, 10 insertions(+) diff --git a/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt b/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt index e8a2be048..6a2482d43 100644 --- a/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt @@ -35,6 +35,9 @@ interface ReplaceRuleDao { @Query("update replace_rules set isEnabled = 1 where id in (:ids)") fun enableSection(vararg ids: Long) + @Query("update replace_rules set isEnabled = 0 where id in (:ids)") + fun disableSection(vararg ids: Long) + @Query( """SELECT * FROM replace_rules WHERE isEnabled = 1 AND (scope LIKE '%' || :scope || '%' or scope = null or scope = '')""" diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt index 7ef6eea0e..40adfd95d 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt @@ -63,6 +63,7 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi R.id.menu_select_all -> adapter.selectAll() R.id.menu_revert_selection -> adapter.revertSelection() R.id.menu_enable_selection -> viewModel.enableSelection(adapter.selectedIds) + R.id.menu_disable_selection -> viewModel.disableSelection(adapter.selectedIds) } return super.onCompatOptionsItemSelected(item) } diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt index d6c874649..0311b58a9 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt @@ -45,6 +45,12 @@ class ReplaceRuleViewModel(application: Application) : BaseViewModel(application } } + fun disableSelection(ids: LinkedHashSet) { + execute { + App.db.replaceRuleDao().disableSection(*ids.toLongArray()) + } + } + fun addGroup(group: String) { execute { val sources = App.db.replaceRuleDao().noGroup From 39e3ffe5a37520694423441c709268fa50e5dc13 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 8 Sep 2019 10:40:49 +0800 Subject: [PATCH 1383/1997] up --- .../io/legado/app/ui/replacerule/ReplaceRuleActivity.kt | 1 - .../io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt | 9 +++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt index 40adfd95d..b043f4af7 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt @@ -102,7 +102,6 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi } replaceRuleLiveData?.observe(this, Observer { val diffResult = DiffUtil.calculateDiff(DiffCallBack(adapter.getItems(), it)) - adapter.selectedIds.clear() adapter.setItemsNoNotify(it) diffResult.dispatchUpdatesTo(adapter) }) diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt index e32b509ef..00af7e1ac 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt @@ -20,13 +20,10 @@ class ReplaceRuleAdapter(context: Context, var callBack: CallBack) : val selectedIds = linkedSetOf() fun selectAll() { - if (selectedIds.size == itemCount) { - selectedIds.clear() - notifyItemRangeChanged(0, itemCount, 1) - } else { - getItems().forEach { selectedIds.add(it.id) } - notifyItemRangeChanged(0, itemCount, 1) + getItems().forEach { + selectedIds.add(it.id) } + notifyItemRangeChanged(0, itemCount, 1) } fun revertSelection() { From b1d99da41b736bcc84053d33161f7db6f985d778 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 8 Sep 2019 10:48:40 +0800 Subject: [PATCH 1384/1997] up --- .../java/io/legado/app/data/dao/ReplaceRuleDao.kt | 3 +++ .../legado/app/ui/replacerule/ReplaceRuleActivity.kt | 5 +++-- .../legado/app/ui/replacerule/ReplaceRuleAdapter.kt | 12 +++++++++++- .../app/ui/replacerule/ReplaceRuleViewModel.kt | 6 ++++++ app/src/main/res/menu/replace_rule.xml | 2 +- 5 files changed, 24 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt b/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt index 6a2482d43..5940272af 100644 --- a/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/ReplaceRuleDao.kt @@ -38,6 +38,9 @@ interface ReplaceRuleDao { @Query("update replace_rules set isEnabled = 0 where id in (:ids)") fun disableSection(vararg ids: Long) + @Query("delete from replace_rules where id in (:ids)") + fun delSection(vararg ids: Long) + @Query( """SELECT * FROM replace_rules WHERE isEnabled = 1 AND (scope LIKE '%' || :scope || '%' or scope = null or scope = '')""" diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt index b043f4af7..966891a9c 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt @@ -62,8 +62,9 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi GroupManageDialog().show(supportFragmentManager, "groupManage") R.id.menu_select_all -> adapter.selectAll() R.id.menu_revert_selection -> adapter.revertSelection() - R.id.menu_enable_selection -> viewModel.enableSelection(adapter.selectedIds) - R.id.menu_disable_selection -> viewModel.disableSelection(adapter.selectedIds) + R.id.menu_enable_selection -> viewModel.enableSelection(adapter.getSelectionIds()) + R.id.menu_disable_selection -> viewModel.disableSelection(adapter.getSelectionIds()) + R.id.menu_del_selection -> viewModel.disableSelection(adapter.getSelectionIds()) } return super.onCompatOptionsItemSelected(item) } diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt index 00af7e1ac..e6a43ba79 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt @@ -17,7 +17,7 @@ class ReplaceRuleAdapter(context: Context, var callBack: CallBack) : SimpleRecyclerAdapter(context, R.layout.item_replace_rule), ItemTouchCallback.OnItemTouchCallbackListener { - val selectedIds = linkedSetOf() + private val selectedIds = linkedSetOf() fun selectAll() { getItems().forEach { @@ -37,6 +37,16 @@ class ReplaceRuleAdapter(context: Context, var callBack: CallBack) : notifyItemRangeChanged(0, itemCount, 1) } + fun getSelectionIds(): LinkedHashSet { + val selection = linkedSetOf() + getItems().map { + if (selectedIds.contains(it.id)) { + selection.add(it.id) + } + } + return selection + } + override fun convert(holder: ItemViewHolder, item: ReplaceRule, payloads: MutableList) { with(holder.itemView) { if (payloads.isEmpty()) { diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt index 0311b58a9..c820749ef 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleViewModel.kt @@ -51,6 +51,12 @@ class ReplaceRuleViewModel(application: Application) : BaseViewModel(application } } + fun delSelection(ids: LinkedHashSet) { + execute { + App.db.replaceRuleDao().delSection(*ids.toLongArray()) + } + } + fun addGroup(group: String) { execute { val sources = App.db.replaceRuleDao().noGroup diff --git a/app/src/main/res/menu/replace_rule.xml b/app/src/main/res/menu/replace_rule.xml index 29b21845d..eec4b7abd 100644 --- a/app/src/main/res/menu/replace_rule.xml +++ b/app/src/main/res/menu/replace_rule.xml @@ -33,7 +33,7 @@ app:showAsAction="never" /> From c8f28b434d2b60dbf8b256fdc5c6e8150e19c070 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 8 Sep 2019 10:57:09 +0800 Subject: [PATCH 1385/1997] up --- .../java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt index 966891a9c..06ffd991b 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt @@ -64,7 +64,7 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi R.id.menu_revert_selection -> adapter.revertSelection() R.id.menu_enable_selection -> viewModel.enableSelection(adapter.getSelectionIds()) R.id.menu_disable_selection -> viewModel.disableSelection(adapter.getSelectionIds()) - R.id.menu_del_selection -> viewModel.disableSelection(adapter.getSelectionIds()) + R.id.menu_del_selection -> viewModel.delSelection(adapter.getSelectionIds()) } return super.onCompatOptionsItemSelected(item) } From d194145c8e123e62ebfdac3b361facfc3dafdc3b Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 8 Sep 2019 10:58:51 +0800 Subject: [PATCH 1386/1997] up --- .../io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt index e6a43ba79..49f01a828 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleAdapter.kt @@ -51,7 +51,12 @@ class ReplaceRuleAdapter(context: Context, var callBack: CallBack) : with(holder.itemView) { if (payloads.isEmpty()) { this.setBackgroundColor(context.backgroundColor) - cb_name.text = item.name + if (item.group.isNullOrEmpty()) { + cb_name.text = item.name + } else { + cb_name.text = + String.format("%s (%s)", item.name, item.group) + } swt_enabled.isChecked = item.isEnabled swt_enabled.onClick { item.isEnabled = swt_enabled.isChecked From c0fa0821a1705ff2b0855d7701b0fd2068235986 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 8 Sep 2019 11:53:42 +0800 Subject: [PATCH 1387/1997] up --- .../io/legado/app/data/dao/BookSourceDao.kt | 4 +- .../app/ui/booksource/BookSourceActivity.kt | 38 +++++--- .../app/ui/booksource/BookSourceAdapter.kt | 97 ++++++------------- .../app/ui/booksource/BookSourceViewModel.kt | 10 ++ .../legado/app/ui/booksource/DiffCallBack.kt | 43 ++++++++ 5 files changed, 106 insertions(+), 86 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/booksource/DiffCallBack.kt diff --git a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt index ef66a2372..a68e7e9e3 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt @@ -9,10 +9,10 @@ import io.legado.app.data.entities.BookSource interface BookSourceDao { @Query("select * from book_sources order by customOrder asc") - fun observeAll(): DataSource.Factory + fun liveDataAll(): LiveData> @Query("select * from book_sources where bookSourceName like :searchKey or `bookSourceGroup` like :searchKey or bookSourceUrl like :searchKey order by customOrder asc") - fun observeSearch(searchKey: String = ""): DataSource.Factory + fun liveDataSearch(searchKey: String = ""): LiveData> @Query("select * from book_sources where enabledExplore = 1 and exploreUrl is not null and exploreUrl <> '' order by customOrder asc") fun liveExplore(): LiveData> diff --git a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt index b98a8bf2f..6de1926ef 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt @@ -9,8 +9,7 @@ import androidx.appcompat.widget.SearchView import androidx.core.content.ContextCompat import androidx.lifecycle.LiveData import androidx.lifecycle.Observer -import androidx.paging.LivePagedListBuilder -import androidx.paging.PagedList +import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager @@ -42,15 +41,16 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity private val qrRequestCode = 101 private lateinit var adapter: BookSourceAdapter - private var bookSourceLiveDate: LiveData>? = null + private var bookSourceLiveDate: LiveData>? = null private var groups = hashSetOf() private var groupMenu: SubMenu? = null override fun onActivityCreated(savedInstanceState: Bundle?) { setSupportActionBar(toolbar) initRecyclerView() - initDataObserve() initSearchView() + initLiveDataBookSource() + initLiveDataGroup() } override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { @@ -104,7 +104,7 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity this.setDrawable(it) } }) - adapter = BookSourceAdapter(this) + adapter = BookSourceAdapter(this, this) recycler_view.adapter = adapter val itemTouchCallback = ItemTouchCallback() itemTouchCallback.onItemTouchCallbackListener = adapter @@ -120,12 +120,22 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity search_view.setOnQueryTextListener(this) } - private fun initDataObserve(searchKey: String = "") { + private fun initLiveDataBookSource(searchKey: String? = null) { bookSourceLiveDate?.removeObservers(this) - val dataFactory = App.db.bookSourceDao().observeSearch("%$searchKey%") - bookSourceLiveDate = LivePagedListBuilder(dataFactory, 10000).build() - bookSourceLiveDate?.observe(this, Observer { adapter.submitList(it) }) + bookSourceLiveDate = if (searchKey.isNullOrEmpty()) { + App.db.bookSourceDao().liveDataAll() + } else { + App.db.bookSourceDao().liveDataSearch("%$searchKey%") + } + bookSourceLiveDate?.observe(this, Observer { + search_view.queryHint = getString(R.string.search_book_source_num, it.size) + val diffResult = DiffUtil.calculateDiff(DiffCallBack(adapter.getItems(), it)) + adapter.setItemsNoNotify(it) + diffResult.dispatchUpdatesTo(adapter) + }) + } + private fun initLiveDataGroup() { App.db.bookSourceDao().liveGroup().observe(this, Observer { groups.clear() it.map { group -> @@ -144,7 +154,7 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity override fun onQueryTextChange(newText: String?): Boolean { newText?.let { - initDataObserve(it) + initLiveDataBookSource(it) } return false } @@ -153,10 +163,6 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity return false } - override fun upCount(count: Int) { - search_view.queryHint = getString(R.string.search_book_source_num, count) - } - override fun del(bookSource: BookSource) { viewModel.del(bookSource) } @@ -169,6 +175,10 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity startActivity(Pair("data", bookSource.bookSourceUrl)) } + override fun upOrder() { + viewModel.upOrder() + } + override fun topSource(bookSource: BookSource) { viewModel.topSource(bookSource) } diff --git a/app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt b/app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt index 4faf0de8e..4e5100e25 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt @@ -1,107 +1,64 @@ package io.legado.app.ui.booksource -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.paging.PagedList -import androidx.paging.PagedListAdapter -import androidx.recyclerview.widget.DiffUtil -import androidx.recyclerview.widget.RecyclerView +import android.content.Context import io.legado.app.R +import io.legado.app.base.adapter.ItemViewHolder +import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.data.entities.BookSource import io.legado.app.help.ItemTouchCallback.OnItemTouchCallbackListener import io.legado.app.lib.theme.backgroundColor import kotlinx.android.synthetic.main.item_book_source.view.* import org.jetbrains.anko.sdk27.listeners.onClick -class BookSourceAdapter(val callBack: CallBack) : - PagedListAdapter(DIFF_CALLBACK), +class BookSourceAdapter(context: Context, val callBack: CallBack) : + SimpleRecyclerAdapter(context, R.layout.item_book_source), OnItemTouchCallbackListener { - companion object { - - @JvmField - val DIFF_CALLBACK = object : DiffUtil.ItemCallback() { - override fun areItemsTheSame(oldItem: BookSource, newItem: BookSource): Boolean = - oldItem.bookSourceUrl == newItem.bookSourceUrl - - override fun areContentsTheSame(oldItem: BookSource, newItem: BookSource): Boolean = - oldItem.bookSourceUrl == newItem.bookSourceUrl - && oldItem.bookSourceName == newItem.bookSourceName - && oldItem.bookSourceGroup == newItem.bookSourceGroup - && oldItem.enabled == newItem.enabled - } - } - override fun onSwiped(adapterPosition: Int) { } override fun onMove(srcPosition: Int, targetPosition: Int): Boolean { - currentList?.let { - val srcSource = it[srcPosition] - val targetSource = it[targetPosition] - srcSource?.let { a -> - targetSource?.let { b -> - a.customOrder = targetPosition - b.customOrder = srcPosition - callBack.update(a, b) - } + val srcItem = getItem(srcPosition) + val targetItem = getItem(targetPosition) + if (srcItem != null && targetItem != null) { + if (srcItem.customOrder == targetItem.customOrder) { + callBack.upOrder() + } else { + val srcOrder = srcItem.customOrder + srcItem.customOrder = targetItem.customOrder + targetItem.customOrder = srcOrder + callBack.update(srcItem, targetItem) } } return true } - override fun onCurrentListChanged( - previousList: PagedList?, - currentList: PagedList? - ) { - super.onCurrentListChanged(previousList, currentList) - callBack.upCount(itemCount) - } - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { - return MyViewHolder( - LayoutInflater.from(parent.context).inflate( - R.layout.item_book_source, - parent, - false - ) - ) - } - - - override fun onBindViewHolder(holder: MyViewHolder, position: Int) { - getItem(position)?.let { holder.bind(it, callBack) } - } - - - class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { - - fun bind(bookSource: BookSource, callBack: CallBack) = with(itemView) { + override fun convert(holder: ItemViewHolder, item: BookSource, payloads: MutableList) { + with(holder.itemView) { this.setBackgroundColor(context.backgroundColor) - if (bookSource.bookSourceGroup.isNullOrEmpty()) { - cb_book_source.text = bookSource.bookSourceName + if (item.bookSourceGroup.isNullOrEmpty()) { + cb_book_source.text = item.bookSourceName } else { cb_book_source.text = - String.format("%s (%s)", bookSource.bookSourceName, bookSource.bookSourceGroup) + String.format("%s (%s)", item.bookSourceName, item.bookSourceGroup) } - cb_book_source.isChecked = bookSource.enabled + cb_book_source.isChecked = item.enabled cb_book_source.setOnClickListener { - bookSource.enabled = cb_book_source.isChecked - callBack.update(bookSource) + item.enabled = cb_book_source.isChecked + callBack.update(item) } - iv_edit_source.onClick { callBack.edit(bookSource) } - iv_top_source.onClick { callBack.topSource(bookSource) } - iv_del_source.onClick { callBack.del(bookSource) } + iv_edit_source.onClick { callBack.edit(item) } + iv_top_source.onClick { callBack.topSource(item) } + iv_del_source.onClick { callBack.del(item) } } } interface CallBack { - fun upCount(count: Int) fun del(bookSource: BookSource) fun edit(bookSource: BookSource) fun update(vararg bookSource: BookSource) fun topSource(bookSource: BookSource) + fun upOrder() } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/booksource/BookSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/booksource/BookSourceViewModel.kt index ab58abc35..605fefce1 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/BookSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/BookSourceViewModel.kt @@ -26,6 +26,16 @@ class BookSourceViewModel(application: Application) : BaseViewModel(application) execute { App.db.bookSourceDao().update(*bookSource) } } + fun upOrder() { + execute { + val sources = App.db.bookSourceDao().all + for ((index: Int, source: BookSource) in sources.withIndex()) { + source.customOrder = index + 1 + } + App.db.bookSourceDao().update(*sources.toTypedArray()) + } + } + fun addGroup(group: String) { execute { val sources = App.db.bookSourceDao().noGroup diff --git a/app/src/main/java/io/legado/app/ui/booksource/DiffCallBack.kt b/app/src/main/java/io/legado/app/ui/booksource/DiffCallBack.kt new file mode 100644 index 000000000..90036ba58 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/booksource/DiffCallBack.kt @@ -0,0 +1,43 @@ +package io.legado.app.ui.booksource + +import androidx.recyclerview.widget.DiffUtil +import io.legado.app.data.entities.BookSource + +class DiffCallBack( + private val oldItems: List, + private val newItems: List +) : DiffUtil.Callback() { + + override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { + val oldItem = oldItems[oldItemPosition] + val newItem = newItems[newItemPosition] + return oldItem.bookSourceUrl == newItem.bookSourceUrl + } + + override fun getOldListSize(): Int { + return oldItems.size + } + + override fun getNewListSize(): Int { + return newItems.size + } + + override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { + val oldItem = oldItems[oldItemPosition] + val newItem = newItems[newItemPosition] + return oldItem.bookSourceName == newItem.bookSourceName + && oldItem.bookSourceGroup == newItem.bookSourceGroup + && oldItem.enabled == newItem.enabled + } + + override fun getChangePayload(oldItemPosition: Int, newItemPosition: Int): Any? { + val oldItem = oldItems[oldItemPosition] + val newItem = newItems[newItemPosition] + return when { + oldItem.bookSourceName == newItem.bookSourceName + && oldItem.bookSourceGroup == newItem.bookSourceGroup + && oldItem.enabled != newItem.enabled -> 2 + else -> null + } + } +} \ No newline at end of file From a3ff57aa4478f9472787848d7549bc60d5bb472c Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 8 Sep 2019 12:15:13 +0800 Subject: [PATCH 1388/1997] up --- .../io/legado/app/data/dao/BookSourceDao.kt | 10 +++- .../app/ui/booksource/BookSourceActivity.kt | 20 +++---- .../app/ui/booksource/BookSourceAdapter.kt | 52 +++++++++++++++++-- .../app/ui/booksource/BookSourceViewModel.kt | 19 ++++++- app/src/main/res/layout/item_book_source.xml | 37 ++++++------- app/src/main/res/menu/book_source.xml | 49 +++++++++++------ 6 files changed, 131 insertions(+), 56 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt index a68e7e9e3..36dfc3d22 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt @@ -23,8 +23,14 @@ interface BookSourceDao { @Query("select distinct enabled from book_sources where bookSourceName like :searchKey or `bookSourceGroup` like :searchKey or bookSourceUrl like :searchKey") fun searchIsEnable(searchKey: String = ""): List - @Query("UPDATE book_sources SET enabled = :enable where bookSourceName like :searchKey or `bookSourceGroup` like :searchKey or bookSourceUrl like :searchKey") - fun enableAllSearch(searchKey: String = "", enable: String = "1") + @Query("update book_sources set enabled = 1 where bookSourceUrl in (:sourceUrls)") + fun enableSection(vararg sourceUrls: String) + + @Query("update book_sources set enabled = 0 where bookSourceUrl in (:sourceUrls)") + fun disableSection(vararg sourceUrls: String) + + @Query("delete from book_sources where bookSourceUrl in (:sourceUrls)") + fun delSection(vararg sourceUrls: String) @Query("select * from book_sources where enabledExplore = 1 order by customOrder asc") fun observeFind(): DataSource.Factory diff --git a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt index 6de1926ef..597cbeffa 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt @@ -28,8 +28,6 @@ import io.legado.app.utils.splitNotBlank import kotlinx.android.synthetic.main.activity_book_source.* import kotlinx.android.synthetic.main.view_search.* import kotlinx.android.synthetic.main.view_title_bar.* -import kotlinx.coroutines.Dispatchers.IO -import kotlinx.coroutines.launch import org.jetbrains.anko.startActivity import org.jetbrains.anko.startActivityForResult @@ -72,22 +70,16 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity R.id.menu_import_book_source_qr -> { this.startActivityForResult(qrRequestCode) } - R.id.menu_select_all -> { - launch(IO) { - val isEnableList = - App.db.bookSourceDao().searchIsEnable("%${search_view.query}%") - if (isEnableList.contains(false)) { - App.db.bookSourceDao().enableAllSearch("%${search_view.query}%", "1") - } else { - App.db.bookSourceDao().enableAllSearch("%${search_view.query}%", "0") - } - } - } R.id.menu_group_manage -> GroupManageDialog().show( supportFragmentManager, "groupManage" ) R.id.menu_import_book_source_local -> Restore.importYueDuData(this) + R.id.menu_select_all -> adapter.selectAll() + R.id.menu_revert_selection -> adapter.revertSelection() + R.id.menu_enable_selection -> viewModel.enableSelection(adapter.getSelectionIds()) + R.id.menu_disable_selection -> viewModel.disableSelection(adapter.getSelectionIds()) + R.id.menu_del_selection -> viewModel.delSelection(adapter.getSelectionIds()) } if (item.groupId == R.id.source_group) { search_view.setQuery(item.title, true) @@ -179,7 +171,7 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity viewModel.upOrder() } - override fun topSource(bookSource: BookSource) { + override fun toTop(bookSource: BookSource) { viewModel.topSource(bookSource) } diff --git a/app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt b/app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt index 4e5100e25..9b4261e4c 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt @@ -1,6 +1,8 @@ package io.legado.app.ui.booksource import android.content.Context +import android.view.Menu +import android.widget.PopupMenu import io.legado.app.R import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter @@ -14,6 +16,36 @@ class BookSourceAdapter(context: Context, val callBack: CallBack) : SimpleRecyclerAdapter(context, R.layout.item_book_source), OnItemTouchCallbackListener { + private val selectedIds = linkedSetOf() + + fun selectAll() { + getItems().forEach { + selectedIds.add(it.bookSourceUrl) + } + notifyItemRangeChanged(0, itemCount, 1) + } + + fun revertSelection() { + getItems().forEach { + if (selectedIds.contains(it.bookSourceUrl)) { + selectedIds.remove(it.bookSourceUrl) + } else { + selectedIds.add(it.bookSourceUrl) + } + } + notifyItemRangeChanged(0, itemCount, 1) + } + + fun getSelectionIds(): LinkedHashSet { + val selection = linkedSetOf() + getItems().map { + if (selectedIds.contains(it.bookSourceUrl)) { + selection.add(it.bookSourceUrl) + } + } + return selection + } + override fun onSwiped(adapterPosition: Int) { } @@ -48,9 +80,21 @@ class BookSourceAdapter(context: Context, val callBack: CallBack) : item.enabled = cb_book_source.isChecked callBack.update(item) } - iv_edit_source.onClick { callBack.edit(item) } - iv_top_source.onClick { callBack.topSource(item) } - iv_del_source.onClick { callBack.del(item) } + iv_edit.onClick { callBack.edit(item) } + iv_menu_more.onClick { + val popupMenu = PopupMenu(context, it) + popupMenu.menu.add(Menu.NONE, R.id.menu_top, Menu.NONE, R.string.to_top) + popupMenu.menu.add(Menu.NONE, R.id.menu_del, Menu.NONE, R.string.delete) + popupMenu.setOnMenuItemClickListener { menuItem -> + when (menuItem.itemId) { + R.id.menu_top -> callBack.toTop(item) + R.id.menu_del -> callBack.del(item) + } + true + } + popupMenu.show() + } + } } @@ -58,7 +102,7 @@ class BookSourceAdapter(context: Context, val callBack: CallBack) : fun del(bookSource: BookSource) fun edit(bookSource: BookSource) fun update(vararg bookSource: BookSource) - fun topSource(bookSource: BookSource) + fun toTop(bookSource: BookSource) fun upOrder() } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/booksource/BookSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/booksource/BookSourceViewModel.kt index 605fefce1..d2842a579 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/BookSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/BookSourceViewModel.kt @@ -9,7 +9,6 @@ import io.legado.app.utils.splitNotBlank class BookSourceViewModel(application: Application) : BaseViewModel(application) { - fun topSource(bookSource: BookSource) { execute { val minXh = App.db.bookSourceDao().minOrder @@ -36,6 +35,24 @@ class BookSourceViewModel(application: Application) : BaseViewModel(application) } } + fun enableSelection(ids: LinkedHashSet) { + execute { + App.db.bookSourceDao().enableSection(*ids.toTypedArray()) + } + } + + fun disableSelection(ids: LinkedHashSet) { + execute { + App.db.bookSourceDao().disableSection(*ids.toTypedArray()) + } + } + + fun delSelection(ids: LinkedHashSet) { + execute { + App.db.bookSourceDao().delSection(*ids.toTypedArray()) + } + } + fun addGroup(group: String) { execute { val sources = App.db.bookSourceDao().noGroup diff --git a/app/src/main/res/layout/item_book_source.xml b/app/src/main/res/layout/item_book_source.xml index a95216088..53d171ab2 100644 --- a/app/src/main/res/layout/item_book_source.xml +++ b/app/src/main/res/layout/item_book_source.xml @@ -1,6 +1,6 @@ + + + android:tint="@color/tv_text_default" /> - - + android:src="@drawable/ic_more_vert" + android:tint="@color/tv_text_default" + tools:ignore="RtlHardcoded" /> \ No newline at end of file diff --git a/app/src/main/res/menu/book_source.xml b/app/src/main/res/menu/book_source.xml index ce1ab7368..6900e82ae 100644 --- a/app/src/main/res/menu/book_source.xml +++ b/app/src/main/res/menu/book_source.xml @@ -4,11 +4,42 @@ xmlns:tools="http://schemas.android.com/tools"> + tools:ignore="AlwaysShowAction"> + + + + + + + + + + + + + + + + - - - - Date: Sun, 8 Sep 2019 13:40:56 +0800 Subject: [PATCH 1389/1997] up --- .../legado/app/ui/booksource/BookSourceAdapter.kt | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt b/app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt index 9b4261e4c..ac683d367 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt @@ -75,11 +75,19 @@ class BookSourceAdapter(context: Context, val callBack: CallBack) : cb_book_source.text = String.format("%s (%s)", item.bookSourceName, item.bookSourceGroup) } - cb_book_source.isChecked = item.enabled - cb_book_source.setOnClickListener { - item.enabled = cb_book_source.isChecked + swt_enabled.isChecked = item.enabled + swt_enabled.onClick { + item.enabled = swt_enabled.isChecked callBack.update(item) } + cb_book_source.isChecked = selectedIds.contains(item.bookSourceUrl) + cb_book_source.setOnClickListener { + if (cb_book_source.isChecked) { + selectedIds.add(item.bookSourceUrl) + } else { + selectedIds.remove(item.bookSourceUrl) + } + } iv_edit.onClick { callBack.edit(item) } iv_menu_more.onClick { val popupMenu = PopupMenu(context, it) From 1f6fc5ed274fffa1f70a050aa8e52f9f2ed663c8 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 8 Sep 2019 13:51:05 +0800 Subject: [PATCH 1390/1997] up --- app/src/main/java/io/legado/app/lib/theme/TintHelper.kt | 9 +++++++-- app/src/main/res/layout/item_book_source.xml | 1 - app/src/main/res/layout/item_replace_rule.xml | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt b/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt index b7b042ebc..c33d1e163 100644 --- a/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt +++ b/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt @@ -18,6 +18,7 @@ import androidx.core.content.ContextCompat import androidx.core.graphics.drawable.DrawableCompat import com.google.android.material.floatingactionbutton.FloatingActionButton import io.legado.app.R +import io.legado.app.utils.isNightTheme /** * @author afollestad, plusCubed @@ -127,7 +128,7 @@ object TintHelper { view: View, @ColorInt color: Int, isBackground: Boolean ) { - setTintAuto(view, color, isBackground, view.context.isDarkTheme) + setTintAuto(view, color, isBackground, view.context.isNightTheme) } fun setTintAuto( @@ -395,7 +396,11 @@ object TintHelper { if (switchView.trackDrawable != null) { switchView.trackDrawable = modifySwitchDrawable( switchView.context, - switchView.trackDrawable, color, false, false, useDarker + switchView.trackDrawable, + color, + thumb = false, + compatSwitch = false, + useDarker = useDarker ) } if (switchView.thumbDrawable != null) { diff --git a/app/src/main/res/layout/item_book_source.xml b/app/src/main/res/layout/item_book_source.xml index 53d171ab2..7d9513d98 100644 --- a/app/src/main/res/layout/item_book_source.xml +++ b/app/src/main/res/layout/item_book_source.xml @@ -15,7 +15,6 @@ android:layout_gravity="center" android:layout_weight="1" android:singleLine="true" - android:text="" android:textColor="@color/tv_text_default" /> - Date: Sun, 8 Sep 2019 13:55:12 +0800 Subject: [PATCH 1391/1997] up --- .../main/java/io/legado/app/lib/theme/ATH.kt | 29 ++++++++++++++----- .../io/legado/app/lib/theme/TintHelper.kt | 8 ----- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/theme/ATH.kt b/app/src/main/java/io/legado/app/lib/theme/ATH.kt index a09750b2a..0fafab3b3 100644 --- a/app/src/main/java/io/legado/app/lib/theme/ATH.kt +++ b/app/src/main/java/io/legado/app/lib/theme/ATH.kt @@ -17,6 +17,7 @@ import androidx.viewpager.widget.ViewPager import com.google.android.material.bottomnavigation.BottomNavigationView import io.legado.app.R import io.legado.app.utils.getCompatColor +import io.legado.app.utils.isNightTheme import io.legado.app.utils.isTransparentStatusBar import kotlinx.android.synthetic.main.activity_main.view.* import org.jetbrains.anko.backgroundColor @@ -67,9 +68,11 @@ object ATH { val decorView = activity.window.decorView val systemUiVisibility = decorView.systemUiVisibility if (enabled) { - decorView.systemUiVisibility = systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR + decorView.systemUiVisibility = + systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR } else { - decorView.systemUiVisibility = systemUiVisibility and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv() + decorView.systemUiVisibility = + systemUiVisibility and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv() } } } @@ -111,16 +114,28 @@ object ATH { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { color1 = ColorUtils.stripAlpha(color) @Suppress("DEPRECATION") - activity.setTaskDescription(ActivityManager.TaskDescription(activity.title as String, null, color1)) + activity.setTaskDescription( + ActivityManager.TaskDescription( + activity.title as String, + null, + color1 + ) + ) } } - fun setTint(view: View, @ColorInt color: Int) { - TintHelper.setTintAuto(view, color, false) + fun setTint( + view: View, @ColorInt color: Int, isDark: + Boolean = view.context.isNightTheme + ) { + TintHelper.setTintAuto(view, color, false, isDark) } - fun setBackgroundTint(view: View, @ColorInt color: Int) { - TintHelper.setTintAuto(view, color, true) + fun setBackgroundTint( + view: View, @ColorInt color: Int, + isDark: Boolean = view.context.isNightTheme + ) { + TintHelper.setTintAuto(view, color, true, isDark) } fun setAlertDialogTint(dialog: AlertDialog): AlertDialog { diff --git a/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt b/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt index c33d1e163..7b3653eb2 100644 --- a/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt +++ b/app/src/main/java/io/legado/app/lib/theme/TintHelper.kt @@ -18,7 +18,6 @@ import androidx.core.content.ContextCompat import androidx.core.graphics.drawable.DrawableCompat import com.google.android.material.floatingactionbutton.FloatingActionButton import io.legado.app.R -import io.legado.app.utils.isNightTheme /** * @author afollestad, plusCubed @@ -124,13 +123,6 @@ object TintHelper { } } - fun setTintAuto( - view: View, @ColorInt color: Int, - isBackground: Boolean - ) { - setTintAuto(view, color, isBackground, view.context.isNightTheme) - } - fun setTintAuto( view: View, @ColorInt color: Int, isBackground: Boolean, isDark: Boolean From f6ad6b02424a3d0af967317eceb6bd27075b2640 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 8 Sep 2019 14:01:07 +0800 Subject: [PATCH 1392/1997] up --- .../app/ui/booksource/BookSourceAdapter.kt | 66 ++++++++++--------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt b/app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt index ac683d367..8152ba18a 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt @@ -68,41 +68,47 @@ class BookSourceAdapter(context: Context, val callBack: CallBack) : override fun convert(holder: ItemViewHolder, item: BookSource, payloads: MutableList) { with(holder.itemView) { - this.setBackgroundColor(context.backgroundColor) - if (item.bookSourceGroup.isNullOrEmpty()) { - cb_book_source.text = item.bookSourceName - } else { - cb_book_source.text = - String.format("%s (%s)", item.bookSourceName, item.bookSourceGroup) - } - swt_enabled.isChecked = item.enabled - swt_enabled.onClick { - item.enabled = swt_enabled.isChecked - callBack.update(item) - } - cb_book_source.isChecked = selectedIds.contains(item.bookSourceUrl) - cb_book_source.setOnClickListener { - if (cb_book_source.isChecked) { - selectedIds.add(item.bookSourceUrl) + if (payloads.isEmpty()) { + this.setBackgroundColor(context.backgroundColor) + if (item.bookSourceGroup.isNullOrEmpty()) { + cb_book_source.text = item.bookSourceName } else { - selectedIds.remove(item.bookSourceUrl) + cb_book_source.text = + String.format("%s (%s)", item.bookSourceName, item.bookSourceGroup) } - } - iv_edit.onClick { callBack.edit(item) } - iv_menu_more.onClick { - val popupMenu = PopupMenu(context, it) - popupMenu.menu.add(Menu.NONE, R.id.menu_top, Menu.NONE, R.string.to_top) - popupMenu.menu.add(Menu.NONE, R.id.menu_del, Menu.NONE, R.string.delete) - popupMenu.setOnMenuItemClickListener { menuItem -> - when (menuItem.itemId) { - R.id.menu_top -> callBack.toTop(item) - R.id.menu_del -> callBack.del(item) + swt_enabled.isChecked = item.enabled + swt_enabled.onClick { + item.enabled = swt_enabled.isChecked + callBack.update(item) + } + cb_book_source.isChecked = selectedIds.contains(item.bookSourceUrl) + cb_book_source.setOnClickListener { + if (cb_book_source.isChecked) { + selectedIds.add(item.bookSourceUrl) + } else { + selectedIds.remove(item.bookSourceUrl) } - true } - popupMenu.show() + iv_edit.onClick { callBack.edit(item) } + iv_menu_more.onClick { + val popupMenu = PopupMenu(context, it) + popupMenu.menu.add(Menu.NONE, R.id.menu_top, Menu.NONE, R.string.to_top) + popupMenu.menu.add(Menu.NONE, R.id.menu_del, Menu.NONE, R.string.delete) + popupMenu.setOnMenuItemClickListener { menuItem -> + when (menuItem.itemId) { + R.id.menu_top -> callBack.toTop(item) + R.id.menu_del -> callBack.del(item) + } + true + } + popupMenu.show() + } + } else { + when (payloads[0]) { + 1 -> cb_book_source.isChecked = selectedIds.contains(item.bookSourceUrl) + 2 -> swt_enabled.isChecked = item.enabled + } } - } } From f19dc4c3c3204c5ce4faffb20dd5124cbb1c045a Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 8 Sep 2019 17:10:15 +0800 Subject: [PATCH 1393/1997] up --- app/src/main/java/io/legado/app/service/ReadAloudService.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index e6b62b68f..114b0bf72 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -234,9 +234,9 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, ReadAloudNotification.upNotification(this) for (i in nowSpeak until contentList.size) { if (i == 0) { - textToSpeech?.speak(contentList[i], TextToSpeech.QUEUE_FLUSH, null, "content") + textToSpeech?.speak(contentList[i], TextToSpeech.QUEUE_FLUSH, null, "content$i") } else { - textToSpeech?.speak(contentList[i], TextToSpeech.QUEUE_ADD, null, "content") + textToSpeech?.speak(contentList[i], TextToSpeech.QUEUE_ADD, null, "content$i") } } } From 1b8fd1036825db0b652c8cc13fe0c21c78838cb5 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 8 Sep 2019 17:18:24 +0800 Subject: [PATCH 1394/1997] up --- .../io/legado/app/service/ReadAloudService.kt | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index 114b0bf72..42f214931 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -120,6 +120,9 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, } private val handler = Handler() + private val ttsParams by lazy { + hashMapOf(Pair(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "content")) + } private var ttsIsSuccess: Boolean = false private lateinit var audioManager: AudioManager private lateinit var mFocusRequest: AudioFocusRequest @@ -234,14 +237,22 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, ReadAloudNotification.upNotification(this) for (i in nowSpeak until contentList.size) { if (i == 0) { - textToSpeech?.speak(contentList[i], TextToSpeech.QUEUE_FLUSH, null, "content$i") + speak(contentList[i], TextToSpeech.QUEUE_FLUSH) } else { - textToSpeech?.speak(contentList[i], TextToSpeech.QUEUE_ADD, null, "content$i") + speak(contentList[i], TextToSpeech.QUEUE_ADD) } } } } + private fun speak(content: String, queueMode: Int) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + textToSpeech?.speak(content, queueMode, null, "content") + } else { + textToSpeech?.speak(content, queueMode, ttsParams) + } + } + private fun setTimer(minute: Int) { timeMinute = minute if (minute > 0) { From 8e84bf06278c58a0d0a053643e42b0b3a5934995 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 8 Sep 2019 17:22:15 +0800 Subject: [PATCH 1395/1997] up --- app/src/main/java/io/legado/app/service/ReadAloudService.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index 42f214931..2b1fa11a1 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -13,6 +13,7 @@ import android.support.v4.media.session.PlaybackStateCompat import io.legado.app.R import io.legado.app.base.BaseService import io.legado.app.constant.Action +import io.legado.app.constant.AppConst import io.legado.app.constant.Bus import io.legado.app.constant.Status import io.legado.app.help.IntentDataHelp @@ -121,7 +122,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, private val handler = Handler() private val ttsParams by lazy { - hashMapOf(Pair(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "content")) + hashMapOf(Pair(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, AppConst.APP_TAG)) } private var ttsIsSuccess: Boolean = false private lateinit var audioManager: AudioManager @@ -247,8 +248,9 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, private fun speak(content: String, queueMode: Int) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - textToSpeech?.speak(content, queueMode, null, "content") + textToSpeech?.speak(content, queueMode, null, AppConst.APP_TAG) } else { + @Suppress("DEPRECATION") textToSpeech?.speak(content, queueMode, ttsParams) } } From 12c41b13a915685fbeea1ca269a4d3ae6ef43e58 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 8 Sep 2019 17:29:27 +0800 Subject: [PATCH 1396/1997] up --- .../io/legado/app/service/ReadAloudService.kt | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index 2b1fa11a1..02675489a 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -121,9 +121,6 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, } private val handler = Handler() - private val ttsParams by lazy { - hashMapOf(Pair(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, AppConst.APP_TAG)) - } private var ttsIsSuccess: Boolean = false private lateinit var audioManager: AudioManager private lateinit var mFocusRequest: AudioFocusRequest @@ -238,20 +235,24 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, ReadAloudNotification.upNotification(this) for (i in nowSpeak until contentList.size) { if (i == 0) { - speak(contentList[i], TextToSpeech.QUEUE_FLUSH) + speak(contentList[i], TextToSpeech.QUEUE_FLUSH, AppConst.APP_TAG + i) } else { - speak(contentList[i], TextToSpeech.QUEUE_ADD) + speak(contentList[i], TextToSpeech.QUEUE_ADD, AppConst.APP_TAG + i) } } } } - private fun speak(content: String, queueMode: Int) { + private fun speak(content: String, queueMode: Int, utteranceId: String) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - textToSpeech?.speak(content, queueMode, null, AppConst.APP_TAG) + textToSpeech?.speak(content, queueMode, null, utteranceId) } else { @Suppress("DEPRECATION") - textToSpeech?.speak(content, queueMode, ttsParams) + textToSpeech?.speak( + content, + queueMode, + hashMapOf(Pair(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, utteranceId)) + ) } } From 78481ee3c454f8a384d76ca6217db7adfb1479f5 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 8 Sep 2019 17:34:52 +0800 Subject: [PATCH 1397/1997] up --- .../main/java/io/legado/app/service/ReadAloudService.kt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index 02675489a..604c27830 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -424,6 +424,13 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, override fun onStart(s: String) { postEvent(Bus.TTS_START, readAloudNumber + 1) + textChapter?.let { + if (readAloudNumber + 1 > it.getReadLength(pageIndex + 1)) { + pageIndex++ + postEvent(Bus.TTS_TURN_PAGE, 1) + postEvent(Bus.TTS_START, readAloudNumber + 1) + } + } } override fun onDone(s: String) { From 8d812e18f66290431bba30bf88cfa74a94bc5560 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 8 Sep 2019 17:36:57 +0800 Subject: [PATCH 1398/1997] up --- app/src/main/java/io/legado/app/service/ReadAloudService.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index 604c27830..cdad6785d 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -423,14 +423,13 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, private inner class TTSUtteranceListener : UtteranceProgressListener() { override fun onStart(s: String) { - postEvent(Bus.TTS_START, readAloudNumber + 1) textChapter?.let { if (readAloudNumber + 1 > it.getReadLength(pageIndex + 1)) { pageIndex++ postEvent(Bus.TTS_TURN_PAGE, 1) - postEvent(Bus.TTS_START, readAloudNumber + 1) } } + postEvent(Bus.TTS_START, readAloudNumber + 1) } override fun onDone(s: String) { From 796b817ea67cb4ea09bc1c27e53fcdc5903d59a6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 8 Sep 2019 21:41:07 +0800 Subject: [PATCH 1399/1997] up --- .../widget/dynamiclayout/DynamicFrameLayout.kt | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/dynamiclayout/DynamicFrameLayout.kt b/app/src/main/java/io/legado/app/ui/widget/dynamiclayout/DynamicFrameLayout.kt index 2b25fe55a..00bba86dd 100644 --- a/app/src/main/java/io/legado/app/ui/widget/dynamiclayout/DynamicFrameLayout.kt +++ b/app/src/main/java/io/legado/app/ui/widget/dynamiclayout/DynamicFrameLayout.kt @@ -62,33 +62,25 @@ class DynamicFrameLayout(context: Context, attrs: AttributeSet?) : FrameLayout(c } override fun addView(child: View) { - if (childCount > 2) { - throw IllegalStateException("DynamicFrameLayout can host only one direct child") - } + check(childCount <= 2) { "DynamicFrameLayout can host only one direct child" } super.addView(child) } override fun addView(child: View, index: Int) { - if (childCount > 2) { - throw IllegalStateException("DynamicFrameLayout can host only one direct child") - } + check(childCount <= 2) { "DynamicFrameLayout can host only one direct child" } super.addView(child, index) } override fun addView(child: View, params: ViewGroup.LayoutParams) { - if (childCount > 2) { - throw IllegalStateException("DynamicFrameLayout can host only one direct child") - } + check(childCount <= 2) { "DynamicFrameLayout can host only one direct child" } super.addView(child, params) } override fun addView(child: View, index: Int, params: ViewGroup.LayoutParams) { - if (childCount > 2) { - throw IllegalStateException("DynamicFrameLayout can host only one direct child") - } + check(childCount <= 2) { "DynamicFrameLayout can host only one direct child" } super.addView(child, index, params) } From 6c588b0e25abb418009a429620b142c3e3a23100 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 9 Sep 2019 08:17:17 +0800 Subject: [PATCH 1400/1997] up --- .../ui/main/bookshelf/BookshelfFragment.kt | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index 94b17e6dc..2e389815d 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -19,10 +19,7 @@ import io.legado.app.base.VMBaseFragment import io.legado.app.constant.Bus import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookGroup -import io.legado.app.lib.dialogs.alert -import io.legado.app.lib.dialogs.customView -import io.legado.app.lib.dialogs.noButton -import io.legado.app.lib.dialogs.yesButton +import io.legado.app.lib.dialogs.* import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.accentColor import io.legado.app.ui.bookinfo.BookInfoActivity @@ -64,6 +61,7 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b super.onCompatOptionsItemSelected(item) when (item.itemId) { R.id.menu_search -> startActivity() + R.id.menu_bookshelf_layout -> selectBookshelfLayout() } } @@ -75,12 +73,18 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b viewModel.upChapterList() } tv_recent_reading.textColor = accentColor - rv_book_group.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) + rv_book_group.layoutManager = + LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) bookGroupAdapter = BookGroupAdapter() rv_book_group.adapter = bookGroupAdapter bookGroupAdapter.callBack = this rv_bookshelf.layoutManager = LinearLayoutManager(context) - rv_bookshelf.addItemDecoration(DividerItemDecoration(rv_bookshelf.context, LinearLayoutManager.VERTICAL)) + rv_bookshelf.addItemDecoration( + DividerItemDecoration( + rv_bookshelf.context, + LinearLayoutManager.VERTICAL + ) + ) bookshelfAdapter = BookshelfAdapter() rv_bookshelf.adapter = bookshelfAdapter bookshelfAdapter.callBack = this @@ -150,4 +154,12 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b }.show().applyTint().requestInputMethod() } + private fun selectBookshelfLayout() { + selector( + title = "选择书架布局", + items = resources.getStringArray(R.array.bookshelf_layout).toList() + ) { _, index -> + putPrefInt("bookshelf", index) + } + } } \ No newline at end of file From bccb527b7782c496aca9d193828affe1fc5980ef Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 9 Sep 2019 08:43:36 +0800 Subject: [PATCH 1401/1997] up --- app/src/main/res/menu/main_bookshelf.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/menu/main_bookshelf.xml b/app/src/main/res/menu/main_bookshelf.xml index 6815c9cae..19bbbdb7f 100644 --- a/app/src/main/res/menu/main_bookshelf.xml +++ b/app/src/main/res/menu/main_bookshelf.xml @@ -27,7 +27,7 @@ app:showAsAction="never" /> From 0f0405480f0a1da713166046364d9c1319205238 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 9 Sep 2019 08:59:57 +0800 Subject: [PATCH 1402/1997] up --- .../java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt | 1 - .../java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt | 4 ---- 2 files changed, 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt index 213a325e6..4f5a271c2 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt @@ -100,7 +100,6 @@ class BookshelfAdapter : PagedListAdapter(D interface CallBack { fun open(book: Book) fun openBookInfo(book: Book) - fun search() fun isUpdate(bookUrl: String): Boolean } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index 2e389815d..415a7cafe 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -118,10 +118,6 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b context?.startActivity(Pair("bookUrl", book.bookUrl)) } - override fun search() { - - } - override fun isUpdate(bookUrl: String): Boolean { return bookUrl in viewModel.updateList } From 59ae98bac5a166b60cd0a501d6b723d86619706c Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 9 Sep 2019 11:07:00 +0800 Subject: [PATCH 1403/1997] up --- .../io/legado/app/data/dao/RssSourceDao.kt | 6 +-- .../io/legado/app/ui/main/rss/RssAdapter.kt | 45 ++++--------------- .../io/legado/app/ui/main/rss/RssFragment.kt | 20 ++++----- 3 files changed, 21 insertions(+), 50 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt b/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt index 49532a846..cb4d695ab 100644 --- a/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt @@ -1,6 +1,6 @@ package io.legado.app.data.dao -import androidx.paging.DataSource +import androidx.lifecycle.LiveData import androidx.room.Dao import androidx.room.Query import io.legado.app.data.entities.RssSource @@ -9,8 +9,8 @@ import io.legado.app.data.entities.RssSource interface RssSourceDao { @Query("SELECT * FROM rssSources") - fun observeAll(): DataSource.Factory + fun liveAll(): LiveData> @Query("SELECT * FROM rssSources where enabled = 1") - fun observeEnabled(): DataSource.Factory + fun liveEnabled(): LiveData> } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/rss/RssAdapter.kt b/app/src/main/java/io/legado/app/ui/main/rss/RssAdapter.kt index 882e4f738..6bef664c6 100644 --- a/app/src/main/java/io/legado/app/ui/main/rss/RssAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/rss/RssAdapter.kt @@ -1,48 +1,19 @@ package io.legado.app.ui.main.rss -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.paging.PagedListAdapter -import androidx.recyclerview.widget.DiffUtil -import androidx.recyclerview.widget.RecyclerView +import android.content.Context import io.legado.app.R +import io.legado.app.base.adapter.ItemViewHolder +import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.data.entities.RssSource -class RssAdapter : PagedListAdapter(DIFF_CALLBACK) { +class RssAdapter(context: Context, val callBack: CallBack) : + SimpleRecyclerAdapter(context, R.layout.item_rss) { - companion object { - @JvmField - val DIFF_CALLBACK = object : DiffUtil.ItemCallback() { - override fun areItemsTheSame(oldItem: RssSource, newItem: RssSource): Boolean = - oldItem.sourceUrl == newItem.sourceUrl + override fun convert(holder: ItemViewHolder, item: RssSource, payloads: MutableList) { - override fun areContentsTheSame(oldItem: RssSource, newItem: RssSource): Boolean = - oldItem.sourceName == newItem.sourceName - } } - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { - return MyViewHolder( - LayoutInflater.from(parent.context).inflate( - R.layout.item_rss, - parent, - false - ) - ) - } - - override fun onBindViewHolder(holder: MyViewHolder, position: Int) { - getItem(position)?.let { - holder.onBind(it) - } - } - - class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { - - fun onBind(rssSource: RssSource) { - - } - + interface CallBack { + fun openRss() } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt b/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt index fba701142..70df16148 100644 --- a/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt @@ -2,22 +2,18 @@ package io.legado.app.ui.main.rss import android.os.Bundle import android.view.View -import androidx.lifecycle.LiveData import androidx.lifecycle.Observer -import androidx.paging.LivePagedListBuilder -import androidx.paging.PagedList import androidx.recyclerview.widget.GridLayoutManager import io.legado.app.App import io.legado.app.R import io.legado.app.base.BaseFragment -import io.legado.app.data.entities.RssSource import io.legado.app.lib.theme.ATH import kotlinx.android.synthetic.main.fragment_rss.* -class RssFragment : BaseFragment(R.layout.fragment_rss) { +class RssFragment : BaseFragment(R.layout.fragment_rss), + RssAdapter.CallBack { private lateinit var adapter: RssAdapter - private var rssLiveData: LiveData>? = null override fun onViewCreated(view: View, savedInstanceState: Bundle?) { initRecyclerView() @@ -26,14 +22,18 @@ class RssFragment : BaseFragment(R.layout.fragment_rss) { private fun initRecyclerView() { ATH.applyEdgeEffectColor(recycler_view) - adapter = RssAdapter() + adapter = RssAdapter(requireContext(), this) recycler_view.layoutManager = GridLayoutManager(requireContext(), 4) recycler_view.adapter = adapter } private fun initData() { - rssLiveData?.removeObservers(viewLifecycleOwner) - rssLiveData = LivePagedListBuilder(App.db.rssSourceDao().observeEnabled(), 50).build() - rssLiveData?.observe(viewLifecycleOwner, Observer { adapter.submitList(it) }) + App.db.rssSourceDao().liveEnabled().observe(viewLifecycleOwner, Observer { + adapter.setItems(it) + }) + } + + override fun openRss() { + } } \ No newline at end of file From e1d6e55b1c967678bce3c413a4b3a21762b87e84 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 9 Sep 2019 14:04:28 +0800 Subject: [PATCH 1404/1997] up --- app/build.gradle | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 250200bea..7d48f51f8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -82,17 +82,17 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" //androidX - implementation 'androidx.core:core-ktx:1.2.0-alpha03' - implementation 'androidx.appcompat:appcompat:1.1.0-rc01' - implementation 'androidx.preference:preference:1.1.0-rc01' + implementation 'androidx.core:core-ktx:1.2.0-alpha04' + implementation 'androidx.appcompat:appcompat:1.1.0' + implementation 'androidx.preference:preference:1.1.0' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0' - implementation 'androidx.media:media:1.1.0-rc01' - implementation 'com.google.android.material:material:1.1.0-alpha09' + implementation 'androidx.media:media:1.1.0' + implementation 'com.google.android.material:material:1.1.0-alpha10' implementation 'com.google.android:flexbox:1.1.0' //lifecycle - def lifecycle_version = '2.0.0' + def lifecycle_version = '2.1.0' implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version" implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version" From 2581ebca16ef8885cd1ed683030fab02949cd738 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 9 Sep 2019 16:18:39 +0800 Subject: [PATCH 1405/1997] up --- app/src/debug/res/xml/shortcuts.xml | 8 ++++---- app/src/main/res/xml/shortcuts.xml | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/src/debug/res/xml/shortcuts.xml b/app/src/debug/res/xml/shortcuts.xml index d653992cc..d78c05d83 100644 --- a/app/src/debug/res/xml/shortcuts.xml +++ b/app/src/debug/res/xml/shortcuts.xml @@ -12,8 +12,8 @@ + android:targetPackage="${applicationId}" + android:targetClass="io.legado.app.ui.readbook.ReadBookActivity" />
    @@ -28,8 +28,8 @@ + android:targetPackage="${applicationId}" + android:targetClass="io.legado.app.ui.main.MainActivity" /> \ No newline at end of file diff --git a/app/src/main/res/xml/shortcuts.xml b/app/src/main/res/xml/shortcuts.xml index 639773ea7..9c5ca598d 100644 --- a/app/src/main/res/xml/shortcuts.xml +++ b/app/src/main/res/xml/shortcuts.xml @@ -12,8 +12,8 @@ + android:targetPackage="${applicationId}" + android:targetClass="io.legado.app.ui.readbook.ReadBookActivity" /> @@ -28,8 +28,8 @@ + android:targetPackage="${applicationId}" + android:targetClass="io.legado.app.ui.main.MainActivity" /> From 965f5ca29c8f743936996ef3a7afbbfc7d3cfa39 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 9 Sep 2019 16:20:51 +0800 Subject: [PATCH 1406/1997] up --- app/src/main/AndroidManifest.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 86b1d669a..d0689f9eb 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -33,6 +33,9 @@ + Date: Mon, 9 Sep 2019 16:25:25 +0800 Subject: [PATCH 1407/1997] up --- app/src/debug/res/xml/shortcuts.xml | 4 ++-- app/src/main/res/xml/shortcuts.xml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/debug/res/xml/shortcuts.xml b/app/src/debug/res/xml/shortcuts.xml index d78c05d83..f51f154cc 100644 --- a/app/src/debug/res/xml/shortcuts.xml +++ b/app/src/debug/res/xml/shortcuts.xml @@ -12,7 +12,7 @@ @@ -28,7 +28,7 @@ diff --git a/app/src/main/res/xml/shortcuts.xml b/app/src/main/res/xml/shortcuts.xml index 9c5ca598d..e3247442f 100644 --- a/app/src/main/res/xml/shortcuts.xml +++ b/app/src/main/res/xml/shortcuts.xml @@ -12,7 +12,7 @@ @@ -28,7 +28,7 @@ From 6f9d8d7d089e9f13259be5b242da3bc0f0857b1f Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 9 Sep 2019 22:19:00 +0800 Subject: [PATCH 1408/1997] up --- app/build.gradle | 4 ++++ app/src/debug/res/xml/shortcuts.xml | 35 ----------------------------- app/src/main/res/xml/shortcuts.xml | 4 ++-- build.gradle | 6 ++--- 4 files changed, 9 insertions(+), 40 deletions(-) delete mode 100644 app/src/debug/res/xml/shortcuts.xml diff --git a/app/build.gradle b/app/build.gradle index 7d48f51f8..648e65cae 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -2,6 +2,7 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-kapt' +apply plugin: "de.timfreiheit.resourceplaceholders" androidExtensions { experimental = true @@ -66,6 +67,9 @@ android { } } +resourcePlaceholders { + files = ['xml/shortcuts.xml'] +} kapt { arguments { diff --git a/app/src/debug/res/xml/shortcuts.xml b/app/src/debug/res/xml/shortcuts.xml deleted file mode 100644 index f51f154cc..000000000 --- a/app/src/debug/res/xml/shortcuts.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/xml/shortcuts.xml b/app/src/main/res/xml/shortcuts.xml index e3247442f..9c5ca598d 100644 --- a/app/src/main/res/xml/shortcuts.xml +++ b/app/src/main/res/xml/shortcuts.xml @@ -12,7 +12,7 @@ @@ -28,7 +28,7 @@ diff --git a/build.gradle b/build.gradle index c6798862d..3c95124c7 100644 --- a/build.gradle +++ b/build.gradle @@ -1,17 +1,17 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = '1.3.41' + ext.kotlin_version = '1.3.50' repositories { google() jcenter() maven { url 'https://maven.fabric.io/public' } + maven { url 'https://plugins.gradle.org/m2/' } } dependencies { classpath 'com.android.tools.build:gradle:3.5.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - // NOTE: Do not place your application dependencies here; they belong - // in the individual module build.gradle files + classpath 'de.timfreiheit.resourceplaceholders:placeholders:0.3' } } From fab0d7c76fe4ba1637d5fb4f6574b17b9572e690 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 10 Sep 2019 10:20:17 +0800 Subject: [PATCH 1409/1997] up --- app/src/main/java/io/legado/app/ui/readbook/Help.kt | 5 ++--- .../io/legado/app/ui/readbook/config/BgTextConfigDialog.kt | 3 +++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/Help.kt b/app/src/main/java/io/legado/app/ui/readbook/Help.kt index eaf448006..72d65da5f 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/Help.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/Help.kt @@ -55,9 +55,8 @@ object Help { if (vp != null) { for (i in 0 until vp.childCount) { vp.getChildAt(i).context.packageName - if (vp.getChildAt(i).id != NO_ID && NAVIGATION == activity.resources.getResourceEntryName( - vp.getChildAt(i).id - ) + if (vp.getChildAt(i).id != NO_ID + && NAVIGATION == activity.resources.getResourceEntryName(vp.getChildAt(i).id) ) { return true } diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt index 529654ae2..98abc2dd2 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt @@ -103,6 +103,9 @@ class BgTextConfigDialog : DialogFragment() { sw_dark_status_icon.onCheckedChange { buttonView, isChecked -> if (buttonView?.isPressed == true) { setStatusIconDark(isChecked) + activity?.let { + Help.upSystemUiVisibility(it) + } } } tv_text_color.onClick { From f045b83689ab6dfdaebc815864a3f322fc48719c Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 10 Sep 2019 10:31:54 +0800 Subject: [PATCH 1410/1997] up --- .../main/java/io/legado/app/lib/theme/ATH.kt | 26 ++++++++++--------- .../java/io/legado/app/ui/readbook/Help.kt | 11 ++++---- .../app/ui/readbook/ReadBookActivity.kt | 2 +- .../ui/readbook/config/BgTextConfigDialog.kt | 4 +-- .../ui/readbook/config/MoreConfigDialog.kt | 2 +- .../ui/readbook/config/PaddingConfigDialog.kt | 2 +- .../app/ui/readbook/config/ReadAloudDialog.kt | 2 +- .../app/ui/readbook/config/ReadStyleDialog.kt | 2 +- 8 files changed, 27 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/theme/ATH.kt b/app/src/main/java/io/legado/app/lib/theme/ATH.kt index 0fafab3b3..64dffaa2a 100644 --- a/app/src/main/java/io/legado/app/lib/theme/ATH.kt +++ b/app/src/main/java/io/legado/app/lib/theme/ATH.kt @@ -8,6 +8,7 @@ import android.graphics.Color import android.os.Build import android.view.View import android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR +import android.view.Window import android.widget.EdgeEffect import android.widget.ScrollView import androidx.annotation.ColorInt @@ -15,6 +16,7 @@ import androidx.appcompat.app.AlertDialog import androidx.recyclerview.widget.RecyclerView import androidx.viewpager.widget.ViewPager import com.google.android.material.bottomnavigation.BottomNavigationView +import io.legado.app.App import io.legado.app.R import io.legado.app.utils.getCompatColor import io.legado.app.utils.isNightTheme @@ -36,36 +38,36 @@ object ATH { ) > since } - fun setStatusBarColorAuto(activity: Activity, fullScreen: Boolean) { - val isTransparentStatusBar = activity.isTransparentStatusBar + fun setStatusBarColorAuto(window: Window, fullScreen: Boolean) { + val isTransparentStatusBar = App.INSTANCE.isTransparentStatusBar setStatusBarColor( - activity, - ThemeStore.statusBarColor(activity, isTransparentStatusBar), + window, + ThemeStore.statusBarColor(App.INSTANCE, isTransparentStatusBar), isTransparentStatusBar, fullScreen ) } fun setStatusBarColor( - activity: Activity, + window: Window, color: Int, isTransparentStatusBar: Boolean, fullScreen: Boolean ) { if (fullScreen && isTransparentStatusBar) { - activity.window.statusBarColor = Color.TRANSPARENT + window.statusBarColor = Color.TRANSPARENT } else { - activity.window.statusBarColor = color + window.statusBarColor = color } - setLightStatusBarAuto(activity, color) + setLightStatusBarAuto(window, color) } - fun setLightStatusBarAuto(activity: Activity, bgColor: Int) { - setLightStatusBar(activity, ColorUtils.isColorLight(bgColor)) + fun setLightStatusBarAuto(window: Window, bgColor: Int) { + setLightStatusBar(window, ColorUtils.isColorLight(bgColor)) } - fun setLightStatusBar(activity: Activity, enabled: Boolean) { + fun setLightStatusBar(window: Window, enabled: Boolean) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - val decorView = activity.window.decorView + val decorView = window.decorView val systemUiVisibility = decorView.systemUiVisibility if (enabled) { decorView.systemUiVisibility = diff --git a/app/src/main/java/io/legado/app/ui/readbook/Help.kt b/app/src/main/java/io/legado/app/ui/readbook/Help.kt index 72d65da5f..1bc10c1db 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/Help.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/Help.kt @@ -4,6 +4,7 @@ import android.app.Activity import android.view.View import android.view.View.NO_ID import android.view.ViewGroup +import android.view.Window import io.legado.app.App import io.legado.app.help.ReadBookConfig import io.legado.app.lib.theme.ATH @@ -16,7 +17,7 @@ object Help { private const val NAVIGATION = "navigationBarBackground" - fun upSystemUiVisibility(activity: Activity, toolBarHide: Boolean = true) { + fun upSystemUiVisibility(window: Window, toolBarHide: Boolean = true) { var flag = (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_IMMERSIVE @@ -33,13 +34,13 @@ object Help { flag = flag or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION } } - activity.window.decorView.systemUiVisibility = flag + window.decorView.systemUiVisibility = flag if (toolBarHide) { - ATH.setLightStatusBar(activity, ReadBookConfig.getConfig().statusIconDark()) + ATH.setLightStatusBar(window, ReadBookConfig.getConfig().statusIconDark()) } else { ATH.setLightStatusBarAuto( - activity, - ThemeStore.statusBarColor(activity, activity.isTransparentStatusBar) + window, + ThemeStore.statusBarColor(App.INSTANCE, App.INSTANCE.isTransparentStatusBar) ) } } diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 3e45d65d2..65417911c 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -437,7 +437,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } override fun upSystemUiVisibility() { - Help.upSystemUiVisibility(this, !read_menu.isVisible) + Help.upSystemUiVisibility(window, !read_menu.isVisible) } /** diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt index 98abc2dd2..80a3a93b4 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt @@ -55,10 +55,10 @@ class BgTextConfigDialog : DialogFragment() { super.onStart() val dm = DisplayMetrics() activity?.let { - Help.upSystemUiVisibility(it) it.windowManager?.defaultDisplay?.getMetrics(dm) } dialog?.window?.let { + Help.upSystemUiVisibility(it) it.setBackgroundDrawableResource(R.color.transparent) it.decorView.setPadding(0, 0, 0, 0) val attr = it.attributes @@ -103,7 +103,7 @@ class BgTextConfigDialog : DialogFragment() { sw_dark_status_icon.onCheckedChange { buttonView, isChecked -> if (buttonView?.isPressed == true) { setStatusIconDark(isChecked) - activity?.let { + activity?.window?.let { Help.upSystemUiVisibility(it) } } diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt index 3e1652645..a5c5e2980 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt @@ -31,10 +31,10 @@ class MoreConfigDialog : DialogFragment() { super.onStart() val dm = DisplayMetrics() activity?.let { - Help.upSystemUiVisibility(it) it.windowManager?.defaultDisplay?.getMetrics(dm) } dialog?.window?.let { + Help.upSystemUiVisibility(it) it.setBackgroundDrawableResource(R.color.transparent) it.decorView.setPadding(0, 0, 0, 0) val attr = it.attributes diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.kt index 779ba3dab..ac0c6eef7 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.kt @@ -29,10 +29,10 @@ class PaddingConfigDialog : DialogFragment() { super.onStart() val dm = DisplayMetrics() activity?.let { - Help.upSystemUiVisibility(it) it.windowManager?.defaultDisplay?.getMetrics(dm) } dialog?.window?.let { + Help.upSystemUiVisibility(it) it.setBackgroundDrawableResource(R.color.transparent) it.decorView.setPadding(0, 0, 0, 0) val attr = it.attributes diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt index 3922ee122..46f2dae92 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt @@ -34,10 +34,10 @@ class ReadAloudDialog : DialogFragment() { super.onStart() val dm = DisplayMetrics() activity?.let { - Help.upSystemUiVisibility(it) it.windowManager?.defaultDisplay?.getMetrics(dm) } dialog?.window?.let { + Help.upSystemUiVisibility(it) it.setBackgroundDrawableResource(R.color.transparent) it.decorView.setPadding(0, 0, 0, 0) val attr = it.attributes diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt index 15fa51590..dbe571869 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt @@ -46,10 +46,10 @@ class ReadStyleDialog : DialogFragment() { super.onStart() val dm = DisplayMetrics() activity?.let { - Help.upSystemUiVisibility(it) it.windowManager?.defaultDisplay?.getMetrics(dm) } dialog?.window?.let { + Help.upSystemUiVisibility(it) it.setBackgroundDrawableResource(R.color.transparent) it.decorView.setPadding(0, 0, 0, 0) val attr = it.attributes From 369c8ffba098d2d16ee2f7b046ab6b7c3bd7784d Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 10 Sep 2019 10:37:32 +0800 Subject: [PATCH 1411/1997] up --- app/src/main/java/io/legado/app/base/BaseActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/base/BaseActivity.kt b/app/src/main/java/io/legado/app/base/BaseActivity.kt index c02f4731a..dacf41b3a 100644 --- a/app/src/main/java/io/legado/app/base/BaseActivity.kt +++ b/app/src/main/java/io/legado/app/base/BaseActivity.kt @@ -85,7 +85,7 @@ abstract class BaseActivity(private val layoutID: Int, private val fullScreen: B window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_STABLE } - ATH.setStatusBarColorAuto(this, fullScreen) + ATH.setStatusBarColorAuto(window, fullScreen) } open fun observeLiveBus() { From 0f2b08b56f2894a5a1b6e53c052e52ed225d299d Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 10 Sep 2019 10:40:23 +0800 Subject: [PATCH 1412/1997] up --- .../java/io/legado/app/base/BaseActivity.kt | 2 +- .../main/java/io/legado/app/lib/theme/ATH.kt | 26 +++++++++---------- .../java/io/legado/app/ui/readbook/Help.kt | 11 ++++---- .../app/ui/readbook/ReadBookActivity.kt | 2 +- .../ui/readbook/config/BgTextConfigDialog.kt | 4 +-- .../ui/readbook/config/MoreConfigDialog.kt | 2 +- .../ui/readbook/config/PaddingConfigDialog.kt | 2 +- .../app/ui/readbook/config/ReadAloudDialog.kt | 2 +- .../app/ui/readbook/config/ReadStyleDialog.kt | 2 +- 9 files changed, 25 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/io/legado/app/base/BaseActivity.kt b/app/src/main/java/io/legado/app/base/BaseActivity.kt index dacf41b3a..c02f4731a 100644 --- a/app/src/main/java/io/legado/app/base/BaseActivity.kt +++ b/app/src/main/java/io/legado/app/base/BaseActivity.kt @@ -85,7 +85,7 @@ abstract class BaseActivity(private val layoutID: Int, private val fullScreen: B window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_STABLE } - ATH.setStatusBarColorAuto(window, fullScreen) + ATH.setStatusBarColorAuto(this, fullScreen) } open fun observeLiveBus() { diff --git a/app/src/main/java/io/legado/app/lib/theme/ATH.kt b/app/src/main/java/io/legado/app/lib/theme/ATH.kt index 64dffaa2a..0fafab3b3 100644 --- a/app/src/main/java/io/legado/app/lib/theme/ATH.kt +++ b/app/src/main/java/io/legado/app/lib/theme/ATH.kt @@ -8,7 +8,6 @@ import android.graphics.Color import android.os.Build import android.view.View import android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR -import android.view.Window import android.widget.EdgeEffect import android.widget.ScrollView import androidx.annotation.ColorInt @@ -16,7 +15,6 @@ import androidx.appcompat.app.AlertDialog import androidx.recyclerview.widget.RecyclerView import androidx.viewpager.widget.ViewPager import com.google.android.material.bottomnavigation.BottomNavigationView -import io.legado.app.App import io.legado.app.R import io.legado.app.utils.getCompatColor import io.legado.app.utils.isNightTheme @@ -38,36 +36,36 @@ object ATH { ) > since } - fun setStatusBarColorAuto(window: Window, fullScreen: Boolean) { - val isTransparentStatusBar = App.INSTANCE.isTransparentStatusBar + fun setStatusBarColorAuto(activity: Activity, fullScreen: Boolean) { + val isTransparentStatusBar = activity.isTransparentStatusBar setStatusBarColor( - window, - ThemeStore.statusBarColor(App.INSTANCE, isTransparentStatusBar), + activity, + ThemeStore.statusBarColor(activity, isTransparentStatusBar), isTransparentStatusBar, fullScreen ) } fun setStatusBarColor( - window: Window, + activity: Activity, color: Int, isTransparentStatusBar: Boolean, fullScreen: Boolean ) { if (fullScreen && isTransparentStatusBar) { - window.statusBarColor = Color.TRANSPARENT + activity.window.statusBarColor = Color.TRANSPARENT } else { - window.statusBarColor = color + activity.window.statusBarColor = color } - setLightStatusBarAuto(window, color) + setLightStatusBarAuto(activity, color) } - fun setLightStatusBarAuto(window: Window, bgColor: Int) { - setLightStatusBar(window, ColorUtils.isColorLight(bgColor)) + fun setLightStatusBarAuto(activity: Activity, bgColor: Int) { + setLightStatusBar(activity, ColorUtils.isColorLight(bgColor)) } - fun setLightStatusBar(window: Window, enabled: Boolean) { + fun setLightStatusBar(activity: Activity, enabled: Boolean) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - val decorView = window.decorView + val decorView = activity.window.decorView val systemUiVisibility = decorView.systemUiVisibility if (enabled) { decorView.systemUiVisibility = diff --git a/app/src/main/java/io/legado/app/ui/readbook/Help.kt b/app/src/main/java/io/legado/app/ui/readbook/Help.kt index 1bc10c1db..72d65da5f 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/Help.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/Help.kt @@ -4,7 +4,6 @@ import android.app.Activity import android.view.View import android.view.View.NO_ID import android.view.ViewGroup -import android.view.Window import io.legado.app.App import io.legado.app.help.ReadBookConfig import io.legado.app.lib.theme.ATH @@ -17,7 +16,7 @@ object Help { private const val NAVIGATION = "navigationBarBackground" - fun upSystemUiVisibility(window: Window, toolBarHide: Boolean = true) { + fun upSystemUiVisibility(activity: Activity, toolBarHide: Boolean = true) { var flag = (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_IMMERSIVE @@ -34,13 +33,13 @@ object Help { flag = flag or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION } } - window.decorView.systemUiVisibility = flag + activity.window.decorView.systemUiVisibility = flag if (toolBarHide) { - ATH.setLightStatusBar(window, ReadBookConfig.getConfig().statusIconDark()) + ATH.setLightStatusBar(activity, ReadBookConfig.getConfig().statusIconDark()) } else { ATH.setLightStatusBarAuto( - window, - ThemeStore.statusBarColor(App.INSTANCE, App.INSTANCE.isTransparentStatusBar) + activity, + ThemeStore.statusBarColor(activity, activity.isTransparentStatusBar) ) } } diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 65417911c..3e45d65d2 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -437,7 +437,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } override fun upSystemUiVisibility() { - Help.upSystemUiVisibility(window, !read_menu.isVisible) + Help.upSystemUiVisibility(this, !read_menu.isVisible) } /** diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt index 80a3a93b4..98abc2dd2 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt @@ -55,10 +55,10 @@ class BgTextConfigDialog : DialogFragment() { super.onStart() val dm = DisplayMetrics() activity?.let { + Help.upSystemUiVisibility(it) it.windowManager?.defaultDisplay?.getMetrics(dm) } dialog?.window?.let { - Help.upSystemUiVisibility(it) it.setBackgroundDrawableResource(R.color.transparent) it.decorView.setPadding(0, 0, 0, 0) val attr = it.attributes @@ -103,7 +103,7 @@ class BgTextConfigDialog : DialogFragment() { sw_dark_status_icon.onCheckedChange { buttonView, isChecked -> if (buttonView?.isPressed == true) { setStatusIconDark(isChecked) - activity?.window?.let { + activity?.let { Help.upSystemUiVisibility(it) } } diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt index a5c5e2980..3e1652645 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt @@ -31,10 +31,10 @@ class MoreConfigDialog : DialogFragment() { super.onStart() val dm = DisplayMetrics() activity?.let { + Help.upSystemUiVisibility(it) it.windowManager?.defaultDisplay?.getMetrics(dm) } dialog?.window?.let { - Help.upSystemUiVisibility(it) it.setBackgroundDrawableResource(R.color.transparent) it.decorView.setPadding(0, 0, 0, 0) val attr = it.attributes diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.kt index ac0c6eef7..779ba3dab 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.kt @@ -29,10 +29,10 @@ class PaddingConfigDialog : DialogFragment() { super.onStart() val dm = DisplayMetrics() activity?.let { + Help.upSystemUiVisibility(it) it.windowManager?.defaultDisplay?.getMetrics(dm) } dialog?.window?.let { - Help.upSystemUiVisibility(it) it.setBackgroundDrawableResource(R.color.transparent) it.decorView.setPadding(0, 0, 0, 0) val attr = it.attributes diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt index 46f2dae92..3922ee122 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt @@ -34,10 +34,10 @@ class ReadAloudDialog : DialogFragment() { super.onStart() val dm = DisplayMetrics() activity?.let { + Help.upSystemUiVisibility(it) it.windowManager?.defaultDisplay?.getMetrics(dm) } dialog?.window?.let { - Help.upSystemUiVisibility(it) it.setBackgroundDrawableResource(R.color.transparent) it.decorView.setPadding(0, 0, 0, 0) val attr = it.attributes diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt index dbe571869..15fa51590 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt @@ -46,10 +46,10 @@ class ReadStyleDialog : DialogFragment() { super.onStart() val dm = DisplayMetrics() activity?.let { + Help.upSystemUiVisibility(it) it.windowManager?.defaultDisplay?.getMetrics(dm) } dialog?.window?.let { - Help.upSystemUiVisibility(it) it.setBackgroundDrawableResource(R.color.transparent) it.decorView.setPadding(0, 0, 0, 0) val attr = it.attributes From 37f91e8ed4fe8e550627a6bca542c7c3b5a4e977 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 10 Sep 2019 10:58:06 +0800 Subject: [PATCH 1413/1997] up --- .../app/ui/widget/anima/RefreshProgressBar.kt | 204 ++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 app/src/main/java/io/legado/app/ui/widget/anima/RefreshProgressBar.kt diff --git a/app/src/main/java/io/legado/app/ui/widget/anima/RefreshProgressBar.kt b/app/src/main/java/io/legado/app/ui/widget/anima/RefreshProgressBar.kt new file mode 100644 index 000000000..3eee366be --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/anima/RefreshProgressBar.kt @@ -0,0 +1,204 @@ +package io.legado.app.ui.widget.anima + +import android.content.Context +import android.graphics.Canvas +import android.graphics.Paint +import android.graphics.Rect +import android.graphics.RectF +import android.os.Looper +import android.util.AttributeSet +import android.view.View + +import io.legado.app.R + +class RefreshProgressBar @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : View(context, attrs, defStyleAttr) { + internal var a = 1 + var maxProgress = 100 + private var durProgress = 0 + var secondMaxProgress = 100 + private var secondDurProgress = 0 + var bgColor = 0x00000000 + var secondColor = -0x3e3e3f + var fontColor = -0xc9c9ca + var speed = 1 + var secondFinalProgress = 0 + private set + private var paint: Paint = Paint() + private val bgRect = Rect() + private val secondRect = Rect() + private val fontRectF = RectF() + + var isAutoLoading: Boolean = false + set(loading) { + if (loading && visibility != VISIBLE) { + visibility = VISIBLE + } + field = loading + if (!this.isAutoLoading) { + secondDurProgress = 0 + secondFinalProgress = 0 + } + maxProgress = 0 + + invalidate() + } + + init { + paint.style = Paint.Style.FILL + + val a = context.obtainStyledAttributes(attrs, R.styleable.RefreshProgressBar) + speed = a.getDimensionPixelSize(R.styleable.RefreshProgressBar_speed, speed) + maxProgress = a.getInt(R.styleable.RefreshProgressBar_max_progress, maxProgress) + durProgress = a.getInt(R.styleable.RefreshProgressBar_dur_progress, durProgress) + secondDurProgress = a.getDimensionPixelSize( + R.styleable.RefreshProgressBar_second_dur_progress, + secondDurProgress + ) + secondFinalProgress = secondDurProgress + secondMaxProgress = a.getDimensionPixelSize( + R.styleable.RefreshProgressBar_second_max_progress, + secondMaxProgress + ) + bgColor = a.getColor(R.styleable.RefreshProgressBar_bg_color, bgColor) + secondColor = a.getColor(R.styleable.RefreshProgressBar_second_color, secondColor) + fontColor = a.getColor(R.styleable.RefreshProgressBar_font_color, fontColor) + a.recycle() + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + + paint.color = bgColor + bgRect.set(0, 0, measuredWidth, measuredHeight) + canvas.drawRect(bgRect, paint) + + if (secondDurProgress > 0 && secondMaxProgress > 0) { + var secondDur = secondDurProgress + if (secondDur < 0) { + secondDur = 0 + } + if (secondDur > secondMaxProgress) { + secondDur = secondMaxProgress + } + paint.color = secondColor + val tempW = + (measuredWidth.toFloat() * 1.0f * (secondDur * 1.0f / secondMaxProgress)).toInt() + secondRect.set( + measuredWidth / 2 - tempW / 2, + 0, + measuredWidth / 2 + tempW / 2, + measuredHeight + ) + canvas.drawRect(secondRect, paint) + } + + if (durProgress > 0 && maxProgress > 0) { + paint.color = fontColor + fontRectF.set( + 0f, + 0f, + measuredWidth.toFloat() * 1.0f * (durProgress * 1.0f / maxProgress), + measuredHeight.toFloat() + ) + canvas.drawRect(fontRectF, paint) + } + + if (this.isAutoLoading) { + if (secondDurProgress >= secondMaxProgress) { + a = -1 + } else if (secondDurProgress <= 0) { + a = 1 + } + secondDurProgress += a * speed + if (secondDurProgress < 0) + secondDurProgress = 0 + else if (secondDurProgress > secondMaxProgress) + secondDurProgress = secondMaxProgress + secondFinalProgress = secondDurProgress + invalidate() + } else { + if (secondDurProgress != secondFinalProgress) { + if (secondDurProgress > secondFinalProgress) { + secondDurProgress -= speed + if (secondDurProgress < secondFinalProgress) { + secondDurProgress = secondFinalProgress + } + } else { + secondDurProgress += speed + if (secondDurProgress > secondFinalProgress) { + secondDurProgress = secondFinalProgress + } + } + this.invalidate() + } + if (secondDurProgress == 0 && durProgress == 0 && secondFinalProgress == 0 && visibility == VISIBLE) { + visibility = INVISIBLE + } + } + } + + fun getDurProgress(): Int { + return durProgress + } + + fun setDurProgress(durProgress: Int) { + var durProgress1 = durProgress + if (durProgress1 < 0) { + durProgress1 = 0 + } + if (durProgress1 > maxProgress) { + durProgress1 = maxProgress + } + this.durProgress = durProgress1 + if (Looper.myLooper() == Looper.getMainLooper()) { + this.invalidate() + } else { + this.postInvalidate() + } + } + + fun getSecondDurProgress(): Int { + return secondDurProgress + } + + fun setSecondDurProgress(secondDur: Int) { + this.secondDurProgress = secondDur + this.secondFinalProgress = secondDurProgress + if (Looper.myLooper() == Looper.getMainLooper()) { + this.invalidate() + } else { + this.postInvalidate() + } + } + + fun setSecondDurProgressWithAnim(secondDur: Int) { + var secondDur1 = secondDur + if (secondDur1 < 0) { + secondDur1 = 0 + } + if (secondDur1 > secondMaxProgress) { + secondDur1 = secondMaxProgress + } + this.secondFinalProgress = secondDur1 + if (Looper.myLooper() == Looper.getMainLooper()) { + this.invalidate() + } else { + this.postInvalidate() + } + } + + fun clean() { + durProgress = 0 + secondDurProgress = 0 + secondFinalProgress = 0 + if (Looper.myLooper() == Looper.getMainLooper()) { + this.invalidate() + } else { + this.postInvalidate() + } + } +} From d224a54e252ccca0519db9441b35a7315c91510e Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 10 Sep 2019 14:13:04 +0800 Subject: [PATCH 1414/1997] up --- .../io/legado/app/ui/search/SearchActivity.kt | 3 ++- .../dynamiclayout/DynamicFrameLayout.kt | 25 ------------------- app/src/main/res/layout/activity_search.xml | 5 +++- 3 files changed, 6 insertions(+), 27 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt index d8b9cdf7e..7d206cb43 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt @@ -50,10 +50,11 @@ class SearchActivity : VMBaseActivity(R.layout.activity_search) search_view.clearFocus() query?.let { viewModel.search(it, { - content_view.showContentView() + refresh_progress_bar.isAutoLoading = true initData() fb_stop.visible() }, { + refresh_progress_bar.isAutoLoading = false fb_stop.invisible() }) } diff --git a/app/src/main/java/io/legado/app/ui/widget/dynamiclayout/DynamicFrameLayout.kt b/app/src/main/java/io/legado/app/ui/widget/dynamiclayout/DynamicFrameLayout.kt index 00bba86dd..99e0cd702 100644 --- a/app/src/main/java/io/legado/app/ui/widget/dynamiclayout/DynamicFrameLayout.kt +++ b/app/src/main/java/io/legado/app/ui/widget/dynamiclayout/DynamicFrameLayout.kt @@ -4,7 +4,6 @@ import android.content.Context import android.graphics.drawable.Drawable import android.util.AttributeSet import android.view.View -import android.view.ViewGroup import android.widget.FrameLayout import android.widget.ProgressBar import androidx.appcompat.widget.AppCompatButton @@ -61,30 +60,6 @@ class DynamicFrameLayout(context: Context, attrs: AttributeSet?) : FrameLayout(c } } - override fun addView(child: View) { - check(childCount <= 2) { "DynamicFrameLayout can host only one direct child" } - - super.addView(child) - } - - override fun addView(child: View, index: Int) { - check(childCount <= 2) { "DynamicFrameLayout can host only one direct child" } - - super.addView(child, index) - } - - override fun addView(child: View, params: ViewGroup.LayoutParams) { - check(childCount <= 2) { "DynamicFrameLayout can host only one direct child" } - - super.addView(child, params) - } - - override fun addView(child: View, index: Int, params: ViewGroup.LayoutParams) { - check(childCount <= 2) { "DynamicFrameLayout can host only one direct child" } - - super.addView(child, index, params) - } - override fun showErrorView(message: CharSequence) { ensureErrorView() diff --git a/app/src/main/res/layout/activity_search.xml b/app/src/main/res/layout/activity_search.xml index df00899cd..7d74faad8 100644 --- a/app/src/main/res/layout/activity_search.xml +++ b/app/src/main/res/layout/activity_search.xml @@ -23,12 +23,15 @@ app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintTop_toBottomOf="@id/title_bar"> - + From 1f00a3dac94b0dee0dba34b54112ccfe2a21dca6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 10 Sep 2019 14:24:06 +0800 Subject: [PATCH 1415/1997] up --- .../legado/app/ui/changesource/ChangeSourceDialog.kt | 4 ++++ .../app/ui/changesource/ChangeSourceViewModel.kt | 10 +++++++++- app/src/main/res/layout/dialog_change_source.xml | 8 +++++++- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt index dcb1398cd..f5a1a6699 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt @@ -141,6 +141,10 @@ class ChangeSourceDialog : DialogFragment(), return changeSourceAdapter } + override fun upSearchState(isSearch: Boolean) { + refresh_progress_bar.isAutoLoading = isSearch + } + interface CallBack { fun curOrigin(): String? fun oldBook(): Book? diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt index 5d7410b5b..3839bebef 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt @@ -7,6 +7,7 @@ import io.legado.app.R import io.legado.app.base.BaseViewModel import io.legado.app.data.entities.Book import io.legado.app.data.entities.SearchBook +import io.legado.app.help.coroutine.Coroutine import io.legado.app.model.WebBook import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.Main @@ -18,6 +19,7 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio var callBack: CallBack? = null var name: String = "" var author: String = "" + private var task: Coroutine<*>? = null private var screenKey: String = "" private val searchBooks = linkedSetOf() @@ -47,7 +49,8 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio } fun search() { - execute { + task = execute { + callBack?.upSearchState(true) val bookSourceList = App.db.bookSourceDao().allEnabled for (item in bookSourceList) { //task取消时自动取消 by (scope = this@execute) @@ -68,6 +71,10 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio delay(100) } } + + task?.invokeOnCompletion { + callBack?.upSearchState(false) + } } private fun loadBookInfo(book: Book) { @@ -118,5 +125,6 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio interface CallBack { fun adapter(): ChangeSourceAdapter + fun upSearchState(isSearch: Boolean) } } \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_change_source.xml b/app/src/main/res/layout/dialog_change_source.xml index 5d96cbdf8..21683d69d 100644 --- a/app/src/main/res/layout/dialog_change_source.xml +++ b/app/src/main/res/layout/dialog_change_source.xml @@ -15,11 +15,17 @@ app:fitStatusBar="false" app:layout_constraintTop_toTopOf="parent" /> + + \ No newline at end of file From 42f019eb4325deff463a53a261a7121cb6b648bf Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 10 Sep 2019 16:03:06 +0800 Subject: [PATCH 1416/1997] up --- app/src/main/res/layout/activity_search.xml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/app/src/main/res/layout/activity_search.xml b/app/src/main/res/layout/activity_search.xml index 7d74faad8..b840cd032 100644 --- a/app/src/main/res/layout/activity_search.xml +++ b/app/src/main/res/layout/activity_search.xml @@ -16,23 +16,24 @@ app:layout_constraintTop_toTopOf="parent" app:title="搜索"/> + + + app:layout_constraintTop_toBottomOf="@id/refresh_progress_bar"> - - Date: Tue, 10 Sep 2019 16:12:53 +0800 Subject: [PATCH 1417/1997] up --- .../app/ui/main/bookshelf/BookshelfAdapter.kt | 29 +++++++++---------- .../ui/main/bookshelf/BookshelfFragment.kt | 3 +- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt index 4f5a271c2..4c2dd9d6e 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt @@ -17,7 +17,8 @@ import kotlinx.android.synthetic.main.item_bookshelf_list.view.* import org.jetbrains.anko.sdk27.listeners.onClick import org.jetbrains.anko.sdk27.listeners.onLongClick -class BookshelfAdapter : PagedListAdapter(DIFF_CALLBACK) { +class BookshelfAdapter(private val callBack: CallBack) : + PagedListAdapter(DIFF_CALLBACK) { companion object { @JvmField @@ -34,8 +35,6 @@ class BookshelfAdapter : PagedListAdapter(D } } - var callBack: CallBack? = null - fun notification(bookUrl: String) { for (i in 0..itemCount) { getItem(i)?.let { @@ -66,7 +65,7 @@ class BookshelfAdapter : PagedListAdapter(D itemView.setBackgroundColor(ThemeStore.backgroundColor(itemView.context)) } - fun bind(book: Book, callBack: CallBack?) = with(itemView) { + fun bind(book: Book, callBack: CallBack) = with(itemView) { this.setBackgroundColor(context.getCompatColor(R.color.background)) tv_name.text = book.name tv_author.text = book.author @@ -79,21 +78,19 @@ class BookshelfAdapter : PagedListAdapter(D .centerCrop() .setAsDrawable(iv_cover) } - itemView.onClick { callBack?.open(book) } + itemView.onClick { callBack.open(book) } itemView.onLongClick { - callBack?.openBookInfo(book) + callBack.openBookInfo(book) true } - callBack?.let { - if (book.origin != BookType.local && it.isUpdate(book.bookUrl)) { - bv_unread.invisible() - rl_loading.show() - } else { - rl_loading.hide() - bv_unread.setBadgeCount(book.getUnreadChapterNum()) - bv_unread.setHighlight(book.lastCheckCount > 0) - } - } ?: rl_loading.hide() + if (book.origin != BookType.local && callBack.isUpdate(book.bookUrl)) { + bv_unread.invisible() + rl_loading.show() + } else { + rl_loading.hide() + bv_unread.setBadgeCount(book.getUnreadChapterNum()) + bv_unread.setHighlight(book.lastCheckCount > 0) + } } } diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index 415a7cafe..77a91e0a6 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -85,9 +85,8 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b LinearLayoutManager.VERTICAL ) ) - bookshelfAdapter = BookshelfAdapter() + bookshelfAdapter = BookshelfAdapter(this) rv_bookshelf.adapter = bookshelfAdapter - bookshelfAdapter.callBack = this observeEvent(Bus.UP_BOOK) { bookshelfAdapter.notification(it) } } From 030b450000ac73e127b3f9de0422ab5ae59536c7 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 10 Sep 2019 16:18:07 +0800 Subject: [PATCH 1418/1997] up --- .../java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt index 4c2dd9d6e..34172056d 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt @@ -27,8 +27,7 @@ class BookshelfAdapter(private val callBack: CallBack) : oldItem.bookUrl == newItem.bookUrl override fun areContentsTheSame(oldItem: Book, newItem: Book): Boolean = - oldItem.bookUrl == newItem.bookUrl - && oldItem.durChapterTitle == newItem.durChapterTitle + oldItem.durChapterTitle == newItem.durChapterTitle && oldItem.latestChapterTitle == newItem.latestChapterTitle && oldItem.durChapterTime == newItem.durChapterTime && oldItem.lastCheckTime == newItem.lastCheckTime From 277406e0e65b234da0f592203c7e2578f3adceed Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 10 Sep 2019 16:33:16 +0800 Subject: [PATCH 1419/1997] up --- .../ui/main/bookshelf/BookshelfViewModel.kt | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt index b1fd24966..c9baf1494 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt @@ -31,31 +31,30 @@ class BookshelfViewModel(application: Application) : BaseViewModel(application) fun upChapterList() { execute { - App.db.bookDao().getRecentRead().map { book -> + App.db.bookDao().getRecentRead().forEach { book -> if (book.origin != BookType.local) { - val bookSource = App.db.bookSourceDao().getBookSource(book.origin) - bookSource?.let { + App.db.bookSourceDao().getBookSource(book.origin)?.let { bookSource -> synchronized(this) { updateList.add(book.bookUrl) postEvent(Bus.UP_BOOK, book.bookUrl) } WebBook(bookSource).getChapterList(book) .onSuccess(IO) { - it?.let { - App.db.bookDao().update(book) - App.db.bookChapterDao().delByBook(book.bookUrl) - App.db.bookChapterDao().insert(*it.toTypedArray()) - } + it?.let { + App.db.bookDao().update(book) + App.db.bookChapterDao().delByBook(book.bookUrl) + App.db.bookChapterDao().insert(*it.toTypedArray()) + } } .onError { it.printStackTrace() } .onFinally { - synchronized(this) { - updateList.remove(book.bookUrl) - postEvent(Bus.UP_BOOK, book.bookUrl) + synchronized(this) { + updateList.remove(book.bookUrl) + postEvent(Bus.UP_BOOK, book.bookUrl) + } } - } } } delay(50) From 92d41aa7a4c395249b9c5cbcfe5445c0dfb6e37a Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 10 Sep 2019 17:13:37 +0800 Subject: [PATCH 1420/1997] up --- .../app/ui/readbook/config/ReadStyleDialog.kt | 95 ++++++++++++------- 1 file changed, 59 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt index 15fa51590..6232ae321 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt @@ -71,23 +71,17 @@ class ReadStyleDialog : DialogFragment() { rg_page_anim.check(rg_page_anim[it].id) } } - ReadBookConfig.getConfig().let { - tv_text_bold.isSelected = it.textBold - seek_text_size.progress = it.textSize - 5 - tv_text_size.text = it.textSize.toString() - seek_text_letter_spacing.progress = (it.letterSpacing * 10).toInt() + 5 - tv_text_letter_spacing.text = it.letterSpacing.toString() - seek_line_size.progress = it.lineSpacingExtra - tv_line_size.text = it.lineSpacingExtra.toString() - } + upStyle() setBg() upBg() } - private fun initOnClick() = with(ReadBookConfig.getConfig()) { + private fun initOnClick() { tv_text_bold.onClick { - textBold = !textBold - tv_text_bold.isSelected = textBold + with(ReadBookConfig.getConfig()) { + textBold = !textBold + tv_text_bold.isSelected = textBold + } postEvent(Bus.UP_CONFIG, false) } tv_text_font.onClick { @@ -121,8 +115,8 @@ class ReadStyleDialog : DialogFragment() { } seek_text_size.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { - textSize = progress + 5 - tv_text_size.text = textSize.toString() + ReadBookConfig.getConfig().textSize = progress + 5 + tv_text_size.text = ReadBookConfig.getConfig().textSize.toString() } override fun onStartTrackingTouch(seekBar: SeekBar?) {} @@ -131,24 +125,30 @@ class ReadStyleDialog : DialogFragment() { } }) iv_text_size_add.onClick { - textSize++ - if (textSize > 50) textSize = 50 - seek_text_size.progress = textSize - 5 - tv_text_size.text = textSize.toString() + with(ReadBookConfig.getConfig()) { + textSize++ + if (textSize > 50) textSize = 50 + seek_text_size.progress = textSize - 5 + tv_text_size.text = textSize.toString() + } postEvent(Bus.UP_CONFIG, true) } iv_text_size_remove.onClick { - textSize-- - if (textSize < 5) textSize = 5 - seek_text_size.progress = textSize - 5 - tv_text_size.text = textSize.toString() + with(ReadBookConfig.getConfig()) { + textSize-- + if (textSize < 5) textSize = 5 + seek_text_size.progress = textSize - 5 + tv_text_size.text = textSize.toString() + } postEvent(Bus.UP_CONFIG, true) } seek_text_letter_spacing.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { - letterSpacing = (seek_text_letter_spacing.progress - 5) / 10f - tv_text_letter_spacing.text = letterSpacing.toString() + with(ReadBookConfig.getConfig()) { + letterSpacing = (seek_text_letter_spacing.progress - 5) / 10f + tv_text_letter_spacing.text = letterSpacing.toString() + } } override fun onStartTrackingTouch(seekBar: SeekBar?) {} @@ -157,22 +157,28 @@ class ReadStyleDialog : DialogFragment() { } }) iv_text_letter_spacing_add.onClick { - letterSpacing += 0.1f - seek_text_letter_spacing.progress = (letterSpacing * 10).toInt() + 5 - tv_text_letter_spacing.text = letterSpacing.toString() + with(ReadBookConfig.getConfig()) { + letterSpacing += 0.1f + seek_text_letter_spacing.progress = (letterSpacing * 10).toInt() + 5 + tv_text_letter_spacing.text = letterSpacing.toString() + } postEvent(Bus.UP_CONFIG, true) } iv_text_letter_spacing_remove.onClick { - letterSpacing -= 0.1f - seek_text_letter_spacing.progress = (letterSpacing * 10).toInt() + 5 - tv_text_letter_spacing.text = letterSpacing.toString() + with(ReadBookConfig.getConfig()) { + letterSpacing -= 0.1f + seek_text_letter_spacing.progress = (letterSpacing * 10).toInt() + 5 + tv_text_letter_spacing.text = letterSpacing.toString() + } postEvent(Bus.UP_CONFIG, true) } seek_line_size.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { - lineSpacingExtra = seek_line_size.progress - tv_line_size.text = lineSpacingExtra.toString() + with(ReadBookConfig.getConfig()) { + lineSpacingExtra = seek_line_size.progress + tv_line_size.text = lineSpacingExtra.toString() + } } override fun onStartTrackingTouch(seekBar: SeekBar?) {} @@ -181,13 +187,17 @@ class ReadStyleDialog : DialogFragment() { } }) iv_line_size_add.onClick { - lineSpacingExtra++ - tv_line_size.text = lineSpacingExtra.toString() + with(ReadBookConfig.getConfig()) { + lineSpacingExtra++ + tv_line_size.text = lineSpacingExtra.toString() + } postEvent(Bus.UP_CONFIG, true) } iv_line_size_remove.onClick { - lineSpacingExtra-- - tv_line_size.text = lineSpacingExtra.toString() + with(ReadBookConfig.getConfig()) { + lineSpacingExtra-- + tv_line_size.text = lineSpacingExtra.toString() + } postEvent(Bus.UP_CONFIG, true) } rg_page_anim.onCheckedChange { _, checkedId -> @@ -218,6 +228,7 @@ class ReadStyleDialog : DialogFragment() { if (ReadBookConfig.styleSelect != index) { ReadBookConfig.styleSelect = index ReadBookConfig.upBg() + upStyle() upBg() postEvent(Bus.UP_CONFIG, true) } @@ -233,6 +244,18 @@ class ReadStyleDialog : DialogFragment() { return true } + private fun upStyle() { + ReadBookConfig.getConfig().let { + tv_text_bold.isSelected = it.textBold + seek_text_size.progress = it.textSize - 5 + tv_text_size.text = it.textSize.toString() + seek_text_letter_spacing.progress = (it.letterSpacing * 10).toInt() + 5 + tv_text_letter_spacing.text = it.letterSpacing.toString() + seek_line_size.progress = it.lineSpacingExtra + tv_line_size.text = it.lineSpacingExtra.toString() + } + } + private fun setBg() { tv_bg0.setTextColor(ReadBookConfig.getConfig(0).textColor()) tv_bg1.setTextColor(ReadBookConfig.getConfig(1).textColor()) From 8bb4f19b9d408425eb5241bd45503f9cfa44434d Mon Sep 17 00:00:00 2001 From: yangyxd Date: Tue, 10 Sep 2019 17:52:12 +0800 Subject: [PATCH 1421/1997] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=B9=A6=E8=AF=A6?= =?UTF-8?q?=E6=83=85=E9=A1=B5UI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/ui/bookinfo/BookInfoActivity.kt | 22 +- .../app/ui/bookinfo/ChapterListAdapter.kt | 2 +- .../res/drawable/bg_chapter_item_divider.xml | 2 +- app/src/main/res/drawable/ic_divider.xml | 2 +- .../main/res/drawable/ic_exchange_order.xml | 11 + .../drawable/recyclerview_item_divider.xml | 12 + .../res/drawable/selector_btn_accent_bg.xml | 5 + .../res/drawable/selector_btn_write_bg.xml | 5 + .../main/res/layout/activity_book_info.xml | 264 +++++++++++------- app/src/main/res/values/colors.xml | 6 +- 10 files changed, 214 insertions(+), 117 deletions(-) create mode 100644 app/src/main/res/drawable/ic_exchange_order.xml create mode 100644 app/src/main/res/drawable/recyclerview_item_divider.xml create mode 100644 app/src/main/res/drawable/selector_btn_accent_bg.xml create mode 100644 app/src/main/res/drawable/selector_btn_write_bg.xml diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index 599a26acc..1ca198a1e 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -24,6 +24,9 @@ import kotlinx.android.synthetic.main.activity_book_info.* import kotlinx.android.synthetic.main.view_title_bar.* import org.jetbrains.anko.sdk27.listeners.onClick import org.jetbrains.anko.startActivity +import androidx.recyclerview.widget.RecyclerView + + class BookInfoActivity : VMBaseActivity(R.layout.activity_book_info), ChapterListAdapter.CallBack, @@ -33,6 +36,7 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo private var changeSourceDialog: ChangeSourceDialog? = null private lateinit var adapter: ChapterListAdapter + private var reorder: Boolean = false; // 是否倒序 override fun onActivityCreated(savedInstanceState: Bundle?) { setSupportActionBar(toolbar) @@ -82,7 +86,7 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo tv_author.text = getString(R.string.author_show, book.author) tv_origin.text = getString(R.string.origin_show, book.originName) tv_lasted.text = getString(R.string.lasted_show, book.latestChapterTitle) - tv_intro.text = getString(R.string.intro_show, book.getDisplayIntro()) + tv_intro.text = book.getDisplayIntro(); // getString(R.string.intro_show, book.getDisplayIntro()) book.getDisplayCover()?.let { ImageLoader.load(this, it) .placeholder(R.drawable.img_cover_default) @@ -153,10 +157,16 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo adapter = ChapterListAdapter(this, this) ATH.applyEdgeEffectColor(rv_chapter_list) rv_chapter_list.layoutManager = LinearLayoutManager(this) - rv_chapter_list.addItemDecoration(DividerItemDecoration(this, LinearLayout.VERTICAL)) + rv_chapter_list.addItemDecoration(getRecyclerViewDivider()) rv_chapter_list.adapter = adapter } + private fun getRecyclerViewDivider(): RecyclerView.ItemDecoration { + val itemDecoration = DividerItemDecoration(this, DividerItemDecoration.VERTICAL) + itemDecoration.setDrawable(resources.getDrawable(R.drawable.recyclerview_item_divider)) + return itemDecoration + } + private fun initOnClick() { tv_read.onClick { viewModel.bookData.value?.let { @@ -195,12 +205,8 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo } } iv_chapter_top.onClick { - rv_chapter_list.scrollToPosition(0) - } - iv_chapter_bottom.onClick { - viewModel.chapterListData.value?.let { - rv_chapter_list.scrollToPosition(it.size - 1) - } + reorder = !reorder; + adapter.notifyDataSetChanged(); } } diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/ChapterListAdapter.kt b/app/src/main/java/io/legado/app/ui/bookinfo/ChapterListAdapter.kt index 31468c980..d6851e193 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/ChapterListAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/ChapterListAdapter.kt @@ -19,7 +19,7 @@ class ChapterListAdapter(context: Context, var callBack: CallBack) : if (item.index == callBack.durChapterIndex()) { tv_chapter_name.setTextColor(context.accentColor) } else { - tv_chapter_name.textColorResource = R.color.tv_text_default + tv_chapter_name.textColorResource = R.color.tv_text_secondary } this.onClick { callBack.openChapter(item) diff --git a/app/src/main/res/drawable/bg_chapter_item_divider.xml b/app/src/main/res/drawable/bg_chapter_item_divider.xml index a8bce5ae4..38db10eaf 100644 --- a/app/src/main/res/drawable/bg_chapter_item_divider.xml +++ b/app/src/main/res/drawable/bg_chapter_item_divider.xml @@ -2,7 +2,7 @@ diff --git a/app/src/main/res/drawable/ic_divider.xml b/app/src/main/res/drawable/ic_divider.xml index 7515c3960..1ecb2d6d8 100644 --- a/app/src/main/res/drawable/ic_divider.xml +++ b/app/src/main/res/drawable/ic_divider.xml @@ -1,6 +1,6 @@ - + diff --git a/app/src/main/res/drawable/ic_exchange_order.xml b/app/src/main/res/drawable/ic_exchange_order.xml new file mode 100644 index 000000000..36c2bcefc --- /dev/null +++ b/app/src/main/res/drawable/ic_exchange_order.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/recyclerview_item_divider.xml b/app/src/main/res/drawable/recyclerview_item_divider.xml new file mode 100644 index 000000000..cf8d2882a --- /dev/null +++ b/app/src/main/res/drawable/recyclerview_item_divider.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_btn_accent_bg.xml b/app/src/main/res/drawable/selector_btn_accent_bg.xml new file mode 100644 index 000000000..a888e77e0 --- /dev/null +++ b/app/src/main/res/drawable/selector_btn_accent_bg.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/selector_btn_write_bg.xml b/app/src/main/res/drawable/selector_btn_write_bg.xml new file mode 100644 index 000000000..8ba143cb2 --- /dev/null +++ b/app/src/main/res/drawable/selector_btn_write_bg.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_book_info.xml b/app/src/main/res/layout/activity_book_info.xml index 8ddbb5cd7..a54649937 100644 --- a/app/src/main/res/layout/activity_book_info.xml +++ b/app/src/main/res/layout/activity_book_info.xml @@ -13,46 +13,58 @@ app:title="@string/book_info" app:layout_constraintTop_toTopOf="parent" /> - + app:layout_constraintTop_toBottomOf="@+id/title_bar" + app:cardCornerRadius="5.0dp" + android:layout_margin="12dp" + android:layout_width="wrap_content" + android:layout_height="wrap_content"> + + + + + android:minHeight="115dp" + android:paddingBottom="8dp" + app:layout_constraintTop_toTopOf="@+id/iv_cover_s" + app:layout_constraintLeft_toRightOf="@+id/iv_cover_s" + app:layout_constraintRight_toRightOf="parent"> + android:layout_marginBottom="12dp" + android:textColor="@color/tv_text_default" + android:textSize="18sp" /> @@ -119,113 +133,162 @@ - - - - + android:layout_height="wrap_content"> + + + android:textSize="16sp" + android:textColor="@color/tv_text_default" + android:text="简介" + android:padding="8dp" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> + + + + + + + + + + + + + + + android:orientation="horizontal" + app:layout_constraintTop_toBottomOf="@+id/view_chapter"> + + + + + + + - - - + + + android:orientation="horizontal"> - - - + android:layout_height="1px" /> + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 8bd010541..59b1bea6c 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -40,7 +40,7 @@ #aaaaaaaa - #FFD4D4D4 + #8fe0e0e0 #19000000 #f4f4f4 @@ -50,6 +50,10 @@ #000000 #ffffff + + #ffffffff + #efe0e0e0 + From 9ab42d512b8d1daf0f5bbc2d0d212b186e85cff9 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 10 Sep 2019 19:05:54 +0800 Subject: [PATCH 1422/1997] up --- .../java/io/legado/app/ui/readbook/ReadBookActivity.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index 3e45d65d2..da9028d0e 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -485,9 +485,10 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } - override fun onDialogDismissed(dialogId: Int) { - - } + /** + * colorSelectDialog + */ + override fun onDialogDismissed(dialogId: Int) = Unit override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) From d37280a30cd333e4524ca332358975148db944d2 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 10 Sep 2019 19:12:50 +0800 Subject: [PATCH 1423/1997] up --- .../ui/readbook/config/PaddingConfigDialog.kt | 16 ++++------------ .../app/ui/readbook/config/ReadAloudDialog.kt | 6 ++---- .../app/ui/readbook/config/ReadStyleDialog.kt | 6 +++--- 3 files changed, 9 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.kt index 779ba3dab..4d349b9cb 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.kt @@ -116,9 +116,7 @@ class PaddingConfigDialog : DialogFragment() { tv_padding_top.text = paddingTop.toString() } - override fun onStartTrackingTouch(seekBar: SeekBar?) { - - } + override fun onStartTrackingTouch(seekBar: SeekBar?) = Unit override fun onStopTrackingTouch(seekBar: SeekBar?) { postEvent(Bus.UP_CONFIG, true) @@ -130,9 +128,7 @@ class PaddingConfigDialog : DialogFragment() { tv_padding_bottom.text = paddingBottom.toString() } - override fun onStartTrackingTouch(seekBar: SeekBar?) { - - } + override fun onStartTrackingTouch(seekBar: SeekBar?) = Unit override fun onStopTrackingTouch(seekBar: SeekBar?) { postEvent(Bus.UP_CONFIG, true) @@ -144,9 +140,7 @@ class PaddingConfigDialog : DialogFragment() { tv_padding_left.text = paddingLeft.toString() } - override fun onStartTrackingTouch(seekBar: SeekBar?) { - - } + override fun onStartTrackingTouch(seekBar: SeekBar?) = Unit override fun onStopTrackingTouch(seekBar: SeekBar?) { postEvent(Bus.UP_CONFIG, true) @@ -158,9 +152,7 @@ class PaddingConfigDialog : DialogFragment() { tv_padding_right.text = paddingRight.toString() } - override fun onStartTrackingTouch(seekBar: SeekBar?) { - - } + override fun onStartTrackingTouch(seekBar: SeekBar?) = Unit override fun onStopTrackingTouch(seekBar: SeekBar?) { postEvent(Bus.UP_CONFIG, true) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt index 3922ee122..686c0e7b5 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt @@ -87,8 +87,7 @@ class ReadAloudDialog : DialogFragment() { override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { } - override fun onStartTrackingTouch(seekBar: SeekBar?) { - } + override fun onStartTrackingTouch(seekBar: SeekBar?) = Unit override fun onStopTrackingTouch(seekBar: SeekBar?) { requireContext().putPrefInt("ttsSpeechRate", seek_tts_SpeechRate.progress) @@ -101,8 +100,7 @@ class ReadAloudDialog : DialogFragment() { tv_timer.text = requireContext().getString(R.string.timer_m, progress) } - override fun onStartTrackingTouch(seekBar: SeekBar?) { - } + override fun onStartTrackingTouch(seekBar: SeekBar?) = Unit override fun onStopTrackingTouch(seekBar: SeekBar?) { ReadAloudService.setTimer(requireContext(), seek_timer.progress) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt index 6232ae321..a0080036c 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt @@ -119,7 +119,7 @@ class ReadStyleDialog : DialogFragment() { tv_text_size.text = ReadBookConfig.getConfig().textSize.toString() } - override fun onStartTrackingTouch(seekBar: SeekBar?) {} + override fun onStartTrackingTouch(seekBar: SeekBar?) = Unit override fun onStopTrackingTouch(seekBar: SeekBar?) { postEvent(Bus.UP_CONFIG, true) } @@ -151,7 +151,7 @@ class ReadStyleDialog : DialogFragment() { } } - override fun onStartTrackingTouch(seekBar: SeekBar?) {} + override fun onStartTrackingTouch(seekBar: SeekBar?) = Unit override fun onStopTrackingTouch(seekBar: SeekBar?) { postEvent(Bus.UP_CONFIG, true) } @@ -181,7 +181,7 @@ class ReadStyleDialog : DialogFragment() { } } - override fun onStartTrackingTouch(seekBar: SeekBar?) {} + override fun onStartTrackingTouch(seekBar: SeekBar?) = Unit override fun onStopTrackingTouch(seekBar: SeekBar?) { postEvent(Bus.UP_CONFIG, true) } From b81bac5a5294b1c3c2f09661900e22943eca7832 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 10 Sep 2019 20:35:41 +0800 Subject: [PATCH 1424/1997] up --- .../io/legado/app/data/entities/RssArticle.kt | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 app/src/main/java/io/legado/app/data/entities/RssArticle.kt diff --git a/app/src/main/java/io/legado/app/data/entities/RssArticle.kt b/app/src/main/java/io/legado/app/data/entities/RssArticle.kt new file mode 100644 index 000000000..6f8773ba3 --- /dev/null +++ b/app/src/main/java/io/legado/app/data/entities/RssArticle.kt @@ -0,0 +1,20 @@ +package io.legado.app.data.entities + +import androidx.room.Entity +import androidx.room.PrimaryKey + + +@Entity(tableName = "rssArticles") +data class RssArticle( + var origin: String = "", + @PrimaryKey + var guid: String? = null, + var title: String? = null, + var author: String? = null, + var link: String? = null, + var pubDate: String? = null, + var description: String? = null, + var content: String? = null, + var image: String? = null, + var categories: MutableList = mutableListOf() +) \ No newline at end of file From 0a179d3a58940c333fd2037fcf14b5642d75e243 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 10 Sep 2019 23:13:19 +0800 Subject: [PATCH 1425/1997] up --- .../io/legado/app/constant/RSSKeywords.kt | 19 ++++++++++++++++ .../io/legado/app/service/ReadAloudService.kt | 22 +++++++++++-------- 2 files changed, 32 insertions(+), 9 deletions(-) create mode 100644 app/src/main/java/io/legado/app/constant/RSSKeywords.kt diff --git a/app/src/main/java/io/legado/app/constant/RSSKeywords.kt b/app/src/main/java/io/legado/app/constant/RSSKeywords.kt new file mode 100644 index 000000000..5a4119e05 --- /dev/null +++ b/app/src/main/java/io/legado/app/constant/RSSKeywords.kt @@ -0,0 +1,19 @@ +package io.legado.app.constant + +object RSSKeywords { + + const val RSS_ITEM = "item" + const val RSS_ITEM_TITLE = "title" + const val RSS_ITEM_LINK = "link" + const val RSS_ITEM_AUTHOR = "dc:creator" + const val RSS_ITEM_CATEGORY = "category" + const val RSS_ITEM_THUMBNAIL = "media:thumbnail" + const val RSS_ITEM_ENCLOSURE = "enclosure" + const val RSS_ITEM_DESCRIPTION = "description" + const val RSS_ITEM_CONTENT = "content:encoded" + const val RSS_ITEM_PUB_DATE = "pubDate" + const val RSS_ITEM_TIME = "time" + const val RSS_ITEM_URL = "url" + const val RSS_ITEM_TYPE = "type" + const val RSS_ITEM_GUID = "guid" +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index cdad6785d..c6c2cec12 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -147,13 +147,14 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, } initMediaSession() initBroadcastReceiver() - upMediaSessionPlaybackState() + upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PLAYING) upSpeechRate() ReadAloudNotification.upNotification(this) } override fun onDestroy() { super.onDestroy() + upMediaSessionPlaybackState(PlaybackStateCompat.STATE_STOPPED) clearTTS() unregisterReceiver(broadcastReceiver) postEvent(Bus.ALOUD_STATE, Status.STOP) @@ -231,6 +232,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, return } if (requestFocus()) { + upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PLAYING) postEvent(Bus.ALOUD_STATE, Status.PLAY) ReadAloudNotification.upNotification(this) for (i in nowSpeak until contentList.size) { @@ -322,7 +324,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, } /** - * 初始化MediaSession + * 初始化MediaSession, 注册多媒体按钮 */ private fun initMediaSession() { val mComponent = ComponentName(packageName, MediaButtonReceiver::class.java.name) @@ -333,17 +335,21 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, mediaButtonIntent, PendingIntent.FLAG_CANCEL_CURRENT ) - mediaSessionCompat = - MediaSessionCompat(this, tag, mComponent, mediaButtonReceiverPendingIntent) + mediaSessionCompat = MediaSessionCompat( + this, tag, mComponent, + mediaButtonReceiverPendingIntent + ) mediaSessionCompat?.setCallback(object : MediaSessionCompat.Callback() { override fun onMediaButtonEvent(mediaButtonEvent: Intent): Boolean { return MediaButtonReceiver.handleIntent(this@ReadAloudService, mediaButtonEvent) } }) mediaSessionCompat?.setMediaButtonReceiver(mediaButtonReceiverPendingIntent) + mediaSessionCompat?.isActive = true } private fun initBroadcastReceiver() { + //断开耳机监听 broadcastReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { val action = intent.action @@ -360,6 +366,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, if (pause) postEvent(Bus.ALOUD_STATE, Status.PAUSE) this.pause = pause textToSpeech?.stop() + upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PAUSED) ReadAloudNotification.upNotification(this) } @@ -386,14 +393,11 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, return request == AudioManager.AUDIOFOCUS_REQUEST_GRANTED } - private fun upMediaSessionPlaybackState() { + private fun upMediaSessionPlaybackState(state: Int) { mediaSessionCompat?.setPlaybackState( PlaybackStateCompat.Builder() .setActions(MediaHelp.MEDIA_SESSION_ACTIONS) - .setState( - if (speak) PlaybackStateCompat.STATE_PLAYING else PlaybackStateCompat.STATE_PAUSED, - nowSpeak.toLong(), 1f - ) + .setState(state, nowSpeak.toLong(), 1f) .build() ) } From 8882a0bdff9cef4e42194ed5ff246df3ebdc1758 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 11 Sep 2019 08:42:29 +0800 Subject: [PATCH 1426/1997] up --- .../java/io/legado/app/ui/booksource/GroupManageDialog.kt | 8 ++++---- .../io/legado/app/ui/replacerule/GroupManageDialog.kt | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt b/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt index 5d4996fb0..e5ed98578 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt +++ b/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt @@ -64,7 +64,7 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { tool_bar.inflateMenu(R.menu.group_manage) tool_bar.menu.applyTint(requireContext(), false) tool_bar.setOnMenuItemClickListener(this) - adapter = GroupAdapter(requireContext(), this) + adapter = GroupAdapter(requireContext()) recycler_view.layoutManager = LinearLayoutManager(requireContext()) recycler_view.addItemDecoration( DividerItemDecoration(requireContext(), RecyclerView.VERTICAL) @@ -129,14 +129,14 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { }.show().applyTint().requestInputMethod() } - class GroupAdapter(context: Context, val dialog: GroupManageDialog) : + private inner class GroupAdapter(context: Context) : SimpleRecyclerAdapter(context, R.layout.item_group_manage) { override fun convert(holder: ItemViewHolder, item: String, payloads: MutableList) { with(holder.itemView) { tv_group.text = item - tv_edit.onClick { dialog.editGroup(item) } - tv_del.onClick { dialog.viewModel.delGroup(item) } + tv_edit.onClick { editGroup(item) } + tv_del.onClick { viewModel.delGroup(item) } } } } diff --git a/app/src/main/java/io/legado/app/ui/replacerule/GroupManageDialog.kt b/app/src/main/java/io/legado/app/ui/replacerule/GroupManageDialog.kt index a7799cc87..e653947f8 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/GroupManageDialog.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/GroupManageDialog.kt @@ -64,7 +64,7 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { tool_bar.inflateMenu(R.menu.group_manage) tool_bar.menu.applyTint(requireContext(), false) tool_bar.setOnMenuItemClickListener(this) - adapter = GroupAdapter(requireContext(), this) + adapter = GroupAdapter(requireContext()) recycler_view.layoutManager = LinearLayoutManager(requireContext()) recycler_view.addItemDecoration( DividerItemDecoration(requireContext(), RecyclerView.VERTICAL) @@ -129,14 +129,14 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { }.show().applyTint().requestInputMethod() } - class GroupAdapter(context: Context, val dialog: GroupManageDialog) : + private inner class GroupAdapter(context: Context) : SimpleRecyclerAdapter(context, R.layout.item_group_manage) { override fun convert(holder: ItemViewHolder, item: String, payloads: MutableList) { with(holder.itemView) { tv_group.text = item - tv_edit.onClick { dialog.editGroup(item) } - tv_del.onClick { dialog.viewModel.delGroup(item) } + tv_edit.onClick { editGroup(item) } + tv_del.onClick { viewModel.delGroup(item) } } } } From 0c7c225e9f9cd74727651a306f4949f93b99b0af Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 11 Sep 2019 09:10:21 +0800 Subject: [PATCH 1427/1997] up --- app/src/main/java/io/legado/app/service/ReadAloudService.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index c6c2cec12..5e4638dc1 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -125,7 +125,6 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, private lateinit var audioManager: AudioManager private lateinit var mFocusRequest: AudioFocusRequest private var broadcastReceiver: BroadcastReceiver? = null - private var speak: Boolean = true private var nowSpeak: Int = 0 private val contentList = arrayListOf() private var readAloudNumber: Int = 0 @@ -147,7 +146,6 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, } initMediaSession() initBroadcastReceiver() - upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PLAYING) upSpeechRate() ReadAloudNotification.upNotification(this) } @@ -363,7 +361,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, } private fun pauseReadAloud(pause: Boolean) { - if (pause) postEvent(Bus.ALOUD_STATE, Status.PAUSE) + postEvent(Bus.ALOUD_STATE, Status.PAUSE) this.pause = pause textToSpeech?.stop() upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PAUSED) From 430a444bf3d68cfe8c1347649c7d1adad13bb38f Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 11 Sep 2019 09:39:28 +0800 Subject: [PATCH 1428/1997] up --- .../main/java/io/legado/app/service/ReadAloudService.kt | 5 +---- .../io/legado/app/ui/changesource/ChangeSourceDialog.kt | 8 ++++---- .../legado/app/ui/changesource/ChangeSourceViewModel.kt | 7 ++++--- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index 5e4638dc1..1af82c149 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -333,10 +333,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, mediaButtonIntent, PendingIntent.FLAG_CANCEL_CURRENT ) - mediaSessionCompat = MediaSessionCompat( - this, tag, mComponent, - mediaButtonReceiverPendingIntent - ) + mediaSessionCompat = MediaSessionCompat(this, tag) mediaSessionCompat?.setCallback(object : MediaSessionCompat.Callback() { override fun onMediaButtonEvent(mediaButtonEvent: Intent): Boolean { return MediaButtonReceiver.handleIntent(this@ReadAloudService, mediaButtonEvent) diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt index f5a1a6699..df03b920e 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt @@ -8,6 +8,7 @@ import android.view.ViewGroup import android.widget.LinearLayout import androidx.appcompat.widget.SearchView import androidx.fragment.app.DialogFragment +import androidx.lifecycle.Observer import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.R @@ -48,6 +49,9 @@ class ChangeSourceDialog : DialogFragment(), override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + viewModel.searchStateData.observe(viewLifecycleOwner, Observer { + refresh_progress_bar.isAutoLoading = it + }) arguments?.let { bundle -> bundle.getString("name")?.let { viewModel.name = it @@ -141,10 +145,6 @@ class ChangeSourceDialog : DialogFragment(), return changeSourceAdapter } - override fun upSearchState(isSearch: Boolean) { - refresh_progress_bar.isAutoLoading = isSearch - } - interface CallBack { fun curOrigin(): String? fun oldBook(): Book? diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt index 3839bebef..3159db258 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt @@ -1,6 +1,7 @@ package io.legado.app.ui.changesource import android.app.Application +import androidx.lifecycle.MutableLiveData import androidx.recyclerview.widget.DiffUtil import io.legado.app.App import io.legado.app.R @@ -17,6 +18,7 @@ import org.jetbrains.anko.debug class ChangeSourceViewModel(application: Application) : BaseViewModel(application) { var callBack: CallBack? = null + val searchStateData = MutableLiveData() var name: String = "" var author: String = "" private var task: Coroutine<*>? = null @@ -50,7 +52,7 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio fun search() { task = execute { - callBack?.upSearchState(true) + searchStateData.postValue(true) val bookSourceList = App.db.bookSourceDao().allEnabled for (item in bookSourceList) { //task取消时自动取消 by (scope = this@execute) @@ -73,7 +75,7 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio } task?.invokeOnCompletion { - callBack?.upSearchState(false) + searchStateData.postValue(false) } } @@ -125,6 +127,5 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio interface CallBack { fun adapter(): ChangeSourceAdapter - fun upSearchState(isSearch: Boolean) } } \ No newline at end of file From a2fa8e1adb2631132fecec2130fe07c22cb16a02 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 11 Sep 2019 10:19:24 +0800 Subject: [PATCH 1429/1997] up --- .../java/io/legado/app/service/ReadAloudService.kt | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index 1af82c149..baa368760 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -325,12 +325,14 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, * 初始化MediaSession, 注册多媒体按钮 */ private fun initMediaSession() { - val mComponent = ComponentName(packageName, MediaButtonReceiver::class.java.name) - val mediaButtonIntent = Intent(Intent.ACTION_MEDIA_BUTTON) - mediaButtonIntent.component = mComponent + val mediaButtonIntent = Intent(Intent.ACTION_MEDIA_BUTTON).apply { + component = ComponentName(packageName, MediaButtonReceiver::class.java.name) + } val mediaButtonReceiverPendingIntent = PendingIntent.getBroadcast( - this, 0, - mediaButtonIntent, PendingIntent.FLAG_CANCEL_CURRENT + this, + 0, + mediaButtonIntent, + PendingIntent.FLAG_CANCEL_CURRENT ) mediaSessionCompat = MediaSessionCompat(this, tag) From 5a3224f55fb867847727de51006468fa8fe6be75 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 11 Sep 2019 10:43:50 +0800 Subject: [PATCH 1430/1997] up --- .../main/java/io/legado/app/service/ReadAloudService.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index baa368760..e3c47eec2 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -345,12 +345,13 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, mediaSessionCompat?.isActive = true } + /** + * 断开耳机监听 + */ private fun initBroadcastReceiver() { - //断开耳机监听 broadcastReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { - val action = intent.action - if (AudioManager.ACTION_AUDIO_BECOMING_NOISY == action) { + if (AudioManager.ACTION_AUDIO_BECOMING_NOISY == intent.action) { pauseReadAloud(true) } } From 37ced84112142e9569117e89a2b88a24ed19b9ff Mon Sep 17 00:00:00 2001 From: yangyxd Date: Wed, 11 Sep 2019 11:35:05 +0800 Subject: [PATCH 1431/1997] . --- .../io/legado/app/ui/bookinfo/BookInfoActivity.kt | 3 +-- .../io/legado/app/ui/bookinfo/ChapterListAdapter.kt | 12 +++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index 1ca198a1e..b1998cfb5 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -36,7 +36,6 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo private var changeSourceDialog: ChangeSourceDialog? = null private lateinit var adapter: ChapterListAdapter - private var reorder: Boolean = false; // 是否倒序 override fun onActivityCreated(savedInstanceState: Bundle?) { setSupportActionBar(toolbar) @@ -205,7 +204,7 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo } } iv_chapter_top.onClick { - reorder = !reorder; + adapter.reorder = !adapter.reorder; adapter.notifyDataSetChanged(); } } diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/ChapterListAdapter.kt b/app/src/main/java/io/legado/app/ui/bookinfo/ChapterListAdapter.kt index d6851e193..3b2edf158 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/ChapterListAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/ChapterListAdapter.kt @@ -13,16 +13,22 @@ import org.jetbrains.anko.textColorResource class ChapterListAdapter(context: Context, var callBack: CallBack) : SimpleRecyclerAdapter(context, R.layout.item_chapter_list) { + var reorder: Boolean = false; // 是否倒序 + override fun convert(holder: ItemViewHolder, item: BookChapter, payloads: MutableList) { holder.itemView.apply { - tv_chapter_name.text = item.title - if (item.index == callBack.durChapterIndex()) { + var _item: BookChapter = item; + if (reorder) { + _item = getItems().get(getItems().size - item.index - 1); + } + tv_chapter_name.text = _item.title + if (_item.index == callBack.durChapterIndex()) { tv_chapter_name.setTextColor(context.accentColor) } else { tv_chapter_name.textColorResource = R.color.tv_text_secondary } this.onClick { - callBack.openChapter(item) + callBack.openChapter(_item) } } } From 84cc13d169766c36d13f5dcdb94510488a489bf3 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 11 Sep 2019 12:22:36 +0800 Subject: [PATCH 1432/1997] up --- .../main/res/layout/activity_book_info.xml | 99 +++++++++---------- app/src/main/res/layout/view_read_menu.xml | 2 + 2 files changed, 51 insertions(+), 50 deletions(-) diff --git a/app/src/main/res/layout/activity_book_info.xml b/app/src/main/res/layout/activity_book_info.xml index a54649937..f5491461b 100644 --- a/app/src/main/res/layout/activity_book_info.xml +++ b/app/src/main/res/layout/activity_book_info.xml @@ -2,32 +2,31 @@ + android:layout_height="match_parent" + android:orientation="vertical"> + app:layout_constraintTop_toTopOf="parent" + app:title="@string/book_info" /> + android:layout_height="wrap_content" + android:layout_margin="12dp" + app:cardCornerRadius="5.0dp" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintTop_toBottomOf="@+id/title_bar"> + android:src="@drawable/img_cover_default" /> @@ -37,19 +36,19 @@ android:layout_height="wrap_content" android:layout_marginLeft="12dp" android:layout_marginRight="6dp" - android:orientation="vertical" android:minHeight="115dp" + android:orientation="vertical" android:paddingBottom="8dp" - app:layout_constraintTop_toTopOf="@+id/iv_cover_s" app:layout_constraintLeft_toRightOf="@+id/iv_cover_s" - app:layout_constraintRight_toRightOf="parent"> + app:layout_constraintRight_toRightOf="parent" + app:layout_constraintTop_toTopOf="@+id/iv_cover_s"> @@ -58,8 +57,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="4dp" - android:textSize="14sp" - android:singleLine="true" /> + android:singleLine="true" + android:textSize="14sp" /> + android:orientation="horizontal" + android:visibility="gone"> + app:layout_constraintRight_toRightOf="@id/tv_name" /> + android:layout_height="wrap_content" + android:orientation="vertical" + app:layout_constraintTop_toBottomOf="@+id/ll_book_info"> + android:layout_height="wrap_content" + android:padding="8dp" + android:text="简介" + android:textColor="@color/tv_text_default" + android:textSize="16sp" /> @@ -180,10 +179,10 @@ + android:layout_height="wrap_content" + android:orientation="vertical" + app:layout_constraintTop_toBottomOf="@+id/view_info"> + android:layout_height="wrap_content" + android:orientation="horizontal"> + android:layout_height="wrap_content" + android:layout_weight="1.0" + android:paddingLeft="8dp" + android:paddingTop="8dp" + android:text="目录" + android:textColor="@color/tv_text_default" + android:textSize="16sp" /> @@ -212,11 +211,11 @@ android:id="@+id/ll_chapter_base_info" android:layout_width="match_parent" android:layout_height="36dp" - android:paddingLeft="10dp" - android:paddingRight="10dp" android:elevation="5dp" android:gravity="center_vertical" android:orientation="horizontal" + android:paddingLeft="10dp" + android:paddingRight="10dp" app:layout_constraintTop_toBottomOf="@+id/view_chapter"> @@ -257,8 +256,8 @@ android:id="@+id/rv_chapter_list" android:layout_width="match_parent" android:layout_height="0dp" - app:layout_constraintTop_toBottomOf="@+id/view_chapter" - app:layout_constraintBottom_toTopOf="@id/fl_action" /> + app:layout_constraintBottom_toTopOf="@id/fl_action" + app:layout_constraintTop_toBottomOf="@+id/view_chapter" /> + android:layout_height="1px" + android:background="@color/bg_divider_line" /> diff --git a/app/src/main/res/layout/view_read_menu.xml b/app/src/main/res/layout/view_read_menu.xml index 515353389..7ffd97ee2 100644 --- a/app/src/main/res/layout/view_read_menu.xml +++ b/app/src/main/res/layout/view_read_menu.xml @@ -26,6 +26,7 @@ android:layout_height="wrap_content" android:paddingLeft="10dp" android:paddingRight="10dp" + android:singleLine="true" android:text="@string/chapter" android:textSize="12sp" android:visibility="gone" /> @@ -36,6 +37,7 @@ android:layout_height="wrap_content" android:paddingLeft="10dp" android:paddingRight="10dp" + android:singleLine="true" android:text="@string/chapter" android:textSize="12sp" android:visibility="gone" /> From d3329951d9e91ac3afab1813e1d448299fc87f34 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 11 Sep 2019 12:37:35 +0800 Subject: [PATCH 1433/1997] up --- app/src/main/res/layout/activity_book_info.xml | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/app/src/main/res/layout/activity_book_info.xml b/app/src/main/res/layout/activity_book_info.xml index f5491461b..31383bd1c 100644 --- a/app/src/main/res/layout/activity_book_info.xml +++ b/app/src/main/res/layout/activity_book_info.xml @@ -24,8 +24,9 @@ @@ -35,7 +36,7 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginLeft="12dp" - android:layout_marginRight="6dp" + android:layout_marginRight="12dp" android:minHeight="115dp" android:orientation="vertical" android:paddingBottom="8dp" @@ -47,7 +48,7 @@ android:id="@+id/tv_name" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginBottom="12dp" + android:layout_marginBottom="6dp" android:singleLine="true" android:textColor="@color/tv_text_default" android:textSize="18sp" /> @@ -56,7 +57,7 @@ android:id="@+id/tv_author" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginBottom="4dp" + android:layout_marginBottom="3dp" android:singleLine="true" android:textSize="14sp" /> @@ -70,7 +71,6 @@ android:id="@+id/tv_origin" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginRight="8dp" android:layout_weight="1" android:singleLine="true" android:textSize="14sp" @@ -80,6 +80,7 @@ android:id="@+id/tv_change_source" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:layout_marginStart="8dp" android:paddingLeft="5dp" android:paddingRight="5dp" android:text="@string/change_origin" /> @@ -90,7 +91,7 @@ android:id="@+id/ll_kind" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginBottom="4dp" + android:layout_marginBottom="3dp" android:orientation="horizontal" android:visibility="gone"> @@ -109,7 +110,6 @@ android:id="@+id/tv_kind_1" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginEnd="6dp" android:paddingLeft="3dp" android:paddingRight="3dp" android:singleLine="true" @@ -152,7 +152,6 @@ Date: Wed, 11 Sep 2019 12:49:16 +0800 Subject: [PATCH 1434/1997] up --- .../res/layout-land/activity_book_info.xml | 233 ++++++++++-------- 1 file changed, 133 insertions(+), 100 deletions(-) diff --git a/app/src/main/res/layout-land/activity_book_info.xml b/app/src/main/res/layout-land/activity_book_info.xml index 239f2961a..b6f176070 100644 --- a/app/src/main/res/layout-land/activity_book_info.xml +++ b/app/src/main/res/layout-land/activity_book_info.xml @@ -25,8 +25,8 @@ + android:textColor="@color/tv_text_default" + android:textSize="18sp" /> + android:layout_height="wrap_content" + android:layout_marginBottom="3dp" + android:singleLine="true" + android:textSize="14sp" /> @@ -86,10 +90,10 @@ + android:layout_height="wrap_content" + android:layout_marginBottom="3dp" + android:orientation="horizontal" + android:visibility="gone"> - + app:layout_constraintRight_toRightOf="@id/tv_name" /> - + app:layout_constraintRight_toLeftOf="@+id/fg"> - + + + + + + + - + android:orientation="horizontal"> - + + + + + app:layout_constraintTop_toBottomOf="@+id/view_chapter"> + + + + + + + - - - @@ -232,19 +265,29 @@ android:background="@color/background" app:layout_constraintBottom_toBottomOf="parent"> + + + android:orientation="horizontal"> - - - + android:layout_height="1px" + android:background="@color/bg_divider_line" /> + \ No newline at end of file From 34434ae02b22b431764889ff0fa0cf4e3ea9ae52 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 11 Sep 2019 13:42:09 +0800 Subject: [PATCH 1435/1997] up --- .../res/layout-land/activity_book_info.xml | 1 + .../main/res/layout/activity_book_info.xml | 32 +++++++------------ 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/app/src/main/res/layout-land/activity_book_info.xml b/app/src/main/res/layout-land/activity_book_info.xml index b6f176070..a8f1d8521 100644 --- a/app/src/main/res/layout-land/activity_book_info.xml +++ b/app/src/main/res/layout-land/activity_book_info.xml @@ -145,6 +145,7 @@ android:id="@+id/view_info" android:layout_width="0dp" android:layout_height="wrap_content" + android:layout_marginTop="10dp" android:orientation="vertical" app:layout_constraintTop_toBottomOf="@+id/iv_cover" app:layout_constraintBottom_toTopOf="@+id/fl_action" diff --git a/app/src/main/res/layout/activity_book_info.xml b/app/src/main/res/layout/activity_book_info.xml index 31383bd1c..7fa704096 100644 --- a/app/src/main/res/layout/activity_book_info.xml +++ b/app/src/main/res/layout/activity_book_info.xml @@ -13,23 +13,15 @@ app:layout_constraintTop_toTopOf="parent" app:title="@string/book_info" /> - - - - - + app:layout_constraintTop_toBottomOf="@+id/title_bar" /> + app:layout_constraintTop_toTopOf="@+id/iv_cover"> + app:layout_constraintTop_toBottomOf="@+id/iv_cover"> Date: Wed, 11 Sep 2019 13:49:20 +0800 Subject: [PATCH 1436/1997] up --- app/src/main/res/drawable/selector_btn_write_bg.xml | 5 ----- app/src/main/res/layout-land/activity_book_info.xml | 2 +- app/src/main/res/layout/activity_book_info.xml | 2 +- 3 files changed, 2 insertions(+), 7 deletions(-) delete mode 100644 app/src/main/res/drawable/selector_btn_write_bg.xml diff --git a/app/src/main/res/drawable/selector_btn_write_bg.xml b/app/src/main/res/drawable/selector_btn_write_bg.xml deleted file mode 100644 index 8ba143cb2..000000000 --- a/app/src/main/res/drawable/selector_btn_write_bg.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout-land/activity_book_info.xml b/app/src/main/res/layout-land/activity_book_info.xml index a8f1d8521..7711735ad 100644 --- a/app/src/main/res/layout-land/activity_book_info.xml +++ b/app/src/main/res/layout-land/activity_book_info.xml @@ -288,7 +288,7 @@ android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" - android:background="@drawable/selector_btn_write_bg" + android:background="?attr/selectableItemBackground" android:clickable="true" android:focusable="true" android:gravity="center" diff --git a/app/src/main/res/layout/activity_book_info.xml b/app/src/main/res/layout/activity_book_info.xml index 7fa704096..4812c5e25 100644 --- a/app/src/main/res/layout/activity_book_info.xml +++ b/app/src/main/res/layout/activity_book_info.xml @@ -277,7 +277,7 @@ android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" - android:background="@drawable/selector_btn_write_bg" + android:background="?attr/selectableItemBackground" android:clickable="true" android:focusable="true" android:gravity="center" From 803f81e8cf016d28a811505adf543b6d0d1c2781 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 11 Sep 2019 14:16:21 +0800 Subject: [PATCH 1437/1997] up --- .../app/lib/theme/view/ATEAccentBgTextView.kt | 20 ++++++++----------- .../res/layout-land/activity_book_info.xml | 16 +++++++++------ .../main/res/layout/activity_book_info.xml | 16 +++++++++------ app/src/main/res/layout/item_search.xml | 9 ++++++--- app/src/main/res/values/attrs.xml | 4 ++++ 5 files changed, 38 insertions(+), 27 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATEAccentBgTextView.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATEAccentBgTextView.kt index 6aef2175a..fe1f0b0ea 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATEAccentBgTextView.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATEAccentBgTextView.kt @@ -4,25 +4,21 @@ import android.content.Context import android.graphics.Color import android.util.AttributeSet import androidx.appcompat.widget.AppCompatTextView +import io.legado.app.R import io.legado.app.lib.theme.ColorUtils import io.legado.app.lib.theme.Selector import io.legado.app.lib.theme.ThemeStore -import io.legado.app.utils.dp -class ATEAccentBgTextView : AppCompatTextView { - constructor(context: Context) : super(context) - - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) - - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super( - context, - attrs, - defStyleAttr - ) +class ATEAccentBgTextView(context: Context, attrs: AttributeSet) : + AppCompatTextView(context, attrs) { init { + val typedArray = context.obtainStyledAttributes(attrs, R.styleable.ATEAccentBgTextView) + val radios = + typedArray.getDimensionPixelOffset(R.styleable.ATEAccentBgTextView_abt_radius, 0) + typedArray.recycle() background = Selector.shapeBuild() - .setCornerRadius(3.dp) + .setCornerRadius(radios) .setDefaultBgColor(ThemeStore.accentColor(context)) .setPressedBgColor(ColorUtils.darkenColor(ThemeStore.accentColor(context))) .create() diff --git a/app/src/main/res/layout-land/activity_book_info.xml b/app/src/main/res/layout-land/activity_book_info.xml index 7711735ad..49fba475e 100644 --- a/app/src/main/res/layout-land/activity_book_info.xml +++ b/app/src/main/res/layout-land/activity_book_info.xml @@ -83,7 +83,8 @@ android:layout_marginStart="8dp" android:paddingLeft="5dp" android:paddingRight="5dp" - android:text="@string/change_origin" /> + android:text="@string/change_origin" + app:abt_radius="2dp" /> @@ -104,7 +105,8 @@ android:paddingRight="3dp" android:singleLine="true" android:text="@string/app_name" - android:textSize="12sp" /> + android:textSize="12sp" + app:abt_radius="2dp" /> + android:textSize="12sp" + app:abt_radius="2dp" /> + android:textSize="12sp" + app:abt_radius="2dp" /> @@ -226,7 +230,7 @@ android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" - android:background="?android:attr/selectableItemBackgroundBorderless" + android:background="?android:attr/selectableItemBackground" android:ellipsize="middle" android:gravity="center_vertical" android:paddingLeft="10dp" @@ -297,7 +301,7 @@ android:textColor="@color/tv_text_default" android:textSize="15sp" /> - + android:text="@string/change_origin" + app:abt_radius="2dp" /> @@ -95,7 +96,8 @@ android:paddingRight="3dp" android:singleLine="true" android:text="@string/app_name" - android:textSize="12sp" /> + android:textSize="12sp" + app:abt_radius="2dp" /> + android:textSize="12sp" + app:abt_radius="2dp" /> + android:textSize="12sp" + app:abt_radius="2dp" /> @@ -218,7 +222,7 @@ android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" - android:background="?android:attr/selectableItemBackgroundBorderless" + android:background="?android:attr/selectableItemBackground" android:ellipsize="middle" android:gravity="center_vertical" android:paddingLeft="10dp" @@ -286,7 +290,7 @@ android:textColor="@color/tv_text_default" android:textSize="15sp" /> - + android:textSize="12sp" + app:abt_radius="2dp" /> + android:textSize="12sp" + app:abt_radius="2dp" /> + android:textSize="12sp" + app:abt_radius="2dp" /> diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index d4b45f4ea..f121f58ae 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -130,4 +130,8 @@ + + + + \ No newline at end of file From 28156f66bbc2c641e0f3149fb843a4c9b6df7898 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 11 Sep 2019 14:22:20 +0800 Subject: [PATCH 1438/1997] up --- .../legado/app/ui/bookinfo/BookInfoActivity.kt | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt index b1998cfb5..3334adfb4 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt @@ -3,7 +3,6 @@ package io.legado.app.ui.bookinfo import android.os.Bundle import android.view.Menu import android.view.MenuItem -import android.widget.LinearLayout import androidx.lifecycle.Observer import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager @@ -17,6 +16,7 @@ import io.legado.app.ui.bookinfo.edit.BookInfoEditActivity import io.legado.app.ui.changesource.ChangeSourceDialog import io.legado.app.ui.readbook.ReadBookActivity import io.legado.app.ui.sourceedit.SourceEditActivity +import io.legado.app.utils.getCompatDrawable import io.legado.app.utils.getViewModel import io.legado.app.utils.gone import io.legado.app.utils.visible @@ -24,8 +24,6 @@ import kotlinx.android.synthetic.main.activity_book_info.* import kotlinx.android.synthetic.main.view_title_bar.* import org.jetbrains.anko.sdk27.listeners.onClick import org.jetbrains.anko.startActivity -import androidx.recyclerview.widget.RecyclerView - class BookInfoActivity : VMBaseActivity(R.layout.activity_book_info), @@ -156,16 +154,16 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo adapter = ChapterListAdapter(this, this) ATH.applyEdgeEffectColor(rv_chapter_list) rv_chapter_list.layoutManager = LinearLayoutManager(this) - rv_chapter_list.addItemDecoration(getRecyclerViewDivider()) + getCompatDrawable(R.drawable.recyclerview_item_divider)?.let { drawable -> + rv_chapter_list.addItemDecoration( + DividerItemDecoration(this, DividerItemDecoration.VERTICAL).apply { + setDrawable(drawable) + } + ) + } rv_chapter_list.adapter = adapter } - private fun getRecyclerViewDivider(): RecyclerView.ItemDecoration { - val itemDecoration = DividerItemDecoration(this, DividerItemDecoration.VERTICAL) - itemDecoration.setDrawable(resources.getDrawable(R.drawable.recyclerview_item_divider)) - return itemDecoration - } - private fun initOnClick() { tv_read.onClick { viewModel.bookData.value?.let { From da8a354ccc3d99dba1963aeb12f028c0d382b4a7 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 11 Sep 2019 14:42:12 +0800 Subject: [PATCH 1439/1997] up --- .../lib/theme/view/ATEAccentStrokeTextView.kt | 12 ++-------- .../lib/theme/view/ATEAutoCompleteTextView.kt | 13 ++--------- .../legado/app/lib/theme/view/ATECheckBox.kt | 12 +--------- .../legado/app/lib/theme/view/ATEEditText.kt | 12 +--------- .../app/lib/theme/view/ATEPrimaryTextView.kt | 13 ++--------- .../app/lib/theme/view/ATEProgressBar.kt | 22 +------------------ .../app/lib/theme/view/ATERadioButton.kt | 12 +--------- .../app/lib/theme/view/ATERadioNoButton.kt | 13 ++--------- .../lib/theme/view/ATESecondaryTextView.kt | 13 ++--------- .../legado/app/lib/theme/view/ATESeekBar.kt | 12 +--------- .../app/lib/theme/view/ATEStrokeTextView.kt | 11 +--------- .../io/legado/app/lib/theme/view/ATESwitch.kt | 12 +--------- .../app/lib/theme/view/ATETextInputLayout.kt | 11 +--------- 13 files changed, 18 insertions(+), 150 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATEAccentStrokeTextView.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATEAccentStrokeTextView.kt index 30ff4da44..355ed65a6 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATEAccentStrokeTextView.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATEAccentStrokeTextView.kt @@ -9,16 +9,8 @@ import io.legado.app.lib.theme.ThemeStore import io.legado.app.utils.dp import io.legado.app.utils.getCompatColor -class ATEAccentStrokeTextView : AppCompatTextView { - constructor(context: Context) : super(context) - - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) - - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super( - context, - attrs, - defStyleAttr - ) +class ATEAccentStrokeTextView(context: Context, attrs: AttributeSet) : + AppCompatTextView(context, attrs) { init { background = Selector.shapeBuild() diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt index f54f24eb4..4e6d04b2f 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt @@ -8,17 +8,8 @@ import io.legado.app.lib.theme.Selector import io.legado.app.lib.theme.ThemeStore -class ATEAutoCompleteTextView : AppCompatAutoCompleteTextView { - - constructor(context: Context) : super(context) - - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) - - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super( - context, - attrs, - defStyleAttr - ) +class ATEAutoCompleteTextView(context: Context, attrs: AttributeSet) : + AppCompatAutoCompleteTextView(context, attrs) { init { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATECheckBox.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATECheckBox.kt index f910115df..fa009b01b 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATECheckBox.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATECheckBox.kt @@ -9,17 +9,7 @@ import io.legado.app.lib.theme.accentColor /** * @author Aidan Follestad (afollestad) */ -class ATECheckBox : AppCompatCheckBox { - - constructor(context: Context) : super(context) - - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) - - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super( - context, - attrs, - defStyleAttr - ) +class ATECheckBox(context: Context, attrs: AttributeSet) : AppCompatCheckBox(context, attrs) { init { ATH.setTint(this, context.accentColor) diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATEEditText.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATEEditText.kt index b38bdd6ab..c6c692634 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATEEditText.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATEEditText.kt @@ -9,17 +9,7 @@ import io.legado.app.lib.theme.ThemeStore /** * @author Aidan Follestad (afollestad) */ -class ATEEditText : AppCompatEditText { - - constructor(context: Context) : super(context) - - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) - - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super( - context, - attrs, - defStyleAttr - ) +class ATEEditText(context: Context, attrs: AttributeSet) : AppCompatEditText(context, attrs) { init { ATH.setTint(this, ThemeStore.accentColor(context)) diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATEPrimaryTextView.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATEPrimaryTextView.kt index 44d1e1acd..b28a97305 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATEPrimaryTextView.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATEPrimaryTextView.kt @@ -8,17 +8,8 @@ import io.legado.app.lib.theme.ThemeStore /** * @author Aidan Follestad (afollestad) */ -class ATEPrimaryTextView : AppCompatTextView { - - constructor(context: Context) : super(context) - - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) - - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super( - context, - attrs, - defStyleAttr - ) +class ATEPrimaryTextView(context: Context, attrs: AttributeSet) : + AppCompatTextView(context, attrs) { init { setTextColor(ThemeStore.textColorPrimary(context)) diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATEProgressBar.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATEProgressBar.kt index aae4d914a..20f13e03c 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATEProgressBar.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATEProgressBar.kt @@ -1,8 +1,6 @@ package io.legado.app.lib.theme.view -import android.annotation.TargetApi import android.content.Context -import android.os.Build import android.util.AttributeSet import android.widget.ProgressBar import io.legado.app.lib.theme.ATH @@ -11,25 +9,7 @@ import io.legado.app.lib.theme.ThemeStore /** * @author Aidan Follestad (afollestad) */ -class ATEProgressBar : ProgressBar { - - constructor(context: Context) : super(context) - - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) - - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super( - context, - attrs, - defStyleAttr - ) - - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super( - context, - attrs, - defStyleAttr, - defStyleRes - ) +class ATEProgressBar(context: Context, attrs: AttributeSet) : ProgressBar(context, attrs) { init { ATH.setTint(this, ThemeStore.accentColor(context)) diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATERadioButton.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATERadioButton.kt index c8715728e..d416d6f8f 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATERadioButton.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATERadioButton.kt @@ -9,17 +9,7 @@ import io.legado.app.lib.theme.accentColor /** * @author Aidan Follestad (afollestad) */ -class ATERadioButton : AppCompatRadioButton { - - constructor(context: Context) : super(context) - - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) - - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super( - context, - attrs, - defStyleAttr - ) +class ATERadioButton(context: Context, attrs: AttributeSet) : AppCompatRadioButton(context, attrs) { init { ATH.setTint(this@ATERadioButton, context.accentColor) diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATERadioNoButton.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATERadioNoButton.kt index 41ce5dbe5..12e93ec4f 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATERadioNoButton.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATERadioNoButton.kt @@ -12,17 +12,8 @@ import io.legado.app.utils.getCompatColor /** * @author Aidan Follestad (afollestad) */ -class ATERadioNoButton : AppCompatRadioButton { - - constructor(context: Context) : super(context) - - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) - - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super( - context, - attrs, - defStyleAttr - ) +class ATERadioNoButton(context: Context, attrs: AttributeSet) : + AppCompatRadioButton(context, attrs) { init { background = Selector.shapeBuild() diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATESecondaryTextView.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATESecondaryTextView.kt index d7dc8ca3d..8031961d3 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATESecondaryTextView.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATESecondaryTextView.kt @@ -8,17 +8,8 @@ import io.legado.app.lib.theme.secondaryTextColor /** * @author Aidan Follestad (afollestad) */ -class ATESecondaryTextView : AppCompatTextView { - - constructor(context: Context) : super(context) - - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) - - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super( - context, - attrs, - defStyleAttr - ) +class ATESecondaryTextView(context: Context, attrs: AttributeSet) : + AppCompatTextView(context, attrs) { init { setTextColor(context.secondaryTextColor) diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATESeekBar.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATESeekBar.kt index e6725c42a..2d793ba82 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATESeekBar.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATESeekBar.kt @@ -9,17 +9,7 @@ import io.legado.app.lib.theme.accentColor /** * @author Aidan Follestad (afollestad) */ -class ATESeekBar : AppCompatSeekBar { - - constructor(context: Context) : super(context) - - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) - - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super( - context, - attrs, - defStyleAttr - ) +class ATESeekBar(context: Context, attrs: AttributeSet) : AppCompatSeekBar(context, attrs) { init { ATH.setTint(this, context.accentColor) diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATEStrokeTextView.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATEStrokeTextView.kt index 04416929c..3efb796f9 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATEStrokeTextView.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATEStrokeTextView.kt @@ -8,16 +8,7 @@ import io.legado.app.lib.theme.Selector import io.legado.app.lib.theme.ThemeStore import io.legado.app.utils.dp -class ATEStrokeTextView : AppCompatTextView { - constructor(context: Context) : super(context) - - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) - - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super( - context, - attrs, - defStyleAttr - ) +class ATEStrokeTextView(context: Context, attrs: AttributeSet) : AppCompatTextView(context, attrs) { init { background = Selector.shapeBuild() diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATESwitch.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATESwitch.kt index 1a1c331a4..ceaec7f21 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATESwitch.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATESwitch.kt @@ -9,17 +9,7 @@ import io.legado.app.lib.theme.accentColor /** * @author Aidan Follestad (afollestad) */ -class ATESwitch : SwitchCompat { - - constructor(context: Context) : super(context) - - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) - - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super( - context, - attrs, - defStyleAttr - ) +class ATESwitch(context: Context, attrs: AttributeSet) : SwitchCompat(context, attrs) { init { ATH.setTint(this, context.accentColor) diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATETextInputLayout.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATETextInputLayout.kt index b420f3e01..5444a309c 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATETextInputLayout.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATETextInputLayout.kt @@ -6,16 +6,7 @@ import com.google.android.material.textfield.TextInputLayout import io.legado.app.lib.theme.Selector import io.legado.app.lib.theme.ThemeStore -class ATETextInputLayout : TextInputLayout { - constructor(context: Context) : super(context) - - constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) - - constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super( - context, - attrs, - defStyleAttr - ) +class ATETextInputLayout(context: Context, attrs: AttributeSet?) : TextInputLayout(context, attrs) { init { defaultHintTextColor = Selector.colorBuild().setDefaultColor(ThemeStore.accentColor(context)).create() From cb2aa7ce7541800da674993ee09537d1d30c276b Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 11 Sep 2019 15:02:16 +0800 Subject: [PATCH 1440/1997] up --- .../io/legado/app/service/ReadAloudService.kt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index e3c47eec2..8d1a2c4fc 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -279,6 +279,9 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, ReadAloudNotification.upNotification(this) } + /** + * 定时 + */ private fun doDs() { if (!pause) { timeMinute-- @@ -292,6 +295,9 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, ReadAloudNotification.upNotification(this) } + /** + * 更新朗读速度 + */ private fun upSpeechRate(reset: Boolean = false) { if (this.getPrefBoolean("ttsFollowSys", true)) { if (reset) { @@ -303,6 +309,9 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, } } + /** + * 上一段 + */ private fun prevP() { if (nowSpeak > 0) { textToSpeech?.stop() @@ -312,6 +321,9 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, } } + /** + * 下一段 + */ private fun nextP() { if (nowSpeak < contentList.size - 1) { textToSpeech?.stop() @@ -360,6 +372,9 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, registerReceiver(broadcastReceiver, intentFilter) } + /** + * 暂停朗读 + */ private fun pauseReadAloud(pause: Boolean) { postEvent(Bus.ALOUD_STATE, Status.PAUSE) this.pause = pause @@ -368,6 +383,9 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, ReadAloudNotification.upNotification(this) } + /** + * 恢复朗读 + */ private fun resumeReadAloud() { pause = false playTTS() From 7c386573976876601f8b7eeee044ddfb503aa0f0 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 11 Sep 2019 15:04:46 +0800 Subject: [PATCH 1441/1997] up --- app/src/main/java/io/legado/app/service/ReadAloudService.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/ReadAloudService.kt index 8d1a2c4fc..b3c864a80 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt @@ -130,8 +130,8 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, private var readAloudNumber: Int = 0 private var textChapter: TextChapter? = null private var pageIndex = 0 - var mediaSessionCompat: MediaSessionCompat? = null private val dsRunnable: Runnable? = Runnable { doDs() } + var mediaSessionCompat: MediaSessionCompat? = null var pause = false var title: String = "" var subtitle: String = "" From 7f6302d80d5b41933a1a5418c78eb6894dfa0f43 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 11 Sep 2019 16:07:35 +0800 Subject: [PATCH 1442/1997] up --- app/src/main/AndroidManifest.xml | 2 +- .../java/io/legado/app/help/CrashHandler.kt | 4 +- .../io/legado/app/help/PendingIntentHelp.kt | 4 +- ...loudService.kt => BaseReadAloudService.kt} | 368 ++++++------------ .../legado/app/service/TTSReadAloudService.kt | 218 +++++++++++ .../notification/ReadAloudNotification.kt | 68 ---- .../app/ui/readbook/ReadBookActivity.kt | 14 +- .../app/ui/readbook/ReadBookViewModel.kt | 4 +- .../app/ui/readbook/config/ReadAloudDialog.kt | 21 +- 9 files changed, 370 insertions(+), 333 deletions(-) rename app/src/main/java/io/legado/app/service/{ReadAloudService.kt => BaseReadAloudService.kt} (54%) create mode 100644 app/src/main/java/io/legado/app/service/TTSReadAloudService.kt delete mode 100644 app/src/main/java/io/legado/app/service/notification/ReadAloudNotification.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d0689f9eb..7bd159503 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -68,7 +68,7 @@ - + diff --git a/app/src/main/java/io/legado/app/help/CrashHandler.kt b/app/src/main/java/io/legado/app/help/CrashHandler.kt index 35c29304c..a8fe0d05f 100644 --- a/app/src/main/java/io/legado/app/help/CrashHandler.kt +++ b/app/src/main/java/io/legado/app/help/CrashHandler.kt @@ -8,7 +8,7 @@ import android.os.Handler import android.os.Looper import android.util.Log import android.widget.Toast -import io.legado.app.service.ReadAloudService +import io.legado.app.service.TTSReadAloudService import java.io.File import java.io.FileOutputStream import java.io.PrintWriter @@ -54,7 +54,7 @@ class CrashHandler : Thread.UncaughtExceptionHandler { * uncaughtException 回调函数 */ override fun uncaughtException(thread: Thread, ex: Throwable) { - ReadAloudService.clearTTS() + TTSReadAloudService.clearTTS() handleException(ex) mDefaultHandler?.uncaughtException(thread, ex) } diff --git a/app/src/main/java/io/legado/app/help/PendingIntentHelp.kt b/app/src/main/java/io/legado/app/help/PendingIntentHelp.kt index e0725cb27..280469f3e 100644 --- a/app/src/main/java/io/legado/app/help/PendingIntentHelp.kt +++ b/app/src/main/java/io/legado/app/help/PendingIntentHelp.kt @@ -3,7 +3,7 @@ package io.legado.app.help import android.app.PendingIntent import android.content.Context import android.content.Intent -import io.legado.app.service.ReadAloudService +import io.legado.app.service.TTSReadAloudService import io.legado.app.ui.readbook.ReadBookActivity object PendingIntentHelp { @@ -15,7 +15,7 @@ object PendingIntentHelp { } fun aloudServicePendingIntent(context: Context, actionStr: String): PendingIntent { - val intent = Intent(context, ReadAloudService::class.java) + val intent = Intent(context, TTSReadAloudService::class.java) intent.action = actionStr return PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) } diff --git a/app/src/main/java/io/legado/app/service/ReadAloudService.kt b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt similarity index 54% rename from app/src/main/java/io/legado/app/service/ReadAloudService.kt rename to app/src/main/java/io/legado/app/service/BaseReadAloudService.kt index b3c864a80..35e3ad6c1 100644 --- a/app/src/main/java/io/legado/app/service/ReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt @@ -2,40 +2,32 @@ package io.legado.app.service import android.app.PendingIntent import android.content.* +import android.graphics.BitmapFactory import android.media.AudioFocusRequest import android.media.AudioManager import android.os.Build import android.os.Handler -import android.speech.tts.TextToSpeech -import android.speech.tts.UtteranceProgressListener import android.support.v4.media.session.MediaSessionCompat import android.support.v4.media.session.PlaybackStateCompat +import androidx.annotation.CallSuper +import androidx.core.app.NotificationCompat import io.legado.app.R import io.legado.app.base.BaseService import io.legado.app.constant.Action import io.legado.app.constant.AppConst import io.legado.app.constant.Bus import io.legado.app.constant.Status -import io.legado.app.help.IntentDataHelp -import io.legado.app.help.IntentHelp import io.legado.app.help.MediaHelp +import io.legado.app.help.PendingIntentHelp import io.legado.app.receiver.MediaButtonReceiver -import io.legado.app.service.notification.ReadAloudNotification import io.legado.app.ui.widget.page.TextChapter -import io.legado.app.utils.getPrefBoolean -import io.legado.app.utils.getPrefInt import io.legado.app.utils.postEvent -import kotlinx.coroutines.launch -import org.jetbrains.anko.toast -import java.util.* -class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, +abstract class BaseReadAloudService : BaseService(), AudioManager.OnAudioFocusChangeListener { companion object { - val tag: String = ReadAloudService::class.java.simpleName var isRun = false - var textToSpeech: TextToSpeech? = null var timeMinute: Int = 0 fun play( @@ -46,7 +38,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, dataKey: String, play: Boolean = true ) { - val readAloudIntent = Intent(context, ReadAloudService::class.java) + val readAloudIntent = Intent(context, TTSReadAloudService::class.java) readAloudIntent.action = Action.play readAloudIntent.putExtra("title", title) readAloudIntent.putExtra("subtitle", subtitle) @@ -58,7 +50,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, fun pause(context: Context) { if (isRun) { - val intent = Intent(context, ReadAloudService::class.java) + val intent = Intent(context, TTSReadAloudService::class.java) intent.action = Action.pause context.startService(intent) } @@ -66,7 +58,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, fun resume(context: Context) { if (isRun) { - val intent = Intent(context, ReadAloudService::class.java) + val intent = Intent(context, TTSReadAloudService::class.java) intent.action = Action.resume context.startService(intent) } @@ -74,7 +66,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, fun stop(context: Context) { if (isRun) { - val intent = Intent(context, ReadAloudService::class.java) + val intent = Intent(context, TTSReadAloudService::class.java) intent.action = Action.stop context.startService(intent) } @@ -82,7 +74,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, fun prevParagraph(context: Context) { if (isRun) { - val intent = Intent(context, ReadAloudService::class.java) + val intent = Intent(context, TTSReadAloudService::class.java) intent.action = Action.prevParagraph context.startService(intent) } @@ -90,7 +82,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, fun nextParagraph(context: Context) { if (isRun) { - val intent = Intent(context, ReadAloudService::class.java) + val intent = Intent(context, TTSReadAloudService::class.java) intent.action = Action.nextParagraph context.startService(intent) } @@ -98,7 +90,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, fun upTtsSpeechRate(context: Context) { if (isRun) { - val intent = Intent(context, ReadAloudService::class.java) + val intent = Intent(context, TTSReadAloudService::class.java) intent.action = Action.upTtsSpeechRate context.startService(intent) } @@ -106,57 +98,46 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, fun setTimer(context: Context, minute: Int) { if (isRun) { - val intent = Intent(context, ReadAloudService::class.java) + val intent = Intent(context, TTSReadAloudService::class.java) intent.action = Action.setTimer intent.putExtra("minute", minute) context.startService(intent) } } - - fun clearTTS() { - textToSpeech?.stop() - textToSpeech?.shutdown() - textToSpeech = null - } } private val handler = Handler() - private var ttsIsSuccess: Boolean = false private lateinit var audioManager: AudioManager private lateinit var mFocusRequest: AudioFocusRequest private var broadcastReceiver: BroadcastReceiver? = null - private var nowSpeak: Int = 0 - private val contentList = arrayListOf() - private var readAloudNumber: Int = 0 - private var textChapter: TextChapter? = null - private var pageIndex = 0 - private val dsRunnable: Runnable? = Runnable { doDs() } - var mediaSessionCompat: MediaSessionCompat? = null - var pause = false + private var mediaSessionCompat: MediaSessionCompat? = null + private var pause = false var title: String = "" - var subtitle: String = "" + private var subtitle: String = "" + val contentList = arrayListOf() + var nowSpeak: Int = 0 + var readAloudNumber: Int = 0 + var textChapter: TextChapter? = null + var pageIndex = 0 + private val dsRunnable: Runnable? = Runnable { doDs() } override fun onCreate() { super.onCreate() isRun = true - textToSpeech = TextToSpeech(this, this) audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { mFocusRequest = MediaHelp.getFocusRequest(this) } initMediaSession() initBroadcastReceiver() - upSpeechRate() - ReadAloudNotification.upNotification(this) + upNotification() } override fun onDestroy() { super.onDestroy() - upMediaSessionPlaybackState(PlaybackStateCompat.STATE_STOPPED) - clearTTS() + isRun = false unregisterReceiver(broadcastReceiver) postEvent(Bus.ALOUD_STATE, Status.STOP) - isRun = false } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { @@ -184,77 +165,24 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, return super.onStartCommand(intent, flags, startId) } - override fun onInit(status: Int) { - launch { - if (status == TextToSpeech.SUCCESS) { - val result = textToSpeech?.setLanguage(Locale.CHINA) - if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) { - toast(R.string.tts_fix) - IntentHelp.toTTSSetting(this@ReadAloudService) - stopSelf() - } else { - textToSpeech?.setOnUtteranceProgressListener(TTSUtteranceListener()) - ttsIsSuccess = true - playTTS() - } - } else { - toast(R.string.tts_init_failed) - } - } - } + abstract fun newReadAloud(dataKey: String?, play: Boolean) - private fun newReadAloud(dataKey: String?, play: Boolean) { - dataKey?.let { - textChapter = IntentDataHelp.getData(dataKey) as? TextChapter - textChapter?.let { textChapter -> - nowSpeak = 0 - readAloudNumber = textChapter.getReadLength(pageIndex) - contentList.clear() - if (getPrefBoolean("readAloudByPage")) { - for (index in pageIndex..textChapter.lastIndex()) { - textChapter.page(index)?.text?.split("\n")?.let { - contentList.addAll(it) - } - } - } else { - contentList.addAll(textChapter.getUnRead(pageIndex).split("\n")) - } - if (play) playTTS() - } ?: stopSelf() - } ?: stopSelf() + @CallSuper + open fun pauseReadAloud(pause: Boolean) { + postEvent(Bus.ALOUD_STATE, Status.PAUSE) + this.pause = pause } - @Suppress("DEPRECATION") - private fun playTTS() { - if (contentList.size < 1 || !ttsIsSuccess) { - return - } - if (requestFocus()) { - upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PLAYING) - postEvent(Bus.ALOUD_STATE, Status.PLAY) - ReadAloudNotification.upNotification(this) - for (i in nowSpeak until contentList.size) { - if (i == 0) { - speak(contentList[i], TextToSpeech.QUEUE_FLUSH, AppConst.APP_TAG + i) - } else { - speak(contentList[i], TextToSpeech.QUEUE_ADD, AppConst.APP_TAG + i) - } - } - } + @CallSuper + open fun resumeReadAloud() { + pause = false } - private fun speak(content: String, queueMode: Int, utteranceId: String) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - textToSpeech?.speak(content, queueMode, null, utteranceId) - } else { - @Suppress("DEPRECATION") - textToSpeech?.speak( - content, - queueMode, - hashMapOf(Pair(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, utteranceId)) - ) - } - } + abstract fun upSpeechRate(reset: Boolean = false) + + abstract fun prevP() + + abstract fun nextP() private fun setTimer(minute: Int) { timeMinute = minute @@ -262,7 +190,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, handler.removeCallbacks(dsRunnable) handler.postDelayed(dsRunnable, 60000) } - ReadAloudNotification.upNotification(this) + upNotification() } private fun addTimer() { @@ -276,7 +204,7 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, handler.postDelayed(dsRunnable, 60000) } postEvent(Bus.TTS_DS, timeMinute) - ReadAloudNotification.upNotification(this) + upNotification() } /** @@ -292,47 +220,57 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, } } postEvent(Bus.TTS_DS, timeMinute) - ReadAloudNotification.upNotification(this) + upNotification() } - /** - * 更新朗读速度 - */ - private fun upSpeechRate(reset: Boolean = false) { - if (this.getPrefBoolean("ttsFollowSys", true)) { - if (reset) { - clearTTS() - textToSpeech = TextToSpeech(this, this) + + override fun onAudioFocusChange(focusChange: Int) { + when (focusChange) { + AudioManager.AUDIOFOCUS_GAIN -> { + // 重新获得焦点, 可做恢复播放,恢复后台音量的操作 + if (!pause) resumeReadAloud() + } + AudioManager.AUDIOFOCUS_LOSS -> { + // 永久丢失焦点除非重新主动获取,这种情况是被其他播放器抢去了焦点, 为避免与其他播放器混音,可将音乐暂停 + } + AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> { + // 暂时丢失焦点,这种情况是被其他应用申请了短暂的焦点,可压低后台音量 + if (!pause) pauseReadAloud(false) + } + AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> { + // 短暂丢失焦点,这种情况是被其他应用申请了短暂的焦点希望其他声音能压低音量(或者关闭声音)凸显这个声音(比如短信提示音), } - } else { - textToSpeech?.setSpeechRate((this.getPrefInt("ttsSpeechRate", 5) + 5) / 10f) } } /** - * 上一段 + * @return 音频焦点 */ - private fun prevP() { - if (nowSpeak > 0) { - textToSpeech?.stop() - nowSpeak-- - readAloudNumber -= contentList[nowSpeak].length.minus(1) - playTTS() + fun requestFocus(): Boolean { + MediaHelp.playSilentSound(this) + val request: Int = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + audioManager.requestAudioFocus(mFocusRequest) + } else { + @Suppress("DEPRECATION") + audioManager.requestAudioFocus( + this, + AudioManager.STREAM_MUSIC, + AudioManager.AUDIOFOCUS_GAIN + ) } + return request == AudioManager.AUDIOFOCUS_REQUEST_GRANTED } - /** - * 下一段 - */ - private fun nextP() { - if (nowSpeak < contentList.size - 1) { - textToSpeech?.stop() - readAloudNumber += contentList[nowSpeak].length.plus(1) - nowSpeak++ - playTTS() - } + fun upMediaSessionPlaybackState(state: Int) { + mediaSessionCompat?.setPlaybackState( + PlaybackStateCompat.Builder() + .setActions(MediaHelp.MEDIA_SESSION_ACTIONS) + .setState(state, nowSpeak.toLong(), 1f) + .build() + ) } + /** * 初始化MediaSession, 注册多媒体按钮 */ @@ -347,10 +285,10 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, PendingIntent.FLAG_CANCEL_CURRENT ) - mediaSessionCompat = MediaSessionCompat(this, tag) + mediaSessionCompat = MediaSessionCompat(this, TTSReadAloudService.tag) mediaSessionCompat?.setCallback(object : MediaSessionCompat.Callback() { override fun onMediaButtonEvent(mediaButtonEvent: Intent): Boolean { - return MediaButtonReceiver.handleIntent(this@ReadAloudService, mediaButtonEvent) + return MediaButtonReceiver.handleIntent(this@BaseReadAloudService, mediaButtonEvent) } }) mediaSessionCompat?.setMediaButtonReceiver(mediaButtonReceiverPendingIntent) @@ -373,110 +311,58 @@ class ReadAloudService : BaseService(), TextToSpeech.OnInitListener, } /** - * 暂停朗读 - */ - private fun pauseReadAloud(pause: Boolean) { - postEvent(Bus.ALOUD_STATE, Status.PAUSE) - this.pause = pause - textToSpeech?.stop() - upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PAUSED) - ReadAloudNotification.upNotification(this) - } - - /** - * 恢复朗读 - */ - private fun resumeReadAloud() { - pause = false - playTTS() - } - - /** - * @return 音频焦点 + * 更新通知 */ - private fun requestFocus(): Boolean { - MediaHelp.playSilentSound(this) - val request: Int = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - audioManager.requestAudioFocus(mFocusRequest) + fun upNotification() { + var nTitle: String = when { + pause -> getString(R.string.read_aloud_pause) + timeMinute in 1..60 -> getString( + R.string.read_aloud_timer, + timeMinute + ) + else -> getString(R.string.read_aloud_t) + } + nTitle += ": $title" + var nSubtitle = subtitle + if (subtitle.isEmpty()) + nSubtitle = getString(R.string.read_aloud_s) + val builder = NotificationCompat.Builder(this, AppConst.channelIdReadAloud) + .setSmallIcon(R.drawable.ic_volume_up) + .setLargeIcon(BitmapFactory.decodeResource(resources, R.drawable.icon_read_book)) + .setOngoing(true) + .setContentTitle(nTitle) + .setContentText(nSubtitle) + .setContentIntent(PendingIntentHelp.readBookActivityPendingIntent(this)) + if (pause) { + builder.addAction( + R.drawable.ic_play_24dp, + getString(R.string.resume), + PendingIntentHelp.aloudServicePendingIntent(this, Action.resume) + ) } else { - @Suppress("DEPRECATION") - audioManager.requestAudioFocus( - this, - AudioManager.STREAM_MUSIC, - AudioManager.AUDIOFOCUS_GAIN + builder.addAction( + R.drawable.ic_pause_24dp, + getString(R.string.pause), + PendingIntentHelp.aloudServicePendingIntent(this, Action.pause) ) } - return request == AudioManager.AUDIOFOCUS_REQUEST_GRANTED - } - - private fun upMediaSessionPlaybackState(state: Int) { - mediaSessionCompat?.setPlaybackState( - PlaybackStateCompat.Builder() - .setActions(MediaHelp.MEDIA_SESSION_ACTIONS) - .setState(state, nowSpeak.toLong(), 1f) - .build() + builder.addAction( + R.drawable.ic_stop_black_24dp, + getString(R.string.stop), + PendingIntentHelp.aloudServicePendingIntent(this, Action.stop) ) + builder.addAction( + R.drawable.ic_time_add_24dp, + getString(R.string.set_timer), + PendingIntentHelp.aloudServicePendingIntent(this, Action.addTimer) + ) + builder.setStyle( + androidx.media.app.NotificationCompat.MediaStyle() + .setMediaSession(mediaSessionCompat?.sessionToken) + .setShowActionsInCompactView(0, 1, 2) + ) + builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) + val notification = builder.build() + startForeground(112201, notification) } - - override fun onAudioFocusChange(focusChange: Int) { - when (focusChange) { - AudioManager.AUDIOFOCUS_GAIN -> { - // 重新获得焦点, 可做恢复播放,恢复后台音量的操作 - if (!pause) resumeReadAloud() - } - AudioManager.AUDIOFOCUS_LOSS -> { - // 永久丢失焦点除非重新主动获取,这种情况是被其他播放器抢去了焦点, 为避免与其他播放器混音,可将音乐暂停 - } - AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> { - // 暂时丢失焦点,这种情况是被其他应用申请了短暂的焦点,可压低后台音量 - if (!pause) pauseReadAloud(false) - } - AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> { - // 短暂丢失焦点,这种情况是被其他应用申请了短暂的焦点希望其他声音能压低音量(或者关闭声音)凸显这个声音(比如短信提示音), - } - } - } - - /** - * 朗读监听 - */ - private inner class TTSUtteranceListener : UtteranceProgressListener() { - - override fun onStart(s: String) { - textChapter?.let { - if (readAloudNumber + 1 > it.getReadLength(pageIndex + 1)) { - pageIndex++ - postEvent(Bus.TTS_TURN_PAGE, 1) - } - } - postEvent(Bus.TTS_START, readAloudNumber + 1) - } - - override fun onDone(s: String) { - readAloudNumber += contentList[nowSpeak].length + 1 - nowSpeak += 1 - if (nowSpeak >= contentList.size) { - postEvent(Bus.TTS_TURN_PAGE, 2) - } - } - - override fun onRangeStart(utteranceId: String?, start: Int, end: Int, frame: Int) { - super.onRangeStart(utteranceId, start, end, frame) - textChapter?.let { - if (readAloudNumber + start > it.getReadLength(pageIndex + 1)) { - pageIndex++ - postEvent(Bus.TTS_TURN_PAGE, 1) - postEvent(Bus.TTS_START, readAloudNumber + start) - } - } - } - - override fun onError(s: String) { - launch { - toast(s) - } - } - - } - } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt b/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt new file mode 100644 index 000000000..195fe4fdf --- /dev/null +++ b/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt @@ -0,0 +1,218 @@ +package io.legado.app.service + +import android.os.Build +import android.speech.tts.TextToSpeech +import android.speech.tts.UtteranceProgressListener +import android.support.v4.media.session.PlaybackStateCompat +import io.legado.app.R +import io.legado.app.constant.AppConst +import io.legado.app.constant.Bus +import io.legado.app.constant.Status +import io.legado.app.help.IntentDataHelp +import io.legado.app.help.IntentHelp +import io.legado.app.ui.widget.page.TextChapter +import io.legado.app.utils.getPrefBoolean +import io.legado.app.utils.getPrefInt +import io.legado.app.utils.postEvent +import kotlinx.coroutines.launch +import org.jetbrains.anko.toast +import java.util.* + +class TTSReadAloudService : BaseReadAloudService(), TextToSpeech.OnInitListener { + + companion object { + val tag: String = TTSReadAloudService::class.java.simpleName + var textToSpeech: TextToSpeech? = null + + fun clearTTS() { + textToSpeech?.stop() + textToSpeech?.shutdown() + textToSpeech = null + } + } + + private var ttsIsSuccess: Boolean = false + + override fun onCreate() { + super.onCreate() + textToSpeech = TextToSpeech(this, this) + upSpeechRate() + } + + override fun onDestroy() { + super.onDestroy() + upMediaSessionPlaybackState(PlaybackStateCompat.STATE_STOPPED) + clearTTS() + } + + override fun onInit(status: Int) { + launch { + if (status == TextToSpeech.SUCCESS) { + val result = textToSpeech?.setLanguage(Locale.CHINA) + if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) { + toast(R.string.tts_fix) + IntentHelp.toTTSSetting(this@TTSReadAloudService) + stopSelf() + } else { + textToSpeech?.setOnUtteranceProgressListener(TTSUtteranceListener()) + ttsIsSuccess = true + playTTS() + } + } else { + toast(R.string.tts_init_failed) + } + } + } + + override fun newReadAloud(dataKey: String?, play: Boolean) { + dataKey?.let { + textChapter = IntentDataHelp.getData(dataKey) as? TextChapter + textChapter?.let { textChapter -> + nowSpeak = 0 + readAloudNumber = textChapter.getReadLength(pageIndex) + contentList.clear() + if (getPrefBoolean("readAloudByPage")) { + for (index in pageIndex..textChapter.lastIndex()) { + textChapter.page(index)?.text?.split("\n")?.let { + contentList.addAll(it) + } + } + } else { + contentList.addAll(textChapter.getUnRead(pageIndex).split("\n")) + } + if (play) playTTS() + } ?: stopSelf() + } ?: stopSelf() + } + + @Suppress("DEPRECATION") + private fun playTTS() { + if (contentList.size < 1 || !ttsIsSuccess) { + return + } + if (requestFocus()) { + upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PLAYING) + postEvent(Bus.ALOUD_STATE, Status.PLAY) + upNotification() + for (i in nowSpeak until contentList.size) { + if (i == 0) { + speak(contentList[i], TextToSpeech.QUEUE_FLUSH, AppConst.APP_TAG + i) + } else { + speak(contentList[i], TextToSpeech.QUEUE_ADD, AppConst.APP_TAG + i) + } + } + } + } + + private fun speak(content: String, queueMode: Int, utteranceId: String) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + textToSpeech?.speak(content, queueMode, null, utteranceId) + } else { + @Suppress("DEPRECATION") + textToSpeech?.speak( + content, + queueMode, + hashMapOf(Pair(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, utteranceId)) + ) + } + } + + /** + * 更新朗读速度 + */ + override fun upSpeechRate(reset: Boolean) { + if (this.getPrefBoolean("ttsFollowSys", true)) { + if (reset) { + clearTTS() + textToSpeech = TextToSpeech(this, this) + } + } else { + textToSpeech?.setSpeechRate((this.getPrefInt("ttsSpeechRate", 5) + 5) / 10f) + } + } + + /** + * 上一段 + */ + override fun prevP() { + if (nowSpeak > 0) { + textToSpeech?.stop() + nowSpeak-- + readAloudNumber -= contentList[nowSpeak].length.minus(1) + playTTS() + } + } + + /** + * 下一段 + */ + override fun nextP() { + if (nowSpeak < contentList.size - 1) { + textToSpeech?.stop() + readAloudNumber += contentList[nowSpeak].length.plus(1) + nowSpeak++ + playTTS() + } + } + + /** + * 暂停朗读 + */ + override fun pauseReadAloud(pause: Boolean) { + super.pauseReadAloud(pause) + textToSpeech?.stop() + upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PAUSED) + upNotification() + } + + /** + * 恢复朗读 + */ + override fun resumeReadAloud() { + super.resumeReadAloud() + playTTS() + } + + /** + * 朗读监听 + */ + private inner class TTSUtteranceListener : UtteranceProgressListener() { + + override fun onStart(s: String) { + textChapter?.let { + if (readAloudNumber + 1 > it.getReadLength(pageIndex + 1)) { + pageIndex++ + postEvent(Bus.TTS_TURN_PAGE, 1) + } + } + postEvent(Bus.TTS_START, readAloudNumber + 1) + } + + override fun onDone(s: String) { + readAloudNumber += contentList[nowSpeak].length + 1 + nowSpeak += 1 + if (nowSpeak >= contentList.size) { + postEvent(Bus.TTS_TURN_PAGE, 2) + } + } + + override fun onRangeStart(utteranceId: String?, start: Int, end: Int, frame: Int) { + super.onRangeStart(utteranceId, start, end, frame) + textChapter?.let { + if (readAloudNumber + start > it.getReadLength(pageIndex + 1)) { + pageIndex++ + postEvent(Bus.TTS_TURN_PAGE, 1) + postEvent(Bus.TTS_START, readAloudNumber + start) + } + } + } + + override fun onError(s: String) { + launch { + toast(s) + } + } + + } + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/service/notification/ReadAloudNotification.kt b/app/src/main/java/io/legado/app/service/notification/ReadAloudNotification.kt deleted file mode 100644 index d7e0c51ca..000000000 --- a/app/src/main/java/io/legado/app/service/notification/ReadAloudNotification.kt +++ /dev/null @@ -1,68 +0,0 @@ -package io.legado.app.service.notification - -import android.graphics.BitmapFactory -import androidx.core.app.NotificationCompat -import io.legado.app.R -import io.legado.app.constant.Action -import io.legado.app.constant.AppConst -import io.legado.app.help.PendingIntentHelp -import io.legado.app.service.ReadAloudService - -object ReadAloudNotification { - - /** - * 更新通知 - */ - fun upNotification(service: ReadAloudService) { - var nTitle: String = when { - service.pause -> service.getString(R.string.read_aloud_pause) - ReadAloudService.timeMinute in 1..60 -> service.getString( - R.string.read_aloud_timer, - ReadAloudService.timeMinute - ) - else -> service.getString(R.string.read_aloud_t) - } - nTitle += ": ${service.title}" - var nSubtitle = service.subtitle - if (service.subtitle.isEmpty()) - nSubtitle = service.getString(R.string.read_aloud_s) - val builder = NotificationCompat.Builder(service, AppConst.channelIdReadAloud) - .setSmallIcon(R.drawable.ic_volume_up) - .setLargeIcon(BitmapFactory.decodeResource(service.resources, R.drawable.icon_read_book)) - .setOngoing(true) - .setContentTitle(nTitle) - .setContentText(nSubtitle) - .setContentIntent(PendingIntentHelp.readBookActivityPendingIntent(service)) - if (service.pause) { - builder.addAction( - R.drawable.ic_play_24dp, - service.getString(R.string.resume), - PendingIntentHelp.aloudServicePendingIntent(service, Action.resume) - ) - } else { - builder.addAction( - R.drawable.ic_pause_24dp, - service.getString(R.string.pause), - PendingIntentHelp.aloudServicePendingIntent(service, Action.pause) - ) - } - builder.addAction( - R.drawable.ic_stop_black_24dp, - service.getString(R.string.stop), - PendingIntentHelp.aloudServicePendingIntent(service, Action.stop) - ) - builder.addAction( - R.drawable.ic_time_add_24dp, - service.getString(R.string.set_timer), - PendingIntentHelp.aloudServicePendingIntent(service, Action.addTimer) - ) - builder.setStyle( - androidx.media.app.NotificationCompat.MediaStyle() - .setMediaSession(service.mediaSessionCompat?.sessionToken) - .setShowActionsInCompactView(0, 1, 2) - ) - builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) - val notification = builder.build() - service.startForeground(112201, notification) - } -} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index da9028d0e..a6da939f5 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -25,7 +25,7 @@ import io.legado.app.lib.dialogs.alert import io.legado.app.lib.dialogs.noButton import io.legado.app.lib.dialogs.okButton import io.legado.app.receiver.TimeElectricityReceiver -import io.legado.app.service.ReadAloudService +import io.legado.app.service.BaseReadAloudService import io.legado.app.ui.changesource.ChangeSourceDialog import io.legado.app.ui.chapterlist.ChapterListActivity import io.legado.app.ui.readbook.config.* @@ -190,7 +190,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea when (keyCode) { KeyEvent.KEYCODE_BACK -> { if (readAloudStatus == Status.PLAY) { - ReadAloudService.pause(this) + BaseReadAloudService.pause(this) toast(R.string.read_aloud_pause) return true } @@ -444,14 +444,14 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea * 朗读按钮 */ private fun onClickReadAloud() { - if (!ReadAloudService.isRun) { + if (!BaseReadAloudService.isRun) { readAloudStatus = Status.STOP SystemUtils.ignoreBatteryOptimization(this) } when (readAloudStatus) { Status.STOP -> readAloud() - Status.PLAY -> ReadAloudService.pause(this) - Status.PAUSE -> ReadAloudService.resume(this) + Status.PLAY -> BaseReadAloudService.pause(this) + Status.PAUSE -> BaseReadAloudService.resume(this) } } @@ -464,7 +464,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea if (book != null && textChapter != null) { val key = System.currentTimeMillis().toString() IntentDataHelp.putData(key, textChapter) - ReadAloudService.play( + BaseReadAloudService.play( this, book.name, textChapter.title, viewModel.durPageIndex, key, play ) @@ -569,7 +569,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea page_view.upContent() viewModel.saveRead() } - 2 -> if (!moveToNextChapter()) ReadAloudService.stop(this) + 2 -> if (!moveToNextChapter()) BaseReadAloudService.stop(this) -1 -> { if (viewModel.durPageIndex > 0) { viewModel.durPageIndex = viewModel.durPageIndex - 1 diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index fe1a00201..14ecccba4 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -11,7 +11,7 @@ import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter import io.legado.app.help.BookHelp import io.legado.app.model.WebBook -import io.legado.app.service.ReadAloudService +import io.legado.app.service.BaseReadAloudService import io.legado.app.ui.widget.page.TextChapter import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.Main @@ -332,7 +332,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { override fun onCleared() { super.onCleared() - ReadAloudService.stop(context) + BaseReadAloudService.stop(context) } interface CallBack { diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt index 686c0e7b5..846d6ff15 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt @@ -11,7 +11,7 @@ import androidx.fragment.app.DialogFragment import io.legado.app.R import io.legado.app.constant.Bus import io.legado.app.constant.Status -import io.legado.app.service.ReadAloudService +import io.legado.app.service.BaseReadAloudService import io.legado.app.ui.readbook.Help import io.legado.app.utils.* import kotlinx.android.synthetic.main.dialog_read_aloud.* @@ -61,8 +61,9 @@ class ReadAloudDialog : DialogFragment() { callBack?.readAloudStatus?.let { upPlayState(it) } - seek_timer.progress = ReadAloudService.timeMinute - tv_timer.text = requireContext().getString(R.string.timer_m, ReadAloudService.timeMinute) + seek_timer.progress = BaseReadAloudService.timeMinute + tv_timer.text = + requireContext().getString(R.string.timer_m, BaseReadAloudService.timeMinute) cb_by_page.isChecked = requireContext().getPrefBoolean("readAloudByPage") cb_tts_follow_sys.isChecked = requireContext().getPrefBoolean("ttsFollowSys", true) seek_tts_SpeechRate.isEnabled = !cb_tts_follow_sys.isChecked @@ -103,7 +104,7 @@ class ReadAloudDialog : DialogFragment() { override fun onStartTrackingTouch(seekBar: SeekBar?) = Unit override fun onStopTrackingTouch(seekBar: SeekBar?) { - ReadAloudService.setTimer(requireContext(), seek_timer.progress) + BaseReadAloudService.setTimer(requireContext(), seek_timer.progress) } }) } @@ -111,11 +112,11 @@ class ReadAloudDialog : DialogFragment() { private fun initOnClick() { iv_menu.onClick { callBack?.showMenu(); dismiss() } iv_menu.onLongClick { callBack?.openChapterList(); true } - iv_stop.onClick { ReadAloudService.stop(requireContext()); dismiss() } + iv_stop.onClick { BaseReadAloudService.stop(requireContext()); dismiss() } iv_play_pause.onClick { postEvent(Bus.READ_ALOUD_BUTTON, true) } - iv_play_prev.onClick { ReadAloudService.prevParagraph(requireContext()) } + iv_play_prev.onClick { BaseReadAloudService.prevParagraph(requireContext()) } iv_play_prev.onLongClick { postEvent(Bus.TTS_TURN_PAGE, -2); true } - iv_play_next.onClick { ReadAloudService.nextParagraph(requireContext()) } + iv_play_next.onClick { BaseReadAloudService.nextParagraph(requireContext()) } iv_play_next.onLongClick { postEvent(Bus.TTS_TURN_PAGE, 2); true } } @@ -128,10 +129,10 @@ class ReadAloudDialog : DialogFragment() { } private fun upTtsSpeechRate() { - ReadAloudService.upTtsSpeechRate(requireContext()) + BaseReadAloudService.upTtsSpeechRate(requireContext()) if (callBack?.readAloudStatus == Status.PLAY) { - ReadAloudService.pause(requireContext()) - ReadAloudService.resume(requireContext()) + BaseReadAloudService.pause(requireContext()) + BaseReadAloudService.resume(requireContext()) } } From d6e0c730db49b273eafeded63b88a514e4dd9f0b Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 11 Sep 2019 16:38:37 +0800 Subject: [PATCH 1443/1997] up --- .../app/service/BaseReadAloudService.kt | 1 + .../app/service/HttpReadAloudService.kt | 21 +++++++++++++++++++ .../legado/app/service/TTSReadAloudService.kt | 1 - 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/io/legado/app/service/HttpReadAloudService.kt diff --git a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt index 35e3ad6c1..cbebfb9f6 100644 --- a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt @@ -138,6 +138,7 @@ abstract class BaseReadAloudService : BaseService(), isRun = false unregisterReceiver(broadcastReceiver) postEvent(Bus.ALOUD_STATE, Status.STOP) + upMediaSessionPlaybackState(PlaybackStateCompat.STATE_STOPPED) } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { diff --git a/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt b/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt new file mode 100644 index 000000000..4092fc01d --- /dev/null +++ b/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt @@ -0,0 +1,21 @@ +package io.legado.app.service + +class HttpReadAloudService : BaseReadAloudService() { + + override fun newReadAloud(dataKey: String?, play: Boolean) { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun upSpeechRate(reset: Boolean) { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun prevP() { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun nextP() { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt b/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt index 195fe4fdf..f29cf244c 100644 --- a/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt @@ -41,7 +41,6 @@ class TTSReadAloudService : BaseReadAloudService(), TextToSpeech.OnInitListener override fun onDestroy() { super.onDestroy() - upMediaSessionPlaybackState(PlaybackStateCompat.STATE_STOPPED) clearTTS() } From af22c601005061a66843f1898ff65d7880480915 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 11 Sep 2019 16:38:58 +0800 Subject: [PATCH 1444/1997] up --- app/src/main/AndroidManifest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7bd159503..242d2710a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -71,6 +71,7 @@ + From fd1570de81f290b469feb386d9233e210db9a409 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 11 Sep 2019 16:43:28 +0800 Subject: [PATCH 1445/1997] up --- .../app/service/BaseReadAloudService.kt | 25 +++++++++++++- .../legado/app/service/TTSReadAloudService.kt | 33 +++---------------- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt index cbebfb9f6..f830109e2 100644 --- a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt @@ -17,10 +17,12 @@ import io.legado.app.constant.Action import io.legado.app.constant.AppConst import io.legado.app.constant.Bus import io.legado.app.constant.Status +import io.legado.app.help.IntentDataHelp import io.legado.app.help.MediaHelp import io.legado.app.help.PendingIntentHelp import io.legado.app.receiver.MediaButtonReceiver import io.legado.app.ui.widget.page.TextChapter +import io.legado.app.utils.getPrefBoolean import io.legado.app.utils.postEvent abstract class BaseReadAloudService : BaseService(), @@ -166,7 +168,28 @@ abstract class BaseReadAloudService : BaseService(), return super.onStartCommand(intent, flags, startId) } - abstract fun newReadAloud(dataKey: String?, play: Boolean) + private fun newReadAloud(dataKey: String?, play: Boolean) { + dataKey?.let { + textChapter = IntentDataHelp.getData(dataKey) as? TextChapter + textChapter?.let { textChapter -> + nowSpeak = 0 + readAloudNumber = textChapter.getReadLength(pageIndex) + contentList.clear() + if (getPrefBoolean("readAloudByPage")) { + for (index in pageIndex..textChapter.lastIndex()) { + textChapter.page(index)?.text?.split("\n")?.let { + contentList.addAll(it) + } + } + } else { + contentList.addAll(textChapter.getUnRead(pageIndex).split("\n")) + } + if (play) play() + } ?: stopSelf() + } ?: stopSelf() + } + + abstract fun play() @CallSuper open fun pauseReadAloud(pause: Boolean) { diff --git a/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt b/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt index f29cf244c..15064598c 100644 --- a/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt @@ -8,9 +8,7 @@ import io.legado.app.R import io.legado.app.constant.AppConst import io.legado.app.constant.Bus import io.legado.app.constant.Status -import io.legado.app.help.IntentDataHelp import io.legado.app.help.IntentHelp -import io.legado.app.ui.widget.page.TextChapter import io.legado.app.utils.getPrefBoolean import io.legado.app.utils.getPrefInt import io.legado.app.utils.postEvent @@ -55,7 +53,7 @@ class TTSReadAloudService : BaseReadAloudService(), TextToSpeech.OnInitListener } else { textToSpeech?.setOnUtteranceProgressListener(TTSUtteranceListener()) ttsIsSuccess = true - playTTS() + play() } } else { toast(R.string.tts_init_failed) @@ -63,29 +61,8 @@ class TTSReadAloudService : BaseReadAloudService(), TextToSpeech.OnInitListener } } - override fun newReadAloud(dataKey: String?, play: Boolean) { - dataKey?.let { - textChapter = IntentDataHelp.getData(dataKey) as? TextChapter - textChapter?.let { textChapter -> - nowSpeak = 0 - readAloudNumber = textChapter.getReadLength(pageIndex) - contentList.clear() - if (getPrefBoolean("readAloudByPage")) { - for (index in pageIndex..textChapter.lastIndex()) { - textChapter.page(index)?.text?.split("\n")?.let { - contentList.addAll(it) - } - } - } else { - contentList.addAll(textChapter.getUnRead(pageIndex).split("\n")) - } - if (play) playTTS() - } ?: stopSelf() - } ?: stopSelf() - } - @Suppress("DEPRECATION") - private fun playTTS() { + override fun play() { if (contentList.size < 1 || !ttsIsSuccess) { return } @@ -138,7 +115,7 @@ class TTSReadAloudService : BaseReadAloudService(), TextToSpeech.OnInitListener textToSpeech?.stop() nowSpeak-- readAloudNumber -= contentList[nowSpeak].length.minus(1) - playTTS() + play() } } @@ -150,7 +127,7 @@ class TTSReadAloudService : BaseReadAloudService(), TextToSpeech.OnInitListener textToSpeech?.stop() readAloudNumber += contentList[nowSpeak].length.plus(1) nowSpeak++ - playTTS() + play() } } @@ -169,7 +146,7 @@ class TTSReadAloudService : BaseReadAloudService(), TextToSpeech.OnInitListener */ override fun resumeReadAloud() { super.resumeReadAloud() - playTTS() + play() } /** From cd6c1d9c49dd78bc5d42e41fd045252348233e68 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 11 Sep 2019 16:46:12 +0800 Subject: [PATCH 1446/1997] up --- .../legado/app/service/HttpReadAloudService.kt | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt b/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt index 4092fc01d..5def5d8a9 100644 --- a/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt @@ -2,20 +2,28 @@ package io.legado.app.service class HttpReadAloudService : BaseReadAloudService() { - override fun newReadAloud(dataKey: String?, play: Boolean) { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + override fun onCreate() { + super.onCreate() + } + + override fun onDestroy() { + super.onDestroy() + } + + override fun play() { + } override fun upSpeechRate(reset: Boolean) { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } override fun prevP() { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } override fun nextP() { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } } \ No newline at end of file From b3e6451d5c1b8ccdc40d231801d0225403962e5a Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 11 Sep 2019 17:40:31 +0800 Subject: [PATCH 1447/1997] up --- .../app/service/HttpReadAloudService.kt | 69 ++++++++++++++++++- .../legado/app/service/TTSReadAloudService.kt | 4 +- 2 files changed, 68 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt b/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt index 5def5d8a9..43bca75b2 100644 --- a/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt @@ -1,29 +1,92 @@ package io.legado.app.service -class HttpReadAloudService : BaseReadAloudService() { +import android.media.MediaPlayer +import io.legado.app.constant.Bus +import io.legado.app.utils.postEvent +import kotlinx.coroutines.launch +import org.jetbrains.anko.toast + +class HttpReadAloudService : BaseReadAloudService(), + MediaPlayer.OnPreparedListener, + MediaPlayer.OnErrorListener, + MediaPlayer.OnCompletionListener { + + private var mediaPlayer = MediaPlayer() override fun onCreate() { super.onCreate() + mediaPlayer.setOnErrorListener(this) + mediaPlayer.setOnPreparedListener(this) + mediaPlayer.setOnCompletionListener(this) } override fun onDestroy() { super.onDestroy() + mediaPlayer.release() + } + + private fun getAudioPath(): String { + val audioText = contentList[nowSpeak] + return "http://tts.baidu.com/text2audio?idx=1&tex=$audioText&cuid=baidu_speech_demo&cod=2&lan=zh&ctp=1&pdt=1&spd=4&per=6&vol=5&pit=5&_res_tag_=audio" } override fun play() { + if (contentList.isEmpty()) return + if (requestFocus()) { + mediaPlayer.reset() + mediaPlayer.setDataSource(getAudioPath()) + mediaPlayer.prepareAsync() + } + } + override fun pauseReadAloud(pause: Boolean) { + super.pauseReadAloud(pause) + mediaPlayer.pause() } - override fun upSpeechRate(reset: Boolean) { + override fun resumeReadAloud() { + super.resumeReadAloud() + mediaPlayer.start() + } + override fun upSpeechRate(reset: Boolean) { + mediaPlayer.stop() + play() } override fun prevP() { - + if (nowSpeak > 0) { + mediaPlayer.stop() + nowSpeak-- + readAloudNumber -= contentList[nowSpeak].length.minus(1) + play() + } } override fun nextP() { + if (nowSpeak < contentList.size - 1) { + mediaPlayer.stop() + readAloudNumber += contentList[nowSpeak].length.plus(1) + nowSpeak++ + play() + } + } + override fun onPrepared(mp: MediaPlayer?) { + mp?.start() } + override fun onError(mp: MediaPlayer?, what: Int, extra: Int): Boolean { + launch { toast("播放出错") } + return false + } + + override fun onCompletion(mp: MediaPlayer?) { + if (nowSpeak < contentList.size) { + nowSpeak++ + play() + } else { + postEvent(Bus.TTS_TURN_PAGE, 2) + } + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt b/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt index 15064598c..eef74c2fe 100644 --- a/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt @@ -63,7 +63,7 @@ class TTSReadAloudService : BaseReadAloudService(), TextToSpeech.OnInitListener @Suppress("DEPRECATION") override fun play() { - if (contentList.size < 1 || !ttsIsSuccess) { + if (contentList.isEmpty() || !ttsIsSuccess) { return } if (requestFocus()) { @@ -166,7 +166,7 @@ class TTSReadAloudService : BaseReadAloudService(), TextToSpeech.OnInitListener override fun onDone(s: String) { readAloudNumber += contentList[nowSpeak].length + 1 - nowSpeak += 1 + nowSpeak++ if (nowSpeak >= contentList.size) { postEvent(Bus.TTS_TURN_PAGE, 2) } From c0779256e298d02f4859c3625ff7a28e6bb460fb Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 11 Sep 2019 17:44:46 +0800 Subject: [PATCH 1448/1997] up --- .../main/java/io/legado/app/service/BaseReadAloudService.kt | 6 +++++- .../main/java/io/legado/app/service/HttpReadAloudService.kt | 1 + .../main/java/io/legado/app/service/TTSReadAloudService.kt | 5 +---- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt index f830109e2..24f82da67 100644 --- a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt @@ -189,7 +189,11 @@ abstract class BaseReadAloudService : BaseService(), } ?: stopSelf() } - abstract fun play() + open fun play() { + upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PLAYING) + postEvent(Bus.ALOUD_STATE, Status.PLAY) + upNotification() + } @CallSuper open fun pauseReadAloud(pause: Boolean) { diff --git a/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt b/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt index 43bca75b2..1de2f030a 100644 --- a/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt @@ -74,6 +74,7 @@ class HttpReadAloudService : BaseReadAloudService(), override fun onPrepared(mp: MediaPlayer?) { mp?.start() + super.play() } override fun onError(mp: MediaPlayer?, what: Int, extra: Int): Boolean { diff --git a/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt b/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt index eef74c2fe..8c7e75dfb 100644 --- a/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt @@ -7,7 +7,6 @@ import android.support.v4.media.session.PlaybackStateCompat import io.legado.app.R import io.legado.app.constant.AppConst import io.legado.app.constant.Bus -import io.legado.app.constant.Status import io.legado.app.help.IntentHelp import io.legado.app.utils.getPrefBoolean import io.legado.app.utils.getPrefInt @@ -67,9 +66,7 @@ class TTSReadAloudService : BaseReadAloudService(), TextToSpeech.OnInitListener return } if (requestFocus()) { - upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PLAYING) - postEvent(Bus.ALOUD_STATE, Status.PLAY) - upNotification() + super.play() for (i in nowSpeak until contentList.size) { if (i == 0) { speak(contentList[i], TextToSpeech.QUEUE_FLUSH, AppConst.APP_TAG + i) From 3abdcb83dce65ce89db4157da5f59e5c51ca8d20 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 11 Sep 2019 17:47:30 +0800 Subject: [PATCH 1449/1997] up --- .../main/java/io/legado/app/service/BaseReadAloudService.kt | 4 +++- .../main/java/io/legado/app/service/TTSReadAloudService.kt | 3 --- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt index 24f82da67..6a9feb3e4 100644 --- a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt @@ -199,6 +199,8 @@ abstract class BaseReadAloudService : BaseService(), open fun pauseReadAloud(pause: Boolean) { postEvent(Bus.ALOUD_STATE, Status.PAUSE) this.pause = pause + upNotification() + upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PAUSED) } @CallSuper @@ -341,7 +343,7 @@ abstract class BaseReadAloudService : BaseService(), /** * 更新通知 */ - fun upNotification() { + private fun upNotification() { var nTitle: String = when { pause -> getString(R.string.read_aloud_pause) timeMinute in 1..60 -> getString( diff --git a/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt b/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt index 8c7e75dfb..7f0ea7e0b 100644 --- a/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt @@ -3,7 +3,6 @@ package io.legado.app.service import android.os.Build import android.speech.tts.TextToSpeech import android.speech.tts.UtteranceProgressListener -import android.support.v4.media.session.PlaybackStateCompat import io.legado.app.R import io.legado.app.constant.AppConst import io.legado.app.constant.Bus @@ -134,8 +133,6 @@ class TTSReadAloudService : BaseReadAloudService(), TextToSpeech.OnInitListener override fun pauseReadAloud(pause: Boolean) { super.pauseReadAloud(pause) textToSpeech?.stop() - upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PAUSED) - upNotification() } /** From 24f6c66b157d4271ed158653130ddc6f57128e61 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 11 Sep 2019 17:47:57 +0800 Subject: [PATCH 1450/1997] up --- .../main/java/io/legado/app/service/BaseReadAloudService.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt index 6a9feb3e4..6164cd83c 100644 --- a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt @@ -291,7 +291,7 @@ abstract class BaseReadAloudService : BaseService(), return request == AudioManager.AUDIOFOCUS_REQUEST_GRANTED } - fun upMediaSessionPlaybackState(state: Int) { + private fun upMediaSessionPlaybackState(state: Int) { mediaSessionCompat?.setPlaybackState( PlaybackStateCompat.Builder() .setActions(MediaHelp.MEDIA_SESSION_ACTIONS) @@ -300,7 +300,6 @@ abstract class BaseReadAloudService : BaseService(), ) } - /** * 初始化MediaSession, 注册多媒体按钮 */ From c7c96f93c683288cb346a4c7dfece1849c686168 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 11 Sep 2019 19:13:28 +0800 Subject: [PATCH 1451/1997] up --- .../io/legado/app/help/PendingIntentHelp.kt | 24 ----- .../main/java/io/legado/app/help/ReadAloud.kt | 87 ++++++++++++++++ .../io/legado/app/lib/theme/ColorUtils.kt | 24 +++-- .../lib/theme/prefs/ATEEditTextPreference.kt | 4 +- .../app/lib/theme/view/ATEStrokeTextView.kt | 7 +- .../java/io/legado/app/lib/webdav/WebDav.kt | 9 +- .../app/service/BaseReadAloudService.kt | 98 ++++--------------- .../app/ui/readbook/ReadBookActivity.kt | 11 ++- .../app/ui/readbook/ReadBookViewModel.kt | 4 +- .../app/ui/readbook/config/ReadAloudDialog.kt | 15 +-- .../app/ui/widget/image/CircleImageView.kt | 3 +- 11 files changed, 144 insertions(+), 142 deletions(-) delete mode 100644 app/src/main/java/io/legado/app/help/PendingIntentHelp.kt create mode 100644 app/src/main/java/io/legado/app/help/ReadAloud.kt diff --git a/app/src/main/java/io/legado/app/help/PendingIntentHelp.kt b/app/src/main/java/io/legado/app/help/PendingIntentHelp.kt deleted file mode 100644 index 280469f3e..000000000 --- a/app/src/main/java/io/legado/app/help/PendingIntentHelp.kt +++ /dev/null @@ -1,24 +0,0 @@ -package io.legado.app.help - -import android.app.PendingIntent -import android.content.Context -import android.content.Intent -import io.legado.app.service.TTSReadAloudService -import io.legado.app.ui.readbook.ReadBookActivity - -object PendingIntentHelp { - - fun readBookActivityPendingIntent(context: Context): PendingIntent { - val intent = Intent(context, ReadBookActivity::class.java) - intent.action = "readBookActivity" - return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) - } - - fun aloudServicePendingIntent(context: Context, actionStr: String): PendingIntent { - val intent = Intent(context, TTSReadAloudService::class.java) - intent.action = actionStr - return PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) - } - - -} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/help/ReadAloud.kt b/app/src/main/java/io/legado/app/help/ReadAloud.kt new file mode 100644 index 000000000..f6794d64f --- /dev/null +++ b/app/src/main/java/io/legado/app/help/ReadAloud.kt @@ -0,0 +1,87 @@ +package io.legado.app.help + +import android.content.Context +import android.content.Intent +import io.legado.app.constant.Action +import io.legado.app.service.BaseReadAloudService +import io.legado.app.service.TTSReadAloudService + +object ReadAloud { + + + fun play( + context: Context, + title: String, + subtitle: String, + pageIndex: Int, + dataKey: String, + play: Boolean = true + ) { + val readAloudIntent = Intent(context, TTSReadAloudService::class.java) + readAloudIntent.action = Action.play + readAloudIntent.putExtra("title", title) + readAloudIntent.putExtra("subtitle", subtitle) + readAloudIntent.putExtra("pageIndex", pageIndex) + readAloudIntent.putExtra("dataKey", dataKey) + readAloudIntent.putExtra("play", play) + context.startService(readAloudIntent) + } + + fun pause(context: Context) { + if (BaseReadAloudService.isRun) { + val intent = Intent(context, TTSReadAloudService::class.java) + intent.action = Action.pause + context.startService(intent) + } + } + + fun resume(context: Context) { + if (BaseReadAloudService.isRun) { + val intent = Intent(context, TTSReadAloudService::class.java) + intent.action = Action.resume + context.startService(intent) + } + } + + fun stop(context: Context) { + if (BaseReadAloudService.isRun) { + val intent = Intent(context, TTSReadAloudService::class.java) + intent.action = Action.stop + context.startService(intent) + } + } + + fun prevParagraph(context: Context) { + if (BaseReadAloudService.isRun) { + val intent = Intent(context, TTSReadAloudService::class.java) + intent.action = Action.prevParagraph + context.startService(intent) + } + } + + fun nextParagraph(context: Context) { + if (BaseReadAloudService.isRun) { + val intent = Intent(context, TTSReadAloudService::class.java) + intent.action = Action.nextParagraph + context.startService(intent) + } + } + + fun upTtsSpeechRate(context: Context) { + if (BaseReadAloudService.isRun) { + val intent = Intent(context, TTSReadAloudService::class.java) + intent.action = Action.upTtsSpeechRate + context.startService(intent) + } + } + + fun setTimer(context: Context, minute: Int) { + if (BaseReadAloudService.isRun) { + val intent = Intent(context, TTSReadAloudService::class.java) + intent.action = Action.setTimer + intent.putExtra("minute", minute) + context.startService(intent) + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/lib/theme/ColorUtils.kt b/app/src/main/java/io/legado/app/lib/theme/ColorUtils.kt index f3942fba4..b4a17748e 100644 --- a/app/src/main/java/io/legado/app/lib/theme/ColorUtils.kt +++ b/app/src/main/java/io/legado/app/lib/theme/ColorUtils.kt @@ -116,9 +116,7 @@ object ColorUtils { } init { - if (upper <= lower) { - throw IllegalArgumentException("must be lower < upper") - } + require(upper > lower) { "must be lower < upper" } setAlpha(alpha) setLower(lower) setUpper(upper) @@ -129,10 +127,10 @@ object ColorUtils { } private fun setAlpha(alpha: Int) { - var alpha = alpha - if (alpha > 255) alpha = 255 - if (alpha < 0) alpha = 0 - this.alpha = alpha + var alpha1 = alpha + if (alpha1 > 255) alpha1 = 255 + if (alpha1 < 0) alpha1 = 0 + this.alpha = alpha1 } private fun getLower(): Int { @@ -140,9 +138,9 @@ object ColorUtils { } private fun setLower(lower: Int) { - var lower = lower - if (lower < 0) lower = 0 - this.lower = lower + var lower1 = lower + if (lower1 < 0) lower1 = 0 + this.lower = lower1 } private fun getUpper(): Int { @@ -150,9 +148,9 @@ object ColorUtils { } private fun setUpper(upper: Int) { - var upper = upper - if (upper > 255) upper = 255 - this.upper = upper + var upper1 = upper + if (upper1 > 255) upper1 = 255 + this.upper = upper1 } } } diff --git a/app/src/main/java/io/legado/app/lib/theme/prefs/ATEEditTextPreference.kt b/app/src/main/java/io/legado/app/lib/theme/prefs/ATEEditTextPreference.kt index 935aa6289..9665e8586 100644 --- a/app/src/main/java/io/legado/app/lib/theme/prefs/ATEEditTextPreference.kt +++ b/app/src/main/java/io/legado/app/lib/theme/prefs/ATEEditTextPreference.kt @@ -92,9 +92,7 @@ class ATEEditTextPreference(context: Context?, attrs: AttributeSet?) : EditTextP protected fun onBindDialogView(view: View) { editText = view.findViewById(android.R.id.edit) - if (editText == null) { - throw IllegalStateException("Dialog view must contain an EditText with id" + " @android:id/edit") - } + checkNotNull(editText) { "Dialog view must contain an EditText with id" + " @android:id/edit" } view.findViewById(android.R.id.message).visibility = View.GONE diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATEStrokeTextView.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATEStrokeTextView.kt index 3efb796f9..d113321d9 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATEStrokeTextView.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATEStrokeTextView.kt @@ -7,6 +7,7 @@ import io.legado.app.R import io.legado.app.lib.theme.Selector import io.legado.app.lib.theme.ThemeStore import io.legado.app.utils.dp +import io.legado.app.utils.getCompatColor class ATEStrokeTextView(context: Context, attrs: AttributeSet) : AppCompatTextView(context, attrs) { @@ -14,16 +15,16 @@ class ATEStrokeTextView(context: Context, attrs: AttributeSet) : AppCompatTextVi background = Selector.shapeBuild() .setCornerRadius(1.dp) .setStrokeWidth(1.dp) - .setDisabledStrokeColor(context.resources.getColor(R.color.md_grey_500)) + .setDisabledStrokeColor(context.getCompatColor(R.color.md_grey_500)) .setDefaultStrokeColor(ThemeStore.textColorSecondary(context)) .setSelectedStrokeColor(ThemeStore.accentColor(context)) - .setPressedBgColor(context.resources.getColor(R.color.transparent30)) + .setPressedBgColor(context.getCompatColor(R.color.transparent30)) .create() setTextColor( Selector.colorBuild() .setDefaultColor(ThemeStore.textColorSecondary(context)) .setSelectedColor(ThemeStore.accentColor(context)) - .setDisabledColor(context.resources.getColor(R.color.md_grey_500)) + .setDisabledColor(context.getCompatColor(R.color.md_grey_500)) .create() ) } diff --git a/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt b/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt index ec1dc573e..d7419aebf 100644 --- a/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt +++ b/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt @@ -6,7 +6,8 @@ import io.legado.app.lib.webdav.http.HttpAuth import okhttp3.Credentials import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.Request -import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.asRequestBody +import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.Response import org.jsoup.Jsoup import java.io.File @@ -132,11 +133,11 @@ constructor(url: String) { .url(url) // 添加RequestBody对象,可以只返回的属性。如果设为null,则会返回全部属性 // 注意:尽量手动指定需要返回的属性。若返回全部属性,可能后由于Prop.java里没有该属性名,而崩溃。 - .method("PROPFIND", RequestBody.create("text/plain".toMediaTypeOrNull(), requestPropsStr)) + .method("PROPFIND", requestPropsStr.toRequestBody("text/plain".toMediaTypeOrNull())) HttpAuth.auth?.let { request.header("Authorization", Credentials.basic(it.user, it.pass)) } - request.header("Depth", if (depth < 0) "infinity" else Integer.toString(depth)) + request.header("Depth", if (depth < 0) "infinity" else depth.toString()) return okHttpClient.newCall(request.build()).execute() } @@ -212,7 +213,7 @@ constructor(url: String) { if (!file.exists()) return false val mediaType = contentType?.toMediaTypeOrNull() // 务必注意RequestBody不要嵌套,不然上传时内容可能会被追加多余的文件信息 - val fileBody = RequestBody.create(mediaType, file) + val fileBody = file.asRequestBody(mediaType) getUrl()?.let { val request = Request.Builder() .url(it) diff --git a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt index 6164cd83c..b41fa1c54 100644 --- a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt @@ -19,8 +19,8 @@ import io.legado.app.constant.Bus import io.legado.app.constant.Status import io.legado.app.help.IntentDataHelp import io.legado.app.help.MediaHelp -import io.legado.app.help.PendingIntentHelp import io.legado.app.receiver.MediaButtonReceiver +import io.legado.app.ui.readbook.ReadBookActivity import io.legado.app.ui.widget.page.TextChapter import io.legado.app.utils.getPrefBoolean import io.legado.app.utils.postEvent @@ -32,80 +32,6 @@ abstract class BaseReadAloudService : BaseService(), var isRun = false var timeMinute: Int = 0 - fun play( - context: Context, - title: String, - subtitle: String, - pageIndex: Int, - dataKey: String, - play: Boolean = true - ) { - val readAloudIntent = Intent(context, TTSReadAloudService::class.java) - readAloudIntent.action = Action.play - readAloudIntent.putExtra("title", title) - readAloudIntent.putExtra("subtitle", subtitle) - readAloudIntent.putExtra("pageIndex", pageIndex) - readAloudIntent.putExtra("dataKey", dataKey) - readAloudIntent.putExtra("play", play) - context.startService(readAloudIntent) - } - - fun pause(context: Context) { - if (isRun) { - val intent = Intent(context, TTSReadAloudService::class.java) - intent.action = Action.pause - context.startService(intent) - } - } - - fun resume(context: Context) { - if (isRun) { - val intent = Intent(context, TTSReadAloudService::class.java) - intent.action = Action.resume - context.startService(intent) - } - } - - fun stop(context: Context) { - if (isRun) { - val intent = Intent(context, TTSReadAloudService::class.java) - intent.action = Action.stop - context.startService(intent) - } - } - - fun prevParagraph(context: Context) { - if (isRun) { - val intent = Intent(context, TTSReadAloudService::class.java) - intent.action = Action.prevParagraph - context.startService(intent) - } - } - - fun nextParagraph(context: Context) { - if (isRun) { - val intent = Intent(context, TTSReadAloudService::class.java) - intent.action = Action.nextParagraph - context.startService(intent) - } - } - - fun upTtsSpeechRate(context: Context) { - if (isRun) { - val intent = Intent(context, TTSReadAloudService::class.java) - intent.action = Action.upTtsSpeechRate - context.startService(intent) - } - } - - fun setTimer(context: Context, minute: Int) { - if (isRun) { - val intent = Intent(context, TTSReadAloudService::class.java) - intent.action = Action.setTimer - intent.putExtra("minute", minute) - context.startService(intent) - } - } } private val handler = Handler() @@ -361,29 +287,29 @@ abstract class BaseReadAloudService : BaseService(), .setOngoing(true) .setContentTitle(nTitle) .setContentText(nSubtitle) - .setContentIntent(PendingIntentHelp.readBookActivityPendingIntent(this)) + .setContentIntent(readBookActivityPendingIntent(this)) if (pause) { builder.addAction( R.drawable.ic_play_24dp, getString(R.string.resume), - PendingIntentHelp.aloudServicePendingIntent(this, Action.resume) + aloudServicePendingIntent(this, Action.resume) ) } else { builder.addAction( R.drawable.ic_pause_24dp, getString(R.string.pause), - PendingIntentHelp.aloudServicePendingIntent(this, Action.pause) + aloudServicePendingIntent(this, Action.pause) ) } builder.addAction( R.drawable.ic_stop_black_24dp, getString(R.string.stop), - PendingIntentHelp.aloudServicePendingIntent(this, Action.stop) + aloudServicePendingIntent(this, Action.stop) ) builder.addAction( R.drawable.ic_time_add_24dp, getString(R.string.set_timer), - PendingIntentHelp.aloudServicePendingIntent(this, Action.addTimer) + aloudServicePendingIntent(this, Action.addTimer) ) builder.setStyle( androidx.media.app.NotificationCompat.MediaStyle() @@ -394,4 +320,16 @@ abstract class BaseReadAloudService : BaseService(), val notification = builder.build() startForeground(112201, notification) } + + fun readBookActivityPendingIntent(context: Context): PendingIntent { + val intent = Intent(context, ReadBookActivity::class.java) + intent.action = "readBookActivity" + return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) + } + + fun aloudServicePendingIntent(context: Context, actionStr: String): PendingIntent { + val intent = Intent(context, TTSReadAloudService::class.java) + intent.action = actionStr + return PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index a6da939f5..e8652e0a3 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -20,6 +20,7 @@ import io.legado.app.constant.Status import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter import io.legado.app.help.IntentDataHelp +import io.legado.app.help.ReadAloud import io.legado.app.help.ReadBookConfig import io.legado.app.lib.dialogs.alert import io.legado.app.lib.dialogs.noButton @@ -190,7 +191,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea when (keyCode) { KeyEvent.KEYCODE_BACK -> { if (readAloudStatus == Status.PLAY) { - BaseReadAloudService.pause(this) + ReadAloud.pause(this) toast(R.string.read_aloud_pause) return true } @@ -450,8 +451,8 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } when (readAloudStatus) { Status.STOP -> readAloud() - Status.PLAY -> BaseReadAloudService.pause(this) - Status.PAUSE -> BaseReadAloudService.resume(this) + Status.PLAY -> ReadAloud.pause(this) + Status.PAUSE -> ReadAloud.resume(this) } } @@ -464,7 +465,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea if (book != null && textChapter != null) { val key = System.currentTimeMillis().toString() IntentDataHelp.putData(key, textChapter) - BaseReadAloudService.play( + ReadAloud.play( this, book.name, textChapter.title, viewModel.durPageIndex, key, play ) @@ -569,7 +570,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea page_view.upContent() viewModel.saveRead() } - 2 -> if (!moveToNextChapter()) BaseReadAloudService.stop(this) + 2 -> if (!moveToNextChapter()) ReadAloud.stop(this) -1 -> { if (viewModel.durPageIndex > 0) { viewModel.durPageIndex = viewModel.durPageIndex - 1 diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt index 14ecccba4..0dcdeef47 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt @@ -10,8 +10,8 @@ import io.legado.app.constant.BookType import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter import io.legado.app.help.BookHelp +import io.legado.app.help.ReadAloud import io.legado.app.model.WebBook -import io.legado.app.service.BaseReadAloudService import io.legado.app.ui.widget.page.TextChapter import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.Main @@ -332,7 +332,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { override fun onCleared() { super.onCleared() - BaseReadAloudService.stop(context) + ReadAloud.stop(context) } interface CallBack { diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt index 846d6ff15..31f07a645 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt @@ -11,6 +11,7 @@ import androidx.fragment.app.DialogFragment import io.legado.app.R import io.legado.app.constant.Bus import io.legado.app.constant.Status +import io.legado.app.help.ReadAloud import io.legado.app.service.BaseReadAloudService import io.legado.app.ui.readbook.Help import io.legado.app.utils.* @@ -104,7 +105,7 @@ class ReadAloudDialog : DialogFragment() { override fun onStartTrackingTouch(seekBar: SeekBar?) = Unit override fun onStopTrackingTouch(seekBar: SeekBar?) { - BaseReadAloudService.setTimer(requireContext(), seek_timer.progress) + ReadAloud.setTimer(requireContext(), seek_timer.progress) } }) } @@ -112,11 +113,11 @@ class ReadAloudDialog : DialogFragment() { private fun initOnClick() { iv_menu.onClick { callBack?.showMenu(); dismiss() } iv_menu.onLongClick { callBack?.openChapterList(); true } - iv_stop.onClick { BaseReadAloudService.stop(requireContext()); dismiss() } + iv_stop.onClick { ReadAloud.stop(requireContext()); dismiss() } iv_play_pause.onClick { postEvent(Bus.READ_ALOUD_BUTTON, true) } - iv_play_prev.onClick { BaseReadAloudService.prevParagraph(requireContext()) } + iv_play_prev.onClick { ReadAloud.prevParagraph(requireContext()) } iv_play_prev.onLongClick { postEvent(Bus.TTS_TURN_PAGE, -2); true } - iv_play_next.onClick { BaseReadAloudService.nextParagraph(requireContext()) } + iv_play_next.onClick { ReadAloud.nextParagraph(requireContext()) } iv_play_next.onLongClick { postEvent(Bus.TTS_TURN_PAGE, 2); true } } @@ -129,10 +130,10 @@ class ReadAloudDialog : DialogFragment() { } private fun upTtsSpeechRate() { - BaseReadAloudService.upTtsSpeechRate(requireContext()) + ReadAloud.upTtsSpeechRate(requireContext()) if (callBack?.readAloudStatus == Status.PLAY) { - BaseReadAloudService.pause(requireContext()) - BaseReadAloudService.resume(requireContext()) + ReadAloud.pause(requireContext()) + ReadAloud.resume(requireContext()) } } diff --git a/app/src/main/java/io/legado/app/ui/widget/image/CircleImageView.kt b/app/src/main/java/io/legado/app/ui/widget/image/CircleImageView.kt index 965236486..31a23f623 100644 --- a/app/src/main/java/io/legado/app/ui/widget/image/CircleImageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/image/CircleImageView.kt @@ -18,6 +18,7 @@ import androidx.annotation.DrawableRes import androidx.annotation.RequiresApi import androidx.appcompat.widget.AppCompatImageView import io.legado.app.R +import io.legado.app.utils.getCompatColor import kotlin.math.min import kotlin.math.pow @@ -190,7 +191,7 @@ class CircleImageView : AppCompatImageView { } fun setCircleBackgroundColorResource(@ColorRes circleBackgroundRes: Int) { - circleBackgroundColor = context.resources.getColor(circleBackgroundRes) + circleBackgroundColor = context.getCompatColor(circleBackgroundRes) } override fun setImageBitmap(bm: Bitmap) { From fd3192e2abdb921c5a02d666e1bbdb25aec77662 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 11 Sep 2019 19:16:47 +0800 Subject: [PATCH 1452/1997] up --- .../java/io/legado/app/service/BaseReadAloudService.kt | 9 +++------ .../java/io/legado/app/service/HttpReadAloudService.kt | 9 +++++++++ .../java/io/legado/app/service/TTSReadAloudService.kt | 9 +++++++++ 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt index b41fa1c54..c4a0f23e4 100644 --- a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt @@ -321,15 +321,12 @@ abstract class BaseReadAloudService : BaseService(), startForeground(112201, notification) } - fun readBookActivityPendingIntent(context: Context): PendingIntent { + private fun readBookActivityPendingIntent(context: Context): PendingIntent { val intent = Intent(context, ReadBookActivity::class.java) intent.action = "readBookActivity" return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) } - fun aloudServicePendingIntent(context: Context, actionStr: String): PendingIntent { - val intent = Intent(context, TTSReadAloudService::class.java) - intent.action = actionStr - return PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) - } + abstract fun aloudServicePendingIntent(context: Context, actionStr: String): PendingIntent + } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt b/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt index 1de2f030a..2d8b15820 100644 --- a/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt @@ -1,5 +1,8 @@ package io.legado.app.service +import android.app.PendingIntent +import android.content.Context +import android.content.Intent import android.media.MediaPlayer import io.legado.app.constant.Bus import io.legado.app.utils.postEvent @@ -90,4 +93,10 @@ class HttpReadAloudService : BaseReadAloudService(), postEvent(Bus.TTS_TURN_PAGE, 2) } } + + override fun aloudServicePendingIntent(context: Context, actionStr: String): PendingIntent { + val intent = Intent(context, HttpReadAloudService::class.java) + intent.action = actionStr + return PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt b/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt index 7f0ea7e0b..1b9078371 100644 --- a/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt @@ -1,5 +1,8 @@ package io.legado.app.service +import android.app.PendingIntent +import android.content.Context +import android.content.Intent import android.os.Build import android.speech.tts.TextToSpeech import android.speech.tts.UtteranceProgressListener @@ -185,4 +188,10 @@ class TTSReadAloudService : BaseReadAloudService(), TextToSpeech.OnInitListener } + override fun aloudServicePendingIntent(context: Context, actionStr: String): PendingIntent { + val intent = Intent(context, TTSReadAloudService::class.java) + intent.action = actionStr + return PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) + } + } \ No newline at end of file From 9b3ae994bd400c7827e065b73acd1ca112091629 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 11 Sep 2019 19:28:01 +0800 Subject: [PATCH 1453/1997] up --- .../main/java/io/legado/app/help/ReadAloud.kt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/ReadAloud.kt b/app/src/main/java/io/legado/app/help/ReadAloud.kt index f6794d64f..91fda2522 100644 --- a/app/src/main/java/io/legado/app/help/ReadAloud.kt +++ b/app/src/main/java/io/legado/app/help/ReadAloud.kt @@ -7,7 +7,7 @@ import io.legado.app.service.BaseReadAloudService import io.legado.app.service.TTSReadAloudService object ReadAloud { - + var aloudClass = TTSReadAloudService::class.java fun play( context: Context, @@ -17,7 +17,7 @@ object ReadAloud { dataKey: String, play: Boolean = true ) { - val readAloudIntent = Intent(context, TTSReadAloudService::class.java) + val readAloudIntent = Intent(context, aloudClass) readAloudIntent.action = Action.play readAloudIntent.putExtra("title", title) readAloudIntent.putExtra("subtitle", subtitle) @@ -29,7 +29,7 @@ object ReadAloud { fun pause(context: Context) { if (BaseReadAloudService.isRun) { - val intent = Intent(context, TTSReadAloudService::class.java) + val intent = Intent(context, aloudClass) intent.action = Action.pause context.startService(intent) } @@ -37,7 +37,7 @@ object ReadAloud { fun resume(context: Context) { if (BaseReadAloudService.isRun) { - val intent = Intent(context, TTSReadAloudService::class.java) + val intent = Intent(context, aloudClass) intent.action = Action.resume context.startService(intent) } @@ -45,7 +45,7 @@ object ReadAloud { fun stop(context: Context) { if (BaseReadAloudService.isRun) { - val intent = Intent(context, TTSReadAloudService::class.java) + val intent = Intent(context, aloudClass) intent.action = Action.stop context.startService(intent) } @@ -53,7 +53,7 @@ object ReadAloud { fun prevParagraph(context: Context) { if (BaseReadAloudService.isRun) { - val intent = Intent(context, TTSReadAloudService::class.java) + val intent = Intent(context, aloudClass) intent.action = Action.prevParagraph context.startService(intent) } @@ -61,7 +61,7 @@ object ReadAloud { fun nextParagraph(context: Context) { if (BaseReadAloudService.isRun) { - val intent = Intent(context, TTSReadAloudService::class.java) + val intent = Intent(context, aloudClass) intent.action = Action.nextParagraph context.startService(intent) } @@ -69,7 +69,7 @@ object ReadAloud { fun upTtsSpeechRate(context: Context) { if (BaseReadAloudService.isRun) { - val intent = Intent(context, TTSReadAloudService::class.java) + val intent = Intent(context, aloudClass) intent.action = Action.upTtsSpeechRate context.startService(intent) } @@ -77,7 +77,7 @@ object ReadAloud { fun setTimer(context: Context, minute: Int) { if (BaseReadAloudService.isRun) { - val intent = Intent(context, TTSReadAloudService::class.java) + val intent = Intent(context, aloudClass) intent.action = Action.setTimer intent.putExtra("minute", minute) context.startService(intent) From d85db50d03f8fc0bc3f8ee63b32d3fdd2035d0cd Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 11 Sep 2019 19:39:22 +0800 Subject: [PATCH 1454/1997] up --- app/src/main/java/io/legado/app/help/ReadAloud.kt | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/help/ReadAloud.kt b/app/src/main/java/io/legado/app/help/ReadAloud.kt index 91fda2522..5be1bd764 100644 --- a/app/src/main/java/io/legado/app/help/ReadAloud.kt +++ b/app/src/main/java/io/legado/app/help/ReadAloud.kt @@ -2,12 +2,23 @@ package io.legado.app.help import android.content.Context import android.content.Intent +import io.legado.app.App import io.legado.app.constant.Action import io.legado.app.service.BaseReadAloudService +import io.legado.app.service.HttpReadAloudService import io.legado.app.service.TTSReadAloudService +import io.legado.app.utils.getPrefBoolean object ReadAloud { - var aloudClass = TTSReadAloudService::class.java + var aloudClass: Class<*> = getReadAloudClass() + + fun getReadAloudClass(): Class<*> { + return if (App.INSTANCE.getPrefBoolean("tts", true)) { + TTSReadAloudService::class.java + } else { + HttpReadAloudService::class.java + } + } fun play( context: Context, From 2a9d537b6e458a774309fcb314d0d5966606d9c7 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 11 Sep 2019 21:07:33 +0800 Subject: [PATCH 1455/1997] up --- .../app/ui/readbook/ReadBookActivity.kt | 6 +- .../io/legado/app/ui/readbook/ReadMenu.kt | 7 +- .../ui/readbook/config/MoreConfigDialog.kt | 39 ++++++++ .../readbook/config/ReadAloudConfigDialog.kt | 92 +++++++++++++++++++ .../app/ui/readbook/config/ReadAloudDialog.kt | 10 +- .../readbook/config/ReadPreferenceFragment.kt | 41 --------- app/src/main/res/layout/dialog_read_aloud.xml | 39 +++++--- app/src/main/res/values/strings.xml | 3 +- app/src/main/res/xml/pref_config_aloud.xml | 12 +++ 9 files changed, 183 insertions(+), 66 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudConfigDialog.kt delete mode 100644 app/src/main/java/io/legado/app/ui/readbook/config/ReadPreferenceFragment.kt create mode 100644 app/src/main/res/xml/pref_config_aloud.xml diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt index e8652e0a3..448f1cbe3 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt @@ -402,12 +402,16 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea override fun clickCenter() { if (readAloudStatus != Status.STOP) { - ReadAloudDialog().show(supportFragmentManager, "readAloud") + showReadAloudDialog() } else { read_menu.runMenuIn() } } + override fun showReadAloudDialog() { + ReadAloudDialog().show(supportFragmentManager, "readAloud") + } + override fun autoPage() { } diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt index 2d42e0d70..b0b79603e 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt @@ -16,6 +16,7 @@ import io.legado.app.lib.theme.buttonDisabledColor import io.legado.app.utils.* import kotlinx.android.synthetic.main.view_read_menu.view.* import org.jetbrains.anko.sdk27.listeners.onClick +import org.jetbrains.anko.sdk27.listeners.onLongClick class ReadMenu : FrameLayout { var cnaShowMenu: Boolean = false @@ -170,7 +171,10 @@ class ReadMenu : FrameLayout { postEvent(Bus.READ_ALOUD_BUTTON, true) } } - + ll_read_aloud.onLongClick { + runMenuOut { callBack?.showReadAloudDialog() } + true + } //界面 ll_font.onClick { runMenuOut { @@ -252,6 +256,7 @@ class ReadMenu : FrameLayout { fun openChapterList() fun showReadStyle() fun showMoreSetting() + fun showReadAloudDialog() fun upSystemUiVisibility() } diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt index 3e1652645..ba7aca78f 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt @@ -1,5 +1,6 @@ package io.legado.app.ui.readbook.config +import android.content.SharedPreferences import android.os.Bundle import android.util.DisplayMetrics import android.view.Gravity @@ -8,8 +9,12 @@ import android.view.View import android.view.ViewGroup import android.widget.LinearLayout import androidx.fragment.app.DialogFragment +import androidx.preference.PreferenceFragmentCompat import io.legado.app.R +import io.legado.app.constant.Bus +import io.legado.app.lib.theme.ATH import io.legado.app.ui.readbook.Help +import io.legado.app.utils.postEvent class MoreConfigDialog : DialogFragment() { @@ -53,4 +58,38 @@ class MoreConfigDialog : DialogFragment() { .replace(view.id, preferenceFragment, readPreferTag) .commit() } + + class ReadPreferenceFragment : PreferenceFragmentCompat(), + SharedPreferences.OnSharedPreferenceChangeListener { + + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + addPreferencesFromResource(R.xml.pref_config_read) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + ATH.applyEdgeEffectColor(listView) + } + + override fun onResume() { + super.onResume() + preferenceManager.sharedPreferences.registerOnSharedPreferenceChangeListener(this) + } + + override fun onPause() { + preferenceManager.sharedPreferences.unregisterOnSharedPreferenceChangeListener(this) + super.onPause() + } + + override fun onSharedPreferenceChanged( + sharedPreferences: SharedPreferences?, + key: String? + ) { + when (key) { + "hideStatusBar" -> postEvent(Bus.UP_CONFIG, true) + "hideNavigationBar" -> postEvent(Bus.UP_CONFIG, true) + } + } + + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudConfigDialog.kt new file mode 100644 index 000000000..a56c1572c --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudConfigDialog.kt @@ -0,0 +1,92 @@ +package io.legado.app.ui.readbook.config + +import android.content.SharedPreferences +import android.os.Bundle +import android.util.DisplayMetrics +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.LinearLayout +import androidx.fragment.app.DialogFragment +import androidx.preference.PreferenceFragmentCompat +import io.legado.app.R +import io.legado.app.constant.Bus +import io.legado.app.lib.theme.ATH +import io.legado.app.ui.readbook.Help +import io.legado.app.utils.postEvent + +class ReadAloudConfigDialog : DialogFragment() { + private val readAloudPreferTag = "readAloudPreferTag" + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + val view = LinearLayout(context) + view.setBackgroundResource(R.color.background) + view.id = R.id.tag1 + container?.addView(view) + return view + } + + override fun onStart() { + super.onStart() + val dm = DisplayMetrics() + activity?.let { + Help.upSystemUiVisibility(it) + it.windowManager?.defaultDisplay?.getMetrics(dm) + } + dialog?.window?.let { + it.setBackgroundDrawableResource(R.color.transparent) + it.decorView.setPadding(0, 0, 0, 0) + val attr = it.attributes + attr.dimAmount = 0.0f + it.attributes = attr + it.setLayout((dm.widthPixels * 0.9).toInt(), ViewGroup.LayoutParams.WRAP_CONTENT) + } + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + var preferenceFragment = childFragmentManager.findFragmentByTag(readAloudPreferTag) + if (preferenceFragment == null) preferenceFragment = ReadAloudPreferenceFragment() + childFragmentManager.beginTransaction() + .replace(view.id, preferenceFragment, readAloudPreferTag) + .commit() + } + + class ReadAloudPreferenceFragment : PreferenceFragmentCompat(), + SharedPreferences.OnSharedPreferenceChangeListener { + + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + addPreferencesFromResource(R.xml.pref_config_aloud) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + ATH.applyEdgeEffectColor(listView) + } + + override fun onResume() { + super.onResume() + preferenceManager.sharedPreferences.registerOnSharedPreferenceChangeListener(this) + } + + override fun onPause() { + preferenceManager.sharedPreferences.unregisterOnSharedPreferenceChangeListener(this) + super.onPause() + } + + override fun onSharedPreferenceChanged( + sharedPreferences: SharedPreferences?, + key: String? + ) { + when (key) { + "readAloudByPage" -> postEvent(Bus.READ_ALOUD_BUTTON, false) + + } + } + + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt index 31f07a645..90f2d9415 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt @@ -65,19 +65,12 @@ class ReadAloudDialog : DialogFragment() { seek_timer.progress = BaseReadAloudService.timeMinute tv_timer.text = requireContext().getString(R.string.timer_m, BaseReadAloudService.timeMinute) - cb_by_page.isChecked = requireContext().getPrefBoolean("readAloudByPage") cb_tts_follow_sys.isChecked = requireContext().getPrefBoolean("ttsFollowSys", true) seek_tts_SpeechRate.isEnabled = !cb_tts_follow_sys.isChecked seek_tts_SpeechRate.progress = requireContext().getPrefInt("ttsSpeechRate", 5) } private fun initOnChange() { - cb_by_page.setOnCheckedChangeListener { buttonView, isChecked -> - if (buttonView.isPressed) { - requireContext().putPrefBoolean("readAloudByPage", isChecked) - postEvent(Bus.READ_ALOUD_BUTTON, false) - } - } cb_tts_follow_sys.setOnCheckedChangeListener { buttonView, isChecked -> if (buttonView.isPressed) { requireContext().putPrefBoolean("ttsFollowSys", isChecked) @@ -112,6 +105,9 @@ class ReadAloudDialog : DialogFragment() { private fun initOnClick() { iv_menu.onClick { callBack?.showMenu(); dismiss() } + iv_other_config.onClick { + ReadAloudConfigDialog().show(childFragmentManager, "readAloudConfigDialog") + } iv_menu.onLongClick { callBack?.openChapterList(); true } iv_stop.onClick { ReadAloud.stop(requireContext()); dismiss() } iv_play_pause.onClick { postEvent(Bus.READ_ALOUD_BUTTON, true) } diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadPreferenceFragment.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadPreferenceFragment.kt deleted file mode 100644 index 47b27bf33..000000000 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadPreferenceFragment.kt +++ /dev/null @@ -1,41 +0,0 @@ -package io.legado.app.ui.readbook.config - -import android.content.SharedPreferences -import android.os.Bundle -import android.view.View -import androidx.preference.PreferenceFragmentCompat -import io.legado.app.R -import io.legado.app.constant.Bus -import io.legado.app.lib.theme.ATH -import io.legado.app.utils.postEvent - -class ReadPreferenceFragment : PreferenceFragmentCompat(), - SharedPreferences.OnSharedPreferenceChangeListener { - - override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - addPreferencesFromResource(R.xml.pref_config_read) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - ATH.applyEdgeEffectColor(listView) - } - - override fun onResume() { - super.onResume() - preferenceManager.sharedPreferences.registerOnSharedPreferenceChangeListener(this) - } - - override fun onPause() { - preferenceManager.sharedPreferences.unregisterOnSharedPreferenceChangeListener(this) - super.onPause() - } - - override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { - when (key) { - "hideStatusBar" -> postEvent(Bus.UP_CONFIG, true) - "hideNavigationBar" -> postEvent(Bus.UP_CONFIG, true) - } - } - -} \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_read_aloud.xml b/app/src/main/res/layout/dialog_read_aloud.xml index 68c0282e4..c1816be96 100644 --- a/app/src/main/res/layout/dialog_read_aloud.xml +++ b/app/src/main/res/layout/dialog_read_aloud.xml @@ -1,10 +1,10 @@ - @@ -29,43 +30,47 @@ android:layout_height="1dp" android:layout_weight="1" /> - - - - @@ -74,21 +79,25 @@ android:layout_height="1dp" android:layout_weight="1" /> - + + android:padding="8dp"> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b4a44b681..d0000ebfb 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -487,7 +487,7 @@ %d%% %d分钟 自动亮度%s - 按页 + 按页朗读 背景图片 背景颜色 文字颜色 @@ -499,5 +499,6 @@ 分组 启用所选 禁用所选 + TTS diff --git a/app/src/main/res/xml/pref_config_aloud.xml b/app/src/main/res/xml/pref_config_aloud.xml new file mode 100644 index 000000000..638cb16c5 --- /dev/null +++ b/app/src/main/res/xml/pref_config_aloud.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file From 9e488031ea49bea1bde45691e709411f51f63510 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 11 Sep 2019 21:17:14 +0800 Subject: [PATCH 1456/1997] up --- .../io/legado/app/ui/readbook/config/ReadAloudConfigDialog.kt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudConfigDialog.kt index a56c1572c..f0358aeed 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudConfigDialog.kt @@ -39,10 +39,6 @@ class ReadAloudConfigDialog : DialogFragment() { } dialog?.window?.let { it.setBackgroundDrawableResource(R.color.transparent) - it.decorView.setPadding(0, 0, 0, 0) - val attr = it.attributes - attr.dimAmount = 0.0f - it.attributes = attr it.setLayout((dm.widthPixels * 0.9).toInt(), ViewGroup.LayoutParams.WRAP_CONTENT) } } From e3aff69916388b77a16550e00e10eb62b3ffe80e Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 11 Sep 2019 21:26:43 +0800 Subject: [PATCH 1457/1997] up --- app/src/main/java/io/legado/app/help/ReadAloud.kt | 6 +++--- .../app/ui/readbook/config/ReadAloudConfigDialog.kt | 13 +++++++++++-- app/src/main/res/values/strings.xml | 1 + app/src/main/res/xml/pref_config_aloud.xml | 6 ++++++ 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/ReadAloud.kt b/app/src/main/java/io/legado/app/help/ReadAloud.kt index 5be1bd764..9dd52c9a4 100644 --- a/app/src/main/java/io/legado/app/help/ReadAloud.kt +++ b/app/src/main/java/io/legado/app/help/ReadAloud.kt @@ -13,10 +13,10 @@ object ReadAloud { var aloudClass: Class<*> = getReadAloudClass() fun getReadAloudClass(): Class<*> { - return if (App.INSTANCE.getPrefBoolean("tts", true)) { - TTSReadAloudService::class.java - } else { + return if (App.INSTANCE.getPrefBoolean("readAloudOnLine")) { HttpReadAloudService::class.java + } else { + TTSReadAloudService::class.java } } diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudConfigDialog.kt index f0358aeed..377ad0242 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudConfigDialog.kt @@ -11,7 +11,9 @@ import androidx.fragment.app.DialogFragment import androidx.preference.PreferenceFragmentCompat import io.legado.app.R import io.legado.app.constant.Bus +import io.legado.app.help.ReadAloud import io.legado.app.lib.theme.ATH +import io.legado.app.service.BaseReadAloudService import io.legado.app.ui.readbook.Help import io.legado.app.utils.postEvent @@ -79,8 +81,15 @@ class ReadAloudConfigDialog : DialogFragment() { key: String? ) { when (key) { - "readAloudByPage" -> postEvent(Bus.READ_ALOUD_BUTTON, false) - + "readAloudByPage" -> { + if (BaseReadAloudService.isRun) { + postEvent(Bus.READ_ALOUD_BUTTON, false) + } + } + "readAloudOnLine" -> { + ReadAloud.stop(requireContext()) + ReadAloud.aloudClass = ReadAloud.getReadAloudClass() + } } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d0000ebfb..d482ba1f6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -488,6 +488,7 @@ %d分钟 自动亮度%s 按页朗读 + 在线朗读 背景图片 背景颜色 文字颜色 diff --git a/app/src/main/res/xml/pref_config_aloud.xml b/app/src/main/res/xml/pref_config_aloud.xml index 638cb16c5..8fb8ef925 100644 --- a/app/src/main/res/xml/pref_config_aloud.xml +++ b/app/src/main/res/xml/pref_config_aloud.xml @@ -8,5 +8,11 @@ android:key="readAloudByPage" app:iconSpaceReserved="false" /> + + \ No newline at end of file From 70816de12870d7bf4097fa31a9dd377b0d2fa5d2 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 11 Sep 2019 21:33:13 +0800 Subject: [PATCH 1458/1997] up --- .../io/legado/app/ui/readbook/config/ReadAloudDialog.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt index 90f2d9415..dc5d26350 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt @@ -118,10 +118,10 @@ class ReadAloudDialog : DialogFragment() { } private fun upPlayState(state: Int) { - if (state == Status.PAUSE) { - iv_play_pause.setImageResource(R.drawable.ic_play_24dp) - } else { + if (state == Status.PLAY) { iv_play_pause.setImageResource(R.drawable.ic_pause_24dp) + } else { + iv_play_pause.setImageResource(R.drawable.ic_play_24dp) } } From 6cd6fbbf4ab59bf7aa541a480ab8444453e98bb1 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 11 Sep 2019 21:50:44 +0800 Subject: [PATCH 1459/1997] up --- .../java/io/legado/app/service/HttpReadAloudService.kt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt b/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt index 2d8b15820..d590ab23d 100644 --- a/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt @@ -76,8 +76,15 @@ class HttpReadAloudService : BaseReadAloudService(), } override fun onPrepared(mp: MediaPlayer?) { - mp?.start() super.play() + mp?.start() + textChapter?.let { + if (readAloudNumber + 1 > it.getReadLength(pageIndex + 1)) { + pageIndex++ + postEvent(Bus.TTS_TURN_PAGE, 1) + } + } + postEvent(Bus.TTS_START, readAloudNumber + 1) } override fun onError(mp: MediaPlayer?, what: Int, extra: Int): Boolean { @@ -86,6 +93,7 @@ class HttpReadAloudService : BaseReadAloudService(), } override fun onCompletion(mp: MediaPlayer?) { + readAloudNumber += contentList[nowSpeak].length + 1 if (nowSpeak < contentList.size) { nowSpeak++ play() From 0ca3931b188524c5a82248910b95a7668a254257 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 11 Sep 2019 23:20:50 +0800 Subject: [PATCH 1460/1997] up --- .../app/service/HttpReadAloudService.kt | 5 ++++- app/src/main/res/values/arrays.xml | 22 +++++++++++++++++++ app/src/main/res/xml/pref_config_aloud.xml | 6 +++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt b/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt index d590ab23d..2cae122be 100644 --- a/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt @@ -5,6 +5,7 @@ import android.content.Context import android.content.Intent import android.media.MediaPlayer import io.legado.app.constant.Bus +import io.legado.app.utils.getPrefInt import io.legado.app.utils.postEvent import kotlinx.coroutines.launch import org.jetbrains.anko.toast @@ -30,7 +31,9 @@ class HttpReadAloudService : BaseReadAloudService(), private fun getAudioPath(): String { val audioText = contentList[nowSpeak] - return "http://tts.baidu.com/text2audio?idx=1&tex=$audioText&cuid=baidu_speech_demo&cod=2&lan=zh&ctp=1&pdt=1&spd=4&per=6&vol=5&pit=5&_res_tag_=audio" + val spd = getPrefInt("ttsSpeechRate", 5) + 5 + val per = getPrefInt("ttsSpeechPer") + return "http://tts.baidu.com/text2audio?idx=1&tex=$audioText&cuid=baidu_speech_demo&cod=2&lan=zh&ctp=1&pdt=1&spd=$spd&per=$per&vol=5&pit=5&_res_tag_=audio" } override fun play() { diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 399afddd8..28a255b75 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -1,5 +1,27 @@ + + 普通女声 + 普通男声 + 度逍遥 + 百度丫丫 + 百度骚男 + 百度暖女 + 百度评书 + 百度主持 + + + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + + @string/layout_list @string/layout_grid3 diff --git a/app/src/main/res/xml/pref_config_aloud.xml b/app/src/main/res/xml/pref_config_aloud.xml index 8fb8ef925..afccbe028 100644 --- a/app/src/main/res/xml/pref_config_aloud.xml +++ b/app/src/main/res/xml/pref_config_aloud.xml @@ -14,5 +14,11 @@ android:key="readAloudOnLine" app:iconSpaceReserved="false" /> + \ No newline at end of file From fe10c289e9b3ff87eeccd2f31f366c973c5ddc56 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 12 Sep 2019 08:31:35 +0800 Subject: [PATCH 1461/1997] up --- .../app/service/HttpReadAloudService.kt | 5 +-- .../readbook/config/ReadAloudConfigDialog.kt | 31 ++++++++++++++++++- app/src/main/res/xml/pref_config_aloud.xml | 1 + 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt b/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt index 2cae122be..9d086e5c6 100644 --- a/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt @@ -6,6 +6,7 @@ import android.content.Intent import android.media.MediaPlayer import io.legado.app.constant.Bus import io.legado.app.utils.getPrefInt +import io.legado.app.utils.getPrefString import io.legado.app.utils.postEvent import kotlinx.coroutines.launch import org.jetbrains.anko.toast @@ -31,8 +32,8 @@ class HttpReadAloudService : BaseReadAloudService(), private fun getAudioPath(): String { val audioText = contentList[nowSpeak] - val spd = getPrefInt("ttsSpeechRate", 5) + 5 - val per = getPrefInt("ttsSpeechPer") + val spd = (getPrefInt("ttsSpeechRate", 25) + 5) / 5 + val per = getPrefString("ttsSpeechPer") ?: "0" return "http://tts.baidu.com/text2audio?idx=1&tex=$audioText&cuid=baidu_speech_demo&cod=2&lan=zh&ctp=1&pdt=1&spd=$spd&per=$per&vol=5&pit=5&_res_tag_=audio" } diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudConfigDialog.kt index 377ad0242..40661d5f4 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudConfigDialog.kt @@ -8,6 +8,8 @@ import android.view.View import android.view.ViewGroup import android.widget.LinearLayout import androidx.fragment.app.DialogFragment +import androidx.preference.ListPreference +import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat import io.legado.app.R import io.legado.app.constant.Bus @@ -15,6 +17,7 @@ import io.legado.app.help.ReadAloud import io.legado.app.lib.theme.ATH import io.legado.app.service.BaseReadAloudService import io.legado.app.ui.readbook.Help +import io.legado.app.utils.getPrefString import io.legado.app.utils.postEvent class ReadAloudConfigDialog : DialogFragment() { @@ -55,7 +58,8 @@ class ReadAloudConfigDialog : DialogFragment() { } class ReadAloudPreferenceFragment : PreferenceFragmentCompat(), - SharedPreferences.OnSharedPreferenceChangeListener { + SharedPreferences.OnSharedPreferenceChangeListener, + Preference.OnPreferenceChangeListener { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { addPreferencesFromResource(R.xml.pref_config_aloud) @@ -64,6 +68,7 @@ class ReadAloudConfigDialog : DialogFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) ATH.applyEdgeEffectColor(listView) + bindPreferenceSummaryToValue(findPreference("ttsSpeechPer")) } override fun onResume() { @@ -93,5 +98,29 @@ class ReadAloudConfigDialog : DialogFragment() { } } + override fun onPreferenceChange(preference: Preference?, newValue: Any?): Boolean { + val stringValue = newValue.toString() + + if (preference is ListPreference) { + val index = preference.findIndexOfValue(stringValue) + // Set the summary to reflect the new value. + preference.setSummary(if (index >= 0) preference.entries[index] else null) + } else { + // For all other preferences, set the summary to the value's + preference?.summary = stringValue + } + return true + } + + private fun bindPreferenceSummaryToValue(preference: Preference?) { + preference?.apply { + onPreferenceChangeListener = this@ReadAloudPreferenceFragment + onPreferenceChange( + this, + context.getPrefString(key) + ) + } + } + } } \ No newline at end of file diff --git a/app/src/main/res/xml/pref_config_aloud.xml b/app/src/main/res/xml/pref_config_aloud.xml index afccbe028..d142c526c 100644 --- a/app/src/main/res/xml/pref_config_aloud.xml +++ b/app/src/main/res/xml/pref_config_aloud.xml @@ -17,6 +17,7 @@ From 0361ed8b18304709b33c2ca48a3f8b3ef8e1a52d Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 12 Sep 2019 09:14:03 +0800 Subject: [PATCH 1462/1997] up --- .../java/io/legado/app/service/BaseReadAloudService.kt | 3 +-- .../java/io/legado/app/service/HttpReadAloudService.kt | 7 ++----- .../main/java/io/legado/app/service/TTSReadAloudService.kt | 2 ++ .../legado/app/ui/readbook/config/ReadAloudConfigDialog.kt | 6 ++++++ 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt index c4a0f23e4..e3cee17be 100644 --- a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt @@ -39,7 +39,7 @@ abstract class BaseReadAloudService : BaseService(), private lateinit var mFocusRequest: AudioFocusRequest private var broadcastReceiver: BroadcastReceiver? = null private var mediaSessionCompat: MediaSessionCompat? = null - private var pause = false + var pause = false var title: String = "" private var subtitle: String = "" val contentList = arrayListOf() @@ -203,7 +203,6 @@ abstract class BaseReadAloudService : BaseService(), * @return 音频焦点 */ fun requestFocus(): Boolean { - MediaHelp.playSilentSound(this) val request: Int = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { audioManager.requestAudioFocus(mFocusRequest) } else { diff --git a/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt b/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt index 9d086e5c6..7c40d15aa 100644 --- a/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt @@ -8,8 +8,6 @@ import io.legado.app.constant.Bus import io.legado.app.utils.getPrefInt import io.legado.app.utils.getPrefString import io.legado.app.utils.postEvent -import kotlinx.coroutines.launch -import org.jetbrains.anko.toast class HttpReadAloudService : BaseReadAloudService(), MediaPlayer.OnPreparedListener, @@ -57,7 +55,6 @@ class HttpReadAloudService : BaseReadAloudService(), } override fun upSpeechRate(reset: Boolean) { - mediaPlayer.stop() play() } @@ -81,6 +78,7 @@ class HttpReadAloudService : BaseReadAloudService(), override fun onPrepared(mp: MediaPlayer?) { super.play() + if (pause) return mp?.start() textChapter?.let { if (readAloudNumber + 1 > it.getReadLength(pageIndex + 1)) { @@ -92,8 +90,7 @@ class HttpReadAloudService : BaseReadAloudService(), } override fun onError(mp: MediaPlayer?, what: Int, extra: Int): Boolean { - launch { toast("播放出错") } - return false + return true } override fun onCompletion(mp: MediaPlayer?) { diff --git a/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt b/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt index 1b9078371..0909d16fa 100644 --- a/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt @@ -10,6 +10,7 @@ import io.legado.app.R import io.legado.app.constant.AppConst import io.legado.app.constant.Bus import io.legado.app.help.IntentHelp +import io.legado.app.help.MediaHelp import io.legado.app.utils.getPrefBoolean import io.legado.app.utils.getPrefInt import io.legado.app.utils.postEvent @@ -68,6 +69,7 @@ class TTSReadAloudService : BaseReadAloudService(), TextToSpeech.OnInitListener return } if (requestFocus()) { + MediaHelp.playSilentSound(this) super.play() for (i in nowSpeak until contentList.size) { if (i == 0) { diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudConfigDialog.kt index 40661d5f4..74ec5b18c 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudConfigDialog.kt @@ -95,6 +95,12 @@ class ReadAloudConfigDialog : DialogFragment() { ReadAloud.stop(requireContext()) ReadAloud.aloudClass = ReadAloud.getReadAloudClass() } + "ttsSpeechPer" -> { + if (BaseReadAloudService.isRun) { + ReadAloud.stop(requireContext()) + postEvent(Bus.READ_ALOUD_BUTTON, true) + } + } } } From 3582bf839ff5e5dc6b8295af8117b6f4226130df Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 12 Sep 2019 09:16:32 +0800 Subject: [PATCH 1463/1997] up --- .../legado/app/ui/readbook/config/ReadAloudConfigDialog.kt | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudConfigDialog.kt b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudConfigDialog.kt index 74ec5b18c..f0bfd6231 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudConfigDialog.kt @@ -92,15 +92,12 @@ class ReadAloudConfigDialog : DialogFragment() { } } "readAloudOnLine" -> { - ReadAloud.stop(requireContext()) - ReadAloud.aloudClass = ReadAloud.getReadAloudClass() - } - "ttsSpeechPer" -> { if (BaseReadAloudService.isRun) { ReadAloud.stop(requireContext()) - postEvent(Bus.READ_ALOUD_BUTTON, true) + ReadAloud.aloudClass = ReadAloud.getReadAloudClass() } } + "ttsSpeechPer" -> ReadAloud.upTtsSpeechRate(requireContext()) } } From 7a38869cf9de606ffe66fecb9a616c44c2d540ee Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 12 Sep 2019 09:39:39 +0800 Subject: [PATCH 1464/1997] up --- app/src/main/res/values/arrays.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 28a255b75..323b10384 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -14,12 +14,12 @@ 0 1 - 2 3 4 + 11 5 6 - 7 + 9 From 03b34d02587738f474db5978bfd674575dec6821 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 12 Sep 2019 12:34:58 +0800 Subject: [PATCH 1465/1997] up --- app/src/main/res/raw/silent_sound.mp3 | Bin 6336 -> 2160 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/app/src/main/res/raw/silent_sound.mp3 b/app/src/main/res/raw/silent_sound.mp3 index ce236a279400c386632265b9e43395e1c37e5f9f..48755f29cf26f8682d89c7bb9fa6dc9a3ebc7d4f 100644 GIT binary patch literal 2160 zcmchYc~Dd58i!A$rixes6(NYSD?~s@5W*s|gCV40Eul3Efw0LU`!>+B2Lok|?28S^ zuIwUi)qw0#0WE@{KobR8TSO>}`I?0B{@s~7_dYXc&Np+udEei2-tWu-3$`riGj4uC zKK!*f|3W~}z7Xhy5FH^#LI^@Ucey0w2O%^e<-1%L(kp}|h!YD0B7if^E_ca1`*D$wOTe zThr;>=9{7`C#bU|?Mya~hTvx|U|ESka2kAVd>)?*pGyKyuuU44xr>ZgF#RTe!64|jnQ zZ=^=YW=hhjioR=wBK11zNrMS)4dzcAB+eb`x}qERS3;hHgS{uOiNt(wbY~4PEy<6| zE)phYQp0(F?88SCh7Uog(M#1e+hG{E7)f1jADMtRWO21>c zR}cU0;j4qeV2&I`?;L$zU@`dVK*e``vt-xNE5!`4-%aeD9ZIf^9Wm~aP*OT?TGZM}V zDMq%8hHPM9a}(esoCquKPC?$|LouV-^+)yDhL(}Xj>*!wGbmr%6+;nt$jyzai@K*F zS&@Ps*d&y=VR3&O2)x)xCY3*T8>q2mQe%|yjFE@7J%X;jGP^205H6{UD;9TE~x=DxD_R`rMgb*dU}_Q@&;D7I1Mq9 zUuS2_Y0Jq(NhFD`ylHHnNGgGX-&?H8SL9B&L#)$*>RE;yHV%6$dfLDV>98#DT9%O` z2=c%-AE}XO$CDk^Jzsh+2Dzd>97_b?(^a1D+Tl#Z@Mgg@s6?YL%u}cGONbGuq#v0| z&BXm~c1jr|{PV2F>N}zlWXeB32+jScRpih(D0m}Tc{LG_?`Y_8jXvp#_>h_Ey zHXL;l&-l_pLEzPmWVs6Kz%sc?uauWc~Ow~H;qQP9Er-VY{5O6!sAA%@p+32)nHw}_dGp01{UzSS3ajZ57j@W1yy z&5kOwCt0mZT`@|9E@}3;&H(VF*Em*^*y~C%pNtaTAMUF9*uwIS&_7XJD$$RlbO(w~ z$!fXxrpwWVUea_jHX0gMbF4Ov5;ai;EGq?czMh9t#$T$Du1Z~Nea5=i?1@^e^Mt^2 z1NF0j6Yzl-Q|pzR^-Zcv9}Tg|46Wg|I!C~*iWgHflHK<|?MutcS>|5-_MTsSBeCjU zsAK!10F+250B$akzOSZ=9{xaEY685g{b{Y)`DO&>M3HvY#goXapBi`P)#S?0W1}ek z^2RS0_C{+kM+dcRYyb0?Yxoxky`<<=V;Km3{$K3>UvCk3Er_v>$si#3-T$K5KRvAo A5C8xG literal 6336 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 Cijidi From db56d367c8f2eacb37adda8d760a57c9f5a55d78 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 12 Sep 2019 15:50:18 +0800 Subject: [PATCH 1466/1997] up --- .../java/io/legado/app/model/rss/RssParser.kt | 189 ++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 app/src/main/java/io/legado/app/model/rss/RssParser.kt diff --git a/app/src/main/java/io/legado/app/model/rss/RssParser.kt b/app/src/main/java/io/legado/app/model/rss/RssParser.kt new file mode 100644 index 000000000..60fea317a --- /dev/null +++ b/app/src/main/java/io/legado/app/model/rss/RssParser.kt @@ -0,0 +1,189 @@ +package io.legado.app.model.rss + +import io.legado.app.constant.RSSKeywords +import io.legado.app.data.entities.RssArticle +import org.xmlpull.v1.XmlPullParser +import org.xmlpull.v1.XmlPullParserException +import org.xmlpull.v1.XmlPullParserFactory +import java.io.IOException +import java.io.StringReader + +object CoreXMLParser { + + @Throws(XmlPullParserException::class, IOException::class) + fun parseXML(xml: String): MutableList { + + val articleList = mutableListOf() + var currentArticle = RssArticle() + + val factory = XmlPullParserFactory.newInstance() + factory.isNamespaceAware = false + + val xmlPullParser = factory.newPullParser() + xmlPullParser.setInput(StringReader(xml)) + + // A flag just to be sure of the correct parsing + var insideItem = false + + var eventType = xmlPullParser.eventType + + // Start parsing the xml + while (eventType != XmlPullParser.END_DOCUMENT) { + + // Start parsing the item + if (eventType == XmlPullParser.START_TAG) { + if (xmlPullParser.name.equals(RSSKeywords.RSS_ITEM, ignoreCase = true)) { + insideItem = true + + } else if (xmlPullParser.name.equals( + RSSKeywords.RSS_ITEM_TITLE, + ignoreCase = true + ) + ) { + if (insideItem) { + currentArticle.title = xmlPullParser.nextText().trim() + } + + } else if (xmlPullParser.name.equals( + RSSKeywords.RSS_ITEM_LINK, + ignoreCase = true + ) + ) { + if (insideItem) { + currentArticle.link = xmlPullParser.nextText().trim() + } + + } else if (xmlPullParser.name.equals( + RSSKeywords.RSS_ITEM_AUTHOR, + ignoreCase = true + ) + ) { + if (insideItem) { + currentArticle.author = xmlPullParser.nextText().trim() + } + + } else if (xmlPullParser.name.equals( + RSSKeywords.RSS_ITEM_CATEGORY, + ignoreCase = true + ) + ) { + if (insideItem) { + currentArticle.categories.add(xmlPullParser.nextText().trim()) + } + + } else if (xmlPullParser.name.equals( + RSSKeywords.RSS_ITEM_THUMBNAIL, + ignoreCase = true + ) + ) { + if (insideItem) { + currentArticle.image = + xmlPullParser.getAttributeValue(null, RSSKeywords.RSS_ITEM_URL) + } + + } else if (xmlPullParser.name.equals( + RSSKeywords.RSS_ITEM_ENCLOSURE, + ignoreCase = true + ) + ) { + if (insideItem) { + val type = xmlPullParser.getAttributeValue(null, RSSKeywords.RSS_ITEM_TYPE) + if (type != null && type.contains("image/")) { + currentArticle.image = + xmlPullParser.getAttributeValue(null, RSSKeywords.RSS_ITEM_URL) + } + } + + } else if (xmlPullParser.name.equals( + RSSKeywords.RSS_ITEM_DESCRIPTION, + ignoreCase = true + ) + ) { + if (insideItem) { + val description = xmlPullParser.nextText() + currentArticle.description = description.trim() + if (currentArticle.image == null) { + currentArticle.image = getImageUrl(description) + } + } + + } else if (xmlPullParser.name.equals( + RSSKeywords.RSS_ITEM_CONTENT, + ignoreCase = true + ) + ) { + if (insideItem) { + val content = xmlPullParser.nextText().trim() + currentArticle.content = content + if (currentArticle.image == null) { + currentArticle.image = getImageUrl(content) + } + } + + } else if (xmlPullParser.name.equals( + RSSKeywords.RSS_ITEM_PUB_DATE, + ignoreCase = true + ) + ) { + if (insideItem) { + val nextTokenType = xmlPullParser.next() + if (nextTokenType == XmlPullParser.TEXT) { + currentArticle.pubDate = xmlPullParser.text.trim() + } + // Skip to be able to find date inside 'tag' tag + continue + } + } else if (xmlPullParser.name.equals( + RSSKeywords.RSS_ITEM_TIME, + ignoreCase = true + ) + ) { + if (insideItem) { + currentArticle.pubDate = xmlPullParser.nextText() + } + } else if (xmlPullParser.name.equals( + RSSKeywords.RSS_ITEM_GUID, + ignoreCase = true + ) + ) { + if (insideItem) { + currentArticle.guid = xmlPullParser.nextText().trim() + } + } + } else if (eventType == XmlPullParser.END_TAG && xmlPullParser.name.equals( + "item", + ignoreCase = true + ) + ) { + // The item is correctly parsed + insideItem = false + articleList.add(currentArticle) + currentArticle = RssArticle() + } + eventType = xmlPullParser.next() + } + return articleList + } + + /** + * Finds the first img tag and get the src as featured image + * + * @param input The content in which to search for the tag + * @return The url, if there is one + */ + private fun getImageUrl(input: String): String? { + + var url: String? = null + val patternImg = "()".toPattern() + val matcherImg = patternImg.matcher(input) + if (matcherImg.find()) { + val imgTag = matcherImg.group(1) + val patternLink = "src\\s*=\\s*\"(.+?)\"".toPattern() + val matcherLink = patternLink.matcher(imgTag) + if (matcherLink.find()) { + url = matcherLink.group(1).trim() + } + } + return url + } +} \ No newline at end of file From 79db2a7234ad6b24ce828d69781741bdc3cdc921 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 12 Sep 2019 16:00:07 +0800 Subject: [PATCH 1467/1997] up --- app/src/main/java/io/legado/app/model/rss/RssParser.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/model/rss/RssParser.kt b/app/src/main/java/io/legado/app/model/rss/RssParser.kt index 60fea317a..19bb003eb 100644 --- a/app/src/main/java/io/legado/app/model/rss/RssParser.kt +++ b/app/src/main/java/io/legado/app/model/rss/RssParser.kt @@ -8,7 +8,7 @@ import org.xmlpull.v1.XmlPullParserFactory import java.io.IOException import java.io.StringReader -object CoreXMLParser { +object RssParser { @Throws(XmlPullParserException::class, IOException::class) fun parseXML(xml: String): MutableList { From 9cc4a8083b4b801688b5295073a777528b276584 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 12 Sep 2019 16:02:34 +0800 Subject: [PATCH 1468/1997] up --- .../java/io/legado/app/model/rss/RssParser.kt | 75 +++++++------------ 1 file changed, 29 insertions(+), 46 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/rss/RssParser.kt b/app/src/main/java/io/legado/app/model/rss/RssParser.kt index 19bb003eb..c3fd923bc 100644 --- a/app/src/main/java/io/legado/app/model/rss/RssParser.kt +++ b/app/src/main/java/io/legado/app/model/rss/RssParser.kt @@ -28,125 +28,108 @@ object RssParser { var eventType = xmlPullParser.eventType // Start parsing the xml - while (eventType != XmlPullParser.END_DOCUMENT) { + loop@ while (eventType != XmlPullParser.END_DOCUMENT) { // Start parsing the item if (eventType == XmlPullParser.START_TAG) { - if (xmlPullParser.name.equals(RSSKeywords.RSS_ITEM, ignoreCase = true)) { - insideItem = true - - } else if (xmlPullParser.name.equals( + when { + xmlPullParser.name.equals( + RSSKeywords.RSS_ITEM, + ignoreCase = true + ) -> insideItem = true + xmlPullParser.name.equals( RSSKeywords.RSS_ITEM_TITLE, ignoreCase = true ) - ) { - if (insideItem) { + -> if (insideItem) { currentArticle.title = xmlPullParser.nextText().trim() } - - } else if (xmlPullParser.name.equals( + xmlPullParser.name.equals( RSSKeywords.RSS_ITEM_LINK, ignoreCase = true ) - ) { - if (insideItem) { + -> if (insideItem) { currentArticle.link = xmlPullParser.nextText().trim() } - - } else if (xmlPullParser.name.equals( + xmlPullParser.name.equals( RSSKeywords.RSS_ITEM_AUTHOR, ignoreCase = true ) - ) { - if (insideItem) { + -> if (insideItem) { currentArticle.author = xmlPullParser.nextText().trim() } - - } else if (xmlPullParser.name.equals( + xmlPullParser.name.equals( RSSKeywords.RSS_ITEM_CATEGORY, ignoreCase = true ) - ) { - if (insideItem) { + -> if (insideItem) { currentArticle.categories.add(xmlPullParser.nextText().trim()) } - - } else if (xmlPullParser.name.equals( + xmlPullParser.name.equals( RSSKeywords.RSS_ITEM_THUMBNAIL, ignoreCase = true ) - ) { - if (insideItem) { + -> if (insideItem) { currentArticle.image = xmlPullParser.getAttributeValue(null, RSSKeywords.RSS_ITEM_URL) } - - } else if (xmlPullParser.name.equals( + xmlPullParser.name.equals( RSSKeywords.RSS_ITEM_ENCLOSURE, ignoreCase = true ) - ) { - if (insideItem) { + -> if (insideItem) { val type = xmlPullParser.getAttributeValue(null, RSSKeywords.RSS_ITEM_TYPE) if (type != null && type.contains("image/")) { currentArticle.image = xmlPullParser.getAttributeValue(null, RSSKeywords.RSS_ITEM_URL) } } - - } else if (xmlPullParser.name.equals( + xmlPullParser.name.equals( RSSKeywords.RSS_ITEM_DESCRIPTION, ignoreCase = true ) - ) { - if (insideItem) { + -> if (insideItem) { val description = xmlPullParser.nextText() currentArticle.description = description.trim() if (currentArticle.image == null) { currentArticle.image = getImageUrl(description) } } - - } else if (xmlPullParser.name.equals( + xmlPullParser.name.equals( RSSKeywords.RSS_ITEM_CONTENT, ignoreCase = true ) - ) { - if (insideItem) { + -> if (insideItem) { val content = xmlPullParser.nextText().trim() currentArticle.content = content if (currentArticle.image == null) { currentArticle.image = getImageUrl(content) } } - - } else if (xmlPullParser.name.equals( + xmlPullParser.name.equals( RSSKeywords.RSS_ITEM_PUB_DATE, ignoreCase = true ) - ) { - if (insideItem) { + -> if (insideItem) { val nextTokenType = xmlPullParser.next() if (nextTokenType == XmlPullParser.TEXT) { currentArticle.pubDate = xmlPullParser.text.trim() } // Skip to be able to find date inside 'tag' tag - continue + continue@loop } - } else if (xmlPullParser.name.equals( + xmlPullParser.name.equals( RSSKeywords.RSS_ITEM_TIME, ignoreCase = true ) - ) { - if (insideItem) { + -> if (insideItem) { currentArticle.pubDate = xmlPullParser.nextText() } - } else if (xmlPullParser.name.equals( + xmlPullParser.name.equals( RSSKeywords.RSS_ITEM_GUID, ignoreCase = true ) - ) { - if (insideItem) { + -> if (insideItem) { currentArticle.guid = xmlPullParser.nextText().trim() } } From 4f4a96581f6b2a0655ea98ee05a792393e4b9688 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 12 Sep 2019 17:08:37 +0800 Subject: [PATCH 1469/1997] up --- .../java/io/legado/app/data/entities/RssSource.kt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/data/entities/RssSource.kt b/app/src/main/java/io/legado/app/data/entities/RssSource.kt index 1f5cba92a..8adac6170 100644 --- a/app/src/main/java/io/legado/app/data/entities/RssSource.kt +++ b/app/src/main/java/io/legado/app/data/entities/RssSource.kt @@ -11,5 +11,15 @@ data class RssSource( var sourceName: String, @PrimaryKey var sourceUrl: String, - var enabled: Boolean = true + var iconUrl: String, + var enabled: Boolean = true, + var ruleGuid: String? = null, + var ruleTitle: String? = null, + var ruleAuthor: String? = null, + var ruleLink: String? = null, + var rulePubDate: String? = null, + var ruleDescription: String? = null, + var ruleContent: String? = null, + var ruleImage: String? = null, + var ruleCategories: String? = null ) : Parcelable \ No newline at end of file From 48b197fc0ec0be99b1d4b0d4a2649dc92b67a473 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 12 Sep 2019 18:02:39 +0800 Subject: [PATCH 1470/1997] up --- .../app/ui/changesource/ChangeSourceViewModel.kt | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt index 3159db258..db4a5e889 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt @@ -117,11 +117,13 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio * 筛选 */ fun screen(key: String?) { - screenKey = key ?: "" - if (key.isNullOrEmpty()) { - initData() - } else { - + execute { + screenKey = key ?: "" + if (key.isNullOrEmpty()) { + initData() + } else { + App.db.searchBookDao() + } } } From 8895a8dc5e12b3881fbbed4c34851bc550b4d32b Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 12 Sep 2019 22:02:02 +0800 Subject: [PATCH 1471/1997] up --- app/src/main/java/io/legado/app/ui/about/AboutActivity.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/about/AboutActivity.kt b/app/src/main/java/io/legado/app/ui/about/AboutActivity.kt index 4648bb02d..f5636c134 100644 --- a/app/src/main/java/io/legado/app/ui/about/AboutActivity.kt +++ b/app/src/main/java/io/legado/app/ui/about/AboutActivity.kt @@ -27,9 +27,7 @@ class AboutActivity : BaseActivity(R.layout.activity_about) { override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { - R.id.menu_scoring -> { - openIntent("market://details?id=$packageName") - } + R.id.menu_scoring -> openIntent("market://details?id=$packageName") } return super.onCompatOptionsItemSelected(item) } From 5505659dcf5212ec32ac9df5a1ad74d9089f3541 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 12 Sep 2019 22:07:00 +0800 Subject: [PATCH 1472/1997] up --- .../io/legado/app/ui/main/my/MyFragment.kt | 72 ++++++++++++++++++- .../app/ui/main/my/PreferenceFragment.kt | 71 ------------------ app/src/main/res/menu/my_config.xml | 2 +- 3 files changed, 71 insertions(+), 74 deletions(-) delete mode 100644 app/src/main/java/io/legado/app/ui/main/my/PreferenceFragment.kt diff --git a/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt b/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt index d88b87669..553b6fee7 100644 --- a/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt @@ -1,14 +1,25 @@ package io.legado.app.ui.main.my +import android.content.SharedPreferences import android.os.Bundle import android.view.Menu import android.view.MenuItem import android.view.View +import androidx.preference.Preference +import androidx.preference.PreferenceFragmentCompat +import io.legado.app.App import io.legado.app.R import io.legado.app.base.BaseFragment -import io.legado.app.ui.readbook.ReadBookActivity +import io.legado.app.lib.theme.ATH +import io.legado.app.ui.about.AboutActivity +import io.legado.app.ui.about.DonateActivity +import io.legado.app.ui.booksource.BookSourceActivity +import io.legado.app.ui.config.ConfigActivity +import io.legado.app.ui.config.ConfigViewModel +import io.legado.app.ui.replacerule.ReplaceRuleActivity import io.legado.app.utils.startActivity import kotlinx.android.synthetic.main.view_title_bar.* +import org.jetbrains.anko.startActivity class MyFragment : BaseFragment(R.layout.fragment_my_config) { @@ -26,7 +37,64 @@ class MyFragment : BaseFragment(R.layout.fragment_my_config) { override fun onCompatOptionsItemSelected(item: MenuItem) { when (item.itemId) { - R.id.action_settings -> startActivity() + R.id.menu_help -> startActivity() } } + + class PreferenceFragment : PreferenceFragmentCompat(), + SharedPreferences.OnSharedPreferenceChangeListener { + + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + addPreferencesFromResource(R.xml.pref_main) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + ATH.applyEdgeEffectColor(listView) + } + + override fun onResume() { + super.onResume() + preferenceManager.sharedPreferences.registerOnSharedPreferenceChangeListener(this) + } + + override fun onPause() { + preferenceManager.sharedPreferences.unregisterOnSharedPreferenceChangeListener(this) + super.onPause() + } + + override fun onSharedPreferenceChanged( + sharedPreferences: SharedPreferences?, + key: String? + ) { + when (key) { + "isNightTheme" -> { + App.INSTANCE.applyDayNight() + } + } + } + + override fun onPreferenceTreeClick(preference: Preference?): Boolean { + preference?.let { + when (preference.key) { + "bookSourceManage" -> context?.startActivity() + "replaceManage" -> context?.startActivity() + "setting" -> context?.startActivity( + Pair("configType", ConfigViewModel.TYPE_CONFIG) + ) + "web_dav_setting" -> context?.startActivity( + Pair("configType", ConfigViewModel.TYPE_WEB_DAV_CONFIG) + ) + "theme_setting" -> context?.startActivity( + Pair("configType", ConfigViewModel.TYPE_THEME_CONFIG) + ) + "donate" -> context?.startActivity() + "about" -> context?.startActivity() + else -> null + } + } + return super.onPreferenceTreeClick(preference) + } + + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/my/PreferenceFragment.kt b/app/src/main/java/io/legado/app/ui/main/my/PreferenceFragment.kt deleted file mode 100644 index 5b6eabd1c..000000000 --- a/app/src/main/java/io/legado/app/ui/main/my/PreferenceFragment.kt +++ /dev/null @@ -1,71 +0,0 @@ -package io.legado.app.ui.main.my - -import android.content.SharedPreferences -import android.os.Bundle -import android.view.View -import androidx.preference.Preference -import androidx.preference.PreferenceFragmentCompat -import io.legado.app.App -import io.legado.app.R -import io.legado.app.lib.theme.ATH -import io.legado.app.ui.about.AboutActivity -import io.legado.app.ui.about.DonateActivity -import io.legado.app.ui.booksource.BookSourceActivity -import io.legado.app.ui.config.ConfigActivity -import io.legado.app.ui.config.ConfigViewModel -import io.legado.app.ui.replacerule.ReplaceRuleActivity -import org.jetbrains.anko.startActivity - -class PreferenceFragment : PreferenceFragmentCompat(), - SharedPreferences.OnSharedPreferenceChangeListener { - - override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - addPreferencesFromResource(R.xml.pref_main) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - ATH.applyEdgeEffectColor(listView) - } - - override fun onResume() { - super.onResume() - preferenceManager.sharedPreferences.registerOnSharedPreferenceChangeListener(this) - } - - override fun onPause() { - preferenceManager.sharedPreferences.unregisterOnSharedPreferenceChangeListener(this) - super.onPause() - } - - override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { - when (key) { - "isNightTheme" -> { - App.INSTANCE.applyDayNight() - } - } - } - - override fun onPreferenceTreeClick(preference: Preference?): Boolean { - preference?.let { - when (preference.key) { - "bookSourceManage" -> context?.startActivity() - "replaceManage" -> context?.startActivity() - "setting" -> context?.startActivity( - Pair("configType", ConfigViewModel.TYPE_CONFIG) - ) - "web_dav_setting" -> context?.startActivity( - Pair("configType", ConfigViewModel.TYPE_WEB_DAV_CONFIG) - ) - "theme_setting" -> context?.startActivity( - Pair("configType", ConfigViewModel.TYPE_THEME_CONFIG) - ) - "donate" -> context?.startActivity() - "about" -> context?.startActivity() - else -> null - } - } - return super.onPreferenceTreeClick(preference) - } - -} \ No newline at end of file diff --git a/app/src/main/res/menu/my_config.xml b/app/src/main/res/menu/my_config.xml index 6d6a37970..e54b68733 100644 --- a/app/src/main/res/menu/my_config.xml +++ b/app/src/main/res/menu/my_config.xml @@ -3,7 +3,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> From 095d3126c68a74af4728071cbc7cc0f78342f0d7 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 12 Sep 2019 23:01:34 +0800 Subject: [PATCH 1473/1997] up --- app/src/main/AndroidManifest.xml | 16 +- .../app/receiver/MediaButtonReceiver.kt | 2 +- .../app/service/BaseReadAloudService.kt | 2 +- .../info}/BookInfoActivity.kt | 8 +- .../info}/BookInfoViewModel.kt | 2 +- .../info}/ChapterListAdapter.kt | 2 +- .../info}/edit/BookInfoEditActivity.kt | 2 +- .../info}/edit/BookInfoEditViewModel.kt | 2 +- .../app/ui/{readbook => book/read}/Help.kt | 2 +- .../read}/ReadBookActivity.kt | 9 +- .../read}/ReadBookViewModel.kt | 2 +- .../ui/{readbook => book/read}/ReadMenu.kt | 2 +- .../read}/config/BgTextConfigDialog.kt | 4 +- .../read}/config/MoreConfigDialog.kt | 7 +- .../read}/config/PaddingConfigDialog.kt | 4 +- .../read}/config/ReadAloudConfigDialog.kt | 7 +- .../read}/config/ReadAloudDialog.kt | 4 +- .../read}/config/ReadStyleDialog.kt | 6 +- .../app/ui/{ => book}/search/DiffCallBack.kt | 2 +- .../ui/{ => book}/search/SearchActivity.kt | 4 +- .../app/ui/{ => book}/search/SearchAdapter.kt | 2 +- .../ui/{ => book}/search/SearchViewModel.kt | 2 +- .../source/debug}/SourceDebugActivity.kt | 4 +- .../source/debug}/SourceDebugAdapter.kt | 2 +- .../source/debug}/SourceDebugModel.kt | 2 +- .../source/edit}/SourceEditActivity.kt | 320 +++++++++++++++--- .../source/edit}/SourceEditAdapter.kt | 8 +- .../source/edit}/SourceEditViewModel.kt | 2 +- .../source/manage}/BookSourceActivity.kt | 11 +- .../source/manage}/BookSourceAdapter.kt | 2 +- .../source/manage}/BookSourceViewModel.kt | 2 +- .../source/manage}/DiffCallBack.kt | 2 +- .../source/manage}/GroupManageDialog.kt | 2 +- .../app/ui/explore/ExploreShowActivity.kt | 2 +- .../ui/main/bookshelf/BookshelfFragment.kt | 6 +- .../app/ui/main/explore/ExploreFragment.kt | 2 +- .../io/legado/app/ui/main/my/MyFragment.kt | 2 +- .../app/ui/rss/article/RssArticlesActivity.kt | 3 + .../{readrss => rss/read}/ReadRssActivity.kt | 2 +- .../app/ui/rss/source/RssSourceActivity.kt | 2 + .../main/res/layout/activity_explore_show.xml | 2 +- .../main/res/layout/activity_read_book.xml | 2 +- app/src/main/res/layout/activity_search.xml | 2 +- app/src/main/res/xml/shortcuts.xml | 2 +- 44 files changed, 362 insertions(+), 115 deletions(-) rename app/src/main/java/io/legado/app/ui/{bookinfo => book/info}/BookInfoActivity.kt (97%) rename app/src/main/java/io/legado/app/ui/{bookinfo => book/info}/BookInfoViewModel.kt (99%) rename app/src/main/java/io/legado/app/ui/{bookinfo => book/info}/ChapterListAdapter.kt (97%) rename app/src/main/java/io/legado/app/ui/{bookinfo => book/info}/edit/BookInfoEditActivity.kt (98%) rename app/src/main/java/io/legado/app/ui/{bookinfo => book/info}/edit/BookInfoEditViewModel.kt (94%) rename app/src/main/java/io/legado/app/ui/{readbook => book/read}/Help.kt (98%) rename app/src/main/java/io/legado/app/ui/{readbook => book/read}/ReadBookActivity.kt (98%) rename app/src/main/java/io/legado/app/ui/{readbook => book/read}/ReadBookViewModel.kt (99%) rename app/src/main/java/io/legado/app/ui/{readbook => book/read}/ReadMenu.kt (99%) rename app/src/main/java/io/legado/app/ui/{readbook => book/read}/config/BgTextConfigDialog.kt (98%) rename app/src/main/java/io/legado/app/ui/{readbook => book/read}/config/MoreConfigDialog.kt (94%) rename app/src/main/java/io/legado/app/ui/{readbook => book/read}/config/PaddingConfigDialog.kt (98%) rename app/src/main/java/io/legado/app/ui/{readbook => book/read}/config/ReadAloudConfigDialog.kt (96%) rename app/src/main/java/io/legado/app/ui/{readbook => book/read}/config/ReadAloudDialog.kt (98%) rename app/src/main/java/io/legado/app/ui/{readbook => book/read}/config/ReadStyleDialog.kt (98%) rename app/src/main/java/io/legado/app/ui/{ => book}/search/DiffCallBack.kt (97%) rename app/src/main/java/io/legado/app/ui/{ => book}/search/SearchActivity.kt (97%) rename app/src/main/java/io/legado/app/ui/{ => book}/search/SearchAdapter.kt (99%) rename app/src/main/java/io/legado/app/ui/{ => book}/search/SearchViewModel.kt (98%) rename app/src/main/java/io/legado/app/ui/{sourcedebug => book/source/debug}/SourceDebugActivity.kt (96%) rename app/src/main/java/io/legado/app/ui/{sourcedebug => book/source/debug}/SourceDebugAdapter.kt (92%) rename app/src/main/java/io/legado/app/ui/{sourcedebug => book/source/debug}/SourceDebugModel.kt (96%) rename app/src/main/java/io/legado/app/ui/{sourceedit => book/source/edit}/SourceEditActivity.kt (61%) rename app/src/main/java/io/legado/app/ui/{sourceedit => book/source/edit}/SourceEditAdapter.kt (92%) rename app/src/main/java/io/legado/app/ui/{sourceedit => book/source/edit}/SourceEditViewModel.kt (97%) rename app/src/main/java/io/legado/app/ui/{booksource => book/source/manage}/BookSourceActivity.kt (96%) rename app/src/main/java/io/legado/app/ui/{booksource => book/source/manage}/BookSourceAdapter.kt (99%) rename app/src/main/java/io/legado/app/ui/{booksource => book/source/manage}/BookSourceViewModel.kt (98%) rename app/src/main/java/io/legado/app/ui/{booksource => book/source/manage}/DiffCallBack.kt (97%) rename app/src/main/java/io/legado/app/ui/{booksource => book/source/manage}/GroupManageDialog.kt (99%) create mode 100644 app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt rename app/src/main/java/io/legado/app/ui/{readrss => rss/read}/ReadRssActivity.kt (86%) create mode 100644 app/src/main/java/io/legado/app/ui/rss/source/RssSourceActivity.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 242d2710a..3b8e4dab2 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -39,7 +39,7 @@ - + - - - - + + + + - + diff --git a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt index 99d838494..f1c3b5bf6 100644 --- a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt +++ b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt @@ -6,7 +6,7 @@ import android.content.Intent import android.view.KeyEvent import io.legado.app.constant.Bus import io.legado.app.help.ActivityHelp -import io.legado.app.ui.readbook.ReadBookActivity +import io.legado.app.ui.book.read.ReadBookActivity import io.legado.app.utils.postEvent diff --git a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt index e3cee17be..ad204f420 100644 --- a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt @@ -20,7 +20,7 @@ import io.legado.app.constant.Status import io.legado.app.help.IntentDataHelp import io.legado.app.help.MediaHelp import io.legado.app.receiver.MediaButtonReceiver -import io.legado.app.ui.readbook.ReadBookActivity +import io.legado.app.ui.book.read.ReadBookActivity import io.legado.app.ui.widget.page.TextChapter import io.legado.app.utils.getPrefBoolean import io.legado.app.utils.postEvent diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt similarity index 97% rename from app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt rename to app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt index 3334adfb4..b650584c6 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.bookinfo +package io.legado.app.ui.book.info import android.os.Bundle import android.view.Menu @@ -12,10 +12,10 @@ import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter import io.legado.app.help.ImageLoader import io.legado.app.lib.theme.ATH -import io.legado.app.ui.bookinfo.edit.BookInfoEditActivity +import io.legado.app.ui.book.info.edit.BookInfoEditActivity +import io.legado.app.ui.book.read.ReadBookActivity +import io.legado.app.ui.book.source.edit.SourceEditActivity import io.legado.app.ui.changesource.ChangeSourceDialog -import io.legado.app.ui.readbook.ReadBookActivity -import io.legado.app.ui.sourceedit.SourceEditActivity import io.legado.app.utils.getCompatDrawable import io.legado.app.utils.getViewModel import io.legado.app.utils.gone diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt b/app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt similarity index 99% rename from app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt rename to app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt index 5b99563e8..cb54f4df1 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.bookinfo +package io.legado.app.ui.book.info import android.app.Application import android.content.Intent diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/ChapterListAdapter.kt b/app/src/main/java/io/legado/app/ui/book/info/ChapterListAdapter.kt similarity index 97% rename from app/src/main/java/io/legado/app/ui/bookinfo/ChapterListAdapter.kt rename to app/src/main/java/io/legado/app/ui/book/info/ChapterListAdapter.kt index 3b2edf158..bfe98f4d8 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/ChapterListAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/book/info/ChapterListAdapter.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.bookinfo +package io.legado.app.ui.book.info import android.content.Context import io.legado.app.R diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/edit/BookInfoEditActivity.kt b/app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditActivity.kt similarity index 98% rename from app/src/main/java/io/legado/app/ui/bookinfo/edit/BookInfoEditActivity.kt rename to app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditActivity.kt index 6becac683..fcc4e7e24 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/edit/BookInfoEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditActivity.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.bookinfo.edit +package io.legado.app.ui.book.info.edit import android.os.Bundle import android.view.Menu diff --git a/app/src/main/java/io/legado/app/ui/bookinfo/edit/BookInfoEditViewModel.kt b/app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditViewModel.kt similarity index 94% rename from app/src/main/java/io/legado/app/ui/bookinfo/edit/BookInfoEditViewModel.kt rename to app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditViewModel.kt index fb33a22e7..a947719cd 100644 --- a/app/src/main/java/io/legado/app/ui/bookinfo/edit/BookInfoEditViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditViewModel.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.bookinfo.edit +package io.legado.app.ui.book.info.edit import android.app.Application import androidx.lifecycle.MutableLiveData diff --git a/app/src/main/java/io/legado/app/ui/readbook/Help.kt b/app/src/main/java/io/legado/app/ui/book/read/Help.kt similarity index 98% rename from app/src/main/java/io/legado/app/ui/readbook/Help.kt rename to app/src/main/java/io/legado/app/ui/book/read/Help.kt index 72d65da5f..1ff72d7dc 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/Help.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/Help.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.readbook +package io.legado.app.ui.book.read import android.app.Activity import android.view.View diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt similarity index 98% rename from app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt rename to app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt index 448f1cbe3..c61e8cac3 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.readbook +package io.legado.app.ui.book.read import android.app.Activity import android.content.Intent @@ -27,13 +27,14 @@ import io.legado.app.lib.dialogs.noButton import io.legado.app.lib.dialogs.okButton import io.legado.app.receiver.TimeElectricityReceiver import io.legado.app.service.BaseReadAloudService +import io.legado.app.ui.book.read.config.* +import io.legado.app.ui.book.read.config.BgTextConfigDialog.Companion.BG_COLOR +import io.legado.app.ui.book.read.config.BgTextConfigDialog.Companion.TEXT_COLOR +import io.legado.app.ui.book.source.edit.SourceEditActivity import io.legado.app.ui.changesource.ChangeSourceDialog import io.legado.app.ui.chapterlist.ChapterListActivity import io.legado.app.ui.readbook.config.* -import io.legado.app.ui.readbook.config.BgTextConfigDialog.Companion.BG_COLOR -import io.legado.app.ui.readbook.config.BgTextConfigDialog.Companion.TEXT_COLOR import io.legado.app.ui.replacerule.ReplaceRuleActivity -import io.legado.app.ui.sourceedit.SourceEditActivity import io.legado.app.ui.widget.page.ChapterProvider import io.legado.app.ui.widget.page.PageView import io.legado.app.ui.widget.page.TextChapter diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt similarity index 99% rename from app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt rename to app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt index 0dcdeef47..635deb97e 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.readbook +package io.legado.app.ui.book.read import android.app.Application import android.content.Intent diff --git a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadMenu.kt similarity index 99% rename from app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt rename to app/src/main/java/io/legado/app/ui/book/read/ReadMenu.kt index b0b79603e..af02fa16c 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/ReadMenu.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadMenu.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.readbook +package io.legado.app.ui.book.read import android.content.Context import android.util.AttributeSet diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt b/app/src/main/java/io/legado/app/ui/book/read/config/BgTextConfigDialog.kt similarity index 98% rename from app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt rename to app/src/main/java/io/legado/app/ui/book/read/config/BgTextConfigDialog.kt index 98abc2dd2..d8112b538 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/BgTextConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/config/BgTextConfigDialog.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.readbook.config +package io.legado.app.ui.book.read.config import android.annotation.SuppressLint import android.app.Activity.RESULT_OK @@ -24,7 +24,7 @@ import io.legado.app.help.ImageLoader import io.legado.app.help.ReadBookConfig import io.legado.app.help.permission.Permissions import io.legado.app.help.permission.PermissionsCompat -import io.legado.app.ui.readbook.Help +import io.legado.app.ui.book.read.Help import io.legado.app.utils.FileUtils import io.legado.app.utils.getCompatColor import io.legado.app.utils.postEvent diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt b/app/src/main/java/io/legado/app/ui/book/read/config/MoreConfigDialog.kt similarity index 94% rename from app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt rename to app/src/main/java/io/legado/app/ui/book/read/config/MoreConfigDialog.kt index ba7aca78f..51470b2ee 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/MoreConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/config/MoreConfigDialog.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.readbook.config +package io.legado.app.ui.book.read.config import android.content.SharedPreferences import android.os.Bundle @@ -13,7 +13,7 @@ import androidx.preference.PreferenceFragmentCompat import io.legado.app.R import io.legado.app.constant.Bus import io.legado.app.lib.theme.ATH -import io.legado.app.ui.readbook.Help +import io.legado.app.ui.book.read.Help import io.legado.app.utils.postEvent class MoreConfigDialog : DialogFragment() { @@ -53,7 +53,8 @@ class MoreConfigDialog : DialogFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) var preferenceFragment = childFragmentManager.findFragmentByTag(readPreferTag) - if (preferenceFragment == null) preferenceFragment = ReadPreferenceFragment() + if (preferenceFragment == null) preferenceFragment = + ReadPreferenceFragment() childFragmentManager.beginTransaction() .replace(view.id, preferenceFragment, readPreferTag) .commit() diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.kt b/app/src/main/java/io/legado/app/ui/book/read/config/PaddingConfigDialog.kt similarity index 98% rename from app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.kt rename to app/src/main/java/io/legado/app/ui/book/read/config/PaddingConfigDialog.kt index 4d349b9cb..3c172cea2 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/PaddingConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/config/PaddingConfigDialog.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.readbook.config +package io.legado.app.ui.book.read.config import android.os.Bundle import android.util.DisplayMetrics @@ -10,7 +10,7 @@ import androidx.fragment.app.DialogFragment import io.legado.app.R import io.legado.app.constant.Bus import io.legado.app.help.ReadBookConfig -import io.legado.app.ui.readbook.Help +import io.legado.app.ui.book.read.Help import io.legado.app.utils.postEvent import kotlinx.android.synthetic.main.dialog_read_padding.* import org.jetbrains.anko.sdk27.listeners.onClick diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudConfigDialog.kt b/app/src/main/java/io/legado/app/ui/book/read/config/ReadAloudConfigDialog.kt similarity index 96% rename from app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudConfigDialog.kt rename to app/src/main/java/io/legado/app/ui/book/read/config/ReadAloudConfigDialog.kt index f0bfd6231..699037325 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/config/ReadAloudConfigDialog.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.readbook.config +package io.legado.app.ui.book.read.config import android.content.SharedPreferences import android.os.Bundle @@ -16,7 +16,7 @@ import io.legado.app.constant.Bus import io.legado.app.help.ReadAloud import io.legado.app.lib.theme.ATH import io.legado.app.service.BaseReadAloudService -import io.legado.app.ui.readbook.Help +import io.legado.app.ui.book.read.Help import io.legado.app.utils.getPrefString import io.legado.app.utils.postEvent @@ -51,7 +51,8 @@ class ReadAloudConfigDialog : DialogFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) var preferenceFragment = childFragmentManager.findFragmentByTag(readAloudPreferTag) - if (preferenceFragment == null) preferenceFragment = ReadAloudPreferenceFragment() + if (preferenceFragment == null) preferenceFragment = + ReadAloudPreferenceFragment() childFragmentManager.beginTransaction() .replace(view.id, preferenceFragment, readAloudPreferTag) .commit() diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt b/app/src/main/java/io/legado/app/ui/book/read/config/ReadAloudDialog.kt similarity index 98% rename from app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt rename to app/src/main/java/io/legado/app/ui/book/read/config/ReadAloudDialog.kt index dc5d26350..e9f524dcb 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadAloudDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/config/ReadAloudDialog.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.readbook.config +package io.legado.app.ui.book.read.config import android.os.Bundle import android.util.DisplayMetrics @@ -13,7 +13,7 @@ import io.legado.app.constant.Bus import io.legado.app.constant.Status import io.legado.app.help.ReadAloud import io.legado.app.service.BaseReadAloudService -import io.legado.app.ui.readbook.Help +import io.legado.app.ui.book.read.Help import io.legado.app.utils.* import kotlinx.android.synthetic.main.dialog_read_aloud.* import org.jetbrains.anko.sdk27.listeners.onClick diff --git a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt similarity index 98% rename from app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt rename to app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt index a0080036c..42edae9a3 100644 --- a/app/src/main/java/io/legado/app/ui/readbook/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.readbook.config +package io.legado.app.ui.book.read.config import android.os.Bundle import android.util.DisplayMetrics @@ -16,8 +16,8 @@ import io.legado.app.help.ReadBookConfig import io.legado.app.lib.dialogs.selector import io.legado.app.lib.theme.accentColor import io.legado.app.lib.theme.primaryColor -import io.legado.app.ui.readbook.Help -import io.legado.app.ui.readbook.ReadBookActivity +import io.legado.app.ui.book.read.Help +import io.legado.app.ui.book.read.ReadBookActivity import io.legado.app.ui.widget.font.FontSelectDialog import io.legado.app.utils.* import kotlinx.android.synthetic.main.activity_read_book.* diff --git a/app/src/main/java/io/legado/app/ui/search/DiffCallBack.kt b/app/src/main/java/io/legado/app/ui/book/search/DiffCallBack.kt similarity index 97% rename from app/src/main/java/io/legado/app/ui/search/DiffCallBack.kt rename to app/src/main/java/io/legado/app/ui/book/search/DiffCallBack.kt index b974cb059..0de21ee19 100644 --- a/app/src/main/java/io/legado/app/ui/search/DiffCallBack.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/DiffCallBack.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.search +package io.legado.app.ui.book.search import androidx.recyclerview.widget.DiffUtil import io.legado.app.data.entities.SearchShow diff --git a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt similarity index 97% rename from app/src/main/java/io/legado/app/ui/search/SearchActivity.kt rename to app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt index 7d206cb43..64d5d76f8 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.search +package io.legado.app.ui.book.search import android.os.Bundle import androidx.appcompat.widget.SearchView @@ -13,7 +13,7 @@ import io.legado.app.base.VMBaseActivity import io.legado.app.data.entities.SearchShow import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.primaryTextColor -import io.legado.app.ui.bookinfo.BookInfoActivity +import io.legado.app.ui.book.info.BookInfoActivity import io.legado.app.utils.getViewModel import io.legado.app.utils.invisible import io.legado.app.utils.visible diff --git a/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchAdapter.kt similarity index 99% rename from app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt rename to app/src/main/java/io/legado/app/ui/book/search/SearchAdapter.kt index 0b40007ff..a2cb9ad08 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchAdapter.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.search +package io.legado.app.ui.book.search import android.view.LayoutInflater import android.view.View diff --git a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt similarity index 98% rename from app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt rename to app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt index 0fbb8c772..f8550229f 100644 --- a/app/src/main/java/io/legado/app/ui/search/SearchViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.search +package io.legado.app.ui.book.search import android.app.Application import io.legado.app.App diff --git a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/debug/SourceDebugActivity.kt similarity index 96% rename from app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt rename to app/src/main/java/io/legado/app/ui/book/source/debug/SourceDebugActivity.kt index 2290654e4..de2ef20e7 100644 --- a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/debug/SourceDebugActivity.kt @@ -1,10 +1,9 @@ -package io.legado.app.ui.sourcedebug +package io.legado.app.ui.book.source.debug import android.content.Intent import android.os.Bundle import android.view.Menu import android.view.MenuItem -import android.view.View import androidx.appcompat.widget.SearchView import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.R @@ -15,7 +14,6 @@ import io.legado.app.ui.qrcode.QrCodeActivity import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_source_debug.* import kotlinx.android.synthetic.main.view_search.* -import kotlinx.android.synthetic.main.view_title_bar.* import kotlinx.coroutines.launch import org.jetbrains.anko.startActivityForResult import org.jetbrains.anko.toast diff --git a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugAdapter.kt b/app/src/main/java/io/legado/app/ui/book/source/debug/SourceDebugAdapter.kt similarity index 92% rename from app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugAdapter.kt rename to app/src/main/java/io/legado/app/ui/book/source/debug/SourceDebugAdapter.kt index b8b821ea1..0c057fda0 100644 --- a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/debug/SourceDebugAdapter.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.sourcedebug +package io.legado.app.ui.book.source.debug import android.content.Context import io.legado.app.R diff --git a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt b/app/src/main/java/io/legado/app/ui/book/source/debug/SourceDebugModel.kt similarity index 96% rename from app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt rename to app/src/main/java/io/legado/app/ui/book/source/debug/SourceDebugModel.kt index 6873a30cb..a17565820 100644 --- a/app/src/main/java/io/legado/app/ui/sourcedebug/SourceDebugModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/debug/SourceDebugModel.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.sourcedebug +package io.legado.app.ui.book.source.debug import android.app.Application import io.legado.app.App diff --git a/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditActivity.kt similarity index 61% rename from app/src/main/java/io/legado/app/ui/sourceedit/SourceEditActivity.kt rename to app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditActivity.kt index 2bea174be..faaf38ff6 100644 --- a/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditActivity.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.sourceedit +package io.legado.app.ui.book.source.edit import android.app.Activity import android.content.ClipData @@ -20,7 +20,7 @@ import io.legado.app.base.VMBaseActivity import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.rule.* import io.legado.app.lib.theme.ATH -import io.legado.app.ui.sourcedebug.SourceDebugActivity +import io.legado.app.ui.book.source.debug.SourceDebugActivity import io.legado.app.ui.widget.KeyboardToolPop import io.legado.app.utils.GSON import io.legado.app.utils.getViewModel @@ -147,67 +147,243 @@ class SourceEditActivity : with(bookSource) { sourceEntities.clear() sourceEntities - .add(EditEntity("bookSourceUrl", this?.bookSourceUrl, R.string.book_source_url)) + .add( + EditEntity( + "bookSourceUrl", + this?.bookSourceUrl, + R.string.book_source_url + ) + ) sourceEntities - .add(EditEntity("bookSourceName", this?.bookSourceName, R.string.book_source_name)) + .add( + EditEntity( + "bookSourceName", + this?.bookSourceName, + R.string.book_source_name + ) + ) sourceEntities.add( - EditEntity("bookSourceGroup", this?.bookSourceGroup, R.string.book_source_group) + EditEntity( + "bookSourceGroup", + this?.bookSourceGroup, + R.string.book_source_group + ) ) sourceEntities - .add(EditEntity("loginUrl", this?.loginUrl, R.string.book_source_login_url)) + .add( + EditEntity( + "loginUrl", + this?.loginUrl, + R.string.book_source_login_url + ) + ) sourceEntities - .add(EditEntity("bookUrlPattern", this?.bookUrlPattern, R.string.book_url_pattern)) - sourceEntities.add(EditEntity("header", this?.header, R.string.source_http_header)) + .add( + EditEntity( + "bookUrlPattern", + this?.bookUrlPattern, + R.string.book_url_pattern + ) + ) + sourceEntities.add( + EditEntity( + "header", + this?.header, + R.string.source_http_header + ) + ) } //搜索 with(bookSource?.getSearchRule()) { searchEntities.clear() searchEntities - .add(EditEntity("searchUrl", bookSource?.searchUrl, R.string.rule_search_url)) - searchEntities.add(EditEntity("bookList", this?.bookList, R.string.rule_book_list)) - searchEntities.add(EditEntity("name", this?.name, R.string.rule_book_name)) - searchEntities.add(EditEntity("author", this?.author, R.string.rule_book_author)) - searchEntities.add(EditEntity("kind", this?.kind, R.string.rule_book_kind)) - searchEntities.add(EditEntity("wordCount", this?.wordCount, R.string.rule_word_count)) + .add( + EditEntity( + "searchUrl", + bookSource?.searchUrl, + R.string.rule_search_url + ) + ) + searchEntities.add( + EditEntity( + "bookList", + this?.bookList, + R.string.rule_book_list + ) + ) + searchEntities.add( + EditEntity( + "name", + this?.name, + R.string.rule_book_name + ) + ) + searchEntities.add( + EditEntity( + "author", + this?.author, + R.string.rule_book_author + ) + ) + searchEntities.add( + EditEntity( + "kind", + this?.kind, + R.string.rule_book_kind + ) + ) + searchEntities.add( + EditEntity( + "wordCount", + this?.wordCount, + R.string.rule_word_count + ) + ) searchEntities - .add(EditEntity("lastChapter", this?.lastChapter, R.string.rule_last_chapter)) - searchEntities.add(EditEntity("intro", this?.intro, R.string.rule_book_intro)) - searchEntities.add(EditEntity("coverUrl", this?.coverUrl, R.string.rule_cover_url)) - searchEntities.add(EditEntity("bookUrl", this?.bookUrl, R.string.rule_book_url)) + .add( + EditEntity( + "lastChapter", + this?.lastChapter, + R.string.rule_last_chapter + ) + ) + searchEntities.add( + EditEntity( + "intro", + this?.intro, + R.string.rule_book_intro + ) + ) + searchEntities.add( + EditEntity( + "coverUrl", + this?.coverUrl, + R.string.rule_cover_url + ) + ) + searchEntities.add( + EditEntity( + "bookUrl", + this?.bookUrl, + R.string.rule_book_url + ) + ) } //详情页 with(bookSource?.getBookInfoRule()) { infoEntities.clear() - infoEntities.add(EditEntity("init", this?.init, R.string.rule_book_info_init)) - infoEntities.add(EditEntity("name", this?.name, R.string.rule_book_name)) - infoEntities.add(EditEntity("author", this?.author, R.string.rule_book_author)) - infoEntities.add(EditEntity("coverUrl", this?.coverUrl, R.string.rule_cover_url)) - infoEntities.add(EditEntity("intro", this?.intro, R.string.rule_book_intro)) - infoEntities.add(EditEntity("kind", this?.kind, R.string.rule_book_kind)) - infoEntities.add(EditEntity("wordCount", this?.wordCount, R.string.rule_word_count)) infoEntities.add( - EditEntity("lastChapter", this?.lastChapter, R.string.rule_last_chapter) + EditEntity( + "init", + this?.init, + R.string.rule_book_info_init + ) + ) + infoEntities.add( + EditEntity( + "name", + this?.name, + R.string.rule_book_name + ) + ) + infoEntities.add( + EditEntity( + "author", + this?.author, + R.string.rule_book_author + ) + ) + infoEntities.add( + EditEntity( + "coverUrl", + this?.coverUrl, + R.string.rule_cover_url + ) + ) + infoEntities.add( + EditEntity( + "intro", + this?.intro, + R.string.rule_book_intro + ) + ) + infoEntities.add( + EditEntity( + "kind", + this?.kind, + R.string.rule_book_kind + ) + ) + infoEntities.add( + EditEntity( + "wordCount", + this?.wordCount, + R.string.rule_word_count + ) + ) + infoEntities.add( + EditEntity( + "lastChapter", + this?.lastChapter, + R.string.rule_last_chapter + ) + ) + infoEntities.add( + EditEntity( + "tocUrl", + this?.tocUrl, + R.string.rule_toc_url + ) ) - infoEntities.add(EditEntity("tocUrl", this?.tocUrl, R.string.rule_toc_url)) } //目录页 with(bookSource?.getTocRule()) { tocEntities.clear() tocEntities.add( - EditEntity("chapterList", this?.chapterList, R.string.rule_chapter_list) + EditEntity( + "chapterList", + this?.chapterList, + R.string.rule_chapter_list + ) + ) + tocEntities.add( + EditEntity( + "chapterName", + this?.chapterName, + R.string.rule_chapter_name + ) ) tocEntities.add( - EditEntity("chapterName", this?.chapterName, R.string.rule_chapter_name) + EditEntity( + "chapterUrl", + this?.chapterUrl, + R.string.rule_chapter_url + ) + ) + tocEntities.add( + EditEntity( + "nextTocUrl", + this?.nextTocUrl, + R.string.rule_next_toc_url + ) ) - tocEntities.add(EditEntity("chapterUrl", this?.chapterUrl, R.string.rule_chapter_url)) - tocEntities.add(EditEntity("nextTocUrl", this?.nextTocUrl, R.string.rule_next_toc_url)) } //正文页 with(bookSource?.getContentRule()) { contentEntities.clear() - contentEntities.add(EditEntity("content", this?.content, R.string.rule_book_content)) contentEntities.add( - EditEntity("nextContentUrl", this?.nextContentUrl, R.string.rule_content_url_next) + EditEntity( + "content", + this?.content, + R.string.rule_book_content + ) + ) + contentEntities.add( + EditEntity( + "nextContentUrl", + this?.nextContentUrl, + R.string.rule_content_url_next + ) ) } @@ -215,19 +391,75 @@ class SourceEditActivity : with(bookSource?.getExploreRule()) { findEntities.clear() findEntities.add( - EditEntity("exploreUrl", bookSource?.exploreUrl, R.string.rule_find_url) - ) - findEntities.add(EditEntity("bookList", this?.bookList, R.string.rule_book_list)) - findEntities.add(EditEntity("name", this?.name, R.string.rule_book_name)) - findEntities.add(EditEntity("author", this?.author, R.string.rule_book_author)) - findEntities.add(EditEntity("kind", this?.kind, R.string.rule_book_kind)) - findEntities.add(EditEntity("wordCount", this?.wordCount, R.string.rule_word_count)) - findEntities.add(EditEntity("intro", this?.intro, R.string.rule_book_intro)) + EditEntity( + "exploreUrl", + bookSource?.exploreUrl, + R.string.rule_find_url + ) + ) + findEntities.add( + EditEntity( + "bookList", + this?.bookList, + R.string.rule_book_list + ) + ) + findEntities.add( + EditEntity( + "name", + this?.name, + R.string.rule_book_name + ) + ) + findEntities.add( + EditEntity( + "author", + this?.author, + R.string.rule_book_author + ) + ) + findEntities.add( + EditEntity( + "kind", + this?.kind, + R.string.rule_book_kind + ) + ) + findEntities.add( + EditEntity( + "wordCount", + this?.wordCount, + R.string.rule_word_count + ) + ) + findEntities.add( + EditEntity( + "intro", + this?.intro, + R.string.rule_book_intro + ) + ) + findEntities.add( + EditEntity( + "lastChapter", + this?.lastChapter, + R.string.rule_last_chapter + ) + ) + findEntities.add( + EditEntity( + "coverUrl", + this?.coverUrl, + R.string.rule_cover_url + ) + ) findEntities.add( - EditEntity("lastChapter", this?.lastChapter, R.string.rule_last_chapter) + EditEntity( + "bookUrl", + this?.bookUrl, + R.string.rule_book_url + ) ) - findEntities.add(EditEntity("coverUrl", this?.coverUrl, R.string.rule_cover_url)) - findEntities.add(EditEntity("bookUrl", this?.bookUrl, R.string.rule_book_url)) } setEditEntities(0) } diff --git a/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditAdapter.kt b/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditAdapter.kt similarity index 92% rename from app/src/main/java/io/legado/app/ui/sourceedit/SourceEditAdapter.kt rename to app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditAdapter.kt index 87f977082..3ac5fc3d1 100644 --- a/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditAdapter.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.sourceedit +package io.legado.app.ui.book.source.edit import android.text.Editable import android.text.TextWatcher @@ -18,7 +18,11 @@ class SourceEditAdapter : RecyclerView.Adapter() } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { - return MyViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_source_edit, parent, false)) + return MyViewHolder( + LayoutInflater.from( + parent.context + ).inflate(R.layout.item_source_edit, parent, false) + ) } override fun onBindViewHolder(holder: MyViewHolder, position: Int) { diff --git a/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditViewModel.kt b/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditViewModel.kt similarity index 97% rename from app/src/main/java/io/legado/app/ui/sourceedit/SourceEditViewModel.kt rename to app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditViewModel.kt index ef8d75740..c3af29a6a 100644 --- a/app/src/main/java/io/legado/app/ui/sourceedit/SourceEditViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditViewModel.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.sourceedit +package io.legado.app.ui.book.source.edit import android.app.Application import android.content.ClipboardManager diff --git a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt similarity index 96% rename from app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt rename to app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt index 597cbeffa..573444123 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.booksource +package io.legado.app.ui.book.source.manage import android.content.Intent import android.os.Bundle @@ -21,8 +21,8 @@ import io.legado.app.help.ItemTouchCallback import io.legado.app.help.storage.Restore import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.primaryTextColor +import io.legado.app.ui.book.source.edit.SourceEditActivity import io.legado.app.ui.qrcode.QrCodeActivity -import io.legado.app.ui.sourceedit.SourceEditActivity import io.legado.app.utils.getViewModel import io.legado.app.utils.splitNotBlank import kotlinx.android.synthetic.main.activity_book_source.* @@ -121,7 +121,12 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity } bookSourceLiveDate?.observe(this, Observer { search_view.queryHint = getString(R.string.search_book_source_num, it.size) - val diffResult = DiffUtil.calculateDiff(DiffCallBack(adapter.getItems(), it)) + val diffResult = DiffUtil.calculateDiff( + DiffCallBack( + adapter.getItems(), + it + ) + ) adapter.setItemsNoNotify(it) diffResult.dispatchUpdatesTo(adapter) }) diff --git a/app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceAdapter.kt similarity index 99% rename from app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt rename to app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceAdapter.kt index 8152ba18a..c7c432e16 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/BookSourceAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceAdapter.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.booksource +package io.legado.app.ui.book.source.manage import android.content.Context import android.view.Menu diff --git a/app/src/main/java/io/legado/app/ui/booksource/BookSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt similarity index 98% rename from app/src/main/java/io/legado/app/ui/booksource/BookSourceViewModel.kt rename to app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt index d2842a579..289b3a84a 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/BookSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.booksource +package io.legado.app.ui.book.source.manage import android.app.Application import android.text.TextUtils diff --git a/app/src/main/java/io/legado/app/ui/booksource/DiffCallBack.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/DiffCallBack.kt similarity index 97% rename from app/src/main/java/io/legado/app/ui/booksource/DiffCallBack.kt rename to app/src/main/java/io/legado/app/ui/book/source/manage/DiffCallBack.kt index 90036ba58..0e8d9bead 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/DiffCallBack.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/DiffCallBack.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.booksource +package io.legado.app.ui.book.source.manage import androidx.recyclerview.widget.DiffUtil import io.legado.app.data.entities.BookSource diff --git a/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/GroupManageDialog.kt similarity index 99% rename from app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt rename to app/src/main/java/io/legado/app/ui/book/source/manage/GroupManageDialog.kt index e5ed98578..bf44c56a5 100644 --- a/app/src/main/java/io/legado/app/ui/booksource/GroupManageDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/GroupManageDialog.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.booksource +package io.legado.app.ui.book.source.manage import android.annotation.SuppressLint import android.content.Context diff --git a/app/src/main/java/io/legado/app/ui/explore/ExploreShowActivity.kt b/app/src/main/java/io/legado/app/ui/explore/ExploreShowActivity.kt index 9dff24ede..1d2ba0b4e 100644 --- a/app/src/main/java/io/legado/app/ui/explore/ExploreShowActivity.kt +++ b/app/src/main/java/io/legado/app/ui/explore/ExploreShowActivity.kt @@ -8,7 +8,7 @@ import androidx.recyclerview.widget.RecyclerView import io.legado.app.R import io.legado.app.base.VMBaseActivity import io.legado.app.data.entities.SearchBook -import io.legado.app.ui.bookinfo.BookInfoActivity +import io.legado.app.ui.book.info.BookInfoActivity import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_explore_show.* import org.jetbrains.anko.startActivity diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index 77a91e0a6..8e8a581a0 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -22,10 +22,10 @@ import io.legado.app.data.entities.BookGroup import io.legado.app.lib.dialogs.* import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.accentColor -import io.legado.app.ui.bookinfo.BookInfoActivity +import io.legado.app.ui.book.info.BookInfoActivity +import io.legado.app.ui.book.read.ReadBookActivity +import io.legado.app.ui.book.search.SearchActivity import io.legado.app.ui.bookshelf.BookshelfActivity -import io.legado.app.ui.readbook.ReadBookActivity -import io.legado.app.ui.search.SearchActivity import io.legado.app.utils.* import kotlinx.android.synthetic.main.dialog_edittext.view.* import kotlinx.android.synthetic.main.fragment_bookshelf.* diff --git a/app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt b/app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt index 5c7d78e72..888dbe4ac 100644 --- a/app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt @@ -10,8 +10,8 @@ import io.legado.app.R import io.legado.app.base.VMBaseFragment import io.legado.app.data.entities.BookSource import io.legado.app.lib.theme.ATH +import io.legado.app.ui.book.source.edit.SourceEditActivity import io.legado.app.ui.explore.ExploreShowActivity -import io.legado.app.ui.sourceedit.SourceEditActivity import io.legado.app.utils.getViewModel import io.legado.app.utils.startActivity import kotlinx.android.synthetic.main.fragment_find_book.* diff --git a/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt b/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt index 553b6fee7..333fd9689 100644 --- a/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt @@ -13,7 +13,7 @@ import io.legado.app.base.BaseFragment import io.legado.app.lib.theme.ATH import io.legado.app.ui.about.AboutActivity import io.legado.app.ui.about.DonateActivity -import io.legado.app.ui.booksource.BookSourceActivity +import io.legado.app.ui.book.source.manage.BookSourceActivity import io.legado.app.ui.config.ConfigActivity import io.legado.app.ui.config.ConfigViewModel import io.legado.app.ui.replacerule.ReplaceRuleActivity diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt new file mode 100644 index 000000000..a69c70fb5 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt @@ -0,0 +1,3 @@ +package io.legado.app.ui.rss.article + +class RssArticlesActivity \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/readrss/ReadRssActivity.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt similarity index 86% rename from app/src/main/java/io/legado/app/ui/readrss/ReadRssActivity.kt rename to app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt index 32d14c9ce..5e7972c6d 100644 --- a/app/src/main/java/io/legado/app/ui/readrss/ReadRssActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.readrss +package io.legado.app.ui.rss.read import android.os.Bundle import io.legado.app.R diff --git a/app/src/main/java/io/legado/app/ui/rss/source/RssSourceActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/RssSourceActivity.kt new file mode 100644 index 000000000..899e41398 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/rss/source/RssSourceActivity.kt @@ -0,0 +1,2 @@ +package io.legado.app.ui.rss.source + diff --git a/app/src/main/res/layout/activity_explore_show.xml b/app/src/main/res/layout/activity_explore_show.xml index 8df05cb8c..9bfab0f58 100644 --- a/app/src/main/res/layout/activity_explore_show.xml +++ b/app/src/main/res/layout/activity_explore_show.xml @@ -4,7 +4,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context="io.legado.app.ui.search.SearchActivity"> + tools:context=".ui.book.search.SearchActivity"> - + tools:context=".ui.book.search.SearchActivity"> + android:targetClass="io.legado.app.ui.book.read.ReadBookActivity" /> From 888aef12e3995f256d08413e10c222c5f43a9a4e Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 12 Sep 2019 23:04:44 +0800 Subject: [PATCH 1474/1997] up --- app/src/main/java/io/legado/app/ui/qrcode/QrCodeActivity.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/qrcode/QrCodeActivity.kt b/app/src/main/java/io/legado/app/ui/qrcode/QrCodeActivity.kt index dac723182..b84cc3f6f 100644 --- a/app/src/main/java/io/legado/app/ui/qrcode/QrCodeActivity.kt +++ b/app/src/main/java/io/legado/app/ui/qrcode/QrCodeActivity.kt @@ -14,6 +14,7 @@ import io.legado.app.help.permission.PermissionsCompat import io.legado.app.utils.FileUtils import kotlinx.android.synthetic.main.activity_qrcode_capture.* import kotlinx.android.synthetic.main.view_title_bar.* +import org.jetbrains.anko.toast class QrCodeActivity : BaseActivity(R.layout.activity_qrcode_capture), QRCodeView.Delegate { @@ -88,7 +89,7 @@ class QrCodeActivity : BaseActivity(R.layout.activity_qrcode_capture), QRCodeVie } override fun onScanQRCodeOpenCameraError() { - + toast("打开相机失败") } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { From 80ab179477a25d20ce2689da0b58de51f3b11421 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 14 Sep 2019 11:29:20 +0800 Subject: [PATCH 1475/1997] up --- app/src/main/java/io/legado/app/help/storage/Backup.kt | 9 +++++++++ app/src/main/res/menu/read_book.xml | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/help/storage/Backup.kt b/app/src/main/java/io/legado/app/help/storage/Backup.kt index 0f55ac786..1cb43a8db 100644 --- a/app/src/main/java/io/legado/app/help/storage/Backup.kt +++ b/app/src/main/java/io/legado/app/help/storage/Backup.kt @@ -1,5 +1,8 @@ package io.legado.app.help.storage +import io.legado.app.App +import io.legado.app.utils.GSON + object Backup { fun backup() { @@ -9,4 +12,10 @@ object Backup { fun autoBackup() { } + + private fun backupBookshelf() { + val books = App.db.bookDao().allBooks + val json = GSON.toJson(books) + + } } \ No newline at end of file diff --git a/app/src/main/res/menu/read_book.xml b/app/src/main/res/menu/read_book.xml index 8b95f1d3a..d8ea10f3d 100644 --- a/app/src/main/res/menu/read_book.xml +++ b/app/src/main/res/menu/read_book.xml @@ -1,7 +1,7 @@ + tools:context=".ui.main.MainActivity"> Date: Sat, 14 Sep 2019 13:44:43 +0800 Subject: [PATCH 1476/1997] up --- .../book/read/config/PaddingConfigDialog.kt | 40 ++++++------------- .../io/legado/app/utils/ViewExtensions.kt | 10 ++--- 2 files changed, 17 insertions(+), 33 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/read/config/PaddingConfigDialog.kt b/app/src/main/java/io/legado/app/ui/book/read/config/PaddingConfigDialog.kt index 3c172cea2..43aeaad2d 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/config/PaddingConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/config/PaddingConfigDialog.kt @@ -12,6 +12,7 @@ import io.legado.app.constant.Bus import io.legado.app.help.ReadBookConfig import io.legado.app.ui.book.read.Help import io.legado.app.utils.postEvent +import io.legado.app.utils.progressAdd import kotlinx.android.synthetic.main.dialog_read_padding.* import org.jetbrains.anko.sdk27.listeners.onClick @@ -61,52 +62,35 @@ class PaddingConfigDialog : DialogFragment() { private fun initView() = with(ReadBookConfig.getConfig()) { iv_padding_top_add.onClick { - paddingTop++ - if (paddingTop > 100) paddingTop = 100 - seek_padding_top.progress = paddingTop - tv_padding_top.text = paddingTop.toString() + seek_padding_top.progressAdd(1) postEvent(Bus.UP_CONFIG, true) } iv_padding_top_remove.onClick { - paddingTop-- - if (paddingTop < 0) paddingTop = 0 - seek_padding_top.progress = paddingTop - tv_padding_top.text = paddingTop.toString() + seek_padding_top.progressAdd(-1) postEvent(Bus.UP_CONFIG, true) } iv_padding_bottom_add.onClick { - paddingBottom++ - if (paddingBottom > 100) paddingBottom = 100 - seek_padding_bottom.progress = paddingBottom - tv_padding_bottom.text = paddingBottom.toString() + seek_padding_bottom.progressAdd(1) postEvent(Bus.UP_CONFIG, true) } iv_padding_bottom_remove.onClick { - paddingBottom-- - if (paddingBottom < 0) paddingBottom = 0 - seek_padding_bottom.progress = paddingBottom - tv_padding_bottom.text = paddingBottom.toString() + seek_padding_bottom.progressAdd(-1) postEvent(Bus.UP_CONFIG, true) } iv_padding_left_add.onClick { - paddingLeft++ - if (paddingLeft > 100) paddingLeft = 100 - seek_padding_left.progress = paddingLeft - tv_padding_left.text = paddingLeft.toString() + seek_padding_left.progressAdd(1) postEvent(Bus.UP_CONFIG, true) } iv_padding_left_remove.onClick { - paddingLeft++ - if (paddingLeft < 0) paddingLeft = 0 - seek_padding_left.progress = paddingLeft - tv_padding_left.text = paddingLeft.toString() + seek_padding_left.progressAdd(-1) postEvent(Bus.UP_CONFIG, true) } iv_padding_right_add.onClick { - paddingRight++ - if (paddingRight > 100) paddingRight = 100 - seek_padding_right.progress = paddingRight - tv_padding_right.text = paddingRight.toString() + seek_padding_right.progressAdd(1) + postEvent(Bus.UP_CONFIG, true) + } + iv_padding_right_remove.onClick { + seek_padding_right.progressAdd(-1) postEvent(Bus.UP_CONFIG, true) } diff --git a/app/src/main/java/io/legado/app/utils/ViewExtensions.kt b/app/src/main/java/io/legado/app/utils/ViewExtensions.kt index 1c7fb29c3..81cdafe81 100644 --- a/app/src/main/java/io/legado/app/utils/ViewExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/ViewExtensions.kt @@ -3,17 +3,13 @@ package io.legado.app.utils import android.content.Context import android.graphics.Bitmap import android.graphics.Canvas -import android.graphics.Rect import android.os.Build -import android.os.Handler -import android.view.PixelCopy import android.view.View import android.view.View.* import android.view.inputmethod.InputMethodManager +import android.widget.SeekBar import androidx.appcompat.app.AppCompatActivity import io.legado.app.App -import android.opengl.ETC1.getHeight -import android.opengl.ETC1.getWidth private tailrec fun getCompatActivity(context: Context?): AppCompatActivity? { @@ -61,4 +57,8 @@ fun View.screenshot(): Bitmap? { draw(c) screenshot }.getOrNull() +} + +fun SeekBar.progressAdd(int: Int) { + progress += int } \ No newline at end of file From 45a9994a884700a490a74278f0a122afd3cccf90 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 14 Sep 2019 13:50:09 +0800 Subject: [PATCH 1477/1997] up --- .../ui/book/read/config/ReadStyleDialog.kt | 36 ++++--------------- 1 file changed, 6 insertions(+), 30 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt index 42edae9a3..ea80392c8 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt @@ -125,21 +125,11 @@ class ReadStyleDialog : DialogFragment() { } }) iv_text_size_add.onClick { - with(ReadBookConfig.getConfig()) { - textSize++ - if (textSize > 50) textSize = 50 - seek_text_size.progress = textSize - 5 - tv_text_size.text = textSize.toString() - } + seek_text_size.progressAdd(1) postEvent(Bus.UP_CONFIG, true) } iv_text_size_remove.onClick { - with(ReadBookConfig.getConfig()) { - textSize-- - if (textSize < 5) textSize = 5 - seek_text_size.progress = textSize - 5 - tv_text_size.text = textSize.toString() - } + seek_text_size.progressAdd(-1) postEvent(Bus.UP_CONFIG, true) } seek_text_letter_spacing.setOnSeekBarChangeListener(object : @@ -157,19 +147,11 @@ class ReadStyleDialog : DialogFragment() { } }) iv_text_letter_spacing_add.onClick { - with(ReadBookConfig.getConfig()) { - letterSpacing += 0.1f - seek_text_letter_spacing.progress = (letterSpacing * 10).toInt() + 5 - tv_text_letter_spacing.text = letterSpacing.toString() - } + seek_text_letter_spacing.progressAdd(1) postEvent(Bus.UP_CONFIG, true) } iv_text_letter_spacing_remove.onClick { - with(ReadBookConfig.getConfig()) { - letterSpacing -= 0.1f - seek_text_letter_spacing.progress = (letterSpacing * 10).toInt() + 5 - tv_text_letter_spacing.text = letterSpacing.toString() - } + seek_text_letter_spacing.progressAdd(-1) postEvent(Bus.UP_CONFIG, true) } seek_line_size.setOnSeekBarChangeListener(object : @@ -187,17 +169,11 @@ class ReadStyleDialog : DialogFragment() { } }) iv_line_size_add.onClick { - with(ReadBookConfig.getConfig()) { - lineSpacingExtra++ - tv_line_size.text = lineSpacingExtra.toString() - } + seek_line_size.progressAdd(1) postEvent(Bus.UP_CONFIG, true) } iv_line_size_remove.onClick { - with(ReadBookConfig.getConfig()) { - lineSpacingExtra-- - tv_line_size.text = lineSpacingExtra.toString() - } + seek_line_size.progressAdd(-1) postEvent(Bus.UP_CONFIG, true) } rg_page_anim.onCheckedChange { _, checkedId -> From 2f708dc469e2e710e931e6a045b2d1ff72c5537c Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 14 Sep 2019 16:53:59 +0800 Subject: [PATCH 1478/1997] up --- .../io/legado/app/ui/book/info/BookInfoActivity.kt | 10 ++++++---- .../io/legado/app/ui/book/read/ReadBookActivity.kt | 1 - 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt index b650584c6..62bc33ca9 100644 --- a/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt @@ -50,7 +50,8 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo } ?: viewModel.loadBook(intent) initOnClick() savedInstanceState?.let { - changeSourceDialog = supportFragmentManager.findFragmentByTag(ChangeSourceDialog.tag) as? ChangeSourceDialog + changeSourceDialog = + supportFragmentManager.findFragmentByTag(ChangeSourceDialog.tag) as? ChangeSourceDialog } } @@ -83,7 +84,8 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo tv_author.text = getString(R.string.author_show, book.author) tv_origin.text = getString(R.string.origin_show, book.originName) tv_lasted.text = getString(R.string.lasted_show, book.latestChapterTitle) - tv_intro.text = book.getDisplayIntro(); // getString(R.string.intro_show, book.getDisplayIntro()) + tv_intro.text = + book.getDisplayIntro() // getString(R.string.intro_show, book.getDisplayIntro()) book.getDisplayCover()?.let { ImageLoader.load(this, it) .placeholder(R.drawable.img_cover_default) @@ -202,8 +204,8 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo } } iv_chapter_top.onClick { - adapter.reorder = !adapter.reorder; - adapter.notifyDataSetChanged(); + adapter.reorder = !adapter.reorder + adapter.notifyDataSetChanged() } } diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt index c61e8cac3..ebf23f520 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt @@ -33,7 +33,6 @@ import io.legado.app.ui.book.read.config.BgTextConfigDialog.Companion.TEXT_COLOR import io.legado.app.ui.book.source.edit.SourceEditActivity import io.legado.app.ui.changesource.ChangeSourceDialog import io.legado.app.ui.chapterlist.ChapterListActivity -import io.legado.app.ui.readbook.config.* import io.legado.app.ui.replacerule.ReplaceRuleActivity import io.legado.app.ui.widget.page.ChapterProvider import io.legado.app.ui.widget.page.PageView From e06b6b4bfdbdab05b8f5de6dd3c41afc49eff2b5 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 14 Sep 2019 17:35:46 +0800 Subject: [PATCH 1479/1997] up --- app/src/main/java/io/legado/app/lib/theme/ATH.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/theme/ATH.kt b/app/src/main/java/io/legado/app/lib/theme/ATH.kt index 0fafab3b3..c195fe364 100644 --- a/app/src/main/java/io/legado/app/lib/theme/ATH.kt +++ b/app/src/main/java/io/legado/app/lib/theme/ATH.kt @@ -51,8 +51,12 @@ object ATH { isTransparentStatusBar: Boolean, fullScreen: Boolean ) { - if (fullScreen && isTransparentStatusBar) { - activity.window.statusBarColor = Color.TRANSPARENT + if (fullScreen) { + if (isTransparentStatusBar) { + activity.window.statusBarColor = Color.TRANSPARENT + } else { + activity.window.statusBarColor = activity.getCompatColor(R.color.status_bar_bag) + } } else { activity.window.statusBarColor = color } From ecddadad7a447ecdc6a51310995ebf64eeb5d44a Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 14 Sep 2019 17:51:51 +0800 Subject: [PATCH 1480/1997] up --- .../io/legado/app/ui/book/read/config/MoreConfigDialog.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/read/config/MoreConfigDialog.kt b/app/src/main/java/io/legado/app/ui/book/read/config/MoreConfigDialog.kt index 51470b2ee..4a869a1ed 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/config/MoreConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/config/MoreConfigDialog.kt @@ -74,11 +74,15 @@ class MoreConfigDialog : DialogFragment() { override fun onResume() { super.onResume() - preferenceManager.sharedPreferences.registerOnSharedPreferenceChangeListener(this) + preferenceManager + .sharedPreferences + .registerOnSharedPreferenceChangeListener(this) } override fun onPause() { - preferenceManager.sharedPreferences.unregisterOnSharedPreferenceChangeListener(this) + preferenceManager + .sharedPreferences + .unregisterOnSharedPreferenceChangeListener(this) super.onPause() } From ec4728535cdfeb1e192ca161d47ff253e85a8a70 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 14 Sep 2019 18:02:17 +0800 Subject: [PATCH 1481/1997] up --- app/src/main/res/layout/activity_audio_play.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/layout/activity_audio_play.xml b/app/src/main/res/layout/activity_audio_play.xml index d829e291c..f478fe0d1 100644 --- a/app/src/main/res/layout/activity_audio_play.xml +++ b/app/src/main/res/layout/activity_audio_play.xml @@ -1,7 +1,15 @@ + android:layout_height="match_parent" + tools:context=".ui.audio.AudioPlayActivity"> + + + \ No newline at end of file From c6cfccf7ba172fc5beaee72a2ab1e702bdca89da Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 14 Sep 2019 18:13:08 +0800 Subject: [PATCH 1482/1997] up --- app/src/main/res/layout/activity_audio_play.xml | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/layout/activity_audio_play.xml b/app/src/main/res/layout/activity_audio_play.xml index f478fe0d1..77e9163d7 100644 --- a/app/src/main/res/layout/activity_audio_play.xml +++ b/app/src/main/res/layout/activity_audio_play.xml @@ -1,15 +1,23 @@ - + + + android:layout_height="wrap_content" + app:layout_constraintTop_toTopOf="parent" /> - \ No newline at end of file + \ No newline at end of file From 0c05bd50402593215c1d19f514df79856c1b1390 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 14 Sep 2019 18:29:10 +0800 Subject: [PATCH 1483/1997] up --- .../main/res/layout/activity_audio_play.xml | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/app/src/main/res/layout/activity_audio_play.xml b/app/src/main/res/layout/activity_audio_play.xml index 77e9163d7..2a392be02 100644 --- a/app/src/main/res/layout/activity_audio_play.xml +++ b/app/src/main/res/layout/activity_audio_play.xml @@ -19,5 +19,113 @@ android:layout_height="wrap_content" app:layout_constraintTop_toTopOf="parent" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 3798d8b5730da4aa57015a321bc97d7cca27b4c4 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 15 Sep 2019 19:18:57 +0800 Subject: [PATCH 1484/1997] up --- .../io/legado/app/data/dao/RssSourceDao.kt | 3 +++ .../main/java/io/legado/app/help/FileHelp.kt | 2 +- .../java/io/legado/app/help/storage/Backup.kt | 26 ++++++++++++++++--- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt b/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt index cb4d695ab..0d3e6e575 100644 --- a/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt @@ -8,6 +8,9 @@ import io.legado.app.data.entities.RssSource @Dao interface RssSourceDao { + @get:Query("SELECT * FROM rssSources") + val all: List + @Query("SELECT * FROM rssSources") fun liveAll(): LiveData> diff --git a/app/src/main/java/io/legado/app/help/FileHelp.kt b/app/src/main/java/io/legado/app/help/FileHelp.kt index 123f31172..f274c84e4 100644 --- a/app/src/main/java/io/legado/app/help/FileHelp.kt +++ b/app/src/main/java/io/legado/app/help/FileHelp.kt @@ -28,8 +28,8 @@ object FileHelp { file.createNewFile() } } catch (e: IOException) { + e.printStackTrace() } - return file } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/help/storage/Backup.kt b/app/src/main/java/io/legado/app/help/storage/Backup.kt index 1cb43a8db..90a07e0b7 100644 --- a/app/src/main/java/io/legado/app/help/storage/Backup.kt +++ b/app/src/main/java/io/legado/app/help/storage/Backup.kt @@ -1,7 +1,9 @@ package io.legado.app.help.storage import io.legado.app.App +import io.legado.app.help.FileHelp import io.legado.app.utils.GSON +import java.io.File object Backup { @@ -13,9 +15,27 @@ object Backup { } - private fun backupBookshelf() { - val books = App.db.bookDao().allBooks - val json = GSON.toJson(books) + private fun backupBookshelf(path: String) { + val json = GSON.toJson(App.db.bookDao().allBooks) + val file = FileHelp.getFile(path + File.separator + "bookshelf.json") + file.writeText(json) + } + + private fun backupBookSource(path: String) { + val json = GSON.toJson(App.db.bookSourceDao().all) + val file = FileHelp.getFile(path + File.separator + "bookSource.json") + file.writeText(json) + } + + private fun backupCssSource(path: String) { + val json = GSON.toJson(App.db.rssSourceDao().all) + val file = FileHelp.getFile(path + File.separator + "cssSource.json") + file.writeText(json) + } + private fun backupReplaceRule(path: String) { + val json = GSON.toJson(App.db.replaceRuleDao().all) + val file = FileHelp.getFile(path + File.separator + "replaceRule.json") + file.writeText(json) } } \ No newline at end of file From ac9852f71ab68ab25090ea6df30367219bf1e61a Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 15 Sep 2019 19:36:14 +0800 Subject: [PATCH 1485/1997] up --- .../java/io/legado/app/help/storage/Backup.kt | 37 ++++++++++++++++--- .../java/io/legado/app/utils/FileUtils.kt | 1 + 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/storage/Backup.kt b/app/src/main/java/io/legado/app/help/storage/Backup.kt index 90a07e0b7..fe89fb3e1 100644 --- a/app/src/main/java/io/legado/app/help/storage/Backup.kt +++ b/app/src/main/java/io/legado/app/help/storage/Backup.kt @@ -1,18 +1,45 @@ package io.legado.app.help.storage +import androidx.appcompat.app.AppCompatActivity import io.legado.app.App +import io.legado.app.R import io.legado.app.help.FileHelp +import io.legado.app.help.permission.Permissions +import io.legado.app.help.permission.PermissionsCompat +import io.legado.app.utils.FileUtils import io.legado.app.utils.GSON import java.io.File object Backup { - fun backup() { - + fun backup(activity: AppCompatActivity) { + PermissionsCompat.Builder(activity) + .addPermissions(*Permissions.Group.STORAGE) + .rationale(R.string.tip_perm_request_storage) + .onGranted { + val path = + FileUtils.getSdCardPath() + File.separator + "YueDu" + File.separator + "legadoBackUp" + backupBookshelf(path) + backupBookSource(path) + backupRssSource(path) + backupReplaceRule(path) + } + .request() } - fun autoBackup() { - + fun autoBackup(activity: AppCompatActivity) { + PermissionsCompat.Builder(activity) + .addPermissions(*Permissions.Group.STORAGE) + .rationale(R.string.tip_perm_request_storage) + .onGranted { + val path = + FileUtils.getSdCardPath() + File.separator + "YueDu" + File.separator + "legadoBackUp" + backupBookshelf(path) + backupBookSource(path) + backupRssSource(path) + backupReplaceRule(path) + } + .request() } private fun backupBookshelf(path: String) { @@ -27,7 +54,7 @@ object Backup { file.writeText(json) } - private fun backupCssSource(path: String) { + private fun backupRssSource(path: String) { val json = GSON.toJson(App.db.rssSourceDao().all) val file = FileHelp.getFile(path + File.separator + "cssSource.json") file.writeText(json) diff --git a/app/src/main/java/io/legado/app/utils/FileUtils.kt b/app/src/main/java/io/legado/app/utils/FileUtils.kt index e2ecef64e..861d7e88e 100644 --- a/app/src/main/java/io/legado/app/utils/FileUtils.kt +++ b/app/src/main/java/io/legado/app/utils/FileUtils.kt @@ -28,6 +28,7 @@ object FileUtils { try { sdCardDirectory = File(sdCardDirectory).canonicalPath } catch (ioe: IOException) { + ioe.printStackTrace() } return sdCardDirectory From bc83e2a4306423b474fd23bb0205b47caff04287 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 15 Sep 2019 19:56:42 +0800 Subject: [PATCH 1486/1997] up --- .../io/legado/app/data/dao/RssSourceDao.kt | 12 +++- .../main/java/io/legado/app/help/BookHelp.kt | 18 +----- .../java/io/legado/app/help/storage/Backup.kt | 2 +- .../io/legado/app/help/storage/Restore.kt | 57 +++++++++++++++++-- 4 files changed, 66 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt b/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt index 0d3e6e575..999898598 100644 --- a/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt @@ -1,8 +1,7 @@ package io.legado.app.data.dao import androidx.lifecycle.LiveData -import androidx.room.Dao -import androidx.room.Query +import androidx.room.* import io.legado.app.data.entities.RssSource @Dao @@ -16,4 +15,13 @@ interface RssSourceDao { @Query("SELECT * FROM rssSources where enabled = 1") fun liveEnabled(): LiveData> + + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun insert(vararg rssSource: RssSource) + + @Update + fun update(vararg rssSource: RssSource) + + @Query("delete from rssSources where sourceUrl = :sourceUrl") + fun delete(sourceUrl: String) } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/help/BookHelp.kt b/app/src/main/java/io/legado/app/help/BookHelp.kt index d32e4d077..dd68c455b 100644 --- a/app/src/main/java/io/legado/app/help/BookHelp.kt +++ b/app/src/main/java/io/legado/app/help/BookHelp.kt @@ -7,10 +7,7 @@ import io.legado.app.data.entities.ReplaceRule import io.legado.app.utils.getPrefInt import io.legado.app.utils.getPrefString import io.legado.app.utils.similarity -import java.io.BufferedWriter import java.io.File -import java.io.FileWriter -import java.io.IOException import kotlin.math.max import kotlin.math.min @@ -29,21 +26,10 @@ object BookHelp { } fun saveContent(book: Book, bookChapter: BookChapter, content: String) { - if (content.isEmpty()) { - return - } + if (content.isEmpty()) return val filePath = getChapterPath(book, bookChapter) val file = FileHelp.getFile(filePath) - //获取流并存储 - try { - BufferedWriter(FileWriter(file)).use { writer -> - writer.write(content) - writer.flush() - } - } catch (e: IOException) { - e.printStackTrace() - } - + file.writeText(content) } fun hasContent(book: Book, bookChapter: BookChapter): Boolean { diff --git a/app/src/main/java/io/legado/app/help/storage/Backup.kt b/app/src/main/java/io/legado/app/help/storage/Backup.kt index fe89fb3e1..ac381ec52 100644 --- a/app/src/main/java/io/legado/app/help/storage/Backup.kt +++ b/app/src/main/java/io/legado/app/help/storage/Backup.kt @@ -56,7 +56,7 @@ object Backup { private fun backupRssSource(path: String) { val json = GSON.toJson(App.db.rssSourceDao().all) - val file = FileHelp.getFile(path + File.separator + "cssSource.json") + val file = FileHelp.getFile(path + File.separator + "rssSource.json") file.writeText(json) } diff --git a/app/src/main/java/io/legado/app/help/storage/Restore.kt b/app/src/main/java/io/legado/app/help/storage/Restore.kt index 335dd2497..43437a46b 100644 --- a/app/src/main/java/io/legado/app/help/storage/Restore.kt +++ b/app/src/main/java/io/legado/app/help/storage/Restore.kt @@ -2,14 +2,20 @@ package io.legado.app.help.storage import android.content.Context import android.util.Log +import androidx.appcompat.app.AppCompatActivity import com.jayway.jsonpath.Configuration import com.jayway.jsonpath.JsonPath import com.jayway.jsonpath.Option import io.legado.app.App +import io.legado.app.R import io.legado.app.constant.AppConst import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.ReplaceRule +import io.legado.app.data.entities.RssSource +import io.legado.app.help.FileHelp +import io.legado.app.help.permission.Permissions +import io.legado.app.help.permission.PermissionsCompat import io.legado.app.utils.* import org.jetbrains.anko.doAsync import org.jetbrains.anko.toast @@ -23,12 +29,55 @@ object Restore { .build() ) - fun restore() { - + fun restore(activity: AppCompatActivity) { + PermissionsCompat.Builder(activity) + .addPermissions(*Permissions.Group.STORAGE) + .rationale(R.string.tip_perm_request_storage) + .onGranted { + val path = + FileUtils.getSdCardPath() + File.separator + "YueDu" + File.separator + "legadoBackUp" + restore(path) + } + .request() } - fun importFromGithub() { - + fun restore(path: String) { + try { + val file = FileHelp.getFile(path + File.separator + "bookshelf.json") + val json = file.readText() + GSON.fromJsonArray(json)?.let { + App.db.bookDao().insert(*it.toTypedArray()) + } + } catch (e: Exception) { + e.printStackTrace() + } + try { + val file = FileHelp.getFile(path + File.separator + "bookSource.json") + val json = file.readText() + GSON.fromJsonArray(json)?.let { + App.db.bookSourceDao().insert(*it.toTypedArray()) + } + } catch (e: Exception) { + e.printStackTrace() + } + try { + val file = FileHelp.getFile(path + File.separator + "rssSource.json") + val json = file.readText() + GSON.fromJsonArray(json)?.let { + App.db.rssSourceDao().insert(*it.toTypedArray()) + } + } catch (e: Exception) { + e.printStackTrace() + } + try { + val file = FileHelp.getFile(path + File.separator + "replaceRule.json") + val json = file.readText() + GSON.fromJsonArray(json)?.let { + App.db.replaceRuleDao().insert(*it.toTypedArray()) + } + } catch (e: Exception) { + e.printStackTrace() + } } fun importYueDuData(context: Context) { From deae4a8770eeb842d61eb6ced0eac7acd17261c6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 15 Sep 2019 19:57:36 +0800 Subject: [PATCH 1487/1997] up --- app/src/main/java/io/legado/app/help/BookHelp.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/help/BookHelp.kt b/app/src/main/java/io/legado/app/help/BookHelp.kt index dd68c455b..6567dbb5b 100644 --- a/app/src/main/java/io/legado/app/help/BookHelp.kt +++ b/app/src/main/java/io/legado/app/help/BookHelp.kt @@ -48,7 +48,7 @@ object BookHelp { runCatching { val file = File(filePath) if (file.exists()) { - return String(file.readBytes()) + return file.readText() } } return null From 80aeb5d40045a4ddfba6563ca8284d1e26ea8547 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 15 Sep 2019 21:40:32 +0800 Subject: [PATCH 1488/1997] up --- .../main/java/io/legado/app/help/storage/Restore.kt | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/storage/Restore.kt b/app/src/main/java/io/legado/app/help/storage/Restore.kt index 43437a46b..2caae0a40 100644 --- a/app/src/main/java/io/legado/app/help/storage/Restore.kt +++ b/app/src/main/java/io/legado/app/help/storage/Restore.kt @@ -81,10 +81,10 @@ object Restore { } fun importYueDuData(context: Context) { - val yuedu = File(FileUtils.getSdPath(), "YueDu") + val file = File(FileUtils.getSdPath(), "YueDu") // 导入书架 - val shelfFile = File(yuedu, "myBookShelf.json") + val shelfFile = File(file, "myBookShelf.json") val books = mutableListOf() if (shelfFile.exists()) try { doAsync { @@ -130,16 +130,14 @@ object Restore { uiThread { context.toast(if (count > 0) "成功地导入 $count 本新书和音频" else "没有发现新书或音频") } - } - } catch (e: Exception) { Log.e(AppConst.APP_TAG, "Failed to import book shelf.", e) context.toast("Unable to import books:\n${e.localizedMessage}") } // Book source - val sourceFile = File(yuedu, "myBookSource.json") + val sourceFile = File(file, "myBookSource.json") val bookSources = mutableListOf() if (sourceFile.exists()) try { doAsync { @@ -156,9 +154,8 @@ object Restore { e.printStackTrace() } - // Replace rules - val ruleFile = File(yuedu, "myBookReplaceRule.json") + val ruleFile = File(file, "myBookReplaceRule.json") val replaceRules = mutableListOf() if (ruleFile.exists()) try { doAsync { @@ -184,7 +181,6 @@ object Restore { context.toast(if (count > 0) "成功地导入 $count 条净化替换规则" else "没有发现新的净化替换规则") } } - } catch (e: Exception) { Log.e(AppConst.APP_TAG, e.localizedMessage) } From 4b3d4dc84b1bcf53dae7a625dc18fe444034480e Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 15 Sep 2019 22:06:01 +0800 Subject: [PATCH 1489/1997] up --- app/src/main/AndroidManifest.xml | 1 + .../app/ui/rss/source/RssSourceActivity.kt | 16 ++++++++++++++++ .../app/ui/rss/source/RssSourceViewModel.kt | 8 ++++++++ app/src/main/res/layout/activity_rss_source.xml | 7 +++++++ 4 files changed, 32 insertions(+) create mode 100644 app/src/main/java/io/legado/app/ui/rss/source/RssSourceViewModel.kt create mode 100644 app/src/main/res/layout/activity_rss_source.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3b8e4dab2..e9ff5d4f9 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -65,6 +65,7 @@ + diff --git a/app/src/main/java/io/legado/app/ui/rss/source/RssSourceActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/RssSourceActivity.kt index 899e41398..b6707bf0e 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/RssSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/RssSourceActivity.kt @@ -1,2 +1,18 @@ package io.legado.app.ui.rss.source +import android.os.Bundle +import io.legado.app.R +import io.legado.app.base.VMBaseActivity +import io.legado.app.utils.getViewModel + + +class RssSourceActivity : VMBaseActivity(R.layout.activity_rss_source) { + override val viewModel: RssSourceViewModel + get() = getViewModel(RssSourceViewModel::class.java) + + override fun onActivityCreated(savedInstanceState: Bundle?) { + + } + + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/rss/source/RssSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/source/RssSourceViewModel.kt new file mode 100644 index 000000000..ec006964e --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/rss/source/RssSourceViewModel.kt @@ -0,0 +1,8 @@ +package io.legado.app.ui.rss.source + +import android.app.Application +import io.legado.app.base.BaseViewModel + +class RssSourceViewModel(application: Application) : BaseViewModel(application) { + +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_rss_source.xml b/app/src/main/res/layout/activity_rss_source.xml new file mode 100644 index 000000000..d829e291c --- /dev/null +++ b/app/src/main/res/layout/activity_rss_source.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file From 819a359745975bc2334fb488ea87f4e653711409 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 15 Sep 2019 22:41:07 +0800 Subject: [PATCH 1490/1997] up --- .../java/io/legado/app/help/storage/Backup.kt | 48 +++++------ .../io/legado/app/help/storage/Restore.kt | 82 ++++++++----------- .../io/legado/app/ui/main/my/MyFragment.kt | 14 ++++ app/src/main/res/drawable/ic_backup.xml | 30 ++----- app/src/main/res/drawable/ic_restore.xml | 27 ++---- app/src/main/res/menu/my_config.xml | 12 +++ 6 files changed, 94 insertions(+), 119 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/storage/Backup.kt b/app/src/main/java/io/legado/app/help/storage/Backup.kt index ac381ec52..6fd1f079b 100644 --- a/app/src/main/java/io/legado/app/help/storage/Backup.kt +++ b/app/src/main/java/io/legado/app/help/storage/Backup.kt @@ -4,42 +4,38 @@ import androidx.appcompat.app.AppCompatActivity import io.legado.app.App import io.legado.app.R import io.legado.app.help.FileHelp -import io.legado.app.help.permission.Permissions -import io.legado.app.help.permission.PermissionsCompat import io.legado.app.utils.FileUtils import io.legado.app.utils.GSON +import org.jetbrains.anko.doAsync +import org.jetbrains.anko.toast +import org.jetbrains.anko.uiThread import java.io.File object Backup { - fun backup(activity: AppCompatActivity) { - PermissionsCompat.Builder(activity) - .addPermissions(*Permissions.Group.STORAGE) - .rationale(R.string.tip_perm_request_storage) - .onGranted { - val path = - FileUtils.getSdCardPath() + File.separator + "YueDu" + File.separator + "legadoBackUp" - backupBookshelf(path) - backupBookSource(path) - backupRssSource(path) - backupReplaceRule(path) + fun backup() { + doAsync { + val path = + FileUtils.getSdCardPath() + File.separator + "YueDu" + File.separator + "legadoBackUp" + backupBookshelf(path) + backupBookSource(path) + backupRssSource(path) + backupReplaceRule(path) + uiThread { + App.INSTANCE.toast(R.string.backup_success) } - .request() + } } fun autoBackup(activity: AppCompatActivity) { - PermissionsCompat.Builder(activity) - .addPermissions(*Permissions.Group.STORAGE) - .rationale(R.string.tip_perm_request_storage) - .onGranted { - val path = - FileUtils.getSdCardPath() + File.separator + "YueDu" + File.separator + "legadoBackUp" - backupBookshelf(path) - backupBookSource(path) - backupRssSource(path) - backupReplaceRule(path) - } - .request() + doAsync { + val path = + FileUtils.getSdCardPath() + File.separator + "YueDu" + File.separator + "legadoBackUp" + backupBookshelf(path) + backupBookSource(path) + backupRssSource(path) + backupReplaceRule(path) + } } private fun backupBookshelf(path: String) { diff --git a/app/src/main/java/io/legado/app/help/storage/Restore.kt b/app/src/main/java/io/legado/app/help/storage/Restore.kt index 2caae0a40..10bc36bf7 100644 --- a/app/src/main/java/io/legado/app/help/storage/Restore.kt +++ b/app/src/main/java/io/legado/app/help/storage/Restore.kt @@ -2,20 +2,16 @@ package io.legado.app.help.storage import android.content.Context import android.util.Log -import androidx.appcompat.app.AppCompatActivity import com.jayway.jsonpath.Configuration import com.jayway.jsonpath.JsonPath import com.jayway.jsonpath.Option import io.legado.app.App -import io.legado.app.R import io.legado.app.constant.AppConst import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.ReplaceRule import io.legado.app.data.entities.RssSource import io.legado.app.help.FileHelp -import io.legado.app.help.permission.Permissions -import io.legado.app.help.permission.PermissionsCompat import io.legado.app.utils.* import org.jetbrains.anko.doAsync import org.jetbrains.anko.toast @@ -29,54 +25,48 @@ object Restore { .build() ) - fun restore(activity: AppCompatActivity) { - PermissionsCompat.Builder(activity) - .addPermissions(*Permissions.Group.STORAGE) - .rationale(R.string.tip_perm_request_storage) - .onGranted { - val path = - FileUtils.getSdCardPath() + File.separator + "YueDu" + File.separator + "legadoBackUp" - restore(path) - } - .request() + private val defaultPath by lazy { + FileUtils.getSdCardPath() + File.separator + "YueDu" + File.separator + "legadoBackUp" } - fun restore(path: String) { - try { - val file = FileHelp.getFile(path + File.separator + "bookshelf.json") - val json = file.readText() - GSON.fromJsonArray(json)?.let { - App.db.bookDao().insert(*it.toTypedArray()) + fun restore(path: String = defaultPath) { + doAsync { + try { + val file = FileHelp.getFile(path + File.separator + "bookshelf.json") + val json = file.readText() + GSON.fromJsonArray(json)?.let { + App.db.bookDao().insert(*it.toTypedArray()) + } + } catch (e: Exception) { + e.printStackTrace() } - } catch (e: Exception) { - e.printStackTrace() - } - try { - val file = FileHelp.getFile(path + File.separator + "bookSource.json") - val json = file.readText() - GSON.fromJsonArray(json)?.let { - App.db.bookSourceDao().insert(*it.toTypedArray()) + try { + val file = FileHelp.getFile(path + File.separator + "bookSource.json") + val json = file.readText() + GSON.fromJsonArray(json)?.let { + App.db.bookSourceDao().insert(*it.toTypedArray()) + } + } catch (e: Exception) { + e.printStackTrace() } - } catch (e: Exception) { - e.printStackTrace() - } - try { - val file = FileHelp.getFile(path + File.separator + "rssSource.json") - val json = file.readText() - GSON.fromJsonArray(json)?.let { - App.db.rssSourceDao().insert(*it.toTypedArray()) + try { + val file = FileHelp.getFile(path + File.separator + "rssSource.json") + val json = file.readText() + GSON.fromJsonArray(json)?.let { + App.db.rssSourceDao().insert(*it.toTypedArray()) + } + } catch (e: Exception) { + e.printStackTrace() } - } catch (e: Exception) { - e.printStackTrace() - } - try { - val file = FileHelp.getFile(path + File.separator + "replaceRule.json") - val json = file.readText() - GSON.fromJsonArray(json)?.let { - App.db.replaceRuleDao().insert(*it.toTypedArray()) + try { + val file = FileHelp.getFile(path + File.separator + "replaceRule.json") + val json = file.readText() + GSON.fromJsonArray(json)?.let { + App.db.replaceRuleDao().insert(*it.toTypedArray()) + } + } catch (e: Exception) { + e.printStackTrace() } - } catch (e: Exception) { - e.printStackTrace() } } diff --git a/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt b/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt index 333fd9689..b98a655b0 100644 --- a/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt @@ -10,6 +10,10 @@ import androidx.preference.PreferenceFragmentCompat import io.legado.app.App import io.legado.app.R import io.legado.app.base.BaseFragment +import io.legado.app.help.permission.Permissions +import io.legado.app.help.permission.PermissionsCompat +import io.legado.app.help.storage.Backup +import io.legado.app.help.storage.Restore import io.legado.app.lib.theme.ATH import io.legado.app.ui.about.AboutActivity import io.legado.app.ui.about.DonateActivity @@ -38,6 +42,16 @@ class MyFragment : BaseFragment(R.layout.fragment_my_config) { override fun onCompatOptionsItemSelected(item: MenuItem) { when (item.itemId) { R.id.menu_help -> startActivity() + R.id.menu_backup -> PermissionsCompat.Builder(this) + .addPermissions(*Permissions.Group.STORAGE) + .rationale(R.string.tip_perm_request_storage) + .onGranted { Backup.backup() } + .request() + R.id.menu_restore -> PermissionsCompat.Builder(this) + .addPermissions(*Permissions.Group.STORAGE) + .rationale(R.string.tip_perm_request_storage) + .onGranted { Restore.restore() } + .request() } } diff --git a/app/src/main/res/drawable/ic_backup.xml b/app/src/main/res/drawable/ic_backup.xml index fe8737deb..200bb7081 100644 --- a/app/src/main/res/drawable/ic_backup.xml +++ b/app/src/main/res/drawable/ic_backup.xml @@ -1,29 +1,9 @@ - - + android:viewportWidth="24.0" + android:viewportHeight="24.0"> - - - - - - - \ No newline at end of file + android:fillColor="#FF000000" + android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4 9.11,4 6.6,5.64 5.35,8.04 2.34,8.36 0,10.91 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5 0,-2.64 -2.05,-4.78 -4.65,-4.96zM14,13v4h-4v-4H7l5,-5 5,5h-3z" /> + diff --git a/app/src/main/res/drawable/ic_restore.xml b/app/src/main/res/drawable/ic_restore.xml index 75e5490f6..d9f75ea6d 100644 --- a/app/src/main/res/drawable/ic_restore.xml +++ b/app/src/main/res/drawable/ic_restore.xml @@ -1,26 +1,9 @@ - - + android:viewportWidth="24.0" + android:viewportHeight="24.0"> - - - - - - \ No newline at end of file + android:fillColor="#FF000000" + android:pathData="M13,3c-4.97,0 -9,4.03 -9,9L1,12l3.89,3.89 0.07,0.14L9,12L6,12c0,-3.87 3.13,-7 7,-7s7,3.13 7,7 -3.13,7 -7,7c-1.93,0 -3.68,-0.79 -4.94,-2.06l-1.42,1.42C8.27,19.99 10.51,21 13,21c4.97,0 9,-4.03 9,-9s-4.03,-9 -9,-9zM12,8v5l4.28,2.54 0.72,-1.21 -3.5,-2.08L13.5,8L12,8z" /> + diff --git a/app/src/main/res/menu/my_config.xml b/app/src/main/res/menu/my_config.xml index e54b68733..e2cceece0 100644 --- a/app/src/main/res/menu/my_config.xml +++ b/app/src/main/res/menu/my_config.xml @@ -8,4 +8,16 @@ android:icon="@drawable/ic_live_help_black_24dp" app:showAsAction="always" /> + + + + From 9a1cce78d560752909a98fa6bdc11e0be4c5ea81 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 16 Sep 2019 09:11:27 +0800 Subject: [PATCH 1491/1997] up --- app/src/main/java/io/legado/app/help/MediaHelp.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/help/MediaHelp.kt b/app/src/main/java/io/legado/app/help/MediaHelp.kt index b59a88e88..756dadb53 100644 --- a/app/src/main/java/io/legado/app/help/MediaHelp.kt +++ b/app/src/main/java/io/legado/app/help/MediaHelp.kt @@ -17,7 +17,10 @@ object MediaHelp { or PlaybackStateCompat.ACTION_SKIP_TO_NEXT or PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS or PlaybackStateCompat.ACTION_STOP - or PlaybackStateCompat.ACTION_SEEK_TO) + or PlaybackStateCompat.ACTION_SEEK_TO + or PlaybackStateCompat.ACTION_PLAY_FROM_MEDIA_ID + or PlaybackStateCompat.ACTION_PLAY_FROM_SEARCH + or PlaybackStateCompat.ACTION_PLAY_FROM_URI) @RequiresApi(Build.VERSION_CODES.O) fun getFocusRequest(audioFocusChangeListener: AudioManager.OnAudioFocusChangeListener): AudioFocusRequest { From f095d87f61ab2c081295518656cb1aeb6cb3afb6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 16 Sep 2019 09:39:56 +0800 Subject: [PATCH 1492/1997] up --- app/src/main/AndroidManifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e9ff5d4f9..9bb422ffa 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -69,9 +69,9 @@ - + From ff4347e67685d98b44858052032ab4497317b008 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 16 Sep 2019 09:51:54 +0800 Subject: [PATCH 1493/1997] up --- .../main/java/io/legado/app/help/MediaHelp.kt | 21 ++++++++++++++----- .../app/receiver/MediaButtonReceiver.kt | 15 +++---------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/MediaHelp.kt b/app/src/main/java/io/legado/app/help/MediaHelp.kt index 756dadb53..65c15410b 100644 --- a/app/src/main/java/io/legado/app/help/MediaHelp.kt +++ b/app/src/main/java/io/legado/app/help/MediaHelp.kt @@ -11,16 +11,27 @@ import androidx.annotation.RequiresApi import io.legado.app.R object MediaHelp { - const val MEDIA_SESSION_ACTIONS = (PlaybackStateCompat.ACTION_PLAY - or PlaybackStateCompat.ACTION_PAUSE + const val MEDIA_SESSION_ACTIONS = (PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS + or PlaybackStateCompat.ACTION_REWIND + or PlaybackStateCompat.ACTION_PLAY or PlaybackStateCompat.ACTION_PLAY_PAUSE - or PlaybackStateCompat.ACTION_SKIP_TO_NEXT - or PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS + or PlaybackStateCompat.ACTION_PAUSE or PlaybackStateCompat.ACTION_STOP + or PlaybackStateCompat.ACTION_FAST_FORWARD + or PlaybackStateCompat.ACTION_SKIP_TO_NEXT or PlaybackStateCompat.ACTION_SEEK_TO + or PlaybackStateCompat.ACTION_SET_RATING or PlaybackStateCompat.ACTION_PLAY_FROM_MEDIA_ID or PlaybackStateCompat.ACTION_PLAY_FROM_SEARCH - or PlaybackStateCompat.ACTION_PLAY_FROM_URI) + or PlaybackStateCompat.ACTION_SKIP_TO_QUEUE_ITEM + or PlaybackStateCompat.ACTION_PLAY_FROM_URI + or PlaybackStateCompat.ACTION_PREPARE + or PlaybackStateCompat.ACTION_PREPARE_FROM_MEDIA_ID + or PlaybackStateCompat.ACTION_PREPARE_FROM_SEARCH + or PlaybackStateCompat.ACTION_PREPARE_FROM_URI + or PlaybackStateCompat.ACTION_SET_REPEAT_MODE + or PlaybackStateCompat.ACTION_SET_SHUFFLE_MODE + or PlaybackStateCompat.ACTION_SET_CAPTIONING_ENABLED) @RequiresApi(Build.VERSION_CODES.O) fun getFocusRequest(audioFocusChangeListener: AudioManager.OnAudioFocusChangeListener): AudioFocusRequest { diff --git a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt index f1c3b5bf6..9a71568ef 100644 --- a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt +++ b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt @@ -25,20 +25,11 @@ class MediaButtonReceiver : BroadcastReceiver() { val event = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT) ?: return false - val keycode = event.keyCode val action = event.action - when (keycode) { - KeyEvent.KEYCODE_MEDIA_STOP, - KeyEvent.KEYCODE_MEDIA_PAUSE, - KeyEvent.KEYCODE_MEDIA_PLAY, - KeyEvent.KEYCODE_HEADSETHOOK, - KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE -> { - if (action == KeyEvent.ACTION_DOWN) { - readAloud(context) - return true - } - } + if (action == KeyEvent.ACTION_DOWN) { + readAloud(context) + return true } } return false From 8f6e3eca6f8851bb87ef0a794a4a2ce1998c1e30 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 16 Sep 2019 10:02:38 +0800 Subject: [PATCH 1494/1997] up --- .../main/java/io/legado/app/service/BaseReadAloudService.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt index ad204f420..84e610932 100644 --- a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt @@ -179,7 +179,9 @@ abstract class BaseReadAloudService : BaseService(), upNotification() } - + /** + * 音频焦点变化 + */ override fun onAudioFocusChange(focusChange: Int) { when (focusChange) { AudioManager.AUDIOFOCUS_GAIN -> { From ea803610c361ed9563cfc889e4f64e7c430296c2 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 16 Sep 2019 21:52:47 +0800 Subject: [PATCH 1495/1997] up --- .../lib/theme/prefs/ATEEditTextPreference.kt | 25 ++++++++----------- app/src/main/res/xml/pref_config_web_dav.xml | 8 ++++-- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/theme/prefs/ATEEditTextPreference.kt b/app/src/main/java/io/legado/app/lib/theme/prefs/ATEEditTextPreference.kt index 9665e8586..d1b31a9a8 100644 --- a/app/src/main/java/io/legado/app/lib/theme/prefs/ATEEditTextPreference.kt +++ b/app/src/main/java/io/legado/app/lib/theme/prefs/ATEEditTextPreference.kt @@ -20,10 +20,8 @@ import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.ThemeStore import io.legado.app.utils.applyTint -class ATEEditTextPreference(context: Context?, attrs: AttributeSet?) : EditTextPreference( - context, - attrs -), +class ATEEditTextPreference(context: Context?, attrs: AttributeSet?) : + EditTextPreference(context, attrs), DialogInterface.OnClickListener, DialogInterface.OnDismissListener { private var builder: AlertDialog.Builder? = null @@ -36,8 +34,7 @@ class ATEEditTextPreference(context: Context?, attrs: AttributeSet?) : EditTextP private var mWhichButtonClicked: Int = 0 override fun onClick() { - if (dialog != null && dialog!!.isShowing) return - + if (dialog?.isShowing == true) return showDialog(null) } @@ -96,14 +93,14 @@ class ATEEditTextPreference(context: Context?, attrs: AttributeSet?) : EditTextP view.findViewById(android.R.id.message).visibility = View.GONE - val editText = this.editText!! - - ATH.setTint(editText, ThemeStore.accentColor(context)) + editText?.let { + ATH.setTint(it, ThemeStore.accentColor(context)) - editText.requestFocus() - editText.setText(text) - // Place cursor at the end - editText.setSelection(editText.length()) + it.requestFocus() + it.setText(text) + // Place cursor at the end + it.setSelection(it.length()) + } } override fun onClick(dialog: DialogInterface?, which: Int) { @@ -163,7 +160,7 @@ class ATEEditTextPreference(context: Context?, attrs: AttributeSet?) : EditTextP dest.writeBundle(dialogBundle) } - constructor(superState: Parcelable) : super(superState) {} + constructor(superState: Parcelable) : super(superState) companion object { diff --git a/app/src/main/res/xml/pref_config_web_dav.xml b/app/src/main/res/xml/pref_config_web_dav.xml index d9312c992..531698b1c 100644 --- a/app/src/main/res/xml/pref_config_web_dav.xml +++ b/app/src/main/res/xml/pref_config_web_dav.xml @@ -21,13 +21,17 @@ android:title="WebDav 密码" android:summary="输入你的WebDav授权密码" android:singleLine="true" - android:password="true" + android:inputType="textPassword" + app:iconSpaceReserved="false" /> + + \ No newline at end of file From caa723a4a2abfa00c0e784d69039fb5ae0f10511 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 16 Sep 2019 21:54:21 +0800 Subject: [PATCH 1496/1997] up --- .../app/lib/theme/prefs/ATEPreferenceCategory.kt | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/theme/prefs/ATEPreferenceCategory.kt b/app/src/main/java/io/legado/app/lib/theme/prefs/ATEPreferenceCategory.kt index 7f15973ef..90a2abfe5 100644 --- a/app/src/main/java/io/legado/app/lib/theme/prefs/ATEPreferenceCategory.kt +++ b/app/src/main/java/io/legado/app/lib/theme/prefs/ATEPreferenceCategory.kt @@ -13,14 +13,11 @@ import io.legado.app.lib.theme.ThemeStore class ATEPreferenceCategory : PreferenceCategory { @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super( - context, - attrs, - defStyleAttr, - defStyleRes - ) - - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : + super(context, attrs, defStyleAttr, defStyleRes) + + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : + super(context, attrs, defStyleAttr) constructor(context: Context, attrs: AttributeSet) : super(context, attrs) From 5e1d7ccdcc010c6350faa1a33cdb1c1c5c94e058 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 16 Sep 2019 21:58:45 +0800 Subject: [PATCH 1497/1997] up --- .../app/lib/theme/prefs/ATEColorPreference.kt | 17 ++--------------- .../lib/theme/prefs/ATEPreferenceCategory.kt | 11 ----------- .../lib/theme/prefs/ATESwitchPreference.kt | 19 ++----------------- 3 files changed, 4 insertions(+), 43 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/theme/prefs/ATEColorPreference.kt b/app/src/main/java/io/legado/app/lib/theme/prefs/ATEColorPreference.kt index 8e1ec7260..517ba8d68 100644 --- a/app/src/main/java/io/legado/app/lib/theme/prefs/ATEColorPreference.kt +++ b/app/src/main/java/io/legado/app/lib/theme/prefs/ATEColorPreference.kt @@ -15,7 +15,7 @@ import androidx.preference.PreferenceViewHolder import com.jaredrummler.android.colorpicker.* import io.legado.app.lib.theme.ATH -class ATEColorPreference : Preference, +class ATEColorPreference(context: Context, attrs: AttributeSet) : Preference(context, attrs), ColorPickerDialogListener { private val SIZE_NORMAL = 0 @@ -35,20 +35,7 @@ class ATEColorPreference : Preference, private var presets: IntArray? = null private var dialogTitle: Int = 0 - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { - init(attrs) - } - - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super( - context, - attrs, - defStyleAttr, - defStyleRes - ) { - init(attrs) - } - - private fun init(attrs: AttributeSet) { + init { isPersistent = true val a = context.obtainStyledAttributes(attrs, R.styleable.ColorPreference) showDialog = a.getBoolean(R.styleable.ColorPreference_cpv_showDialog, true) diff --git a/app/src/main/java/io/legado/app/lib/theme/prefs/ATEPreferenceCategory.kt b/app/src/main/java/io/legado/app/lib/theme/prefs/ATEPreferenceCategory.kt index 90a2abfe5..ba4363b15 100644 --- a/app/src/main/java/io/legado/app/lib/theme/prefs/ATEPreferenceCategory.kt +++ b/app/src/main/java/io/legado/app/lib/theme/prefs/ATEPreferenceCategory.kt @@ -1,10 +1,8 @@ package io.legado.app.lib.theme.prefs import android.content.Context -import android.os.Build import android.util.AttributeSet import android.widget.TextView -import androidx.annotation.RequiresApi import androidx.preference.PreferenceCategory import androidx.preference.PreferenceViewHolder import io.legado.app.lib.theme.ThemeStore @@ -12,17 +10,8 @@ import io.legado.app.lib.theme.ThemeStore class ATEPreferenceCategory : PreferenceCategory { - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : - super(context, attrs, defStyleAttr, defStyleRes) - - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : - super(context, attrs, defStyleAttr) - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) - constructor(context: Context) : super(context) - override fun onBindViewHolder(holder: PreferenceViewHolder?) { super.onBindViewHolder(holder) holder?.let { diff --git a/app/src/main/java/io/legado/app/lib/theme/prefs/ATESwitchPreference.kt b/app/src/main/java/io/legado/app/lib/theme/prefs/ATESwitchPreference.kt index 2ff1c9c05..998865a7f 100644 --- a/app/src/main/java/io/legado/app/lib/theme/prefs/ATESwitchPreference.kt +++ b/app/src/main/java/io/legado/app/lib/theme/prefs/ATESwitchPreference.kt @@ -1,9 +1,7 @@ package io.legado.app.lib.theme.prefs import android.content.Context -import android.os.Build import android.util.AttributeSet -import androidx.annotation.RequiresApi import androidx.appcompat.widget.SwitchCompat import androidx.preference.PreferenceViewHolder import androidx.preference.SwitchPreferenceCompat @@ -11,21 +9,8 @@ import io.legado.app.R import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.ThemeStore -class ATESwitchPreference : SwitchPreferenceCompat { - - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super( - context, - attrs, - defStyleAttr, - defStyleRes - ) - - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) - - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) - - constructor(context: Context) : super(context) +class ATESwitchPreference(context: Context, attrs: AttributeSet) : + SwitchPreferenceCompat(context, attrs) { override fun onBindViewHolder(holder: PreferenceViewHolder?) { super.onBindViewHolder(holder) From 1f02e47a59172ba2c16ec438d9468620788b7cc7 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 16 Sep 2019 23:07:29 +0800 Subject: [PATCH 1498/1997] up --- .../lib/theme/prefs/ATEEditTextPreference.kt | 20 ++++++++----------- .../app/ui/config/WebDavConfigFragment.kt | 5 +++++ app/src/main/res/xml/pref_config_web_dav.xml | 4 ---- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/theme/prefs/ATEEditTextPreference.kt b/app/src/main/java/io/legado/app/lib/theme/prefs/ATEEditTextPreference.kt index d1b31a9a8..eeba79c78 100644 --- a/app/src/main/java/io/legado/app/lib/theme/prefs/ATEEditTextPreference.kt +++ b/app/src/main/java/io/legado/app/lib/theme/prefs/ATEEditTextPreference.kt @@ -25,10 +25,9 @@ class ATEEditTextPreference(context: Context?, attrs: AttributeSet?) : DialogInterface.OnClickListener, DialogInterface.OnDismissListener { private var builder: AlertDialog.Builder? = null - private var dialog: AlertDialog? = null - private var editText: EditText? = null + var inputType: Int? = null /** Which button was clicked. */ private var mWhichButtonClicked: Int = 0 @@ -92,10 +91,11 @@ class ATEEditTextPreference(context: Context?, attrs: AttributeSet?) : checkNotNull(editText) { "Dialog view must contain an EditText with id" + " @android:id/edit" } view.findViewById(android.R.id.message).visibility = View.GONE - + inputType?.let { + editText?.inputType = it + } editText?.let { ATH.setTint(it, ThemeStore.accentColor(context)) - it.requestFocus() it.setText(text) // Place cursor at the end @@ -108,14 +108,10 @@ class ATEEditTextPreference(context: Context?, attrs: AttributeSet?) : } override fun onDismiss(dialog: DialogInterface?) { - onDialogClosed(mWhichButtonClicked == DialogInterface.BUTTON_POSITIVE) - - text = editText?.text.toString() - callChangeListener(text) - } - - protected fun onDialogClosed(positiveResult: Boolean) { - + if (mWhichButtonClicked == DialogInterface.BUTTON_POSITIVE) { + text = editText?.text.toString() + callChangeListener(text) + } } override fun onSaveInstanceState(): Parcelable { diff --git a/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt index 9faa87b39..909454885 100644 --- a/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt @@ -1,12 +1,14 @@ package io.legado.app.ui.config import android.os.Bundle +import android.text.InputType import android.view.View import androidx.preference.ListPreference import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat import io.legado.app.R import io.legado.app.lib.theme.ATH +import io.legado.app.lib.theme.prefs.ATEEditTextPreference import io.legado.app.utils.getPrefString class WebDavConfigFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChangeListener { @@ -15,6 +17,9 @@ class WebDavConfigFragment : PreferenceFragmentCompat(), Preference.OnPreference addPreferencesFromResource(R.xml.pref_config_web_dav) bindPreferenceSummaryToValue(findPreference("web_dav_url")) bindPreferenceSummaryToValue(findPreference("web_dav_account")) + findPreference("web_dav_password")?.let { + it.inputType = InputType.TYPE_TEXT_VARIATION_PASSWORD or InputType.TYPE_CLASS_TEXT + } } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { diff --git a/app/src/main/res/xml/pref_config_web_dav.xml b/app/src/main/res/xml/pref_config_web_dav.xml index 531698b1c..3bf47eecf 100644 --- a/app/src/main/res/xml/pref_config_web_dav.xml +++ b/app/src/main/res/xml/pref_config_web_dav.xml @@ -6,22 +6,18 @@ android:key="web_dav_url" android:title="WebDav 服务器地址" android:summary="输入你的服务器地址" - android:singleLine="true" app:iconSpaceReserved="false" /> Date: Tue, 17 Sep 2019 08:05:56 +0800 Subject: [PATCH 1499/1997] up --- .../io/legado/app/model/analyzeRule/AnalyzeByJSoup.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSoup.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSoup.kt index 570262f17..33658de3c 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSoup.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSoup.kt @@ -20,16 +20,16 @@ class AnalyzeByJSoup { private var element: Element? = null fun parse(doc: Any): AnalyzeByJSoup { - if (doc is Element) { - element = doc + element = if (doc is Element) { + doc } else if (doc is JXNode) { if (doc.isElement) { - element = doc.asElement() + doc.asElement() } else { - element = Jsoup.parse(doc.value().toString()) + Jsoup.parse(doc.value().toString()) } } else { - element = Jsoup.parse(doc.toString()) + Jsoup.parse(doc.toString()) } return this } From 8171c938a04d328903d742f25d5593df5cb5392c Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 17 Sep 2019 08:10:20 +0800 Subject: [PATCH 1500/1997] up --- .../java/io/legado/app/model/rss/RssParser.kt | 33 +++++++------------ 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/rss/RssParser.kt b/app/src/main/java/io/legado/app/model/rss/RssParser.kt index c3fd923bc..6cec063a6 100644 --- a/app/src/main/java/io/legado/app/model/rss/RssParser.kt +++ b/app/src/main/java/io/legado/app/model/rss/RssParser.kt @@ -40,44 +40,38 @@ object RssParser { xmlPullParser.name.equals( RSSKeywords.RSS_ITEM_TITLE, ignoreCase = true - ) - -> if (insideItem) { + ) -> if (insideItem) { currentArticle.title = xmlPullParser.nextText().trim() } xmlPullParser.name.equals( RSSKeywords.RSS_ITEM_LINK, ignoreCase = true - ) - -> if (insideItem) { + ) -> if (insideItem) { currentArticle.link = xmlPullParser.nextText().trim() } xmlPullParser.name.equals( RSSKeywords.RSS_ITEM_AUTHOR, ignoreCase = true - ) - -> if (insideItem) { + ) -> if (insideItem) { currentArticle.author = xmlPullParser.nextText().trim() } xmlPullParser.name.equals( RSSKeywords.RSS_ITEM_CATEGORY, ignoreCase = true - ) - -> if (insideItem) { + ) -> if (insideItem) { currentArticle.categories.add(xmlPullParser.nextText().trim()) } xmlPullParser.name.equals( RSSKeywords.RSS_ITEM_THUMBNAIL, ignoreCase = true - ) - -> if (insideItem) { + ) -> if (insideItem) { currentArticle.image = xmlPullParser.getAttributeValue(null, RSSKeywords.RSS_ITEM_URL) } xmlPullParser.name.equals( RSSKeywords.RSS_ITEM_ENCLOSURE, ignoreCase = true - ) - -> if (insideItem) { + ) -> if (insideItem) { val type = xmlPullParser.getAttributeValue(null, RSSKeywords.RSS_ITEM_TYPE) if (type != null && type.contains("image/")) { currentArticle.image = @@ -87,8 +81,7 @@ object RssParser { xmlPullParser.name.equals( RSSKeywords.RSS_ITEM_DESCRIPTION, ignoreCase = true - ) - -> if (insideItem) { + ) -> if (insideItem) { val description = xmlPullParser.nextText() currentArticle.description = description.trim() if (currentArticle.image == null) { @@ -98,8 +91,7 @@ object RssParser { xmlPullParser.name.equals( RSSKeywords.RSS_ITEM_CONTENT, ignoreCase = true - ) - -> if (insideItem) { + ) -> if (insideItem) { val content = xmlPullParser.nextText().trim() currentArticle.content = content if (currentArticle.image == null) { @@ -109,8 +101,7 @@ object RssParser { xmlPullParser.name.equals( RSSKeywords.RSS_ITEM_PUB_DATE, ignoreCase = true - ) - -> if (insideItem) { + ) -> if (insideItem) { val nextTokenType = xmlPullParser.next() if (nextTokenType == XmlPullParser.TEXT) { currentArticle.pubDate = xmlPullParser.text.trim() @@ -121,15 +112,13 @@ object RssParser { xmlPullParser.name.equals( RSSKeywords.RSS_ITEM_TIME, ignoreCase = true - ) - -> if (insideItem) { + ) -> if (insideItem) { currentArticle.pubDate = xmlPullParser.nextText() } xmlPullParser.name.equals( RSSKeywords.RSS_ITEM_GUID, ignoreCase = true - ) - -> if (insideItem) { + ) -> if (insideItem) { currentArticle.guid = xmlPullParser.nextText().trim() } } From bf77172bbc2a4215066d15335d14eb2dd860f045 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 17 Sep 2019 08:18:40 +0800 Subject: [PATCH 1501/1997] up --- .../java/io/legado/app/model/rss/RssParser.kt | 137 +++++++----------- 1 file changed, 50 insertions(+), 87 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/rss/RssParser.kt b/app/src/main/java/io/legado/app/model/rss/RssParser.kt index 6cec063a6..3c66389c7 100644 --- a/app/src/main/java/io/legado/app/model/rss/RssParser.kt +++ b/app/src/main/java/io/legado/app/model/rss/RssParser.kt @@ -33,99 +33,62 @@ object RssParser { // Start parsing the item if (eventType == XmlPullParser.START_TAG) { when { - xmlPullParser.name.equals( - RSSKeywords.RSS_ITEM, - ignoreCase = true - ) -> insideItem = true - xmlPullParser.name.equals( - RSSKeywords.RSS_ITEM_TITLE, - ignoreCase = true - ) -> if (insideItem) { - currentArticle.title = xmlPullParser.nextText().trim() - } - xmlPullParser.name.equals( - RSSKeywords.RSS_ITEM_LINK, - ignoreCase = true - ) -> if (insideItem) { - currentArticle.link = xmlPullParser.nextText().trim() - } - xmlPullParser.name.equals( - RSSKeywords.RSS_ITEM_AUTHOR, - ignoreCase = true - ) -> if (insideItem) { - currentArticle.author = xmlPullParser.nextText().trim() - } - xmlPullParser.name.equals( - RSSKeywords.RSS_ITEM_CATEGORY, - ignoreCase = true - ) -> if (insideItem) { - currentArticle.categories.add(xmlPullParser.nextText().trim()) - } - xmlPullParser.name.equals( - RSSKeywords.RSS_ITEM_THUMBNAIL, - ignoreCase = true - ) -> if (insideItem) { - currentArticle.image = + xmlPullParser.name + .equals(RSSKeywords.RSS_ITEM, true) -> insideItem = true + xmlPullParser.name.equals(RSSKeywords.RSS_ITEM_TITLE, true) -> + if (insideItem) currentArticle.title = xmlPullParser.nextText().trim() + xmlPullParser.name.equals(RSSKeywords.RSS_ITEM_LINK, true) -> + if (insideItem) currentArticle.link = xmlPullParser.nextText().trim() + xmlPullParser.name.equals(RSSKeywords.RSS_ITEM_AUTHOR, true) -> + if (insideItem) currentArticle.author = xmlPullParser.nextText().trim() + xmlPullParser.name.equals(RSSKeywords.RSS_ITEM_CATEGORY, true) -> + if (insideItem) currentArticle.categories.add(xmlPullParser.nextText().trim()) + xmlPullParser.name.equals(RSSKeywords.RSS_ITEM_THUMBNAIL, true) -> + if (insideItem) currentArticle.image = xmlPullParser.getAttributeValue(null, RSSKeywords.RSS_ITEM_URL) - } - xmlPullParser.name.equals( - RSSKeywords.RSS_ITEM_ENCLOSURE, - ignoreCase = true - ) -> if (insideItem) { - val type = xmlPullParser.getAttributeValue(null, RSSKeywords.RSS_ITEM_TYPE) - if (type != null && type.contains("image/")) { - currentArticle.image = - xmlPullParser.getAttributeValue(null, RSSKeywords.RSS_ITEM_URL) + xmlPullParser.name.equals(RSSKeywords.RSS_ITEM_ENCLOSURE, true) -> + if (insideItem) { + val type = + xmlPullParser.getAttributeValue(null, RSSKeywords.RSS_ITEM_TYPE) + if (type != null && type.contains("image/")) { + currentArticle.image = + xmlPullParser.getAttributeValue(null, RSSKeywords.RSS_ITEM_URL) + } } - } - xmlPullParser.name.equals( - RSSKeywords.RSS_ITEM_DESCRIPTION, - ignoreCase = true - ) -> if (insideItem) { - val description = xmlPullParser.nextText() - currentArticle.description = description.trim() - if (currentArticle.image == null) { - currentArticle.image = getImageUrl(description) + xmlPullParser.name + .equals(RSSKeywords.RSS_ITEM_DESCRIPTION, true) -> + if (insideItem) { + val description = xmlPullParser.nextText() + currentArticle.description = description.trim() + if (currentArticle.image == null) { + currentArticle.image = getImageUrl(description) + } } - } - xmlPullParser.name.equals( - RSSKeywords.RSS_ITEM_CONTENT, - ignoreCase = true - ) -> if (insideItem) { - val content = xmlPullParser.nextText().trim() - currentArticle.content = content - if (currentArticle.image == null) { - currentArticle.image = getImageUrl(content) + xmlPullParser.name.equals(RSSKeywords.RSS_ITEM_CONTENT, true) -> + if (insideItem) { + val content = xmlPullParser.nextText().trim() + currentArticle.content = content + if (currentArticle.image == null) { + currentArticle.image = getImageUrl(content) + } } - } - xmlPullParser.name.equals( - RSSKeywords.RSS_ITEM_PUB_DATE, - ignoreCase = true - ) -> if (insideItem) { - val nextTokenType = xmlPullParser.next() - if (nextTokenType == XmlPullParser.TEXT) { - currentArticle.pubDate = xmlPullParser.text.trim() + xmlPullParser.name + .equals(RSSKeywords.RSS_ITEM_PUB_DATE, true) -> + if (insideItem) { + val nextTokenType = xmlPullParser.next() + if (nextTokenType == XmlPullParser.TEXT) { + currentArticle.pubDate = xmlPullParser.text.trim() + } + // Skip to be able to find date inside 'tag' tag + continue@loop } - // Skip to be able to find date inside 'tag' tag - continue@loop - } - xmlPullParser.name.equals( - RSSKeywords.RSS_ITEM_TIME, - ignoreCase = true - ) -> if (insideItem) { - currentArticle.pubDate = xmlPullParser.nextText() - } - xmlPullParser.name.equals( - RSSKeywords.RSS_ITEM_GUID, - ignoreCase = true - ) -> if (insideItem) { - currentArticle.guid = xmlPullParser.nextText().trim() - } + xmlPullParser.name.equals(RSSKeywords.RSS_ITEM_TIME, true) -> + if (insideItem) currentArticle.pubDate = xmlPullParser.nextText() + xmlPullParser.name.equals(RSSKeywords.RSS_ITEM_GUID, true) -> + if (insideItem) currentArticle.guid = xmlPullParser.nextText().trim() } - } else if (eventType == XmlPullParser.END_TAG && xmlPullParser.name.equals( - "item", - ignoreCase = true - ) + } else if (eventType == XmlPullParser.END_TAG + && xmlPullParser.name.equals("item", true) ) { // The item is correctly parsed insideItem = false From 9469e525035b7c13591f46cb9641d2a06e8881f3 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 17 Sep 2019 08:20:05 +0800 Subject: [PATCH 1502/1997] up --- app/src/main/java/io/legado/app/model/rss/RssParser.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/rss/RssParser.kt b/app/src/main/java/io/legado/app/model/rss/RssParser.kt index 3c66389c7..2696fb26a 100644 --- a/app/src/main/java/io/legado/app/model/rss/RssParser.kt +++ b/app/src/main/java/io/legado/app/model/rss/RssParser.kt @@ -33,8 +33,8 @@ object RssParser { // Start parsing the item if (eventType == XmlPullParser.START_TAG) { when { - xmlPullParser.name - .equals(RSSKeywords.RSS_ITEM, true) -> insideItem = true + xmlPullParser.name.equals(RSSKeywords.RSS_ITEM, true) -> + insideItem = true xmlPullParser.name.equals(RSSKeywords.RSS_ITEM_TITLE, true) -> if (insideItem) currentArticle.title = xmlPullParser.nextText().trim() xmlPullParser.name.equals(RSSKeywords.RSS_ITEM_LINK, true) -> From dfd21b5c5c1af1881b90e04403de3600f5ee2720 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 17 Sep 2019 08:27:56 +0800 Subject: [PATCH 1503/1997] up --- app/src/main/java/io/legado/app/lib/webdav/WebDav.kt | 2 +- .../java/io/legado/app/lib/webdav/http/Handler.kt | 11 +---------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt b/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt index d7419aebf..225850113 100644 --- a/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt +++ b/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt @@ -21,7 +21,7 @@ import java.util.* class WebDav @Throws(MalformedURLException::class) constructor(url: String) { - private val url: URL = URL(null, url, Handler.HANDLER) + private val url: URL = URL(null, url, Handler) private var httpUrl: String? = null var displayName: String? = null diff --git a/app/src/main/java/io/legado/app/lib/webdav/http/Handler.kt b/app/src/main/java/io/legado/app/lib/webdav/http/Handler.kt index 2bafb9780..c3deec2e2 100644 --- a/app/src/main/java/io/legado/app/lib/webdav/http/Handler.kt +++ b/app/src/main/java/io/legado/app/lib/webdav/http/Handler.kt @@ -4,7 +4,7 @@ import java.net.URL import java.net.URLConnection import java.net.URLStreamHandler -class Handler : URLStreamHandler() { +object Handler : URLStreamHandler() { override fun getDefaultPort(): Int { return 80 @@ -13,13 +13,4 @@ class Handler : URLStreamHandler() { public override fun openConnection(u: URL): URLConnection? { return null } - - override fun parseURL(url: URL, spec: String, start: Int, end: Int) { - super.parseURL(url, spec, start, end) - } - - companion object { - - val HANDLER: URLStreamHandler = Handler() - } } From 8316e13987b68a32208ff97d87a368807fea0c6b Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 17 Sep 2019 10:36:11 +0800 Subject: [PATCH 1504/1997] up --- .../main/java/io/legado/app/help/FileHelp.kt | 6 + .../java/io/legado/app/help/storage/Backup.kt | 10 +- .../io/legado/app/help/storage/Restore.kt | 6 +- .../io/legado/app/help/storage/WebDavHelp.kt | 81 ++++ .../app/service/BaseReadAloudService.kt | 3 +- .../main/java/io/legado/app/utils/ZipUtils.kt | 420 ++++++++++++++++++ 6 files changed, 517 insertions(+), 9 deletions(-) create mode 100644 app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt create mode 100644 app/src/main/java/io/legado/app/utils/ZipUtils.kt diff --git a/app/src/main/java/io/legado/app/help/FileHelp.kt b/app/src/main/java/io/legado/app/help/FileHelp.kt index f274c84e4..cb0228445 100644 --- a/app/src/main/java/io/legado/app/help/FileHelp.kt +++ b/app/src/main/java/io/legado/app/help/FileHelp.kt @@ -1,5 +1,6 @@ package io.legado.app.help +import io.legado.app.App import java.io.File import java.io.IOException @@ -32,4 +33,9 @@ object FileHelp { } return file } + + fun getCachePath(): String { + return App.INSTANCE.externalCacheDir?.absolutePath + ?: App.INSTANCE.cacheDir.absolutePath + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/help/storage/Backup.kt b/app/src/main/java/io/legado/app/help/storage/Backup.kt index 6fd1f079b..cd7c69edc 100644 --- a/app/src/main/java/io/legado/app/help/storage/Backup.kt +++ b/app/src/main/java/io/legado/app/help/storage/Backup.kt @@ -13,10 +13,13 @@ import java.io.File object Backup { + val defaultPath by lazy { + FileUtils.getSdCardPath() + File.separator + "YueDu" + File.separator + "legadoBackUp" + } + fun backup() { doAsync { - val path = - FileUtils.getSdCardPath() + File.separator + "YueDu" + File.separator + "legadoBackUp" + val path = defaultPath backupBookshelf(path) backupBookSource(path) backupRssSource(path) @@ -29,8 +32,7 @@ object Backup { fun autoBackup(activity: AppCompatActivity) { doAsync { - val path = - FileUtils.getSdCardPath() + File.separator + "YueDu" + File.separator + "legadoBackUp" + val path = defaultPath backupBookshelf(path) backupBookSource(path) backupRssSource(path) diff --git a/app/src/main/java/io/legado/app/help/storage/Restore.kt b/app/src/main/java/io/legado/app/help/storage/Restore.kt index 10bc36bf7..94b24cb00 100644 --- a/app/src/main/java/io/legado/app/help/storage/Restore.kt +++ b/app/src/main/java/io/legado/app/help/storage/Restore.kt @@ -12,6 +12,7 @@ import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.ReplaceRule import io.legado.app.data.entities.RssSource import io.legado.app.help.FileHelp +import io.legado.app.help.storage.Backup.defaultPath import io.legado.app.utils.* import org.jetbrains.anko.doAsync import org.jetbrains.anko.toast @@ -25,10 +26,6 @@ object Restore { .build() ) - private val defaultPath by lazy { - FileUtils.getSdCardPath() + File.separator + "YueDu" + File.separator + "legadoBackUp" - } - fun restore(path: String = defaultPath) { doAsync { try { @@ -67,6 +64,7 @@ object Restore { } catch (e: Exception) { e.printStackTrace() } + uiThread { App.INSTANCE.toast("恢复完成") } } } diff --git a/app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt b/app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt new file mode 100644 index 000000000..fb5b9045a --- /dev/null +++ b/app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt @@ -0,0 +1,81 @@ +package io.legado.app.help.storage + +import android.content.Context +import io.legado.app.App +import io.legado.app.help.FileHelp +import io.legado.app.lib.webdav.WebDav +import io.legado.app.lib.webdav.http.HttpAuth +import io.legado.app.utils.ZipUtils +import io.legado.app.utils.getPrefString +import org.jetbrains.anko.doAsync +import org.jetbrains.anko.selector +import org.jetbrains.anko.uiThread +import kotlin.math.min + +object WebDavHelp { + + fun getWebDavUrl(): String? { + var url = App.INSTANCE.getPrefString("web_dav_url") + if (url.isNullOrBlank()) return null + if (!url.endsWith("/")) url += "/" + return url + } + + private fun initWebDav(): Boolean { + val account = App.INSTANCE.getPrefString("web_dav_account") + val password = App.INSTANCE.getPrefString("web_dav_password") + if (!account.isNullOrBlank() && !password.isNullOrBlank()) { + HttpAuth.auth = HttpAuth.Auth(account, password) + return true + } + return false + } + + private fun getWebDavFileNames(): ArrayList { + val url = getWebDavUrl() + val names = arrayListOf() + if (!url.isNullOrBlank() && initWebDav()) { + val files = WebDav(url + "legado/").listFiles() + files.reversed() + for (index: Int in 0 until min(10, files.size)) { + files[index].displayName?.let { + names.add(it) + } + } + } + return names + } + + fun showRestoreDialog(context: Context) { + doAsync { + val names = getWebDavFileNames() + if (names.isNotEmpty()) { + uiThread { + context.selector(title = "选择恢复文件", items = names) { _, index -> + if (index in 0 until names.size) { + restoreWebDav(names[index]) + } + } + } + } else { + Restore.restore() + } + } + } + + private fun restoreWebDav(name: String) { + doAsync { + getWebDavUrl()?.let { + val file = WebDav(it + "legado/" + name) + val zipFilePath = FileHelp.getCachePath() + "/backup" + ".zip" + file.downloadTo(zipFilePath, true) + ZipUtils.unzipFile(zipFilePath, Backup.defaultPath) + Restore.restore() + } + } + } + + fun backUpWebDav() { + + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt index 84e610932..4a74683f5 100644 --- a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt @@ -59,6 +59,7 @@ abstract class BaseReadAloudService : BaseService(), initMediaSession() initBroadcastReceiver() upNotification() + upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PLAYING) } override fun onDestroy() { @@ -116,7 +117,6 @@ abstract class BaseReadAloudService : BaseService(), } open fun play() { - upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PLAYING) postEvent(Bus.ALOUD_STATE, Status.PLAY) upNotification() } @@ -132,6 +132,7 @@ abstract class BaseReadAloudService : BaseService(), @CallSuper open fun resumeReadAloud() { pause = false + upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PLAYING) } abstract fun upSpeechRate(reset: Boolean = false) diff --git a/app/src/main/java/io/legado/app/utils/ZipUtils.kt b/app/src/main/java/io/legado/app/utils/ZipUtils.kt new file mode 100644 index 000000000..fc8aa97ed --- /dev/null +++ b/app/src/main/java/io/legado/app/utils/ZipUtils.kt @@ -0,0 +1,420 @@ +package io.legado.app.utils + +import android.util.Log +import java.io.* +import java.util.* +import java.util.zip.ZipEntry +import java.util.zip.ZipFile +import java.util.zip.ZipOutputStream + +/** + *
    + * author: Blankj
    + * blog  : http://blankj.com
    + * time  : 2016/08/27
    + * desc  : utils about zip
    +
    * + */ +object ZipUtils { + + /** + * Zip the files. + * + * @param srcFiles The source of files. + * @param zipFilePath The path of ZIP file. + * @return `true`: success

    `false`: fail + * @throws IOException if an I/O error has occurred + */ + @Throws(IOException::class) + fun zipFiles( + srcFiles: Collection, + zipFilePath: String + ): Boolean { + return zipFiles(srcFiles, zipFilePath, null) + } + + /** + * Zip the files. + * + * @param srcFilePaths The paths of source files. + * @param zipFilePath The path of ZIP file. + * @param comment The comment. + * @return `true`: success

    `false`: fail + * @throws IOException if an I/O error has occurred + */ + @Throws(IOException::class) + fun zipFiles( + srcFilePaths: Collection?, + zipFilePath: String?, + comment: String? + ): Boolean { + if (srcFilePaths == null || zipFilePath == null) return false + var zos: ZipOutputStream? = null + try { + zos = ZipOutputStream(FileOutputStream(zipFilePath)) + for (srcFile in srcFilePaths) { + if (!zipFile(getFileByPath(srcFile)!!, "", zos, comment)) return false + } + return true + } finally { + if (zos != null) { + zos.finish() + zos.close() + } + } + } + + /** + * Zip the files. + * + * @param srcFiles The source of files. + * @param zipFile The ZIP file. + * @param comment The comment. + * @return `true`: success

    `false`: fail + * @throws IOException if an I/O error has occurred + */ + @Throws(IOException::class) + @JvmOverloads + fun zipFiles( + srcFiles: Collection?, + zipFile: File?, + comment: String? = null + ): Boolean { + if (srcFiles == null || zipFile == null) return false + var zos: ZipOutputStream? = null + try { + zos = ZipOutputStream(FileOutputStream(zipFile)) + for (srcFile in srcFiles) { + if (!zipFile(srcFile, "", zos, comment)) return false + } + return true + } finally { + if (zos != null) { + zos.finish() + zos.close() + } + } + } + + /** + * Zip the file. + * + * @param srcFilePath The path of source file. + * @param zipFilePath The path of ZIP file. + * @return `true`: success

    `false`: fail + * @throws IOException if an I/O error has occurred + */ + @Throws(IOException::class) + fun zipFile( + srcFilePath: String, + zipFilePath: String + ): Boolean { + return zipFile(getFileByPath(srcFilePath), getFileByPath(zipFilePath), null) + } + + /** + * Zip the file. + * + * @param srcFilePath The path of source file. + * @param zipFilePath The path of ZIP file. + * @param comment The comment. + * @return `true`: success

    `false`: fail + * @throws IOException if an I/O error has occurred + */ + @Throws(IOException::class) + fun zipFile( + srcFilePath: String, + zipFilePath: String, + comment: String + ): Boolean { + return zipFile(getFileByPath(srcFilePath), getFileByPath(zipFilePath), comment) + } + + /** + * Zip the file. + * + * @param srcFile The source of file. + * @param zipFile The ZIP file. + * @param comment The comment. + * @return `true`: success

    `false`: fail + * @throws IOException if an I/O error has occurred + */ + @Throws(IOException::class) + @JvmOverloads + fun zipFile( + srcFile: File?, + zipFile: File?, + comment: String? = null + ): Boolean { + if (srcFile == null || zipFile == null) return false + ZipOutputStream(FileOutputStream(zipFile)).use { zos -> + return zipFile( + srcFile, + "", + zos, + comment + ) + } + } + + @Throws(IOException::class) + private fun zipFile( + srcFile: File, + rootPath: String, + zos: ZipOutputStream, + comment: String? + ): Boolean { + var rootPath = rootPath + if (!srcFile.exists()) return true + rootPath = rootPath + (if (isSpace(rootPath)) "" else File.separator) + srcFile.name + if (srcFile.isDirectory) { + val fileList = srcFile.listFiles() + if (fileList == null || fileList.isEmpty()) { + val entry = ZipEntry("$rootPath/") + entry.comment = comment + zos.putNextEntry(entry) + zos.closeEntry() + } else { + for (file in fileList) { + if (!zipFile(file, rootPath, zos, comment)) return false + } + } + } else { + BufferedInputStream(FileInputStream(srcFile)).use { `is` -> + val entry = ZipEntry(rootPath) + entry.comment = comment + zos.putNextEntry(entry) + zos.write(`is`.readBytes()) + zos.closeEntry() + } + } + return true + } + + /** + * Unzip the file. + * + * @param zipFilePath The path of ZIP file. + * @param destDirPath The path of destination directory. + * @return the unzipped files + * @throws IOException if unzip unsuccessfully + */ + @Throws(IOException::class) + fun unzipFile(zipFilePath: String, destDirPath: String): List? { + return unzipFileByKeyword(zipFilePath, destDirPath, null) + } + + /** + * Unzip the file. + * + * @param zipFile The ZIP file. + * @param destDir The destination directory. + * @return the unzipped files + * @throws IOException if unzip unsuccessfully + */ + @Throws(IOException::class) + fun unzipFile( + zipFile: File, + destDir: File + ): List? { + return unzipFileByKeyword(zipFile, destDir, null) + } + + /** + * Unzip the file by keyword. + * + * @param zipFilePath The path of ZIP file. + * @param destDirPath The path of destination directory. + * @param keyword The keyboard. + * @return the unzipped files + * @throws IOException if unzip unsuccessfully + */ + @Throws(IOException::class) + fun unzipFileByKeyword( + zipFilePath: String, + destDirPath: String, + keyword: String? + ): List? { + return unzipFileByKeyword( + getFileByPath(zipFilePath), + getFileByPath(destDirPath), + keyword + ) + } + + /** + * Unzip the file by keyword. + * + * @param zipFile The ZIP file. + * @param destDir The destination directory. + * @param keyword The keyboard. + * @return the unzipped files + * @throws IOException if unzip unsuccessfully + */ + @Throws(IOException::class) + fun unzipFileByKeyword( + zipFile: File?, + destDir: File?, + keyword: String? + ): List? { + if (zipFile == null || destDir == null) return null + val files = ArrayList() + val zip = ZipFile(zipFile) + val entries = zip.entries() + try { + if (isSpace(keyword)) { + while (entries.hasMoreElements()) { + val entry = entries.nextElement() as ZipEntry + val entryName = entry.name + if (entryName.contains("../")) { + Log.e("ZipUtils", "entryName: $entryName is dangerous!") + continue + } + if (!unzipChildFile(destDir, files, zip, entry, entryName)) return files + } + } else { + while (entries.hasMoreElements()) { + val entry = entries.nextElement() as ZipEntry + val entryName = entry.name + if (entryName.contains("../")) { + Log.e("ZipUtils", "entryName: $entryName is dangerous!") + continue + } + if (entryName.contains(keyword!!)) { + if (!unzipChildFile(destDir, files, zip, entry, entryName)) return files + } + } + } + } finally { + zip.close() + } + return files + } + + @Throws(IOException::class) + private fun unzipChildFile( + destDir: File, + files: MutableList, + zip: ZipFile, + entry: ZipEntry, + name: String + ): Boolean { + val file = File(destDir, name) + files.add(file) + if (entry.isDirectory) { + return createOrExistsDir(file) + } else { + if (!createOrExistsFile(file)) return false + BufferedInputStream(zip.getInputStream(entry)).use { `in` -> + BufferedOutputStream(FileOutputStream(file)).use { out -> + out.write(`in`.readBytes()) + } + } + } + return true + } + + /** + * Return the files' path in ZIP file. + * + * @param zipFilePath The path of ZIP file. + * @return the files' path in ZIP file + * @throws IOException if an I/O error has occurred + */ + @Throws(IOException::class) + fun getFilesPath(zipFilePath: String): List? { + return getFilesPath(getFileByPath(zipFilePath)) + } + + /** + * Return the files' path in ZIP file. + * + * @param zipFile The ZIP file. + * @return the files' path in ZIP file + * @throws IOException if an I/O error has occurred + */ + @Throws(IOException::class) + fun getFilesPath(zipFile: File?): List? { + if (zipFile == null) return null + val paths = ArrayList() + val zip = ZipFile(zipFile) + val entries = zip.entries() + while (entries.hasMoreElements()) { + val entryName = (entries.nextElement() as ZipEntry).name + if (entryName.contains("../")) { + Log.e("ZipUtils", "entryName: $entryName is dangerous!") + paths.add(entryName) + } else { + paths.add(entryName) + } + } + zip.close() + return paths + } + + /** + * Return the files' comment in ZIP file. + * + * @param zipFilePath The path of ZIP file. + * @return the files' comment in ZIP file + * @throws IOException if an I/O error has occurred + */ + @Throws(IOException::class) + fun getComments(zipFilePath: String): List? { + return getComments(getFileByPath(zipFilePath)) + } + + /** + * Return the files' comment in ZIP file. + * + * @param zipFile The ZIP file. + * @return the files' comment in ZIP file + * @throws IOException if an I/O error has occurred + */ + @Throws(IOException::class) + fun getComments(zipFile: File?): List? { + if (zipFile == null) return null + val comments = ArrayList() + val zip = ZipFile(zipFile) + val entries = zip.entries() + while (entries.hasMoreElements()) { + val entry = entries.nextElement() as ZipEntry + comments.add(entry.comment) + } + zip.close() + return comments + } + + private fun createOrExistsDir(file: File?): Boolean { + return file != null && if (file.exists()) file.isDirectory else file.mkdirs() + } + + private fun createOrExistsFile(file: File?): Boolean { + if (file == null) return false + if (file.exists()) return file.isFile + if (!createOrExistsDir(file.parentFile)) return false + return try { + file.createNewFile() + } catch (e: IOException) { + e.printStackTrace() + false + } + } + + private fun getFileByPath(filePath: String): File? { + return if (isSpace(filePath)) null else File(filePath) + } + + private fun isSpace(s: String?): Boolean { + if (s == null) return true + var i = 0 + val len = s.length + while (i < len) { + if (!Character.isWhitespace(s[i])) { + return false + } + ++i + } + return true + } +} \ No newline at end of file From 30d1c90ada568723131f94e7186faa0aaaec46af Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 17 Sep 2019 10:52:35 +0800 Subject: [PATCH 1505/1997] up --- .../main/java/io/legado/app/help/FileHelp.kt | 17 ++++++++++++++ .../java/io/legado/app/help/storage/Backup.kt | 2 ++ .../io/legado/app/help/storage/WebDavHelp.kt | 22 +++++++++++++++++-- 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/FileHelp.kt b/app/src/main/java/io/legado/app/help/FileHelp.kt index cb0228445..a208a74a2 100644 --- a/app/src/main/java/io/legado/app/help/FileHelp.kt +++ b/app/src/main/java/io/legado/app/help/FileHelp.kt @@ -38,4 +38,21 @@ object FileHelp { return App.INSTANCE.externalCacheDir?.absolutePath ?: App.INSTANCE.cacheDir.absolutePath } + + //递归删除文件夹下的数据 + @Synchronized + fun deleteFile(filePath: String) { + val file = File(filePath) + if (!file.exists()) return + + if (file.isDirectory) { + val files = file.listFiles() + for (subFile in files) { + val path = subFile.path + deleteFile(path) + } + } + //删除文件 + file.delete() + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/help/storage/Backup.kt b/app/src/main/java/io/legado/app/help/storage/Backup.kt index cd7c69edc..683cf34c1 100644 --- a/app/src/main/java/io/legado/app/help/storage/Backup.kt +++ b/app/src/main/java/io/legado/app/help/storage/Backup.kt @@ -24,6 +24,7 @@ object Backup { backupBookSource(path) backupRssSource(path) backupReplaceRule(path) + WebDavHelp.backUpWebDav() uiThread { App.INSTANCE.toast(R.string.backup_success) } @@ -37,6 +38,7 @@ object Backup { backupBookSource(path) backupRssSource(path) backupReplaceRule(path) + WebDavHelp.backUpWebDav() } } diff --git a/app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt b/app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt index fb5b9045a..c19c3b46f 100644 --- a/app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt +++ b/app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt @@ -10,9 +10,13 @@ import io.legado.app.utils.getPrefString import org.jetbrains.anko.doAsync import org.jetbrains.anko.selector import org.jetbrains.anko.uiThread +import java.io.File +import java.text.SimpleDateFormat +import java.util.* import kotlin.math.min object WebDavHelp { + private val zipFilePath = FileHelp.getCachePath() + "/backup" + ".zip" fun getWebDavUrl(): String? { var url = App.INSTANCE.getPrefString("web_dav_url") @@ -67,7 +71,6 @@ object WebDavHelp { doAsync { getWebDavUrl()?.let { val file = WebDav(it + "legado/" + name) - val zipFilePath = FileHelp.getCachePath() + "/backup" + ".zip" file.downloadTo(zipFilePath, true) ZipUtils.unzipFile(zipFilePath, Backup.defaultPath) Restore.restore() @@ -76,6 +79,21 @@ object WebDavHelp { } fun backUpWebDav() { - + if (initWebDav()) { + val paths = arrayListOf() + paths.add(Backup.defaultPath + File.separator + "bookshelf.json") + paths.add(Backup.defaultPath + File.separator + "bookSource.json") + paths.add(Backup.defaultPath + File.separator + "rssSource.json") + paths.add(Backup.defaultPath + File.separator + "replaceRule.json") + FileHelp.deleteFile(zipFilePath) + if (ZipUtils.zipFiles(paths, zipFilePath)) { + WebDav(getWebDavUrl() + "legado").makeAsDir() + val putUrl = getWebDavUrl() + "legado/backup" + SimpleDateFormat( + "yyyy-MM-dd", + Locale.getDefault() + ).format(Date(System.currentTimeMillis())) + ".zip" + WebDav(putUrl).upload(zipFilePath) + } + } } } \ No newline at end of file From 3e8b62759b0324cd6c06041bfd97364b93681455 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 17 Sep 2019 10:54:15 +0800 Subject: [PATCH 1506/1997] up --- app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt b/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt index b98a655b0..ff96e01cc 100644 --- a/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt @@ -13,7 +13,7 @@ import io.legado.app.base.BaseFragment import io.legado.app.help.permission.Permissions import io.legado.app.help.permission.PermissionsCompat import io.legado.app.help.storage.Backup -import io.legado.app.help.storage.Restore +import io.legado.app.help.storage.WebDavHelp import io.legado.app.lib.theme.ATH import io.legado.app.ui.about.AboutActivity import io.legado.app.ui.about.DonateActivity @@ -50,7 +50,7 @@ class MyFragment : BaseFragment(R.layout.fragment_my_config) { R.id.menu_restore -> PermissionsCompat.Builder(this) .addPermissions(*Permissions.Group.STORAGE) .rationale(R.string.tip_perm_request_storage) - .onGranted { Restore.restore() } + .onGranted { WebDavHelp.showRestoreDialog(requireContext()) } .request() } } From 01223ea0b1ce00920566dafd6f6da5dab37df7ae Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 17 Sep 2019 11:01:59 +0800 Subject: [PATCH 1507/1997] up --- app/src/main/java/io/legado/app/utils/ZipUtils.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/utils/ZipUtils.kt b/app/src/main/java/io/legado/app/utils/ZipUtils.kt index fc8aa97ed..eab9951c7 100644 --- a/app/src/main/java/io/legado/app/utils/ZipUtils.kt +++ b/app/src/main/java/io/legado/app/utils/ZipUtils.kt @@ -164,24 +164,24 @@ object ZipUtils { zos: ZipOutputStream, comment: String? ): Boolean { - var rootPath = rootPath + var rootPath1 = rootPath if (!srcFile.exists()) return true - rootPath = rootPath + (if (isSpace(rootPath)) "" else File.separator) + srcFile.name + rootPath1 = rootPath1 + (if (isSpace(rootPath1)) "" else File.separator) + srcFile.name if (srcFile.isDirectory) { val fileList = srcFile.listFiles() if (fileList == null || fileList.isEmpty()) { - val entry = ZipEntry("$rootPath/") + val entry = ZipEntry("$rootPath1/") entry.comment = comment zos.putNextEntry(entry) zos.closeEntry() } else { for (file in fileList) { - if (!zipFile(file, rootPath, zos, comment)) return false + if (!zipFile(file, rootPath1, zos, comment)) return false } } } else { BufferedInputStream(FileInputStream(srcFile)).use { `is` -> - val entry = ZipEntry(rootPath) + val entry = ZipEntry(rootPath1) entry.comment = comment zos.putNextEntry(entry) zos.write(`is`.readBytes()) From 81c23b9379ebc3aa50f5dec40e903e9040a8e1e9 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 17 Sep 2019 11:19:16 +0800 Subject: [PATCH 1508/1997] up --- .../app/ui/config/WebDavConfigFragment.kt | 37 ++++++++++++++----- app/src/main/res/values/strings.xml | 1 + app/src/main/res/xml/pref_config_web_dav.xml | 4 +- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt index 909454885..bfc2ca0ef 100644 --- a/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt @@ -7,6 +7,8 @@ import androidx.preference.ListPreference import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat import io.legado.app.R +import io.legado.app.help.storage.Backup +import io.legado.app.help.storage.WebDavHelp import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.prefs.ATEEditTextPreference import io.legado.app.utils.getPrefString @@ -19,6 +21,7 @@ class WebDavConfigFragment : PreferenceFragmentCompat(), Preference.OnPreference bindPreferenceSummaryToValue(findPreference("web_dav_account")) findPreference("web_dav_password")?.let { it.inputType = InputType.TYPE_TEXT_VARIATION_PASSWORD or InputType.TYPE_CLASS_TEXT + bindPreferenceSummaryToValue(it) } } @@ -28,15 +31,23 @@ class WebDavConfigFragment : PreferenceFragmentCompat(), Preference.OnPreference } override fun onPreferenceChange(preference: Preference?, newValue: Any?): Boolean { - val stringValue = newValue.toString() - - if (preference is ListPreference) { - val index = preference.findIndexOfValue(stringValue) - // Set the summary to reflect the new value. - preference.setSummary(if (index >= 0) preference.entries[index] else null) - } else { - // For all other preferences, set the summary to the value's - preference?.summary = stringValue + newValue?.let { + val stringValue = it.toString() + if (preference?.key == "web_dav_password") { + if (stringValue.isBlank()) { + preference.summary = getString(R.string.web_dav_pw_s) + } else { + preference.summary = "*".repeat(stringValue.length) + } + } + if (preference is ListPreference) { + val index = preference.findIndexOfValue(stringValue) + // Set the summary to reflect the new value. + preference.setSummary(if (index >= 0) preference.entries[index] else null) + } else { + // For all other preferences, set the summary to the value's + preference?.summary = stringValue + } } return true } @@ -51,4 +62,12 @@ class WebDavConfigFragment : PreferenceFragmentCompat(), Preference.OnPreference } } + override fun onPreferenceTreeClick(preference: Preference?): Boolean { + when (preference?.key) { + "web_dav_backup" -> Backup.backup() + "web_dav_restore" -> WebDavHelp.showRestoreDialog(requireContext()) + } + return super.onPreferenceTreeClick(preference) + } + } \ 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 d482ba1f6..a66f806b6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -501,5 +501,6 @@ 启用所选 禁用所选 TTS + 输入你的WebDav授权密码 diff --git a/app/src/main/res/xml/pref_config_web_dav.xml b/app/src/main/res/xml/pref_config_web_dav.xml index 3bf47eecf..c16768a20 100644 --- a/app/src/main/res/xml/pref_config_web_dav.xml +++ b/app/src/main/res/xml/pref_config_web_dav.xml @@ -17,11 +17,11 @@ From 27829ee3377ec75a03b02b754df11ca1238fc198 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 17 Sep 2019 16:49:55 +0800 Subject: [PATCH 1509/1997] up --- .../io/legado/app/lib/theme/prefs/ATEEditTextPreference.kt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/theme/prefs/ATEEditTextPreference.kt b/app/src/main/java/io/legado/app/lib/theme/prefs/ATEEditTextPreference.kt index eeba79c78..4828e1d66 100644 --- a/app/src/main/java/io/legado/app/lib/theme/prefs/ATEEditTextPreference.kt +++ b/app/src/main/java/io/legado/app/lib/theme/prefs/ATEEditTextPreference.kt @@ -27,7 +27,6 @@ class ATEEditTextPreference(context: Context?, attrs: AttributeSet?) : private var builder: AlertDialog.Builder? = null private var dialog: AlertDialog? = null private var editText: EditText? = null - var inputType: Int? = null /** Which button was clicked. */ private var mWhichButtonClicked: Int = 0 @@ -91,9 +90,7 @@ class ATEEditTextPreference(context: Context?, attrs: AttributeSet?) : checkNotNull(editText) { "Dialog view must contain an EditText with id" + " @android:id/edit" } view.findViewById(android.R.id.message).visibility = View.GONE - inputType?.let { - editText?.inputType = it - } + editText?.let { ATH.setTint(it, ThemeStore.accentColor(context)) it.requestFocus() From 27188c5b72d8abd96fd4b26c032b90ca9775763c Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 17 Sep 2019 16:52:52 +0800 Subject: [PATCH 1510/1997] up --- .../java/io/legado/app/ui/config/WebDavConfigFragment.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt index bfc2ca0ef..0d6e77503 100644 --- a/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt @@ -20,7 +20,10 @@ class WebDavConfigFragment : PreferenceFragmentCompat(), Preference.OnPreference bindPreferenceSummaryToValue(findPreference("web_dav_url")) bindPreferenceSummaryToValue(findPreference("web_dav_account")) findPreference("web_dav_password")?.let { - it.inputType = InputType.TYPE_TEXT_VARIATION_PASSWORD or InputType.TYPE_CLASS_TEXT + it.setOnBindEditTextListener { editText -> + editText.inputType = + InputType.TYPE_TEXT_VARIATION_PASSWORD or InputType.TYPE_CLASS_TEXT + } bindPreferenceSummaryToValue(it) } } From c0b6fd8eedd41424c6146cca783d7729d7e2b786 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 17 Sep 2019 17:00:43 +0800 Subject: [PATCH 1511/1997] up --- .../main/java/io/legado/app/lib/theme/ATH.kt | 3 +- .../lib/theme/prefs/ATEEditTextPreference.kt | 172 ------------------ .../app/ui/config/WebDavConfigFragment.kt | 6 +- app/src/main/res/xml/pref_config_web_dav.xml | 6 +- 4 files changed, 9 insertions(+), 178 deletions(-) delete mode 100644 app/src/main/java/io/legado/app/lib/theme/prefs/ATEEditTextPreference.kt diff --git a/app/src/main/java/io/legado/app/lib/theme/ATH.kt b/app/src/main/java/io/legado/app/lib/theme/ATH.kt index c195fe364..ba1b0dc8e 100644 --- a/app/src/main/java/io/legado/app/lib/theme/ATH.kt +++ b/app/src/main/java/io/legado/app/lib/theme/ATH.kt @@ -129,7 +129,8 @@ object ATH { } fun setTint( - view: View, @ColorInt color: Int, isDark: + view: View, + @ColorInt color: Int, isDark: Boolean = view.context.isNightTheme ) { TintHelper.setTintAuto(view, color, false, isDark) diff --git a/app/src/main/java/io/legado/app/lib/theme/prefs/ATEEditTextPreference.kt b/app/src/main/java/io/legado/app/lib/theme/prefs/ATEEditTextPreference.kt deleted file mode 100644 index 4828e1d66..000000000 --- a/app/src/main/java/io/legado/app/lib/theme/prefs/ATEEditTextPreference.kt +++ /dev/null @@ -1,172 +0,0 @@ -package io.legado.app.lib.theme.prefs - -import android.annotation.SuppressLint -import android.app.Dialog -import android.content.Context -import android.content.DialogInterface -import android.os.Bundle -import android.os.Parcel -import android.os.Parcelable -import android.preference.Preference -import android.util.AttributeSet -import android.view.LayoutInflater -import android.view.View -import android.view.WindowManager -import android.widget.EditText -import android.widget.TextView -import androidx.appcompat.app.AlertDialog -import androidx.preference.EditTextPreference -import io.legado.app.lib.theme.ATH -import io.legado.app.lib.theme.ThemeStore -import io.legado.app.utils.applyTint - -class ATEEditTextPreference(context: Context?, attrs: AttributeSet?) : - EditTextPreference(context, attrs), - DialogInterface.OnClickListener, DialogInterface.OnDismissListener { - - private var builder: AlertDialog.Builder? = null - private var dialog: AlertDialog? = null - private var editText: EditText? = null - - /** Which button was clicked. */ - private var mWhichButtonClicked: Int = 0 - - override fun onClick() { - if (dialog?.isShowing == true) return - showDialog(null) - } - - protected fun showDialog(state: Bundle?) { - val context = context - - mWhichButtonClicked = DialogInterface.BUTTON_NEGATIVE - - builder = AlertDialog.Builder(context) - .setTitle(dialogTitle) - .setIcon(dialogIcon) - .setPositiveButton(positiveButtonText, this) - .setNegativeButton(negativeButtonText, this) - - val builder = this.builder!! - - val contentView = onCreateDialogView() - if (contentView != null) { - onBindDialogView(contentView) - builder.setView(contentView) - } else { - builder.setMessage(dialogMessage) - } - - // Create the dialog - dialog = builder.create() - - val dialog = this.dialog!! - if (state != null) { - dialog.onRestoreInstanceState(state) - } - requestInputMethod(dialog) - dialog.setOnDismissListener(this) - dialog.show() - dialog.applyTint() - } - - protected fun onCreateDialogView(): View? { - if (dialogLayoutResource == 0) { - return null - } - - val inflater = LayoutInflater.from(context) - return inflater.inflate(dialogLayoutResource, null) - } - - private fun requestInputMethod(dialog: Dialog?) { - dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE) - } - - - protected fun onBindDialogView(view: View) { - editText = view.findViewById(android.R.id.edit) - - checkNotNull(editText) { "Dialog view must contain an EditText with id" + " @android:id/edit" } - - view.findViewById(android.R.id.message).visibility = View.GONE - - editText?.let { - ATH.setTint(it, ThemeStore.accentColor(context)) - it.requestFocus() - it.setText(text) - // Place cursor at the end - it.setSelection(it.length()) - } - } - - override fun onClick(dialog: DialogInterface?, which: Int) { - mWhichButtonClicked = which - } - - override fun onDismiss(dialog: DialogInterface?) { - if (mWhichButtonClicked == DialogInterface.BUTTON_POSITIVE) { - text = editText?.text.toString() - callChangeListener(text) - } - } - - override fun onSaveInstanceState(): Parcelable { - val superState = super.onSaveInstanceState() - if (dialog == null || !dialog!!.isShowing) { - return superState - } - - val myState = SavedState(superState) - myState.isDialogShowing = true - myState.dialogBundle = dialog!!.onSaveInstanceState() - return myState - } - - override fun onRestoreInstanceState(state: Parcelable?) { - if (state == null || state.javaClass != SavedState::class.java) { - // Didn't save state for us in onSaveInstanceState - super.onRestoreInstanceState(state) - return - } - - val myState = state as SavedState? - super.onRestoreInstanceState(myState!!.superState) - if (myState.isDialogShowing) { - showDialog(myState.dialogBundle) - } - } - - private class SavedState : Preference.BaseSavedState { - internal var isDialogShowing: Boolean = false - internal var dialogBundle: Bundle? = null - - @SuppressLint("ParcelClassLoader") - constructor(source: Parcel) : super(source) { - isDialogShowing = source.readInt() == 1 - dialogBundle = source.readBundle() - } - - override fun writeToParcel(dest: Parcel, flags: Int) { - super.writeToParcel(dest, flags) - dest.writeInt(if (isDialogShowing) 1 else 0) - dest.writeBundle(dialogBundle) - } - - constructor(superState: Parcelable) : super(superState) - - companion object { - - @JvmField - val CREATOR: Parcelable.Creator = object : Parcelable.Creator { - override fun createFromParcel(`in`: Parcel): SavedState { - return SavedState(`in`) - } - - override fun newArray(size: Int): Array { - return arrayOfNulls(size) - } - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt index 0d6e77503..ed55aedfd 100644 --- a/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt @@ -3,6 +3,7 @@ package io.legado.app.ui.config import android.os.Bundle import android.text.InputType import android.view.View +import androidx.preference.EditTextPreference import androidx.preference.ListPreference import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat @@ -10,7 +11,7 @@ import io.legado.app.R import io.legado.app.help.storage.Backup import io.legado.app.help.storage.WebDavHelp import io.legado.app.lib.theme.ATH -import io.legado.app.lib.theme.prefs.ATEEditTextPreference +import io.legado.app.lib.theme.accentColor import io.legado.app.utils.getPrefString class WebDavConfigFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChangeListener { @@ -19,8 +20,9 @@ class WebDavConfigFragment : PreferenceFragmentCompat(), Preference.OnPreference addPreferencesFromResource(R.xml.pref_config_web_dav) bindPreferenceSummaryToValue(findPreference("web_dav_url")) bindPreferenceSummaryToValue(findPreference("web_dav_account")) - findPreference("web_dav_password")?.let { + findPreference("web_dav_password")?.let { it.setOnBindEditTextListener { editText -> + ATH.setTint(editText, requireContext().accentColor) editText.inputType = InputType.TYPE_TEXT_VARIATION_PASSWORD or InputType.TYPE_CLASS_TEXT } diff --git a/app/src/main/res/xml/pref_config_web_dav.xml b/app/src/main/res/xml/pref_config_web_dav.xml index c16768a20..84cb363ca 100644 --- a/app/src/main/res/xml/pref_config_web_dav.xml +++ b/app/src/main/res/xml/pref_config_web_dav.xml @@ -2,19 +2,19 @@ - - - Date: Tue, 17 Sep 2019 17:06:21 +0800 Subject: [PATCH 1512/1997] up --- .../app/lib/theme/prefs/ATEPreferenceCategory.kt | 5 ++--- .../legado/app/ui/config/WebDavConfigFragment.kt | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/theme/prefs/ATEPreferenceCategory.kt b/app/src/main/java/io/legado/app/lib/theme/prefs/ATEPreferenceCategory.kt index ba4363b15..16f9e168f 100644 --- a/app/src/main/java/io/legado/app/lib/theme/prefs/ATEPreferenceCategory.kt +++ b/app/src/main/java/io/legado/app/lib/theme/prefs/ATEPreferenceCategory.kt @@ -8,9 +8,8 @@ import androidx.preference.PreferenceViewHolder import io.legado.app.lib.theme.ThemeStore -class ATEPreferenceCategory : PreferenceCategory { - - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) +class ATEPreferenceCategory(context: Context, attrs: AttributeSet) : + PreferenceCategory(context, attrs) { override fun onBindViewHolder(holder: PreferenceViewHolder?) { super.onBindViewHolder(holder) diff --git a/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt index ed55aedfd..52837150d 100644 --- a/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt @@ -18,8 +18,18 @@ class WebDavConfigFragment : PreferenceFragmentCompat(), Preference.OnPreference override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { addPreferencesFromResource(R.xml.pref_config_web_dav) - bindPreferenceSummaryToValue(findPreference("web_dav_url")) - bindPreferenceSummaryToValue(findPreference("web_dav_account")) + findPreference("web_dav_url")?.let { + it.setOnBindEditTextListener { editText -> + ATH.setTint(editText, requireContext().accentColor) + } + bindPreferenceSummaryToValue(it) + } + findPreference("web_dav_account")?.let { + it.setOnBindEditTextListener { editText -> + ATH.setTint(editText, requireContext().accentColor) + } + bindPreferenceSummaryToValue(it) + } findPreference("web_dav_password")?.let { it.setOnBindEditTextListener { editText -> ATH.setTint(editText, requireContext().accentColor) From fe8c681064054ef5bbdcd2ddf8b15b25225e3be2 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 17 Sep 2019 17:14:53 +0800 Subject: [PATCH 1513/1997] up --- .../main/java/io/legado/app/lib/webdav/WebDav.kt | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt b/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt index 225850113..424c0d13c 100644 --- a/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt +++ b/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt @@ -21,6 +21,7 @@ import java.util.* class WebDav @Throws(MalformedURLException::class) constructor(url: String) { + private val okHttpClient = HttpHelper.client private val url: URL = URL(null, url, Handler) private var httpUrl: String? = null @@ -36,10 +37,9 @@ constructor(url: String) { return field } - private val okHttpClient = HttpHelper.client + fun getPath() = url.toString() - val path: String - get() = url.toString() + fun getHost() = url.host private val inputStream: InputStream? get() = getUrl()?.let { url -> @@ -56,9 +56,6 @@ constructor(url: String) { return null } - val host: String - get() = url.host - private fun getUrl(): String? { if (httpUrl == null) { val raw = url.toString().replace("davs://", "https://").replace("dav://", "http://") @@ -111,7 +108,6 @@ constructor(url: String) { return parseDir(body.string()) } } - } return ArrayList() } @@ -194,9 +190,7 @@ constructor(url: String) { */ fun downloadTo(savedPath: String, replaceExisting: Boolean): Boolean { if (File(savedPath).exists()) { - if (!replaceExisting) { - return false - } + if (!replaceExisting) return false } val inputS = inputStream ?: return false File(savedPath).writeBytes(inputS.readBytes()) @@ -225,7 +219,6 @@ constructor(url: String) { /** * 执行请求,获取响应结果 - * * @param requestBuilder 因为还需要追加验证信息,所以此处传递Request.Builder的对象,而不是Request的对象 * @return 请求执行的结果 */ From 446e72e856d2bf482bfa958af2d178395535fece Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 17 Sep 2019 19:08:47 +0800 Subject: [PATCH 1514/1997] up --- app/src/main/java/io/legado/app/help/storage/Backup.kt | 6 ++++++ app/src/main/java/io/legado/app/utils/ContextExtensions.kt | 4 ---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/storage/Backup.kt b/app/src/main/java/io/legado/app/help/storage/Backup.kt index 683cf34c1..56bae33eb 100644 --- a/app/src/main/java/io/legado/app/help/storage/Backup.kt +++ b/app/src/main/java/io/legado/app/help/storage/Backup.kt @@ -42,6 +42,12 @@ object Backup { } } + private fun backupPreference(path: String) { + val file = FileHelp.getFile(path + File.separator + "config.xml") + + + } + private fun backupBookshelf(path: String) { val json = GSON.toJson(App.db.bookDao().allBooks) val file = FileHelp.getFile(path + File.separator + "bookshelf.json") diff --git a/app/src/main/java/io/legado/app/utils/ContextExtensions.kt b/app/src/main/java/io/legado/app/utils/ContextExtensions.kt index 7de826fbb..c51be0b80 100644 --- a/app/src/main/java/io/legado/app/utils/ContextExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/ContextExtensions.kt @@ -5,12 +5,8 @@ import android.content.res.ColorStateList import android.graphics.drawable.Drawable import androidx.annotation.ColorRes import androidx.annotation.DrawableRes -import androidx.appcompat.app.AppCompatActivity import androidx.core.content.ContextCompat import androidx.core.content.edit -import androidx.fragment.app.Fragment -import com.jeremyliao.liveeventbus.LiveEventBus -import io.legado.app.R import org.jetbrains.anko.connectivityManager import org.jetbrains.anko.defaultSharedPreferences From 390e64ec72f204f0d4ac7a8149cd8fb53c6912aa Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 17 Sep 2019 20:34:57 +0800 Subject: [PATCH 1515/1997] up --- .../java/io/legado/app/help/storage/Backup.kt | 27 ++++++++--- .../io/legado/app/help/storage/Preferences.kt | 48 +++++++++++++++++++ .../io/legado/app/help/storage/Restore.kt | 16 ++++++- 3 files changed, 84 insertions(+), 7 deletions(-) create mode 100644 app/src/main/java/io/legado/app/help/storage/Preferences.kt diff --git a/app/src/main/java/io/legado/app/help/storage/Backup.kt b/app/src/main/java/io/legado/app/help/storage/Backup.kt index 56bae33eb..14faab468 100644 --- a/app/src/main/java/io/legado/app/help/storage/Backup.kt +++ b/app/src/main/java/io/legado/app/help/storage/Backup.kt @@ -6,11 +6,13 @@ import io.legado.app.R import io.legado.app.help.FileHelp import io.legado.app.utils.FileUtils import io.legado.app.utils.GSON +import org.jetbrains.anko.defaultSharedPreferences import org.jetbrains.anko.doAsync import org.jetbrains.anko.toast import org.jetbrains.anko.uiThread import java.io.File + object Backup { val defaultPath by lazy { @@ -24,6 +26,7 @@ object Backup { backupBookSource(path) backupRssSource(path) backupReplaceRule(path) + backupPreference(path) WebDavHelp.backUpWebDav() uiThread { App.INSTANCE.toast(R.string.backup_success) @@ -42,12 +45,6 @@ object Backup { } } - private fun backupPreference(path: String) { - val file = FileHelp.getFile(path + File.separator + "config.xml") - - - } - private fun backupBookshelf(path: String) { val json = GSON.toJson(App.db.bookDao().allBooks) val file = FileHelp.getFile(path + File.separator + "bookshelf.json") @@ -71,4 +68,22 @@ object Backup { val file = FileHelp.getFile(path + File.separator + "replaceRule.json") file.writeText(json) } + + private fun backupPreference(path: String) { + Preferences.getSharedPreferences(App.INSTANCE, path, "config")?.let { sp -> + val edit = sp.edit() + App.INSTANCE.defaultSharedPreferences.all.map { + when (val value = it.value) { + is Int -> edit.putInt(it.key, value) + is Boolean -> edit.putBoolean(it.key, value) + is Long -> edit.putLong(it.key, value) + is Float -> edit.putFloat(it.key, value) + is String -> edit.putString(it.key, value) + else -> Unit + } + } + edit.commit() + } + } + } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/help/storage/Preferences.kt b/app/src/main/java/io/legado/app/help/storage/Preferences.kt new file mode 100644 index 000000000..11907e83f --- /dev/null +++ b/app/src/main/java/io/legado/app/help/storage/Preferences.kt @@ -0,0 +1,48 @@ +package io.legado.app.help.storage + +import android.app.Activity +import android.content.Context +import android.content.ContextWrapper +import android.content.SharedPreferences +import java.io.File + +object Preferences { + + /** + * 用反射生成 SharedPreferences + * @param context + * @param dir + * @param fileName 文件名,不需要 '.xml' 后缀 + * @return + */ + fun getSharedPreferences( + context: Context, + dir: String, + fileName: String + ): SharedPreferences? { + try { + // 获取 ContextWrapper对象中的mBase变量。该变量保存了 ContextImpl 对象 + val fieldMBase = ContextWrapper::class.java.getDeclaredField("mBase") + fieldMBase.isAccessible = true + // 获取 mBase变量 + val objMBase = fieldMBase.get(context) + // 获取 ContextImpl。mPreferencesDir变量,该变量保存了数据文件的保存路径 + val fieldMPreferencesDir = objMBase.javaClass.getDeclaredField("mPreferencesDir") + fieldMPreferencesDir.isAccessible = true + // 创建自定义路径 + // String FILE_PATH = Environment.getExternalStorageDirectory().getAbsolutePath()+"/Android"; + val file = File(dir) + // 修改mPreferencesDir变量的值 + fieldMPreferencesDir.set(objMBase, file) + // 返回修改路径以后的 SharedPreferences :%FILE_PATH%/%fileName%.xml + return context.getSharedPreferences(fileName, Activity.MODE_PRIVATE) + } catch (e: NoSuchFieldException) { + e.printStackTrace() + } catch (e: IllegalArgumentException) { + e.printStackTrace() + } catch (e: IllegalAccessException) { + e.printStackTrace() + } + return null + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/help/storage/Restore.kt b/app/src/main/java/io/legado/app/help/storage/Restore.kt index 94b24cb00..52ead5de6 100644 --- a/app/src/main/java/io/legado/app/help/storage/Restore.kt +++ b/app/src/main/java/io/legado/app/help/storage/Restore.kt @@ -14,6 +14,7 @@ import io.legado.app.data.entities.RssSource import io.legado.app.help.FileHelp import io.legado.app.help.storage.Backup.defaultPath import io.legado.app.utils.* +import org.jetbrains.anko.defaultSharedPreferences import org.jetbrains.anko.doAsync import org.jetbrains.anko.toast import org.jetbrains.anko.uiThread @@ -64,6 +65,18 @@ object Restore { } catch (e: Exception) { e.printStackTrace() } + Preferences.getSharedPreferences(App.INSTANCE, path, "config")?.all?.map { + val edit = App.INSTANCE.defaultSharedPreferences.edit() + when (val value = it.value) { + is Int -> edit.putInt(it.key, value) + is Boolean -> edit.putBoolean(it.key, value) + is Long -> edit.putLong(it.key, value) + is Float -> edit.putFloat(it.key, value) + is String -> edit.putString(it.key, value) + else -> Unit + } + edit.commit() + } uiThread { App.INSTANCE.toast("恢复完成") } } } @@ -91,7 +104,8 @@ object Restore { book.origin = jsonItem.readString("$.tag") ?: "" book.originName = jsonItem.readString("$.bookInfoBean.origin") ?: "" book.author = jsonItem.readString("$.bookInfoBean.author") ?: "" - book.type = if (jsonItem.readString("$.bookInfoBean.bookSourceType") == "AUDIO") 1 else 0 + book.type = + if (jsonItem.readString("$.bookInfoBean.bookSourceType") == "AUDIO") 1 else 0 book.tocUrl = jsonItem.readString("$.bookInfoBean.chapterUrl") ?: book.bookUrl book.coverUrl = jsonItem.readString("$.bookInfoBean.coverUrl") book.customCoverUrl = jsonItem.readString("$.customCoverPath") From 87a8bd4b3bb6231831ff587752c165e11d06d14f Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 17 Sep 2019 21:56:20 +0800 Subject: [PATCH 1516/1997] up --- app/src/main/res/layout/activity_book_info.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/layout/activity_book_info.xml b/app/src/main/res/layout/activity_book_info.xml index 522d563fa..2e8186fbe 100644 --- a/app/src/main/res/layout/activity_book_info.xml +++ b/app/src/main/res/layout/activity_book_info.xml @@ -274,6 +274,7 @@ Date: Tue, 17 Sep 2019 22:10:38 +0800 Subject: [PATCH 1517/1997] up --- .../res/layout-land/activity_book_info.xml | 24 +++++++++--------- .../main/res/layout/activity_book_info.xml | 25 +++++++++---------- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/app/src/main/res/layout-land/activity_book_info.xml b/app/src/main/res/layout-land/activity_book_info.xml index 49fba475e..a5419f1e6 100644 --- a/app/src/main/res/layout-land/activity_book_info.xml +++ b/app/src/main/res/layout-land/activity_book_info.xml @@ -270,18 +270,6 @@ android:background="@color/background" app:layout_constraintBottom_toBottomOf="parent"> - - + + - - + + Date: Tue, 17 Sep 2019 22:12:07 +0800 Subject: [PATCH 1518/1997] up --- .../java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt | 1 + .../legado/app/ui/replacerule/{ => edit}/ReplaceEditDialog.kt | 2 +- .../app/ui/replacerule/{ => edit}/ReplaceEditViewModel.kt | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) rename app/src/main/java/io/legado/app/ui/replacerule/{ => edit}/ReplaceEditDialog.kt (98%) rename app/src/main/java/io/legado/app/ui/replacerule/{ => edit}/ReplaceEditViewModel.kt (96%) diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt index 06ffd991b..ad7d9e28a 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt @@ -19,6 +19,7 @@ import io.legado.app.data.entities.ReplaceRule import io.legado.app.help.ItemTouchCallback import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.primaryTextColor +import io.legado.app.ui.replacerule.edit.ReplaceEditDialog import io.legado.app.utils.getViewModel import io.legado.app.utils.splitNotBlank import kotlinx.android.synthetic.main.activity_replace_rule.* diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditDialog.kt b/app/src/main/java/io/legado/app/ui/replacerule/edit/ReplaceEditDialog.kt similarity index 98% rename from app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditDialog.kt rename to app/src/main/java/io/legado/app/ui/replacerule/edit/ReplaceEditDialog.kt index 0759f0a2a..3fa28cd69 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditDialog.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/edit/ReplaceEditDialog.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.replacerule +package io.legado.app.ui.replacerule.edit import android.os.Bundle import android.util.DisplayMetrics diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditViewModel.kt b/app/src/main/java/io/legado/app/ui/replacerule/edit/ReplaceEditViewModel.kt similarity index 96% rename from app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditViewModel.kt rename to app/src/main/java/io/legado/app/ui/replacerule/edit/ReplaceEditViewModel.kt index 79ab10c0c..ae8ba8025 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceEditViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/edit/ReplaceEditViewModel.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.replacerule +package io.legado.app.ui.replacerule.edit import android.app.Application import android.os.Bundle From 8427f0b7ff7f62cfc9b8559e6df066549a911cb1 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 17 Sep 2019 22:20:36 +0800 Subject: [PATCH 1519/1997] up --- .../app/ui/config/WebDavConfigFragment.kt | 31 +++++++++++-------- app/src/main/res/values/strings.xml | 2 ++ app/src/main/res/xml/pref_config_web_dav.xml | 4 +-- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt index 52837150d..cbea0803b 100644 --- a/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt @@ -46,23 +46,28 @@ class WebDavConfigFragment : PreferenceFragmentCompat(), Preference.OnPreference } override fun onPreferenceChange(preference: Preference?, newValue: Any?): Boolean { - newValue?.let { - val stringValue = it.toString() - if (preference?.key == "web_dav_password") { - if (stringValue.isBlank()) { - preference.summary = getString(R.string.web_dav_pw_s) - } else { - preference.summary = "*".repeat(stringValue.length) - } + when { + preference?.key == "web_dav_password" -> if (newValue == null) { + preference.summary = getString(R.string.web_dav_pw_s) + } else { + preference.summary = "*".repeat(newValue.toString().length) + } + preference?.key == "web_dav_url" -> if (newValue == null) { + preference.summary = getString(R.string.web_dav_url_s) + } else { + preference.summary = newValue.toString() } - if (preference is ListPreference) { - val index = preference.findIndexOfValue(stringValue) + preference?.key == "web_dav_account" -> if (newValue == null) { + preference.summary = getString(R.string.web_dav_account_s) + } else { + preference.summary = newValue.toString() + } + preference is ListPreference -> { + val index = preference.findIndexOfValue(newValue?.toString()) // Set the summary to reflect the new value. preference.setSummary(if (index >= 0) preference.entries[index] else null) - } else { - // For all other preferences, set the summary to the value's - preference?.summary = stringValue } + else -> preference?.summary = newValue?.toString() } return true } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a66f806b6..f95f3b249 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -502,5 +502,7 @@ 禁用所选 TTS 输入你的WebDav授权密码 + 输入你的服务器地址 + 输入你的WebDav账号 diff --git a/app/src/main/res/xml/pref_config_web_dav.xml b/app/src/main/res/xml/pref_config_web_dav.xml index 84cb363ca..9591ca1b4 100644 --- a/app/src/main/res/xml/pref_config_web_dav.xml +++ b/app/src/main/res/xml/pref_config_web_dav.xml @@ -5,13 +5,13 @@ Date: Tue, 17 Sep 2019 22:40:32 +0800 Subject: [PATCH 1520/1997] up --- .../io/legado/app/data/entities/RssSource.kt | 3 +- .../app/ui/rss/source/RssSourceActivity.kt | 50 ++++++++++++++++++- .../app/ui/rss/source/RssSourceAdapter.kt | 46 +++++++++++++++++ .../main/res/layout/activity_book_source.xml | 32 ++++++------ .../main/res/layout/activity_rss_source.xml | 25 +++++++++- app/src/main/res/layout/item_rss_source.xml | 50 +++++++++++++++++++ app/src/main/res/values/strings.xml | 1 + 7 files changed, 187 insertions(+), 20 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/rss/source/RssSourceAdapter.kt create mode 100644 app/src/main/res/layout/item_rss_source.xml diff --git a/app/src/main/java/io/legado/app/data/entities/RssSource.kt b/app/src/main/java/io/legado/app/data/entities/RssSource.kt index 8adac6170..17a7064e9 100644 --- a/app/src/main/java/io/legado/app/data/entities/RssSource.kt +++ b/app/src/main/java/io/legado/app/data/entities/RssSource.kt @@ -21,5 +21,6 @@ data class RssSource( var ruleDescription: String? = null, var ruleContent: String? = null, var ruleImage: String? = null, - var ruleCategories: String? = null + var ruleCategories: String? = null, + var customOrder: Int = 0 ) : Parcelable \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/rss/source/RssSourceActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/RssSourceActivity.kt index b6707bf0e..0b4240f60 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/RssSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/RssSourceActivity.kt @@ -1,18 +1,66 @@ package io.legado.app.ui.rss.source import android.os.Bundle +import androidx.core.content.ContextCompat +import androidx.recyclerview.widget.DividerItemDecoration +import androidx.recyclerview.widget.ItemTouchHelper +import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.R import io.legado.app.base.VMBaseActivity +import io.legado.app.data.entities.RssSource +import io.legado.app.help.ItemTouchCallback +import io.legado.app.lib.theme.ATH import io.legado.app.utils.getViewModel +import kotlinx.android.synthetic.main.activity_rss_source.* -class RssSourceActivity : VMBaseActivity(R.layout.activity_rss_source) { +class RssSourceActivity : VMBaseActivity(R.layout.activity_rss_source), + RssSourceAdapter.CallBack { + override val viewModel: RssSourceViewModel get() = getViewModel(RssSourceViewModel::class.java) + private lateinit var adapter: RssSourceAdapter + override fun onActivityCreated(savedInstanceState: Bundle?) { } + private fun initRecyclerView() { + ATH.applyEdgeEffectColor(recycler_view) + recycler_view.layoutManager = LinearLayoutManager(this) + recycler_view.addItemDecoration( + DividerItemDecoration(this, DividerItemDecoration.VERTICAL).apply { + ContextCompat.getDrawable(baseContext, R.drawable.ic_divider)?.let { + this.setDrawable(it) + } + }) + adapter = RssSourceAdapter(this, this) + recycler_view.adapter = adapter + val itemTouchCallback = ItemTouchCallback() + itemTouchCallback.onItemTouchCallbackListener = adapter + itemTouchCallback.isCanDrag = true + ItemTouchHelper(itemTouchCallback).attachToRecyclerView(recycler_view) + } + + override fun del(source: RssSource) { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun edit(source: RssSource) { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun update(vararg source: RssSource) { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun toTop(source: RssSource) { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun upOrder() { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/rss/source/RssSourceAdapter.kt b/app/src/main/java/io/legado/app/ui/rss/source/RssSourceAdapter.kt new file mode 100644 index 000000000..a6ef803c4 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/rss/source/RssSourceAdapter.kt @@ -0,0 +1,46 @@ +package io.legado.app.ui.rss.source + +import android.content.Context +import io.legado.app.R +import io.legado.app.base.adapter.ItemViewHolder +import io.legado.app.base.adapter.SimpleRecyclerAdapter +import io.legado.app.data.entities.RssSource +import io.legado.app.help.ItemTouchCallback + +class RssSourceAdapter(context: Context, val callBack: CallBack) : + SimpleRecyclerAdapter(context, R.layout.item_rss_source), + ItemTouchCallback.OnItemTouchCallbackListener { + + override fun convert(holder: ItemViewHolder, item: RssSource, payloads: MutableList) { + + } + + + override fun onSwiped(adapterPosition: Int) { + + } + + override fun onMove(srcPosition: Int, targetPosition: Int): Boolean { + val srcItem = getItem(srcPosition) + val targetItem = getItem(targetPosition) + if (srcItem != null && targetItem != null) { + if (srcItem.customOrder == targetItem.customOrder) { + callBack.upOrder() + } else { + val srcOrder = srcItem.customOrder + srcItem.customOrder = targetItem.customOrder + targetItem.customOrder = srcOrder + callBack.update(srcItem, targetItem) + } + } + return true + } + + interface CallBack { + fun del(source: RssSource) + fun edit(source: RssSource) + fun update(vararg source: RssSource) + fun toTop(source: RssSource) + fun upOrder() + } +} diff --git a/app/src/main/res/layout/activity_book_source.xml b/app/src/main/res/layout/activity_book_source.xml index e884787c0..839d228fb 100644 --- a/app/src/main/res/layout/activity_book_source.xml +++ b/app/src/main/res/layout/activity_book_source.xml @@ -1,27 +1,27 @@ + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + android:id="@+id/title_bar" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:contentInsetStartWithNavigation="0dp" + app:contentLayout="@layout/view_search" + app:displayHomeAsUp="true" + app:title="@string/book_source" /> + android:layout_width="match_parent" + android:layout_height="match_parent"> + android:id="@+id/recycler_view" + android:layout_width="match_parent" + android:layout_height="match_parent" /> diff --git a/app/src/main/res/layout/activity_rss_source.xml b/app/src/main/res/layout/activity_rss_source.xml index d829e291c..e3c5bd53e 100644 --- a/app/src/main/res/layout/activity_rss_source.xml +++ b/app/src/main/res/layout/activity_rss_source.xml @@ -1,7 +1,28 @@ + android:layout_height="match_parent" + android:orientation="vertical"> + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_rss_source.xml b/app/src/main/res/layout/item_rss_source.xml new file mode 100644 index 000000000..7d9513d98 --- /dev/null +++ b/app/src/main/res/layout/item_rss_source.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + \ 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 f95f3b249..1d20b0eec 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -504,5 +504,6 @@ 输入你的WebDav授权密码 输入你的服务器地址 输入你的WebDav账号 + 订阅源 From 3875f046fc4d6af839a982c058204bb4d8f65238 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 18 Sep 2019 08:43:29 +0800 Subject: [PATCH 1521/1997] up --- app/src/main/java/io/legado/app/help/storage/Restore.kt | 2 +- app/src/main/java/io/legado/app/utils/FileUtils.kt | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/storage/Restore.kt b/app/src/main/java/io/legado/app/help/storage/Restore.kt index 52ead5de6..ad0db5710 100644 --- a/app/src/main/java/io/legado/app/help/storage/Restore.kt +++ b/app/src/main/java/io/legado/app/help/storage/Restore.kt @@ -82,7 +82,7 @@ object Restore { } fun importYueDuData(context: Context) { - val file = File(FileUtils.getSdPath(), "YueDu") + val file = File(FileUtils.getSdCardPath(), "YueDu") // 导入书架 val shelfFile = File(file, "myBookShelf.json") diff --git a/app/src/main/java/io/legado/app/utils/FileUtils.kt b/app/src/main/java/io/legado/app/utils/FileUtils.kt index 861d7e88e..4626fe489 100644 --- a/app/src/main/java/io/legado/app/utils/FileUtils.kt +++ b/app/src/main/java/io/legado/app/utils/FileUtils.kt @@ -16,7 +16,6 @@ import java.util.* object FileUtils { - fun getSdPath() = Environment.getExternalStorageDirectory().absolutePath fun getFileByPath(filePath: String): File? { return if (filePath.isBlank()) null else File(filePath) @@ -41,8 +40,8 @@ object FileUtils { try { val getVolumeList = storageManager.javaClass.getMethod("getVolumeList") - val storageValumeClazz = Class.forName("android.os.storage.StorageVolume") - val getPath = storageValumeClazz.getMethod("getPath") + val storageVolumeClazz = Class.forName("android.os.storage.StorageVolume") + val getPath = storageVolumeClazz.getMethod("getPath") val invokeVolumeList = getVolumeList.invoke(storageManager) val length = Array.getLength(invokeVolumeList) From 0d6f48246ff4f8599296cae7b2a564d2c4c5457c Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 18 Sep 2019 10:08:49 +0800 Subject: [PATCH 1522/1997] up --- app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt | 7 +++---- .../legado/app/ui/book/source/debug/SourceDebugActivity.kt | 4 ++-- .../legado/app/ui/book/source/debug/SourceDebugAdapter.kt | 5 +++-- .../legado/app/ui/book/source/edit/SourceEditActivity.kt | 4 ++-- ...ity_source_debug.xml => activity_book_source_debug.xml} | 0 ...ivity_source_edit.xml => activity_book_source_edit.xml} | 0 .../res/layout/{item_source_debug.xml => item_log.xml} | 0 7 files changed, 10 insertions(+), 10 deletions(-) rename app/src/main/res/layout/{activity_source_debug.xml => activity_book_source_debug.xml} (100%) rename app/src/main/res/layout/{activity_source_edit.xml => activity_book_source_edit.xml} (100%) rename app/src/main/res/layout/{item_source_debug.xml => item_log.xml} (100%) diff --git a/app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt b/app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt index c19c3b46f..d99141606 100644 --- a/app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt +++ b/app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt @@ -88,10 +88,9 @@ object WebDavHelp { FileHelp.deleteFile(zipFilePath) if (ZipUtils.zipFiles(paths, zipFilePath)) { WebDav(getWebDavUrl() + "legado").makeAsDir() - val putUrl = getWebDavUrl() + "legado/backup" + SimpleDateFormat( - "yyyy-MM-dd", - Locale.getDefault() - ).format(Date(System.currentTimeMillis())) + ".zip" + val putUrl = getWebDavUrl() + "legado/backup" + + SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) + .format(Date(System.currentTimeMillis())) + ".zip" WebDav(putUrl).upload(zipFilePath) } } diff --git a/app/src/main/java/io/legado/app/ui/book/source/debug/SourceDebugActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/debug/SourceDebugActivity.kt index de2ef20e7..b180f6b17 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/debug/SourceDebugActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/debug/SourceDebugActivity.kt @@ -12,13 +12,13 @@ import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.accentColor import io.legado.app.ui.qrcode.QrCodeActivity import io.legado.app.utils.getViewModel -import kotlinx.android.synthetic.main.activity_source_debug.* +import kotlinx.android.synthetic.main.activity_book_source_debug.* import kotlinx.android.synthetic.main.view_search.* import kotlinx.coroutines.launch import org.jetbrains.anko.startActivityForResult import org.jetbrains.anko.toast -class SourceDebugActivity : VMBaseActivity(R.layout.activity_source_debug) { +class SourceDebugActivity : VMBaseActivity(R.layout.activity_book_source_debug) { override val viewModel: SourceDebugModel get() = getViewModel(SourceDebugModel::class.java) diff --git a/app/src/main/java/io/legado/app/ui/book/source/debug/SourceDebugAdapter.kt b/app/src/main/java/io/legado/app/ui/book/source/debug/SourceDebugAdapter.kt index 0c057fda0..94147a5f1 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/debug/SourceDebugAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/debug/SourceDebugAdapter.kt @@ -4,9 +4,10 @@ import android.content.Context import io.legado.app.R import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter -import kotlinx.android.synthetic.main.item_source_debug.view.* +import kotlinx.android.synthetic.main.item_log.view.* -class SourceDebugAdapter(context: Context) : SimpleRecyclerAdapter(context, R.layout.item_source_debug) { +class SourceDebugAdapter(context: Context) : + SimpleRecyclerAdapter(context, R.layout.item_log) { override fun convert(holder: ItemViewHolder, item: String, payloads: MutableList) { holder.itemView.apply { text_view.text = item diff --git a/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditActivity.kt index faaf38ff6..b49db48bc 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditActivity.kt @@ -24,14 +24,14 @@ import io.legado.app.ui.book.source.debug.SourceDebugActivity import io.legado.app.ui.widget.KeyboardToolPop import io.legado.app.utils.GSON import io.legado.app.utils.getViewModel -import kotlinx.android.synthetic.main.activity_source_edit.* +import kotlinx.android.synthetic.main.activity_book_source_edit.* import org.jetbrains.anko.displayMetrics import org.jetbrains.anko.startActivity import org.jetbrains.anko.toast import kotlin.math.abs class SourceEditActivity : - VMBaseActivity(R.layout.activity_source_edit, false), + VMBaseActivity(R.layout.activity_book_source_edit, false), KeyboardToolPop.OnClickListener { override val viewModel: SourceEditViewModel get() = getViewModel(SourceEditViewModel::class.java) diff --git a/app/src/main/res/layout/activity_source_debug.xml b/app/src/main/res/layout/activity_book_source_debug.xml similarity index 100% rename from app/src/main/res/layout/activity_source_debug.xml rename to app/src/main/res/layout/activity_book_source_debug.xml diff --git a/app/src/main/res/layout/activity_source_edit.xml b/app/src/main/res/layout/activity_book_source_edit.xml similarity index 100% rename from app/src/main/res/layout/activity_source_edit.xml rename to app/src/main/res/layout/activity_book_source_edit.xml diff --git a/app/src/main/res/layout/item_source_debug.xml b/app/src/main/res/layout/item_log.xml similarity index 100% rename from app/src/main/res/layout/item_source_debug.xml rename to app/src/main/res/layout/item_log.xml From 15306321b6ba3d09624d05241fae4e83df884687 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 18 Sep 2019 11:15:43 +0800 Subject: [PATCH 1523/1997] up --- .../app/receiver/MediaButtonReceiver.kt | 2 + .../main/java/io/legado/app/utils/LogUtils.kt | 110 ++++++++++++++++++ app/src/main/res/xml/pref_config.xml | 5 + 3 files changed, 117 insertions(+) create mode 100644 app/src/main/java/io/legado/app/utils/LogUtils.kt diff --git a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt index 9a71568ef..d24faa7d7 100644 --- a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt +++ b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt @@ -7,6 +7,7 @@ import android.view.KeyEvent import io.legado.app.constant.Bus import io.legado.app.help.ActivityHelp import io.legado.app.ui.book.read.ReadBookActivity +import io.legado.app.utils.LogUtils import io.legado.app.utils.postEvent @@ -21,6 +22,7 @@ class MediaButtonReceiver : BroadcastReceiver() { fun handleIntent(context: Context, intent: Intent): Boolean { val intentAction = intent.action + LogUtils.log("耳机按键:$intentAction") if (Intent.ACTION_MEDIA_BUTTON == intentAction) { val event = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT) ?: return false diff --git a/app/src/main/java/io/legado/app/utils/LogUtils.kt b/app/src/main/java/io/legado/app/utils/LogUtils.kt new file mode 100644 index 000000000..a0ddd9b77 --- /dev/null +++ b/app/src/main/java/io/legado/app/utils/LogUtils.kt @@ -0,0 +1,110 @@ +package io.legado.app.utils + +import android.annotation.SuppressLint +import io.legado.app.App +import io.legado.app.help.FileHelp +import java.io.File +import java.io.IOException +import java.text.SimpleDateFormat +import java.util.* +import java.util.logging.* +import java.util.logging.Formatter + + +object LogUtils { + + private val logger: Logger by lazy { + Logger.getGlobal().apply { + addFileHandler( + this, + Level.INFO, + FileHelp.getCachePath() + File.separator + System.currentTimeMillis() + ".log" + ) + } + } + + fun log(msg: String) { + if (App.INSTANCE.getPrefBoolean("recordLog")) { + logger.log(Level.INFO, msg) + } + } + + // 正常的日期格式 + const val DATE_PATTERN_FULL = "yyyy-MM-dd HH:mm:ss" + + /** + * 为log设置等级 + * + * @param log + * @param level + */ + fun setLogLevel(log: Logger, level: Level) { + log.level = level + } + + /** + * 为log添加控制台handler + * + * @param log + * 要添加handler的log + * @param level + * 控制台的输出等级 + */ + fun addConsoleHandler(log: Logger, level: Level) { + // 控制台输出的handler + val consoleHandler = ConsoleHandler() + // 设置控制台输出的等级(如果ConsoleHandler的等级高于或者等于log的level,则按照FileHandler的level输出到控制台,如果低于,则按照Log等级输出) + consoleHandler.level = level + + // 添加控制台的handler + log.addHandler(consoleHandler) + } + + /** + * 为log添加文件输出Handler + * + * @param log + * 要添加文件输出handler的log + * @param level + * log输出等级 + * @param filePath + * 指定文件全路径 + */ + fun addFileHandler(log: Logger, level: Level, filePath: String) { + var fileHandler: FileHandler? = null + try { + fileHandler = FileHandler(filePath) + // 设置输出文件的等级(如果FileHandler的等级高于或者等于log的level,则按照FileHandler的level输出到文件,如果低于,则按照Log等级输出) + fileHandler.level = level + fileHandler.formatter = object : Formatter() { + override fun format(record: LogRecord): String { + + // 设置文件输出格式 + return (getCurrentDateStr(DATE_PATTERN_FULL) + + " - Level:" + record.level.name.substring(0, 1) + + " " + record.message + "\n") + } + } + + } catch (e: SecurityException) { + e.printStackTrace() + } catch (e: IOException) { + e.printStackTrace() + } + + // 添加输出文件handler + log.addHandler(fileHandler) + } + + /** + * 获取当前时间 + * + * @return + */ + @SuppressLint("SimpleDateFormat") + fun getCurrentDateStr(pattern: String): String { + val date = Date() + val sdf = SimpleDateFormat(pattern) + return sdf.format(date) + } +} \ No newline at end of file diff --git a/app/src/main/res/xml/pref_config.xml b/app/src/main/res/xml/pref_config.xml index a682044d0..a58063dd4 100644 --- a/app/src/main/res/xml/pref_config.xml +++ b/app/src/main/res/xml/pref_config.xml @@ -29,4 +29,9 @@ android:title="@string/download_path" app:iconSpaceReserved="false" /> + \ No newline at end of file From 6b6aaeada40b9011d2c244281f3800e5dac077a6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 18 Sep 2019 11:28:50 +0800 Subject: [PATCH 1524/1997] up --- .../main/java/io/legado/app/utils/LogUtils.kt | 22 ++----------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/io/legado/app/utils/LogUtils.kt b/app/src/main/java/io/legado/app/utils/LogUtils.kt index a0ddd9b77..6418a84c4 100644 --- a/app/src/main/java/io/legado/app/utils/LogUtils.kt +++ b/app/src/main/java/io/legado/app/utils/LogUtils.kt @@ -4,7 +4,6 @@ import android.annotation.SuppressLint import io.legado.app.App import io.legado.app.help.FileHelp import java.io.File -import java.io.IOException import java.text.SimpleDateFormat import java.util.* import java.util.logging.* @@ -32,16 +31,6 @@ object LogUtils { // 正常的日期格式 const val DATE_PATTERN_FULL = "yyyy-MM-dd HH:mm:ss" - /** - * 为log设置等级 - * - * @param log - * @param level - */ - fun setLogLevel(log: Logger, level: Level) { - log.level = level - } - /** * 为log添加控制台handler * @@ -78,20 +67,13 @@ object LogUtils { fileHandler.level = level fileHandler.formatter = object : Formatter() { override fun format(record: LogRecord): String { - // 设置文件输出格式 - return (getCurrentDateStr(DATE_PATTERN_FULL) + - " - Level:" + record.level.name.substring(0, 1) + - " " + record.message + "\n") + return (getCurrentDateStr(DATE_PATTERN_FULL) + ":" + record.message + "\n") } } - - } catch (e: SecurityException) { - e.printStackTrace() - } catch (e: IOException) { + } catch (e: Exception) { e.printStackTrace() } - // 添加输出文件handler log.addHandler(fileHandler) } From 91667cf4b16ed8c93e74065b5f6377d75df040d5 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 18 Sep 2019 11:53:43 +0800 Subject: [PATCH 1525/1997] up --- .../java/io/legado/app/lib/webdav/WebDav.kt | 38 +++++++++++++------ 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt b/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt index 424c0d13c..93fc41c7d 100644 --- a/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt +++ b/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt @@ -32,7 +32,9 @@ constructor(url: String) { var urlName = "" get() { if (field.isEmpty()) { - this.urlName = (if (parent.isEmpty()) url.file else url.toString().replace(parent, "")).replace("/", "") + this.urlName = (if (parent.isEmpty()) url.file else url.toString() + .replace(parent, "")) + .replace("/", "") } return field } @@ -44,7 +46,12 @@ constructor(url: String) { private val inputStream: InputStream? get() = getUrl()?.let { url -> val request = Request.Builder().url(url) - HttpAuth.auth?.let { request.header("Authorization", Credentials.basic(it.user, it.pass)) } + HttpAuth.auth?.let { + request.header( + "Authorization", + Credentials.basic(it.user, it.pass) + ) + } try { return okHttpClient.newCall(request.build()).execute().body?.byteStream() @@ -67,7 +74,6 @@ constructor(url: String) { } catch (e: UnsupportedEncodingException) { e.printStackTrace() } - } return httpUrl } @@ -131,7 +137,12 @@ constructor(url: String) { // 注意:尽量手动指定需要返回的属性。若返回全部属性,可能后由于Prop.java里没有该属性名,而崩溃。 .method("PROPFIND", requestPropsStr.toRequestBody("text/plain".toMediaTypeOrNull())) - HttpAuth.auth?.let { request.header("Authorization", Credentials.basic(it.user, it.pass)) } + HttpAuth.auth?.let { + request.header( + "Authorization", + Credentials.basic(it.user, it.pass) + ) + } request.header("Depth", if (depth < 0) "infinity" else depth.toString()) @@ -224,7 +235,12 @@ constructor(url: String) { */ @Throws(IOException::class) private fun execRequest(requestBuilder: Request.Builder): Boolean { - HttpAuth.auth?.let { requestBuilder.header("Authorization", Credentials.basic(it.user, it.pass)) } + HttpAuth.auth?.let { + requestBuilder.header( + "Authorization", + Credentials.basic(it.user, it.pass) + ) + } val response = okHttpClient.newCall(requestBuilder.build()).execute() return response.isSuccessful @@ -250,12 +266,12 @@ constructor(url: String) { val TAG = WebDav::class.java.simpleName val OBJECT_NOT_EXISTS_TAG = "ObjectNotFound" // 指定返回哪些属性 - private val DIR = "\n" + - "\n" + - "\n" + - "\n\n\n\n\n%s" + - "\n" + - "" + private const val DIR = """\n + \n + \n + \n\n\n\n\n%s + \n + """ /** * 打印对象内的所有属性 From d3456e0b4d0f43746da7cfcd9101a2d0f604654e Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 18 Sep 2019 11:55:46 +0800 Subject: [PATCH 1526/1997] up --- .../java/io/legado/app/lib/webdav/WebDav.kt | 29 ++----------------- 1 file changed, 2 insertions(+), 27 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt b/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt index 93fc41c7d..29229bbbb 100644 --- a/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt +++ b/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt @@ -47,10 +47,7 @@ constructor(url: String) { get() = getUrl()?.let { url -> val request = Request.Builder().url(url) HttpAuth.auth?.let { - request.header( - "Authorization", - Credentials.basic(it.user, it.pass) - ) + request.header("Authorization", Credentials.basic(it.user, it.pass)) } try { @@ -263,8 +260,7 @@ constructor(url: String) { } companion object { - val TAG = WebDav::class.java.simpleName - val OBJECT_NOT_EXISTS_TAG = "ObjectNotFound" + // 指定返回哪些属性 private const val DIR = """\n \n @@ -273,26 +269,5 @@ constructor(url: String) { \n """ - /** - * 打印对象内的所有属性 - */ - fun printAllAttrs(className: String, o: Any): T? { - try { - val c = Class.forName(className) - val fields = c.declaredFields - for (f in fields) { - f.isAccessible = true - } - println("=============$className===============") - for (f in fields) { - val field = f.toString().substring(f.toString().lastIndexOf(".") + 1) //取出属性名称 - println(field + " --> " + f.get(o)) - } - } catch (e: Exception) { - e.printStackTrace() - } - - return null - } } } \ No newline at end of file From e8770de5979ab502630bd5cdcae029cabf38c2ba Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 18 Sep 2019 12:21:17 +0800 Subject: [PATCH 1527/1997] up --- app/src/main/java/io/legado/app/utils/LogUtils.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/utils/LogUtils.kt b/app/src/main/java/io/legado/app/utils/LogUtils.kt index 6418a84c4..88778d653 100644 --- a/app/src/main/java/io/legado/app/utils/LogUtils.kt +++ b/app/src/main/java/io/legado/app/utils/LogUtils.kt @@ -17,7 +17,7 @@ object LogUtils { addFileHandler( this, Level.INFO, - FileHelp.getCachePath() + File.separator + System.currentTimeMillis() + ".log" + FileHelp.getCachePath() + File.separator + getCurrentDateStr(DATE_PATTERN) + ".log" ) } } @@ -28,8 +28,8 @@ object LogUtils { } } - // 正常的日期格式 const val DATE_PATTERN_FULL = "yyyy-MM-dd HH:mm:ss" + private const val DATE_PATTERN = "yyyy-MM-dd" /** * 为log添加控制台handler From 91ccee8dce4ceeea442371dc76faa343cad86a8a Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 18 Sep 2019 12:25:23 +0800 Subject: [PATCH 1528/1997] up --- .../main/java/io/legado/app/utils/LogUtils.kt | 27 +++++++------------ 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/io/legado/app/utils/LogUtils.kt b/app/src/main/java/io/legado/app/utils/LogUtils.kt index 88778d653..571c4e4cf 100644 --- a/app/src/main/java/io/legado/app/utils/LogUtils.kt +++ b/app/src/main/java/io/legado/app/utils/LogUtils.kt @@ -17,7 +17,7 @@ object LogUtils { addFileHandler( this, Level.INFO, - FileHelp.getCachePath() + File.separator + getCurrentDateStr(DATE_PATTERN) + ".log" + FileHelp.getCachePath() ) } } @@ -28,23 +28,20 @@ object LogUtils { } } - const val DATE_PATTERN_FULL = "yyyy-MM-dd HH:mm:ss" private const val DATE_PATTERN = "yyyy-MM-dd" + const val TIME_PATTERN = "HH:mm:ss" /** * 为log添加控制台handler * - * @param log - * 要添加handler的log - * @param level - * 控制台的输出等级 + * @param log 要添加handler的log + * @param level 控制台的输出等级 */ fun addConsoleHandler(log: Logger, level: Level) { // 控制台输出的handler val consoleHandler = ConsoleHandler() // 设置控制台输出的等级(如果ConsoleHandler的等级高于或者等于log的level,则按照FileHandler的level输出到控制台,如果低于,则按照Log等级输出) consoleHandler.level = level - // 添加控制台的handler log.addHandler(consoleHandler) } @@ -52,23 +49,21 @@ object LogUtils { /** * 为log添加文件输出Handler * - * @param log - * 要添加文件输出handler的log - * @param level - * log输出等级 - * @param filePath - * 指定文件全路径 + * @param log 要添加文件输出handler的log + * @param level log输出等级 + * @param filePath 指定文件全路径 */ fun addFileHandler(log: Logger, level: Level, filePath: String) { var fileHandler: FileHandler? = null try { - fileHandler = FileHandler(filePath) + fileHandler = + FileHandler(filePath + File.separator + getCurrentDateStr(DATE_PATTERN) + ".log") // 设置输出文件的等级(如果FileHandler的等级高于或者等于log的level,则按照FileHandler的level输出到文件,如果低于,则按照Log等级输出) fileHandler.level = level fileHandler.formatter = object : Formatter() { override fun format(record: LogRecord): String { // 设置文件输出格式 - return (getCurrentDateStr(DATE_PATTERN_FULL) + ":" + record.message + "\n") + return (getCurrentDateStr(TIME_PATTERN) + ":" + record.message + "\n") } } } catch (e: Exception) { @@ -80,8 +75,6 @@ object LogUtils { /** * 获取当前时间 - * - * @return */ @SuppressLint("SimpleDateFormat") fun getCurrentDateStr(pattern: String): String { From de822857d764b7f08b2805ab1576f59da8d81813 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 18 Sep 2019 12:35:26 +0800 Subject: [PATCH 1529/1997] up --- .../io/legado/app/ui/main/MainActivity.kt | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt index eea51eb6e..bcd3fd017 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt @@ -13,15 +13,15 @@ import io.legado.app.base.VMBaseActivity import io.legado.app.constant.Bus import io.legado.app.help.permission.Permissions import io.legado.app.help.permission.PermissionsCompat +import io.legado.app.lib.dialogs.alert +import io.legado.app.lib.dialogs.noButton +import io.legado.app.lib.dialogs.yesButton import io.legado.app.lib.theme.ATH import io.legado.app.ui.main.bookshelf.BookshelfFragment import io.legado.app.ui.main.explore.ExploreFragment import io.legado.app.ui.main.my.MyFragment import io.legado.app.ui.main.rss.RssFragment -import io.legado.app.utils.getPrefInt -import io.legado.app.utils.getViewModel -import io.legado.app.utils.observeEvent -import io.legado.app.utils.putPrefInt +import io.legado.app.utils.* import kotlinx.android.synthetic.main.activity_main.* import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.launch @@ -58,11 +58,17 @@ class MainActivity : VMBaseActivity(R.layout.activity_main), private fun importYueDu() { launch { if (withContext(IO) { App.db.bookDao().allBookCount == 0 }) { - PermissionsCompat.Builder(this@MainActivity) - .addPermissions(*Permissions.Group.STORAGE) - .rationale(R.string.tip_perm_request_storage) - .onGranted { viewModel.restore() } - .request() + alert(title = "导入") { + message = "是否导入旧版本数据" + yesButton { + PermissionsCompat.Builder(this@MainActivity) + .addPermissions(*Permissions.Group.STORAGE) + .rationale(R.string.tip_perm_request_storage) + .onGranted { viewModel.restore() } + .request() + } + noButton { } + }.show().applyTint() } } } From d06532c8cba498e94205dd1b33a76934e816c6d5 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 18 Sep 2019 17:15:42 +0800 Subject: [PATCH 1530/1997] up --- app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt index d24faa7d7..a3f7eb8ac 100644 --- a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt +++ b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt @@ -22,7 +22,7 @@ class MediaButtonReceiver : BroadcastReceiver() { fun handleIntent(context: Context, intent: Intent): Boolean { val intentAction = intent.action - LogUtils.log("耳机按键:$intentAction") + LogUtils.log("耳机按键: $intentAction") if (Intent.ACTION_MEDIA_BUTTON == intentAction) { val event = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT) ?: return false From 1e59df85363f06e7c519650d535cf2bf8d858bfd Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 18 Sep 2019 17:20:59 +0800 Subject: [PATCH 1531/1997] up --- app/src/main/res/drawable/image_yue_du.webp | Bin 7540 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 app/src/main/res/drawable/image_yue_du.webp diff --git a/app/src/main/res/drawable/image_yue_du.webp b/app/src/main/res/drawable/image_yue_du.webp deleted file mode 100644 index 2d3652cdb529062dd27818be7d2958b33cfb37cf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7540 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 KC-mJCKmY)CblHIb From 98003f6e0871cc2c8a0e4991d958ca2a8374e0ea Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 18 Sep 2019 17:52:11 +0800 Subject: [PATCH 1532/1997] up --- .../java/io/legado/app/help/IntentHelp.kt | 12 +++++ .../app/service/BaseReadAloudService.kt | 11 ++--- .../legado/app/service/CheckSourceService.kt | 46 +++++++++++++++++++ 3 files changed, 62 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/IntentHelp.kt b/app/src/main/java/io/legado/app/help/IntentHelp.kt index 55ee61ed0..13a812e8e 100644 --- a/app/src/main/java/io/legado/app/help/IntentHelp.kt +++ b/app/src/main/java/io/legado/app/help/IntentHelp.kt @@ -1,5 +1,6 @@ package io.legado.app.help +import android.app.PendingIntent import android.content.Context import android.content.Intent import io.legado.app.R @@ -19,4 +20,15 @@ object IntentHelp { context.toast(R.string.tip_cannot_jump_setting_page) } } + + inline fun servicePendingIntent(context: Context, action: String): PendingIntent? { + return PendingIntent.getService( + context, + 0, + Intent(context, T::class.java).apply { + this.action = action + }, + PendingIntent.FLAG_UPDATE_CURRENT + ) + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt index 4a74683f5..2e9f34ef8 100644 --- a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt @@ -18,6 +18,7 @@ import io.legado.app.constant.AppConst import io.legado.app.constant.Bus import io.legado.app.constant.Status import io.legado.app.help.IntentDataHelp +import io.legado.app.help.IntentHelp import io.legado.app.help.MediaHelp import io.legado.app.receiver.MediaButtonReceiver import io.legado.app.ui.book.read.ReadBookActivity @@ -289,7 +290,9 @@ abstract class BaseReadAloudService : BaseService(), .setOngoing(true) .setContentTitle(nTitle) .setContentText(nSubtitle) - .setContentIntent(readBookActivityPendingIntent(this)) + .setContentIntent( + IntentHelp.servicePendingIntent(this, "activity") + ) if (pause) { builder.addAction( R.drawable.ic_play_24dp, @@ -323,12 +326,6 @@ abstract class BaseReadAloudService : BaseService(), startForeground(112201, notification) } - private fun readBookActivityPendingIntent(context: Context): PendingIntent { - val intent = Intent(context, ReadBookActivity::class.java) - intent.action = "readBookActivity" - return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) - } - abstract fun aloudServicePendingIntent(context: Context, actionStr: String): PendingIntent } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/service/CheckSourceService.kt b/app/src/main/java/io/legado/app/service/CheckSourceService.kt index 247a137a9..75bb49ee0 100644 --- a/app/src/main/java/io/legado/app/service/CheckSourceService.kt +++ b/app/src/main/java/io/legado/app/service/CheckSourceService.kt @@ -1,8 +1,54 @@ package io.legado.app.service +import android.content.Intent +import androidx.core.app.NotificationCompat +import io.legado.app.R import io.legado.app.base.BaseService +import io.legado.app.constant.Action +import io.legado.app.constant.AppConst +import io.legado.app.data.entities.BookSource +import io.legado.app.help.IntentHelp +import io.legado.app.ui.book.source.manage.BookSourceActivity class CheckSourceService : BaseService() { + private var sourceList: List? = null + + override fun onCreate() { + super.onCreate() + } + + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + return super.onStartCommand(intent, flags, startId) + } + + override fun onDestroy() { + super.onDestroy() + } + + /** + * 更新通知 + */ + private fun updateNotification(state: Int, msg: String) { + val builder = NotificationCompat.Builder(this, AppConst.channelIdReadAloud) + .setSmallIcon(R.drawable.ic_network_check) + .setOngoing(true) + .setContentTitle(getString(R.string.check_book_source)) + .setContentText(msg) + .setContentIntent( + IntentHelp.servicePendingIntent(this, "activity") + ) + .addAction( + R.drawable.ic_stop_black_24dp, + getString(R.string.cancel), + IntentHelp.servicePendingIntent(this, Action.stop) + ) + sourceList?.let { + builder.setProgress(it.size, state, false) + } + builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) + val notification = builder.build() + startForeground(112202, notification) + } } \ No newline at end of file From 0e9e9a842dbe8151ee7c3d9c4b35b114dac42db9 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 18 Sep 2019 17:56:12 +0800 Subject: [PATCH 1533/1997] up --- app/src/main/java/io/legado/app/help/IntentHelp.kt | 4 +--- .../java/io/legado/app/service/BaseReadAloudService.kt | 10 +++++----- .../java/io/legado/app/service/HttpReadAloudService.kt | 9 +++------ .../java/io/legado/app/service/TTSReadAloudService.kt | 8 ++------ 4 files changed, 11 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/IntentHelp.kt b/app/src/main/java/io/legado/app/help/IntentHelp.kt index 13a812e8e..28c33ad9e 100644 --- a/app/src/main/java/io/legado/app/help/IntentHelp.kt +++ b/app/src/main/java/io/legado/app/help/IntentHelp.kt @@ -25,9 +25,7 @@ object IntentHelp { return PendingIntent.getService( context, 0, - Intent(context, T::class.java).apply { - this.action = action - }, + Intent(context, T::class.java).apply { this.action = action }, PendingIntent.FLAG_UPDATE_CURRENT ) } diff --git a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt index 2e9f34ef8..ad0104675 100644 --- a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt @@ -297,24 +297,24 @@ abstract class BaseReadAloudService : BaseService(), builder.addAction( R.drawable.ic_play_24dp, getString(R.string.resume), - aloudServicePendingIntent(this, Action.resume) + aloudServicePendingIntent(Action.resume) ) } else { builder.addAction( R.drawable.ic_pause_24dp, getString(R.string.pause), - aloudServicePendingIntent(this, Action.pause) + aloudServicePendingIntent(Action.pause) ) } builder.addAction( R.drawable.ic_stop_black_24dp, getString(R.string.stop), - aloudServicePendingIntent(this, Action.stop) + aloudServicePendingIntent(Action.stop) ) builder.addAction( R.drawable.ic_time_add_24dp, getString(R.string.set_timer), - aloudServicePendingIntent(this, Action.addTimer) + aloudServicePendingIntent(Action.addTimer) ) builder.setStyle( androidx.media.app.NotificationCompat.MediaStyle() @@ -326,6 +326,6 @@ abstract class BaseReadAloudService : BaseService(), startForeground(112201, notification) } - abstract fun aloudServicePendingIntent(context: Context, actionStr: String): PendingIntent + abstract fun aloudServicePendingIntent(actionStr: String): PendingIntent? } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt b/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt index 7c40d15aa..2dde06378 100644 --- a/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt @@ -1,10 +1,9 @@ package io.legado.app.service import android.app.PendingIntent -import android.content.Context -import android.content.Intent import android.media.MediaPlayer import io.legado.app.constant.Bus +import io.legado.app.help.IntentHelp import io.legado.app.utils.getPrefInt import io.legado.app.utils.getPrefString import io.legado.app.utils.postEvent @@ -103,9 +102,7 @@ class HttpReadAloudService : BaseReadAloudService(), } } - override fun aloudServicePendingIntent(context: Context, actionStr: String): PendingIntent { - val intent = Intent(context, HttpReadAloudService::class.java) - intent.action = actionStr - return PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) + override fun aloudServicePendingIntent(actionStr: String): PendingIntent? { + return IntentHelp.servicePendingIntent(this, actionStr) } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt b/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt index 0909d16fa..b8cbdedfc 100644 --- a/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt @@ -1,8 +1,6 @@ package io.legado.app.service import android.app.PendingIntent -import android.content.Context -import android.content.Intent import android.os.Build import android.speech.tts.TextToSpeech import android.speech.tts.UtteranceProgressListener @@ -190,10 +188,8 @@ class TTSReadAloudService : BaseReadAloudService(), TextToSpeech.OnInitListener } - override fun aloudServicePendingIntent(context: Context, actionStr: String): PendingIntent { - val intent = Intent(context, TTSReadAloudService::class.java) - intent.action = actionStr - return PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) + override fun aloudServicePendingIntent(actionStr: String): PendingIntent? { + return IntentHelp.servicePendingIntent(this, actionStr) } } \ No newline at end of file From ba179cfee8610be3bcc1c2e038d5980a35f1355e Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 18 Sep 2019 18:01:08 +0800 Subject: [PATCH 1534/1997] up --- app/src/main/java/io/legado/app/help/IntentHelp.kt | 9 +++++++++ .../java/io/legado/app/service/BaseReadAloudService.kt | 2 +- .../java/io/legado/app/service/CheckSourceService.kt | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/IntentHelp.kt b/app/src/main/java/io/legado/app/help/IntentHelp.kt index 28c33ad9e..815867694 100644 --- a/app/src/main/java/io/legado/app/help/IntentHelp.kt +++ b/app/src/main/java/io/legado/app/help/IntentHelp.kt @@ -29,4 +29,13 @@ object IntentHelp { PendingIntent.FLAG_UPDATE_CURRENT ) } + + inline fun activityPendingIntent(context: Context, action: String): PendingIntent? { + return PendingIntent.getActivity( + context, + 0, + Intent(context, T::class.java).apply { this.action = action }, + PendingIntent.FLAG_UPDATE_CURRENT + ) + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt index ad0104675..6ee66129b 100644 --- a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt @@ -291,7 +291,7 @@ abstract class BaseReadAloudService : BaseService(), .setContentTitle(nTitle) .setContentText(nSubtitle) .setContentIntent( - IntentHelp.servicePendingIntent(this, "activity") + IntentHelp.activityPendingIntent(this, "activity") ) if (pause) { builder.addAction( diff --git a/app/src/main/java/io/legado/app/service/CheckSourceService.kt b/app/src/main/java/io/legado/app/service/CheckSourceService.kt index 75bb49ee0..5fa36c1ba 100644 --- a/app/src/main/java/io/legado/app/service/CheckSourceService.kt +++ b/app/src/main/java/io/legado/app/service/CheckSourceService.kt @@ -36,7 +36,7 @@ class CheckSourceService : BaseService() { .setContentTitle(getString(R.string.check_book_source)) .setContentText(msg) .setContentIntent( - IntentHelp.servicePendingIntent(this, "activity") + IntentHelp.activityPendingIntent(this, "activity") ) .addAction( R.drawable.ic_stop_black_24dp, From 948f360ebbd147df15d55e086ce9c349ac972b98 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 18 Sep 2019 19:06:13 +0800 Subject: [PATCH 1535/1997] up --- .../main/java/io/legado/app/help/IntentDataHelp.kt | 4 +++- .../io/legado/app/ui/book/read/ReadBookActivity.kt | 11 +++++++---- .../app/ui/book/source/manage/BookSourceActivity.kt | 4 ++++ 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/IntentDataHelp.kt b/app/src/main/java/io/legado/app/help/IntentDataHelp.kt index 4c1ca38d5..e7484949e 100644 --- a/app/src/main/java/io/legado/app/help/IntentDataHelp.kt +++ b/app/src/main/java/io/legado/app/help/IntentDataHelp.kt @@ -4,8 +4,10 @@ object IntentDataHelp { private val bigData: MutableMap = mutableMapOf() - fun putData(key: String, data: Any) { + fun putData(data: Any, tag: String = ""): String { + val key = tag + System.currentTimeMillis() bigData[key] = data + return key } fun getData(key: String): Any? { diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt index ebf23f520..e94febcbe 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt @@ -467,11 +467,14 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea val book = viewModel.bookData.value val textChapter = viewModel.curTextChapter if (book != null && textChapter != null) { - val key = System.currentTimeMillis().toString() - IntentDataHelp.putData(key, textChapter) + val key = IntentDataHelp.putData(textChapter) ReadAloud.play( - this, book.name, textChapter.title, - viewModel.durPageIndex, key, play + this, + book.name, + textChapter.title, + viewModel.durPageIndex, + key, + play ) } } diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt index 573444123..32510192b 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt @@ -21,6 +21,7 @@ import io.legado.app.help.ItemTouchCallback import io.legado.app.help.storage.Restore import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.primaryTextColor +import io.legado.app.service.CheckSourceService import io.legado.app.ui.book.source.edit.SourceEditActivity import io.legado.app.ui.qrcode.QrCodeActivity import io.legado.app.utils.getViewModel @@ -30,6 +31,7 @@ import kotlinx.android.synthetic.main.view_search.* import kotlinx.android.synthetic.main.view_title_bar.* import org.jetbrains.anko.startActivity import org.jetbrains.anko.startActivityForResult +import org.jetbrains.anko.startService class BookSourceActivity : VMBaseActivity(R.layout.activity_book_source), BookSourceAdapter.CallBack, @@ -80,6 +82,8 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity R.id.menu_enable_selection -> viewModel.enableSelection(adapter.getSelectionIds()) R.id.menu_disable_selection -> viewModel.disableSelection(adapter.getSelectionIds()) R.id.menu_del_selection -> viewModel.delSelection(adapter.getSelectionIds()) + R.id.menu_check_book_source -> + startService(Pair("data", adapter.getSelectionIds())) } if (item.groupId == R.id.source_group) { search_view.setQuery(item.title, true) From 15cec309c26418800f41fd675eb6bd10423d0495 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 18 Sep 2019 20:36:23 +0800 Subject: [PATCH 1536/1997] up --- .../main/java/io/legado/app/lib/theme/ATH.kt | 4 +- .../app/lib/theme/MaterialValueHelper.kt | 41 ++----------------- .../app/ui/main/explore/ExploreFragment.kt | 25 ++++++++++- app/src/main/res/drawable/ic_screen.xml | 11 +++++ app/src/main/res/menu/find_book.xml | 11 ----- app/src/main/res/values/strings.xml | 1 + 6 files changed, 42 insertions(+), 51 deletions(-) create mode 100644 app/src/main/res/drawable/ic_screen.xml delete mode 100644 app/src/main/res/menu/find_book.xml diff --git a/app/src/main/java/io/legado/app/lib/theme/ATH.kt b/app/src/main/java/io/legado/app/lib/theme/ATH.kt index ba1b0dc8e..19542ffc4 100644 --- a/app/src/main/java/io/legado/app/lib/theme/ATH.kt +++ b/app/src/main/java/io/legado/app/lib/theme/ATH.kt @@ -130,8 +130,8 @@ object ATH { fun setTint( view: View, - @ColorInt color: Int, isDark: - Boolean = view.context.isNightTheme + @ColorInt color: Int, + isDark: Boolean = view.context.isNightTheme ) { TintHelper.setTintAuto(view, color, false, isDark) } diff --git a/app/src/main/java/io/legado/app/lib/theme/MaterialValueHelper.kt b/app/src/main/java/io/legado/app/lib/theme/MaterialValueHelper.kt index e611ac728..1618884b5 100644 --- a/app/src/main/java/io/legado/app/lib/theme/MaterialValueHelper.kt +++ b/app/src/main/java/io/legado/app/lib/theme/MaterialValueHelper.kt @@ -42,39 +42,6 @@ fun Context.getSecondaryDisabledTextColor(dark: Boolean): Int { } else ContextCompat.getColor(this, R.color.secondary_text_disabled_material_dark) } - -@SuppressLint("PrivateResource") -@ColorInt -fun Fragment.getPrimaryTextColor(dark: Boolean): Int { - return if (dark) { - ContextCompat.getColor(requireContext(), R.color.primary_text_default_material_light) - } else ContextCompat.getColor(requireContext(), R.color.primary_text_default_material_dark) -} - -@SuppressLint("PrivateResource") -@ColorInt -fun Fragment.getSecondaryTextColor(dark: Boolean): Int { - return if (dark) { - ContextCompat.getColor(requireContext(), R.color.secondary_text_default_material_light) - } else ContextCompat.getColor(requireContext(), R.color.secondary_text_default_material_dark) -} - -@SuppressLint("PrivateResource") -@ColorInt -fun Fragment.getPrimaryDisabledTextColor(dark: Boolean): Int { - return if (dark) { - ContextCompat.getColor(requireContext(), R.color.primary_text_disabled_material_light) - } else ContextCompat.getColor(requireContext(), R.color.primary_text_disabled_material_dark) -} - -@SuppressLint("PrivateResource") -@ColorInt -fun Fragment.getSecondaryDisabledTextColor(dark: Boolean): Int { - return if (dark) { - ContextCompat.getColor(requireContext(), R.color.secondary_text_disabled_material_light) - } else ContextCompat.getColor(requireContext(), R.color.secondary_text_disabled_material_dark) -} - val Context.primaryColor: Int get() = ThemeStore.primaryColor(this) @@ -112,16 +79,16 @@ val Fragment.backgroundColor: Int get() = ThemeStore.backgroundColor(requireContext()) val Fragment.primaryTextColor: Int - get() = getPrimaryTextColor(isDarkTheme) + get() = requireContext().getPrimaryTextColor(isDarkTheme) val Fragment.secondaryTextColor: Int - get() = getSecondaryTextColor(isDarkTheme) + get() = requireContext().getSecondaryTextColor(isDarkTheme) val Fragment.primaryDisabledTextColor: Int - get() = getPrimaryDisabledTextColor(isDarkTheme) + get() = requireContext().getPrimaryDisabledTextColor(isDarkTheme) val Fragment.secondaryDisabledTextColor: Int - get() = getSecondaryDisabledTextColor(isDarkTheme) + get() = requireContext().getSecondaryDisabledTextColor(isDarkTheme) val Context.buttonDisabledColor: Int get() = if (isDarkTheme) { diff --git a/app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt b/app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt index 888dbe4ac..503cdc37a 100644 --- a/app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt @@ -3,6 +3,8 @@ package io.legado.app.ui.main.explore import android.os.Bundle import android.view.Menu import android.view.View +import androidx.appcompat.widget.AppCompatImageView +import androidx.appcompat.widget.SearchView import androidx.lifecycle.Observer import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.App @@ -10,13 +12,16 @@ import io.legado.app.R import io.legado.app.base.VMBaseFragment import io.legado.app.data.entities.BookSource import io.legado.app.lib.theme.ATH +import io.legado.app.lib.theme.primaryTextColor import io.legado.app.ui.book.source.edit.SourceEditActivity import io.legado.app.ui.explore.ExploreShowActivity +import io.legado.app.utils.getCompatDrawable import io.legado.app.utils.getViewModel import io.legado.app.utils.startActivity import kotlinx.android.synthetic.main.fragment_find_book.* import kotlinx.android.synthetic.main.view_title_bar.* + class ExploreFragment : VMBaseFragment(R.layout.fragment_find_book), ExploreAdapter.CallBack { override val viewModel: ExploreViewModel @@ -24,6 +29,7 @@ class ExploreFragment : VMBaseFragment(R.layout.fragment_find_ private lateinit var adapter: ExploreAdapter private lateinit var linearLayoutManager: LinearLayoutManager + private var searchView: SearchView? = null override fun onViewCreated(view: View, savedInstanceState: Bundle?) { setSupportToolbar(toolbar) @@ -32,7 +38,24 @@ class ExploreFragment : VMBaseFragment(R.layout.fragment_find_ } override fun onCompatCreateOptionsMenu(menu: Menu) { - menuInflater.inflate(R.menu.find_book, menu) + menuInflater.inflate(R.menu.search_view, menu) + val search = menu.findItem(R.id.menu_search) + searchView = search.actionView as SearchView + val bottom = + searchView?.findViewById(androidx.appcompat.R.id.search_button) as? AppCompatImageView + bottom?.setImageDrawable(getCompatDrawable(R.drawable.ic_screen)) + ATH.setTint(searchView!!, primaryTextColor) + searchView?.maxWidth = resources.displayMetrics.widthPixels + searchView?.onActionViewCollapsed() + searchView?.setOnQueryTextListener(object : SearchView.OnQueryTextListener { + override fun onQueryTextSubmit(query: String): Boolean { + return false + } + + override fun onQueryTextChange(newText: String): Boolean { + return false + } + }) } private fun initRecyclerView() { diff --git a/app/src/main/res/drawable/ic_screen.xml b/app/src/main/res/drawable/ic_screen.xml new file mode 100644 index 000000000..4a641e517 --- /dev/null +++ b/app/src/main/res/drawable/ic_screen.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/find_book.xml b/app/src/main/res/menu/find_book.xml deleted file mode 100644 index 72f4f570a..000000000 --- a/app/src/main/res/menu/find_book.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1d20b0eec..3cda2ca88 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -505,5 +505,6 @@ 输入你的服务器地址 输入你的WebDav账号 订阅源 + 筛选 From 604361c2d22f5bffc0c83f429d8ebf916c324d03 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 18 Sep 2019 21:12:56 +0800 Subject: [PATCH 1537/1997] up --- .../main/java/io/legado/app/ui/main/explore/ExploreFragment.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt b/app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt index 503cdc37a..4041ca5f4 100644 --- a/app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt @@ -91,4 +91,5 @@ class ExploreFragment : VMBaseFragment(R.layout.fragment_find_ override fun toTop(source: BookSource) { viewModel.topSource(source) } + } \ No newline at end of file From 425e40b1676826c8434f9125ef265d155219e913 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 18 Sep 2019 21:24:12 +0800 Subject: [PATCH 1538/1997] up --- .../app/ui/main/explore/ExploreFragment.kt | 32 +++++-------------- .../main/res/layout/fragment_find_book.xml | 5 +-- app/src/main/res/values/strings.xml | 1 + 3 files changed, 12 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt b/app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt index 4041ca5f4..8ac9c93bd 100644 --- a/app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt @@ -1,10 +1,7 @@ package io.legado.app.ui.main.explore import android.os.Bundle -import android.view.Menu import android.view.View -import androidx.appcompat.widget.AppCompatImageView -import androidx.appcompat.widget.SearchView import androidx.lifecycle.Observer import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.App @@ -15,10 +12,10 @@ import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.primaryTextColor import io.legado.app.ui.book.source.edit.SourceEditActivity import io.legado.app.ui.explore.ExploreShowActivity -import io.legado.app.utils.getCompatDrawable import io.legado.app.utils.getViewModel import io.legado.app.utils.startActivity import kotlinx.android.synthetic.main.fragment_find_book.* +import kotlinx.android.synthetic.main.view_search.* import kotlinx.android.synthetic.main.view_title_bar.* @@ -29,33 +26,20 @@ class ExploreFragment : VMBaseFragment(R.layout.fragment_find_ private lateinit var adapter: ExploreAdapter private lateinit var linearLayoutManager: LinearLayoutManager - private var searchView: SearchView? = null override fun onViewCreated(view: View, savedInstanceState: Bundle?) { setSupportToolbar(toolbar) + initSearchView() initRecyclerView() initData() } - override fun onCompatCreateOptionsMenu(menu: Menu) { - menuInflater.inflate(R.menu.search_view, menu) - val search = menu.findItem(R.id.menu_search) - searchView = search.actionView as SearchView - val bottom = - searchView?.findViewById(androidx.appcompat.R.id.search_button) as? AppCompatImageView - bottom?.setImageDrawable(getCompatDrawable(R.drawable.ic_screen)) - ATH.setTint(searchView!!, primaryTextColor) - searchView?.maxWidth = resources.displayMetrics.widthPixels - searchView?.onActionViewCollapsed() - searchView?.setOnQueryTextListener(object : SearchView.OnQueryTextListener { - override fun onQueryTextSubmit(query: String): Boolean { - return false - } - - override fun onQueryTextChange(newText: String): Boolean { - return false - } - }) + private fun initSearchView() { + ATH.setTint(search_view, primaryTextColor) + search_view.onActionViewExpanded() + search_view.isSubmitButtonEnabled = true + search_view.queryHint = getString(R.string.screen_find) + search_view.clearFocus() } private fun initRecyclerView() { diff --git a/app/src/main/res/layout/fragment_find_book.xml b/app/src/main/res/layout/fragment_find_book.xml index 4ea053240..8609db403 100644 --- a/app/src/main/res/layout/fragment_find_book.xml +++ b/app/src/main/res/layout/fragment_find_book.xml @@ -1,15 +1,16 @@ + android:layout_height="match_parent" + android:orientation="vertical"> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3cda2ca88..a143f2e50 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -506,5 +506,6 @@ 输入你的WebDav账号 订阅源 筛选 + 筛选发现 From 134cab4e12e1703566ff029123d067ddb9bfa862 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 18 Sep 2019 21:37:27 +0800 Subject: [PATCH 1539/1997] up --- .../io/legado/app/data/dao/BookSourceDao.kt | 3 +++ .../app/ui/main/explore/ExploreFragment.kt | 22 +++++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt index 36dfc3d22..39dc91264 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt @@ -17,6 +17,9 @@ interface BookSourceDao { @Query("select * from book_sources where enabledExplore = 1 and exploreUrl is not null and exploreUrl <> '' order by customOrder asc") fun liveExplore(): LiveData> + @Query("select * from book_sources where enabledExplore = 1 and exploreUrl is not null and exploreUrl <> '' and (bookSourceGroup like :key or bookSourceName like :key) order by customOrder asc") + fun liveExplore(key: String): LiveData> + @Query("select bookSourceGroup from book_sources where bookSourceGroup is not null and bookSourceGroup <> ''") fun liveGroup(): LiveData> diff --git a/app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt b/app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt index 8ac9c93bd..55df1a26a 100644 --- a/app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt @@ -2,6 +2,8 @@ package io.legado.app.ui.main.explore import android.os.Bundle import android.view.View +import androidx.appcompat.widget.SearchView +import androidx.lifecycle.LiveData import androidx.lifecycle.Observer import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.App @@ -26,6 +28,7 @@ class ExploreFragment : VMBaseFragment(R.layout.fragment_find_ private lateinit var adapter: ExploreAdapter private lateinit var linearLayoutManager: LinearLayoutManager + private var liveExplore: LiveData>? = null override fun onViewCreated(view: View, savedInstanceState: Bundle?) { setSupportToolbar(toolbar) @@ -40,6 +43,15 @@ class ExploreFragment : VMBaseFragment(R.layout.fragment_find_ search_view.isSubmitButtonEnabled = true search_view.queryHint = getString(R.string.screen_find) search_view.clearFocus() + search_view.setOnQueryTextListener(object : SearchView.OnQueryTextListener { + override fun onQueryTextSubmit(query: String?): Boolean { + return false + } + + override fun onQueryTextChange(newText: String?): Boolean { + return false + } + }) } private fun initRecyclerView() { @@ -50,8 +62,14 @@ class ExploreFragment : VMBaseFragment(R.layout.fragment_find_ rv_find.adapter = adapter } - private fun initData() { - App.db.bookSourceDao().liveExplore().observe(viewLifecycleOwner, Observer { + private fun initData(key: String? = null) { + liveExplore?.removeObservers(viewLifecycleOwner) + liveExplore = if (key.isNullOrBlank()) { + App.db.bookSourceDao().liveExplore() + } else { + App.db.bookSourceDao().liveExplore("%$key%") + } + liveExplore?.observe(viewLifecycleOwner, Observer { adapter.setItems(it) }) } From c698b55399e05d5097de529a3fd3f2d98dad753d Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 18 Sep 2019 22:12:17 +0800 Subject: [PATCH 1540/1997] up --- .../main/java/io/legado/app/ui/main/explore/ExploreFragment.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt b/app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt index 55df1a26a..6889124f3 100644 --- a/app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt @@ -49,6 +49,7 @@ class ExploreFragment : VMBaseFragment(R.layout.fragment_find_ } override fun onQueryTextChange(newText: String?): Boolean { + initData(newText) return false } }) From 365c17b52b3326596d247d78911d409d34a5a139 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 18 Sep 2019 22:34:38 +0800 Subject: [PATCH 1541/1997] up --- .../main/java/io/legado/app/receiver/MediaButtonReceiver.kt | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt index a3f7eb8ac..5d3519c22 100644 --- a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt +++ b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt @@ -24,11 +24,7 @@ class MediaButtonReceiver : BroadcastReceiver() { val intentAction = intent.action LogUtils.log("耳机按键: $intentAction") if (Intent.ACTION_MEDIA_BUTTON == intentAction) { - val event = - intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT) ?: return false - - val action = event.action - + val action = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT)?.action if (action == KeyEvent.ACTION_DOWN) { readAloud(context) return true From dea4ab709f9b33bc303c9313820a7841221c50f0 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 18 Sep 2019 22:38:59 +0800 Subject: [PATCH 1542/1997] up --- .../main/java/io/legado/app/receiver/MediaButtonReceiver.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt index 5d3519c22..ea4e91d4e 100644 --- a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt +++ b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt @@ -22,10 +22,10 @@ class MediaButtonReceiver : BroadcastReceiver() { fun handleIntent(context: Context, intent: Intent): Boolean { val intentAction = intent.action - LogUtils.log("耳机按键: $intentAction") + val keyEventAction = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT)?.action + LogUtils.log("耳机按键: $intentAction $keyEventAction") if (Intent.ACTION_MEDIA_BUTTON == intentAction) { - val action = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT)?.action - if (action == KeyEvent.ACTION_DOWN) { + if (keyEventAction == KeyEvent.ACTION_DOWN) { readAloud(context) return true } From 1b66ef0a75dfdf5e963a1989aa3046764eeab777 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 19 Sep 2019 09:32:13 +0800 Subject: [PATCH 1543/1997] up --- app/src/main/java/io/legado/app/service/BaseReadAloudService.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt index 6ee66129b..03591482e 100644 --- a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt @@ -69,6 +69,7 @@ abstract class BaseReadAloudService : BaseService(), unregisterReceiver(broadcastReceiver) postEvent(Bus.ALOUD_STATE, Status.STOP) upMediaSessionPlaybackState(PlaybackStateCompat.STATE_STOPPED) + mediaSessionCompat?.release() } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { From d8dc48e43534dbc19940a68f91787615d3c5bf04 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 19 Sep 2019 11:11:21 +0800 Subject: [PATCH 1544/1997] up --- .../app/service/BaseReadAloudService.kt | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt index 03591482e..9b45d3cef 100644 --- a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt @@ -1,7 +1,10 @@ package io.legado.app.service import android.app.PendingIntent -import android.content.* +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter import android.graphics.BitmapFactory import android.media.AudioFocusRequest import android.media.AudioManager @@ -11,6 +14,7 @@ import android.support.v4.media.session.MediaSessionCompat import android.support.v4.media.session.PlaybackStateCompat import androidx.annotation.CallSuper import androidx.core.app.NotificationCompat +import io.legado.app.App import io.legado.app.R import io.legado.app.base.BaseService import io.legado.app.constant.Action @@ -234,23 +238,25 @@ abstract class BaseReadAloudService : BaseService(), * 初始化MediaSession, 注册多媒体按钮 */ private fun initMediaSession() { - val mediaButtonIntent = Intent(Intent.ACTION_MEDIA_BUTTON).apply { - component = ComponentName(packageName, MediaButtonReceiver::class.java.name) - } - val mediaButtonReceiverPendingIntent = PendingIntent.getBroadcast( - this, - 0, - mediaButtonIntent, - PendingIntent.FLAG_CANCEL_CURRENT - ) - mediaSessionCompat = MediaSessionCompat(this, TTSReadAloudService.tag) mediaSessionCompat?.setCallback(object : MediaSessionCompat.Callback() { override fun onMediaButtonEvent(mediaButtonEvent: Intent): Boolean { return MediaButtonReceiver.handleIntent(this@BaseReadAloudService, mediaButtonEvent) } }) - mediaSessionCompat?.setMediaButtonReceiver(mediaButtonReceiverPendingIntent) + mediaSessionCompat?.setMediaButtonReceiver( + PendingIntent.getBroadcast( + this, + 0, + Intent( + Intent.ACTION_MEDIA_BUTTON, + null, + App.INSTANCE, + MediaButtonReceiver::class.java + ), + PendingIntent.FLAG_CANCEL_CURRENT + ) + ) mediaSessionCompat?.isActive = true } From db02b4a2245bb2440089e77320b11ffa4609fa7e Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 19 Sep 2019 11:14:16 +0800 Subject: [PATCH 1545/1997] up --- .../app/service/BaseReadAloudService.kt | 47 ++++++++++--------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt index 9b45d3cef..19c29dbe3 100644 --- a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt @@ -186,28 +186,6 @@ abstract class BaseReadAloudService : BaseService(), upNotification() } - /** - * 音频焦点变化 - */ - override fun onAudioFocusChange(focusChange: Int) { - when (focusChange) { - AudioManager.AUDIOFOCUS_GAIN -> { - // 重新获得焦点, 可做恢复播放,恢复后台音量的操作 - if (!pause) resumeReadAloud() - } - AudioManager.AUDIOFOCUS_LOSS -> { - // 永久丢失焦点除非重新主动获取,这种情况是被其他播放器抢去了焦点, 为避免与其他播放器混音,可将音乐暂停 - } - AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> { - // 暂时丢失焦点,这种情况是被其他应用申请了短暂的焦点,可压低后台音量 - if (!pause) pauseReadAloud(false) - } - AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> { - // 短暂丢失焦点,这种情况是被其他应用申请了短暂的焦点希望其他声音能压低音量(或者关闭声音)凸显这个声音(比如短信提示音), - } - } - } - /** * @return 音频焦点 */ @@ -225,6 +203,9 @@ abstract class BaseReadAloudService : BaseService(), return request == AudioManager.AUDIOFOCUS_REQUEST_GRANTED } + /** + * 更新媒体状态 + */ private fun upMediaSessionPlaybackState(state: Int) { mediaSessionCompat?.setPlaybackState( PlaybackStateCompat.Builder() @@ -275,6 +256,28 @@ abstract class BaseReadAloudService : BaseService(), registerReceiver(broadcastReceiver, intentFilter) } + /** + * 音频焦点变化 + */ + override fun onAudioFocusChange(focusChange: Int) { + when (focusChange) { + AudioManager.AUDIOFOCUS_GAIN -> { + // 重新获得焦点, 可做恢复播放,恢复后台音量的操作 + if (!pause) resumeReadAloud() + } + AudioManager.AUDIOFOCUS_LOSS -> { + // 永久丢失焦点除非重新主动获取,这种情况是被其他播放器抢去了焦点, 为避免与其他播放器混音,可将音乐暂停 + } + AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> { + // 暂时丢失焦点,这种情况是被其他应用申请了短暂的焦点,可压低后台音量 + if (!pause) pauseReadAloud(false) + } + AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> { + // 短暂丢失焦点,这种情况是被其他应用申请了短暂的焦点希望其他声音能压低音量(或者关闭声音)凸显这个声音(比如短信提示音), + } + } + } + /** * 更新通知 */ From a326b20cb3b502e4ee4c0bb817f461012dcbc02a Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 19 Sep 2019 11:16:57 +0800 Subject: [PATCH 1546/1997] up --- app/src/main/java/io/legado/app/service/BaseReadAloudService.kt | 2 +- app/src/main/java/io/legado/app/service/TTSReadAloudService.kt | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt index 19c29dbe3..9af47f861 100644 --- a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt @@ -219,7 +219,7 @@ abstract class BaseReadAloudService : BaseService(), * 初始化MediaSession, 注册多媒体按钮 */ private fun initMediaSession() { - mediaSessionCompat = MediaSessionCompat(this, TTSReadAloudService.tag) + mediaSessionCompat = MediaSessionCompat(this, "readAloud") mediaSessionCompat?.setCallback(object : MediaSessionCompat.Callback() { override fun onMediaButtonEvent(mediaButtonEvent: Intent): Boolean { return MediaButtonReceiver.handleIntent(this@BaseReadAloudService, mediaButtonEvent) diff --git a/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt b/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt index b8cbdedfc..e3fc37479 100644 --- a/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt @@ -19,7 +19,6 @@ import java.util.* class TTSReadAloudService : BaseReadAloudService(), TextToSpeech.OnInitListener { companion object { - val tag: String = TTSReadAloudService::class.java.simpleName var textToSpeech: TextToSpeech? = null fun clearTTS() { From d763cfe180f5502a4d2e43845610b48eea5e1843 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 19 Sep 2019 15:12:04 +0800 Subject: [PATCH 1547/1997] up --- .../main/java/io/legado/app/ui/book/read/ReadBookActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt index e94febcbe..cbf685604 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt @@ -207,7 +207,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } KeyEvent.KEYCODE_SPACE -> { - + page_view.moveToNextPage() } } return super.onKeyDown(keyCode, event) From 170c7004b3d0c99045db74adba0cc94387ae8125 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 19 Sep 2019 17:09:02 +0800 Subject: [PATCH 1548/1997] up --- app/src/main/java/io/legado/app/help/storage/Backup.kt | 9 ++++----- .../main/java/io/legado/app/help/storage/WebDavHelp.kt | 10 +++++----- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/storage/Backup.kt b/app/src/main/java/io/legado/app/help/storage/Backup.kt index 14faab468..92333d1d3 100644 --- a/app/src/main/java/io/legado/app/help/storage/Backup.kt +++ b/app/src/main/java/io/legado/app/help/storage/Backup.kt @@ -1,6 +1,5 @@ package io.legado.app.help.storage -import androidx.appcompat.app.AppCompatActivity import io.legado.app.App import io.legado.app.R import io.legado.app.help.FileHelp @@ -27,21 +26,21 @@ object Backup { backupRssSource(path) backupReplaceRule(path) backupPreference(path) - WebDavHelp.backUpWebDav() + WebDavHelp.backUpWebDav(path) uiThread { App.INSTANCE.toast(R.string.backup_success) } } } - fun autoBackup(activity: AppCompatActivity) { + fun autoBackup() { doAsync { - val path = defaultPath + val path = defaultPath + File.separator + "autoBackup" backupBookshelf(path) backupBookSource(path) backupRssSource(path) backupReplaceRule(path) - WebDavHelp.backUpWebDav() + WebDavHelp.backUpWebDav(path) } } diff --git a/app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt b/app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt index d99141606..8c624a7e8 100644 --- a/app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt +++ b/app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt @@ -78,13 +78,13 @@ object WebDavHelp { } } - fun backUpWebDav() { + fun backUpWebDav(path: String) { if (initWebDav()) { val paths = arrayListOf() - paths.add(Backup.defaultPath + File.separator + "bookshelf.json") - paths.add(Backup.defaultPath + File.separator + "bookSource.json") - paths.add(Backup.defaultPath + File.separator + "rssSource.json") - paths.add(Backup.defaultPath + File.separator + "replaceRule.json") + paths.add(path + File.separator + "bookshelf.json") + paths.add(path + File.separator + "bookSource.json") + paths.add(path + File.separator + "rssSource.json") + paths.add(path + File.separator + "replaceRule.json") FileHelp.deleteFile(zipFilePath) if (ZipUtils.zipFiles(paths, zipFilePath)) { WebDav(getWebDavUrl() + "legado").makeAsDir() From a4d668cda022754ec63b79eeb358bdba4819d539 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 19 Sep 2019 17:17:00 +0800 Subject: [PATCH 1549/1997] up --- app/src/main/res/xml/shortcuts.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/res/xml/shortcuts.xml b/app/src/main/res/xml/shortcuts.xml index 4e95fc73d..7d389f78e 100644 --- a/app/src/main/res/xml/shortcuts.xml +++ b/app/src/main/res/xml/shortcuts.xml @@ -10,6 +10,10 @@ android:shortcutDisabledMessage="@string/last_read" tools:ignore="UnusedAttribute"> + Date: Thu, 19 Sep 2019 17:20:38 +0800 Subject: [PATCH 1550/1997] up --- .../java/io/legado/app/ui/book/read/ReadBookActivity.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt index cbf685604..332c846f7 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt @@ -22,6 +22,7 @@ import io.legado.app.data.entities.BookChapter import io.legado.app.help.IntentDataHelp import io.legado.app.help.ReadAloud import io.legado.app.help.ReadBookConfig +import io.legado.app.help.storage.Backup import io.legado.app.lib.dialogs.alert import io.legado.app.lib.dialogs.noButton import io.legado.app.lib.dialogs.okButton @@ -521,6 +522,11 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } ?: super.finish() } + override fun onDestroy() { + super.onDestroy() + Backup.autoBackup() + } + override fun observeLiveBus() { super.observeLiveBus() observeEvent(Bus.ALOUD_STATE) { From fa74b902755400fa216f6c01318e044aa3960df0 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 19 Sep 2019 17:28:45 +0800 Subject: [PATCH 1551/1997] up --- .../main/java/io/legado/app/ui/book/read/ReadBookActivity.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt index 332c846f7..bfcebfff5 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt @@ -13,6 +13,7 @@ import android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHO import androidx.core.view.isVisible import androidx.lifecycle.Observer import com.jaredrummler.android.colorpicker.ColorPickerDialogListener +import io.legado.app.BuildConfig import io.legado.app.R import io.legado.app.base.VMBaseActivity import io.legado.app.constant.Bus @@ -524,7 +525,9 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea override fun onDestroy() { super.onDestroy() - Backup.autoBackup() + if (!BuildConfig.DEBUG) { + Backup.autoBackup() + } } override fun observeLiveBus() { From 838e784bcf323c90b334f6e282878514f2cb0976 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 19 Sep 2019 23:07:18 +0800 Subject: [PATCH 1552/1997] up --- .../java/io/legado/app/ui/main/my/MyFragment.kt | 2 +- .../io/legado/app/ui/main/rss/RssFragment.kt | 17 +++++++++++++++++ .../res/menu/{my_config.xml => main_my.xml} | 0 app/src/main/res/menu/main_rss.xml | 11 +++++++++++ 4 files changed, 29 insertions(+), 1 deletion(-) rename app/src/main/res/menu/{my_config.xml => main_my.xml} (100%) create mode 100644 app/src/main/res/menu/main_rss.xml diff --git a/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt b/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt index ff96e01cc..36f2db63b 100644 --- a/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt @@ -36,7 +36,7 @@ class MyFragment : BaseFragment(R.layout.fragment_my_config) { } override fun onCompatCreateOptionsMenu(menu: Menu) { - menuInflater.inflate(R.menu.my_config, menu) + menuInflater.inflate(R.menu.main_my, menu) } override fun onCompatOptionsItemSelected(item: MenuItem) { diff --git a/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt b/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt index 70df16148..2126b3929 100644 --- a/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt @@ -1,6 +1,8 @@ package io.legado.app.ui.main.rss import android.os.Bundle +import android.view.Menu +import android.view.MenuItem import android.view.View import androidx.lifecycle.Observer import androidx.recyclerview.widget.GridLayoutManager @@ -8,7 +10,10 @@ import io.legado.app.App import io.legado.app.R import io.legado.app.base.BaseFragment import io.legado.app.lib.theme.ATH +import io.legado.app.ui.rss.source.RssSourceActivity +import io.legado.app.utils.startActivity import kotlinx.android.synthetic.main.fragment_rss.* +import kotlinx.android.synthetic.main.view_title_bar.* class RssFragment : BaseFragment(R.layout.fragment_rss), RssAdapter.CallBack { @@ -16,10 +21,22 @@ class RssFragment : BaseFragment(R.layout.fragment_rss), private lateinit var adapter: RssAdapter override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + setSupportToolbar(toolbar) initRecyclerView() initData() } + override fun onCompatCreateOptionsMenu(menu: Menu) { + menuInflater.inflate(R.menu.main_rss, menu) + } + + override fun onCompatOptionsItemSelected(item: MenuItem) { + super.onCompatOptionsItemSelected(item) + when (item.itemId) { + R.id.menu_rss_config -> startActivity() + } + } + private fun initRecyclerView() { ATH.applyEdgeEffectColor(recycler_view) adapter = RssAdapter(requireContext(), this) diff --git a/app/src/main/res/menu/my_config.xml b/app/src/main/res/menu/main_my.xml similarity index 100% rename from app/src/main/res/menu/my_config.xml rename to app/src/main/res/menu/main_my.xml diff --git a/app/src/main/res/menu/main_rss.xml b/app/src/main/res/menu/main_rss.xml new file mode 100644 index 000000000..9c051a1d2 --- /dev/null +++ b/app/src/main/res/menu/main_rss.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file From 0d1b8087eb2b44acd1ef308500e4c006ec20108f Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 19 Sep 2019 23:10:33 +0800 Subject: [PATCH 1553/1997] up --- .../io/legado/app/ui/rss/source/RssSourceActivity.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/source/RssSourceActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/RssSourceActivity.kt index 0b4240f60..1c38b1c25 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/RssSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/RssSourceActivity.kt @@ -23,7 +23,7 @@ class RssSourceActivity : VMBaseActivity(R.layout.activity_r private lateinit var adapter: RssSourceAdapter override fun onActivityCreated(savedInstanceState: Bundle?) { - + initRecyclerView() } private fun initRecyclerView() { @@ -44,23 +44,23 @@ class RssSourceActivity : VMBaseActivity(R.layout.activity_r } override fun del(source: RssSource) { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } override fun edit(source: RssSource) { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } override fun update(vararg source: RssSource) { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } override fun toTop(source: RssSource) { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } override fun upOrder() { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } } \ No newline at end of file From c73c39d7c1a5bc75428824f7e49775b6f712261f Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 20 Sep 2019 09:43:38 +0800 Subject: [PATCH 1554/1997] up --- app/src/main/AndroidManifest.xml | 3 ++- .../io/legado/app/ui/main/rss/RssFragment.kt | 2 +- .../rss/source/edit/RssSourceEditActivity.kt | 19 +++++++++++++++++++ .../rss/source/edit/RssSourceEditViewModel.kt | 9 +++++++++ .../source/{ => manage}/RssSourceActivity.kt | 2 +- .../source/{ => manage}/RssSourceAdapter.kt | 2 +- .../source/{ => manage}/RssSourceViewModel.kt | 2 +- .../res/layout/activity_rss_source_edit.xml | 17 +++++++++++++++++ app/src/main/res/values/strings.xml | 1 + 9 files changed, 52 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt create mode 100644 app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt rename app/src/main/java/io/legado/app/ui/rss/source/{ => manage}/RssSourceActivity.kt (97%) rename app/src/main/java/io/legado/app/ui/rss/source/{ => manage}/RssSourceAdapter.kt (97%) rename app/src/main/java/io/legado/app/ui/rss/source/{ => manage}/RssSourceViewModel.kt (78%) create mode 100644 app/src/main/res/layout/activity_rss_source_edit.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 9bb422ffa..a53e2130d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -65,7 +65,8 @@ - + + diff --git a/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt b/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt index 2126b3929..79c82bf1d 100644 --- a/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt @@ -10,7 +10,7 @@ import io.legado.app.App import io.legado.app.R import io.legado.app.base.BaseFragment import io.legado.app.lib.theme.ATH -import io.legado.app.ui.rss.source.RssSourceActivity +import io.legado.app.ui.rss.source.manage.RssSourceActivity import io.legado.app.utils.startActivity import kotlinx.android.synthetic.main.fragment_rss.* import kotlinx.android.synthetic.main.view_title_bar.* diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt new file mode 100644 index 000000000..b94dc1279 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt @@ -0,0 +1,19 @@ +package io.legado.app.ui.rss.source.edit + +import android.os.Bundle +import io.legado.app.R +import io.legado.app.base.VMBaseActivity +import io.legado.app.utils.getViewModel + +class RssSourceEditActivity : + VMBaseActivity(R.layout.activity_rss_source_edit) { + + override val viewModel: RssSourceEditViewModel + get() = getViewModel(RssSourceEditViewModel::class.java) + + override fun onActivityCreated(savedInstanceState: Bundle?) { + + } + + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt new file mode 100644 index 000000000..fdb353c69 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt @@ -0,0 +1,9 @@ +package io.legado.app.ui.rss.source.edit + +import android.app.Application +import io.legado.app.base.BaseViewModel + +class RssSourceEditViewModel(application: Application) : BaseViewModel(application) { + + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/rss/source/RssSourceActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt similarity index 97% rename from app/src/main/java/io/legado/app/ui/rss/source/RssSourceActivity.kt rename to app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt index 1c38b1c25..4d56fb6d7 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/RssSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.rss.source +package io.legado.app.ui.rss.source.manage import android.os.Bundle import androidx.core.content.ContextCompat diff --git a/app/src/main/java/io/legado/app/ui/rss/source/RssSourceAdapter.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceAdapter.kt similarity index 97% rename from app/src/main/java/io/legado/app/ui/rss/source/RssSourceAdapter.kt rename to app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceAdapter.kt index a6ef803c4..85aebdb18 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/RssSourceAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceAdapter.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.rss.source +package io.legado.app.ui.rss.source.manage import android.content.Context import io.legado.app.R diff --git a/app/src/main/java/io/legado/app/ui/rss/source/RssSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt similarity index 78% rename from app/src/main/java/io/legado/app/ui/rss/source/RssSourceViewModel.kt rename to app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt index ec006964e..c91f73ef7 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/RssSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.rss.source +package io.legado.app.ui.rss.source.manage import android.app.Application import io.legado.app.base.BaseViewModel diff --git a/app/src/main/res/layout/activity_rss_source_edit.xml b/app/src/main/res/layout/activity_rss_source_edit.xml new file mode 100644 index 000000000..437330f50 --- /dev/null +++ b/app/src/main/res/layout/activity_rss_source_edit.xml @@ -0,0 +1,17 @@ + + + + + + + \ 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 a143f2e50..16adb03bd 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -505,6 +505,7 @@ 输入你的服务器地址 输入你的WebDav账号 订阅源 + 编辑订阅源 筛选 筛选发现 From bab5d1382cc39514edb1617d74468d226ec63dea Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 20 Sep 2019 09:48:35 +0800 Subject: [PATCH 1555/1997] up --- app/src/main/AndroidManifest.xml | 8 ++++++-- .../app/ui/rss/source/edit/RssSourceEditActivity.kt | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a53e2130d..10b20cba9 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -45,12 +45,17 @@ - + + @@ -66,7 +71,6 @@ - diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt index b94dc1279..599e1d9f7 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt @@ -6,7 +6,7 @@ import io.legado.app.base.VMBaseActivity import io.legado.app.utils.getViewModel class RssSourceEditActivity : - VMBaseActivity(R.layout.activity_rss_source_edit) { + VMBaseActivity(R.layout.activity_rss_source_edit, false) { override val viewModel: RssSourceEditViewModel get() = getViewModel(RssSourceEditViewModel::class.java) From 288cf8603f0bc6a02b1315321ef5ab2dae60d83a Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 20 Sep 2019 10:22:50 +0800 Subject: [PATCH 1556/1997] up --- .../rss/source/edit/RssSourceEditActivity.kt | 2 +- .../ui/rss/source/manage/RssSourceActivity.kt | 21 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt index 599e1d9f7..e58ba568c 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt @@ -11,9 +11,9 @@ class RssSourceEditActivity : override val viewModel: RssSourceEditViewModel get() = getViewModel(RssSourceEditViewModel::class.java) + override fun onActivityCreated(savedInstanceState: Bundle?) { } - } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt index 4d56fb6d7..3b729e01e 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt @@ -1,6 +1,7 @@ package io.legado.app.ui.rss.source.manage import android.os.Bundle +import androidx.appcompat.widget.SearchView import androidx.core.content.ContextCompat import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.ItemTouchHelper @@ -10,8 +11,10 @@ import io.legado.app.base.VMBaseActivity import io.legado.app.data.entities.RssSource import io.legado.app.help.ItemTouchCallback import io.legado.app.lib.theme.ATH +import io.legado.app.lib.theme.primaryTextColor import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_rss_source.* +import kotlinx.android.synthetic.main.view_search.* class RssSourceActivity : VMBaseActivity(R.layout.activity_rss_source), @@ -24,6 +27,7 @@ class RssSourceActivity : VMBaseActivity(R.layout.activity_r override fun onActivityCreated(savedInstanceState: Bundle?) { initRecyclerView() + initSearchView() } private fun initRecyclerView() { @@ -43,6 +47,23 @@ class RssSourceActivity : VMBaseActivity(R.layout.activity_r ItemTouchHelper(itemTouchCallback).attachToRecyclerView(recycler_view) } + private fun initSearchView() { + ATH.setTint(search_view, primaryTextColor) + search_view.onActionViewExpanded() + search_view.queryHint = getString(R.string.search_book_source) + search_view.clearFocus() + search_view.setOnQueryTextListener(object : SearchView.OnQueryTextListener { + override fun onQueryTextSubmit(query: String?): Boolean { + return false + } + + override fun onQueryTextChange(newText: String?): Boolean { + return false + } + + }) + } + override fun del(source: RssSource) { } From a33042eda9facc705b959e9802d70e8d5a07ec81 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 20 Sep 2019 10:26:15 +0800 Subject: [PATCH 1557/1997] up --- .../ui/rss/source/manage/RssSourceActivity.kt | 16 ++++++++++++++++ app/src/main/res/menu/rss_source.xml | 4 ++++ 2 files changed, 20 insertions(+) create mode 100644 app/src/main/res/menu/rss_source.xml diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt index 3b729e01e..e70d8d4e9 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt @@ -1,6 +1,8 @@ package io.legado.app.ui.rss.source.manage import android.os.Bundle +import android.view.Menu +import android.view.MenuItem import androidx.appcompat.widget.SearchView import androidx.core.content.ContextCompat import androidx.recyclerview.widget.DividerItemDecoration @@ -15,6 +17,7 @@ import io.legado.app.lib.theme.primaryTextColor import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_rss_source.* import kotlinx.android.synthetic.main.view_search.* +import kotlinx.android.synthetic.main.view_title_bar.* class RssSourceActivity : VMBaseActivity(R.layout.activity_rss_source), @@ -26,10 +29,23 @@ class RssSourceActivity : VMBaseActivity(R.layout.activity_r private lateinit var adapter: RssSourceAdapter override fun onActivityCreated(savedInstanceState: Bundle?) { + setSupportActionBar(toolbar) initRecyclerView() initSearchView() } + override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { + menuInflater.inflate(R.menu.rss_source, menu) + return super.onCompatCreateOptionsMenu(menu) + } + + override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + + } + return super.onCompatOptionsItemSelected(item) + } + private fun initRecyclerView() { ATH.applyEdgeEffectColor(recycler_view) recycler_view.layoutManager = LinearLayoutManager(this) diff --git a/app/src/main/res/menu/rss_source.xml b/app/src/main/res/menu/rss_source.xml new file mode 100644 index 000000000..e73b6af79 --- /dev/null +++ b/app/src/main/res/menu/rss_source.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file From a4f7413ba3e4c6c95981d5efaa08874678bafe8b Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 20 Sep 2019 11:12:37 +0800 Subject: [PATCH 1558/1997] up --- .../ui/rss/source/manage/RssSourceActivity.kt | 4 +- app/src/main/res/menu/rss_source.xml | 129 +++++++++++++++++- app/src/main/res/values/strings.xml | 1 + 3 files changed, 131 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt index e70d8d4e9..ba709bcc3 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt @@ -14,10 +14,12 @@ import io.legado.app.data.entities.RssSource import io.legado.app.help.ItemTouchCallback import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.primaryTextColor +import io.legado.app.ui.rss.source.edit.RssSourceEditActivity import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_rss_source.* import kotlinx.android.synthetic.main.view_search.* import kotlinx.android.synthetic.main.view_title_bar.* +import org.jetbrains.anko.startActivity class RssSourceActivity : VMBaseActivity(R.layout.activity_rss_source), @@ -41,7 +43,7 @@ class RssSourceActivity : VMBaseActivity(R.layout.activity_r override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { - + R.id.menu_add_book_source -> startActivity() } return super.onCompatOptionsItemSelected(item) } diff --git a/app/src/main/res/menu/rss_source.xml b/app/src/main/res/menu/rss_source.xml index e73b6af79..45ef06792 100644 --- a/app/src/main/res/menu/rss_source.xml +++ b/app/src/main/res/menu/rss_source.xml @@ -1,4 +1,129 @@ - + - \ 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 16adb03bd..aa63506be 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -146,6 +146,7 @@ 编辑书源 禁用书源 新建书源 + 新建订阅源 添加书籍 扫描 拷贝书源 From 27860a0f982a87168a978409e7157ac14b18d60b Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 20 Sep 2019 12:26:33 +0800 Subject: [PATCH 1559/1997] up --- .../java/io/legado/app/constant/AppConst.kt | 37 ++- .../ui/book/source/edit/SourceEditActivity.kt | 3 +- .../source/debug/RssSourceDebugActivity.kt | 2 + .../legado/app/ui/widget/KeyboardToolPop.kt | 41 +-- .../main/res/layout/popup_keyboard_tool.xml | 238 +----------------- app/src/main/res/values/strings.xml | 2 - 6 files changed, 62 insertions(+), 261 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/rss/source/debug/RssSourceDebugActivity.kt diff --git a/app/src/main/java/io/legado/app/constant/AppConst.kt b/app/src/main/java/io/legado/app/constant/AppConst.kt index 158e1e4b4..6cda954e8 100644 --- a/app/src/main/java/io/legado/app/constant/AppConst.kt +++ b/app/src/main/java/io/legado/app/constant/AppConst.kt @@ -1,8 +1,6 @@ package io.legado.app.constant import android.annotation.SuppressLint -import com.google.gson.Gson -import com.google.gson.GsonBuilder import io.legado.app.App import io.legado.app.R import java.text.SimpleDateFormat @@ -29,11 +27,32 @@ object AppConst { SimpleDateFormat("HH:mm") } - val GSON_CONVERTER: Gson by lazy { - GsonBuilder() - .disableHtmlEscaping() - .setPrettyPrinting() - .setDateFormat("yyyy-MM-dd HH:mm:ssZ") - .create() - } + val keyboardToolChars = arrayListOf( + "@", + "&", + "|", + "%", + "/", + ":", + "[", + "]", + "{", + "}", + "<", + ">", + "\\", + "$", + "#", + "!", + ".", + "href", + "src", + "textNodes", + "xpath", + "json", + "css", + "id", + "class", + "tag" + ) } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditActivity.kt index b49db48bc..8a2db83d6 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditActivity.kt @@ -17,6 +17,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import com.google.android.material.tabs.TabLayout import io.legado.app.R import io.legado.app.base.VMBaseActivity +import io.legado.app.constant.AppConst import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.rule.* import io.legado.app.lib.theme.ATH @@ -107,7 +108,7 @@ class SourceEditActivity : private fun initView() { ATH.applyEdgeEffectColor(recycler_view) - mSoftKeyboardTool = KeyboardToolPop(this, this) + mSoftKeyboardTool = KeyboardToolPop(this, AppConst.keyboardToolChars, this) window.decorView.viewTreeObserver.addOnGlobalLayoutListener(KeyboardOnGlobalChangeListener()) recycler_view.layoutManager = LinearLayoutManager(this) recycler_view.adapter = adapter diff --git a/app/src/main/java/io/legado/app/ui/rss/source/debug/RssSourceDebugActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/debug/RssSourceDebugActivity.kt new file mode 100644 index 000000000..de8bf27dc --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/rss/source/debug/RssSourceDebugActivity.kt @@ -0,0 +1,2 @@ +package io.legado.app.ui.rss.source.debug + diff --git a/app/src/main/java/io/legado/app/ui/widget/KeyboardToolPop.kt b/app/src/main/java/io/legado/app/ui/widget/KeyboardToolPop.kt index 076fac6b9..e31afbc0f 100644 --- a/app/src/main/java/io/legado/app/ui/widget/KeyboardToolPop.kt +++ b/app/src/main/java/io/legado/app/ui/widget/KeyboardToolPop.kt @@ -4,34 +4,47 @@ import android.annotation.SuppressLint import android.content.Context import android.view.LayoutInflater import android.view.ViewGroup -import android.widget.LinearLayout import android.widget.PopupWindow -import android.widget.TextView +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView import io.legado.app.R +import io.legado.app.base.adapter.ItemViewHolder +import io.legado.app.base.adapter.SimpleRecyclerAdapter +import kotlinx.android.synthetic.main.item_text.view.* +import kotlinx.android.synthetic.main.popup_keyboard_tool.view.* +import org.jetbrains.anko.sdk27.listeners.onClick -class KeyboardToolPop(context: Context, onClickListener: OnClickListener?) : - PopupWindow(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) { +class KeyboardToolPop( + context: Context, + private val chars: List, + val onClickListener: OnClickListener? +) : PopupWindow(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) { init { @SuppressLint("InflateParams") - val view = LayoutInflater.from(context).inflate(R.layout.popup_keyboard_tool, null) - this.contentView = view + this.contentView = LayoutInflater.from(context).inflate(R.layout.popup_keyboard_tool, null) isTouchable = true isOutsideTouchable = false isFocusable = false inputMethodMode = INPUT_METHOD_NEEDED //解决遮盖输入法 + initRecyclerView() + } + + private fun initRecyclerView() = with(contentView) { + val adapter = Adapter(context) + recycler_view.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false) + recycler_view.adapter = adapter + adapter.setItems(chars) + } - val linearLayout = contentView.findViewById(R.id.ll_content) + inner class Adapter(context: Context) : + SimpleRecyclerAdapter(context, R.layout.item_text) { - for (i in 0 until linearLayout.childCount) { - val tv = linearLayout.getChildAt(i) as TextView - tv.setOnClickListener { v -> - (v as? TextView)?.text.toString().let { - onClickListener?.click(it) - } - } + override fun convert(holder: ItemViewHolder, item: String, payloads: MutableList) { + holder.itemView.text_view.text = item + holder.itemView.onClick { onClickListener?.click(item) } } } diff --git a/app/src/main/res/layout/popup_keyboard_tool.xml b/app/src/main/res/layout/popup_keyboard_tool.xml index 9a00a80c4..649534d76 100644 --- a/app/src/main/res/layout/popup_keyboard_tool.xml +++ b/app/src/main/res/layout/popup_keyboard_tool.xml @@ -1,240 +1,8 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + android:padding="5dp" /> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index aa63506be..e7c886555 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -392,8 +392,6 @@ 调试书源 二维码导入 扫描二维码 - \@ - 选中时点击可弹出菜单 主题 默认主题 From 950395ca74a33383672a2f1034d318c9211ff8a5 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 20 Sep 2019 12:39:33 +0800 Subject: [PATCH 1560/1997] up --- .../main/java/io/legado/app/ui/widget/KeyboardToolPop.kt | 6 ++++-- app/src/main/res/layout/item_text.xml | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/KeyboardToolPop.kt b/app/src/main/java/io/legado/app/ui/widget/KeyboardToolPop.kt index e31afbc0f..57f40c039 100644 --- a/app/src/main/java/io/legado/app/ui/widget/KeyboardToolPop.kt +++ b/app/src/main/java/io/legado/app/ui/widget/KeyboardToolPop.kt @@ -43,8 +43,10 @@ class KeyboardToolPop( SimpleRecyclerAdapter(context, R.layout.item_text) { override fun convert(holder: ItemViewHolder, item: String, payloads: MutableList) { - holder.itemView.text_view.text = item - holder.itemView.onClick { onClickListener?.click(item) } + with(holder.itemView) { + text_view.text = item + onClick { onClickListener?.click(item) } + } } } diff --git a/app/src/main/res/layout/item_text.xml b/app/src/main/res/layout/item_text.xml index 107eebf35..87687a713 100644 --- a/app/src/main/res/layout/item_text.xml +++ b/app/src/main/res/layout/item_text.xml @@ -1,10 +1,11 @@ + android:textSize="14sp" + tools:ignore="UnusedAttribute" /> From 025581bd87504f71d59f7adc07897d0bd1f74c45 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 20 Sep 2019 13:40:14 +0800 Subject: [PATCH 1561/1997] up --- .../java/io/legado/app/constant/AppConst.kt | 50 ++++++------------- 1 file changed, 16 insertions(+), 34 deletions(-) diff --git a/app/src/main/java/io/legado/app/constant/AppConst.kt b/app/src/main/java/io/legado/app/constant/AppConst.kt index 6cda954e8..58c51fb25 100644 --- a/app/src/main/java/io/legado/app/constant/AppConst.kt +++ b/app/src/main/java/io/legado/app/constant/AppConst.kt @@ -9,50 +9,32 @@ import javax.script.ScriptEngineManager @SuppressLint("SimpleDateFormat") object AppConst { + + const val APP_TAG = "Legado" + const val channelIdDownload = "channel_download" const val channelIdReadAloud = "channel_read_aloud" const val channelIdWeb = "channel_web" - const val APP_TAG = "Legado" - const val RC_IMPORT_YUEDU_DATA = 100 + val NOT_AVAILABLE = App.INSTANCE.getString(R.string.not_available) - const val userAgent = + val userAgent: String by lazy { "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36" + } - val SCRIPT_ENGINE: ScriptEngine = ScriptEngineManager().getEngineByName("rhino") - - val NOT_AVAILABLE = App.INSTANCE.getString(R.string.not_available) + val SCRIPT_ENGINE: ScriptEngine by lazy { + ScriptEngineManager().getEngineByName("rhino") + } val TIME_FORMAT: SimpleDateFormat by lazy { SimpleDateFormat("HH:mm") } - val keyboardToolChars = arrayListOf( - "@", - "&", - "|", - "%", - "/", - ":", - "[", - "]", - "{", - "}", - "<", - ">", - "\\", - "$", - "#", - "!", - ".", - "href", - "src", - "textNodes", - "xpath", - "json", - "css", - "id", - "class", - "tag" - ) + val keyboardToolChars: List by lazy { + arrayListOf( + "@", "&", "|", "%", "/", ":", "[", "]", "{", "}", "<", ">", + "\\", "$", "#", "!", ".", "href", "src", "textNodes", "xpath", + "json", "css", "id", "class", "tag" + ) + } } \ No newline at end of file From 9a5679ea2819ffcbb515f2e61b4bfa8db22b58e3 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 20 Sep 2019 14:37:55 +0800 Subject: [PATCH 1562/1997] up --- .../widget/page/delegate/CoverPageDelegate.kt | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/CoverPageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/CoverPageDelegate.kt index ccab1295f..011e7c53f 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/CoverPageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/CoverPageDelegate.kt @@ -8,7 +8,6 @@ import io.legado.app.ui.widget.page.PageView class CoverPageDelegate(pageView: PageView) : PageDelegate(pageView) { private val shadowDrawableR: GradientDrawable - private val shadowDrawableL: GradientDrawable private val bitmapMatrix = Matrix() init { @@ -17,11 +16,6 @@ class CoverPageDelegate(pageView: PageView) : PageDelegate(pageView) { GradientDrawable.Orientation.LEFT_RIGHT, shadowColors ) shadowDrawableR.gradientType = GradientDrawable.LINEAR_GRADIENT - - shadowDrawableL = GradientDrawable( - GradientDrawable.Orientation.RIGHT_LEFT, shadowColors - ) - shadowDrawableL.gradientType = GradientDrawable.LINEAR_GRADIENT } override fun onScrollStart() { @@ -47,6 +41,8 @@ class CoverPageDelegate(pageView: PageView) : PageDelegate(pageView) { } override fun onScrollStop() { + curPage?.x = 0.toFloat() + if (!isCancel) { pageView.fillPage(direction) } @@ -61,9 +57,12 @@ class CoverPageDelegate(pageView: PageView) : PageDelegate(pageView) { val distanceX = if (offsetX > 0) offsetX - viewWidth else offsetX + viewWidth bitmap?.let { - bitmapMatrix.setTranslate(distanceX, 0.toFloat()) - canvas.drawBitmap(it, bitmapMatrix, null) - + if (distanceX < 0) { + bitmapMatrix.setTranslate(distanceX, 0.toFloat()) + canvas.drawBitmap(it, bitmapMatrix, null) + } else { + curPage?.translationX = offsetX + } addShadow(distanceX.toInt(), canvas) } } @@ -73,8 +72,8 @@ class CoverPageDelegate(pageView: PageView) : PageDelegate(pageView) { shadowDrawableR.setBounds(left + viewWidth, 0, left + viewWidth + 30, viewHeight) shadowDrawableR.draw(canvas) } else { - shadowDrawableL.setBounds(left - 30, 0, left, viewHeight) - shadowDrawableL.draw(canvas) + shadowDrawableR.setBounds(left, 0, left + 30, viewHeight) + shadowDrawableR.draw(canvas) } } } From 02cf8d022b68896d77b3759498d820b0068a93c5 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 20 Sep 2019 15:14:53 +0800 Subject: [PATCH 1563/1997] up --- .../ui/widget/page/delegate/CoverPageDelegate.kt | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/CoverPageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/CoverPageDelegate.kt index 011e7c53f..af4f368aa 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/CoverPageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/CoverPageDelegate.kt @@ -57,11 +57,15 @@ class CoverPageDelegate(pageView: PageView) : PageDelegate(pageView) { val distanceX = if (offsetX > 0) offsetX - viewWidth else offsetX + viewWidth bitmap?.let { - if (distanceX < 0) { - bitmapMatrix.setTranslate(distanceX, 0.toFloat()) - canvas.drawBitmap(it, bitmapMatrix, null) - } else { - curPage?.translationX = offsetX + when (direction) { + Direction.PREV -> { + bitmapMatrix.setTranslate(distanceX, 0.toFloat()) + canvas.drawBitmap(it, bitmapMatrix, null) + } + Direction.NEXT -> { + curPage?.translationX = offsetX + } + Direction.NONE -> Unit } addShadow(distanceX.toInt(), canvas) } @@ -71,7 +75,7 @@ class CoverPageDelegate(pageView: PageView) : PageDelegate(pageView) { if (left < 0) { shadowDrawableR.setBounds(left + viewWidth, 0, left + viewWidth + 30, viewHeight) shadowDrawableR.draw(canvas) - } else { + } else if (left > 0) { shadowDrawableR.setBounds(left, 0, left + 30, viewHeight) shadowDrawableR.draw(canvas) } From 4be90289db7f99054ae2f66b98cc85cd2df31f95 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 20 Sep 2019 16:07:27 +0800 Subject: [PATCH 1564/1997] up --- app/src/main/res/layout/dialog_read_book_style.xml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/layout/dialog_read_book_style.xml b/app/src/main/res/layout/dialog_read_book_style.xml index 6cec496aa..f8c997797 100644 --- a/app/src/main/res/layout/dialog_read_book_style.xml +++ b/app/src/main/res/layout/dialog_read_book_style.xml @@ -262,7 +262,19 @@ android:text="@string/page_anim_slide" /> + + Date: Fri, 20 Sep 2019 16:25:56 +0800 Subject: [PATCH 1565/1997] up --- .../io/legado/app/ui/rss/source/manage/RssSourceActivity.kt | 2 +- app/src/main/res/values/strings.xml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt index ba709bcc3..a19dd28b4 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt @@ -68,7 +68,7 @@ class RssSourceActivity : VMBaseActivity(R.layout.activity_r private fun initSearchView() { ATH.setTint(search_view, primaryTextColor) search_view.onActionViewExpanded() - search_view.queryHint = getString(R.string.search_book_source) + search_view.queryHint = getString(R.string.search_rss_source) search_view.clearFocus() search_view.setOnQueryTextListener(object : SearchView.OnQueryTextListener { override fun onQueryTextSubmit(query: String?): Boolean { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e7c886555..72667cbab 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -242,6 +242,7 @@ 整理书架 这将会删除所有书籍,请谨慎操作。 搜索书源 + 搜索订阅源 搜索(共%d个书源) 目录(%d) 加粗 From acc1fef1580aa639624379cda95e8ddfdcee7ceb Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 20 Sep 2019 16:26:52 +0800 Subject: [PATCH 1566/1997] up --- .../java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt index a19dd28b4..047a342d4 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt @@ -78,7 +78,6 @@ class RssSourceActivity : VMBaseActivity(R.layout.activity_r override fun onQueryTextChange(newText: String?): Boolean { return false } - }) } From e38e8168d9fac0e225f89ab35ca4c5b20bf1ad26 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 20 Sep 2019 16:34:04 +0800 Subject: [PATCH 1567/1997] up --- .../io/legado/app/ui/widget/page/PageView.kt | 10 ++++----- .../page/delegate/ScrollPageDelegate.kt | 21 +++++++++++++++++++ 2 files changed, 25 insertions(+), 6 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/widget/page/delegate/ScrollPageDelegate.kt diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index e64df6781..689eae713 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -7,10 +7,7 @@ import android.util.AttributeSet import android.view.MotionEvent import android.widget.FrameLayout import io.legado.app.help.ReadBookConfig -import io.legado.app.ui.widget.page.delegate.CoverPageDelegate -import io.legado.app.ui.widget.page.delegate.NoAnimPageDelegate -import io.legado.app.ui.widget.page.delegate.PageDelegate -import io.legado.app.ui.widget.page.delegate.SlidePageDelegate +import io.legado.app.ui.widget.page.delegate.* import io.legado.app.utils.activity import io.legado.app.utils.getPrefInt @@ -140,9 +137,10 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att fun upPageAnim() { pageDelegate = when (context.getPrefInt("pageAnim")) { + 0 -> CoverPageDelegate(this) 1 -> SlidePageDelegate(this) - 2 -> NoAnimPageDelegate(this) - else -> CoverPageDelegate(this) + 2 -> ScrollPageDelegate(this) + else -> NoAnimPageDelegate(this) } } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/ScrollPageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/ScrollPageDelegate.kt new file mode 100644 index 000000000..2da678320 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/ScrollPageDelegate.kt @@ -0,0 +1,21 @@ +package io.legado.app.ui.widget.page.delegate + +import android.graphics.Canvas +import io.legado.app.ui.widget.page.PageView + +class ScrollPageDelegate(pageView: PageView) : PageDelegate(pageView) { + + override fun onScrollStart() { + + } + + override fun onDraw(canvas: Canvas) { + + } + + override fun onScrollStop() { + + } + + +} \ No newline at end of file From 6014c2f4e13cedd5f3e555c6bb84f073567bd1ab Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 20 Sep 2019 16:41:14 +0800 Subject: [PATCH 1568/1997] up --- app/src/main/java/io/legado/app/ui/widget/page/PageView.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 689eae713..82e3c46bd 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -207,6 +207,7 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att fun chapterSize(): Int fun durChapterIndex(): Int fun durChapterPos(): Int + /** * chapterOnDur: 0为当前页,1为下一页,-1为上一页 */ From e790f6eb5b76876d18af4b9a1afc1492a1b7de87 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 20 Sep 2019 16:52:08 +0800 Subject: [PATCH 1569/1997] up --- .../java/io/legado/app/model/analyzeRule/AnalyzeByJSonPath.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSonPath.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSonPath.kt index e6eee96ed..84b5045e7 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSonPath.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByJSonPath.kt @@ -177,6 +177,7 @@ class AnalyzeByJSonPath { try { return it.read>(rules[0]) } catch (e: Exception) { + e.printStackTrace() } } return null From d0bc02e9a423fa5e4b5ff34ac0ed631deeb60763 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 20 Sep 2019 17:24:20 +0800 Subject: [PATCH 1570/1997] up --- .../legado/app/ui/widget/page/ChapterProvider.kt | 8 ++++++-- .../io/legado/app/ui/widget/page/DataSource.kt | 6 +----- .../io/legado/app/ui/widget/page/PageView.kt | 4 ++++ .../app/ui/widget/page/ScrollContentView.kt | 3 --- .../io/legado/app/ui/widget/page/TextChapter.kt | 16 +++++++++++++++- .../legado/app/ui/widget/page/TextPageFactory.kt | 15 +++++++++++++-- 6 files changed, 39 insertions(+), 13 deletions(-) delete mode 100644 app/src/main/java/io/legado/app/ui/widget/page/ScrollContentView.kt diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt index 7579ee9b6..4e33bdd51 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt @@ -60,8 +60,12 @@ object ChapterProvider { item.pageSize = textPages.size } return TextChapter( - bookChapter.index, bookChapter.title, bookChapter.url, - textPages, pageLengths + bookChapter.index, + bookChapter.title, + bookChapter.url, + textPages, + pageLengths, + chapterSize ) } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt b/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt index 8ba58b6ba..92b09194b 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt @@ -1,8 +1,7 @@ package io.legado.app.ui.widget.page -import io.legado.app.data.entities.BookChapter - interface DataSource { + fun isScroll(): Boolean fun pageIndex(): Int @@ -28,7 +27,4 @@ interface DataSource { fun moveToPrevChapter() - interface CallBack { - fun onLoadFinish(bookChapter: BookChapter, content: String) - } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 82e3c46bd..cdc870198 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -36,6 +36,10 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att upPageAnim() setPageFactory(TextPageFactory.create(object : DataSource { + override fun isScroll(): Boolean { + return pageDelegate is ScrollPageDelegate + } + override fun pageIndex(): Int { return callback?.durChapterPos() ?: 0 } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ScrollContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ScrollContentView.kt deleted file mode 100644 index 0e1be1865..000000000 --- a/app/src/main/java/io/legado/app/ui/widget/page/ScrollContentView.kt +++ /dev/null @@ -1,3 +0,0 @@ -package io.legado.app.ui.widget.page - -class ScrollContentView diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt index 801f23ea7..d9eff7009 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt @@ -1,11 +1,14 @@ package io.legado.app.ui.widget.page +import android.text.SpannableStringBuilder + data class TextChapter( val position: Int, val title: String, val url: String, val pages: List, - val pageLengths: List + val pageLengths: List, + val chaptersSize: Int ) { fun page(index: Int): TextPage? { if (index >= 0 && index < pages.size) { @@ -21,6 +24,17 @@ data class TextChapter( return null } + fun scrollPage(): TextPage? { + if (pages.isNotEmpty()) { + val spannableStringBuilder = SpannableStringBuilder() + pages.forEach { + spannableStringBuilder.append(it.text) + } + return TextPage(0, spannableStringBuilder, title, position, chaptersSize) + } + return null + } + fun lastIndex(): Int { return pages.size - 1 } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt index a3cfa8599..b0eee5632 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt @@ -62,11 +62,18 @@ class TextPageFactory private constructor(dataSource: DataSource) : } override fun currentPage(): TextPage? = dataSource.pageIndex().let { index -> - return dataSource.getCurrentChapter()?.page(index) - ?: TextPage(index = index, title = "index:$index") + return if (dataSource.isScroll()) { + dataSource.getCurrentChapter()?.scrollPage() + } else { + dataSource.getCurrentChapter()?.page(index) + } ?: TextPage(index = index, title = "index:$index") } override fun nextPage(): TextPage? = dataSource.pageIndex().let { index -> + if (dataSource.isScroll()) { + return dataSource.getNextChapter()?.scrollPage() + ?: TextPage(index = index + 1, title = "index:${index + 1}") + } dataSource.getCurrentChapter()?.let { if (index < it.pageSize() - 1) { return dataSource.getCurrentChapter()?.page(index + 1)?.removePageAloudSpan() @@ -78,6 +85,10 @@ class TextPageFactory private constructor(dataSource: DataSource) : } override fun previousPage(): TextPage? = dataSource.pageIndex().let { index -> + if (dataSource.isScroll()) { + return dataSource.getPreviousChapter()?.scrollPage() + ?: TextPage(index = index + 1, title = "index:${index + 1}") + } if (index > 0) { return dataSource.getCurrentChapter()?.page(index - 1)?.removePageAloudSpan() ?: TextPage(index = index - 1, title = "index:${index - 1}") From e13c0e715a6e4551140b68122834117fcd847976 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 20 Sep 2019 17:47:37 +0800 Subject: [PATCH 1571/1997] up --- app/src/main/java/io/legado/app/ui/widget/page/PageView.kt | 4 ++++ app/src/main/res/layout/view_book_page.xml | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index cdc870198..b2481ddbe 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -112,6 +112,10 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att pageDelegate?.scroll() } + override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean { + return true + } + @SuppressLint("ClickableViewAccessibility") override fun onTouchEvent(event: MotionEvent): Boolean { return pageDelegate?.onTouch(event) ?: super.onTouchEvent(event) diff --git a/app/src/main/res/layout/view_book_page.xml b/app/src/main/res/layout/view_book_page.xml index 59784756f..eb27614ad 100644 --- a/app/src/main/res/layout/view_book_page.xml +++ b/app/src/main/res/layout/view_book_page.xml @@ -32,7 +32,8 @@ android:id="@+id/content_text_view" android:layout_width="match_parent" android:layout_height="0dp" - android:layout_weight="1" /> + android:layout_weight="1" + android:textIsSelectable="true" /> Date: Fri, 20 Sep 2019 20:13:08 +0800 Subject: [PATCH 1572/1997] up --- app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt | 2 -- app/src/main/java/io/legado/app/ui/widget/page/PageView.kt | 4 ---- 2 files changed, 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt b/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt index 92b09194b..6c43b1dee 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt @@ -7,8 +7,6 @@ interface DataSource { fun setPageIndex(pageIndex: Int) - fun isPrepared(): Boolean - fun getChapterPosition(): Int fun getChapter(position: Int): TextChapter? diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index b2481ddbe..85d7be3d1 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -48,10 +48,6 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att callback?.setPageIndex(pageIndex) } - override fun isPrepared(): Boolean { - return true - } - override fun getChapterPosition(): Int { return callback?.durChapterIndex() ?: 0 } From 7cd7b39ad8eb4b15ddc0aa81a837a1285f69ad6f Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 20 Sep 2019 21:03:50 +0800 Subject: [PATCH 1573/1997] up --- .../main/java/io/legado/app/ui/widget/page/ContentView.kt | 5 +++++ app/src/main/java/io/legado/app/ui/widget/page/PageView.kt | 1 + 2 files changed, 6 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index 121280b9e..bf96fb382 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -5,6 +5,7 @@ import android.content.Context import android.graphics.Typeface import android.graphics.drawable.Drawable import android.util.AttributeSet +import android.view.MotionEvent import android.widget.FrameLayout import android.widget.ImageView import androidx.appcompat.widget.AppCompatImageView @@ -79,6 +80,10 @@ class ContentView : FrameLayout { } } + fun textViewTouch(event: MotionEvent) { + content_text_view.onTouchEvent(event) + } + fun setBg(bg: Drawable?) { //all supported ImageLoader.load(context, bg) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 85d7be3d1..819b57ab3 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -114,6 +114,7 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att @SuppressLint("ClickableViewAccessibility") override fun onTouchEvent(event: MotionEvent): Boolean { + curPage?.textViewTouch(event) return pageDelegate?.onTouch(event) ?: super.onTouchEvent(event) } From 0beef36e01a861409a1a028c1f95609ac27d5f08 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 20 Sep 2019 21:26:36 +0800 Subject: [PATCH 1574/1997] up --- .../main/java/io/legado/app/ui/widget/page/ContentView.kt | 5 ----- app/src/main/java/io/legado/app/ui/widget/page/PageView.kt | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index bf96fb382..121280b9e 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -5,7 +5,6 @@ import android.content.Context import android.graphics.Typeface import android.graphics.drawable.Drawable import android.util.AttributeSet -import android.view.MotionEvent import android.widget.FrameLayout import android.widget.ImageView import androidx.appcompat.widget.AppCompatImageView @@ -80,10 +79,6 @@ class ContentView : FrameLayout { } } - fun textViewTouch(event: MotionEvent) { - content_text_view.onTouchEvent(event) - } - fun setBg(bg: Drawable?) { //all supported ImageLoader.load(context, bg) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 819b57ab3..448d7d2d4 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -114,7 +114,7 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att @SuppressLint("ClickableViewAccessibility") override fun onTouchEvent(event: MotionEvent): Boolean { - curPage?.textViewTouch(event) + curPage?.dispatchTouchEvent(event) return pageDelegate?.onTouch(event) ?: super.onTouchEvent(event) } From 5f9fd9ec9969a4e37f3d9bc01618524d43fc9f2b Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 20 Sep 2019 22:34:37 +0800 Subject: [PATCH 1575/1997] up --- .../legado/app/ui/widget/page/ContentView.kt | 8 ++++++ .../io/legado/app/ui/widget/page/PageView.kt | 1 - .../ui/widget/page/delegate/PageDelegate.kt | 27 ++++++++++++++----- 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index 121280b9e..747f17497 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -100,4 +100,12 @@ class ContentView : FrameLayout { tv_bottom_left.text = page?.title tv_bottom_right.text = "${page?.index?.plus(1)}/${page?.pageSize}" } + + fun isTextSelected(): Boolean { + return content_text_view.selectionEnd - content_text_view.selectionStart != 0 + } + + fun contentTextView(): ContentTextView? { + return content_text_view + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 448d7d2d4..85d7be3d1 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -114,7 +114,6 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att @SuppressLint("ClickableViewAccessibility") override fun onTouchEvent(event: MotionEvent): Boolean { - curPage?.dispatchTouchEvent(event) return pageDelegate?.onTouch(event) ?: super.onTouchEvent(event) } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt index 229bfcb48..ce4d4beab 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt @@ -50,6 +50,7 @@ abstract class PageDelegate(protected val pageView: PageView) { var isCancel = false var isRunning = false var isStarted = false + var isLongPress = false protected fun setStartPoint(x: Float, y: Float, invalidate: Boolean = true) { startX = x @@ -154,14 +155,21 @@ abstract class PageDelegate(protected val pageView: PageView) { fun onTouch(event: MotionEvent): Boolean { if (isStarted) return false - - if (isMoved && event.action == MotionEvent.ACTION_UP) { - // 开启翻页效果 - if (!noNext) { - onScrollStart() - } + if (curPage?.isTextSelected() == true) { + curPage?.dispatchTouchEvent(event) return true } + if (event.action == MotionEvent.ACTION_DOWN) { + curPage?.contentTextView()?.setTextIsSelectable(true) + curPage?.dispatchTouchEvent(event) + } else if (event.action == MotionEvent.ACTION_UP) { + curPage?.dispatchTouchEvent(event) + if (isMoved) { + // 开启翻页效果 + if (!noNext) onScrollStart() + return true + } + } return detector.onTouchEvent(event) } @@ -182,6 +190,7 @@ abstract class PageDelegate(protected val pageView: PageView) { private inner class GestureListener : GestureDetector.SimpleOnGestureListener() { override fun onDown(e: MotionEvent): Boolean { + isLongPress = false // abort() //是否移动 isMoved = false @@ -229,7 +238,13 @@ abstract class PageDelegate(protected val pageView: PageView) { return true } + override fun onLongPress(e: MotionEvent?) { + curPage?.dispatchTouchEvent(e) + isLongPress = true + } + override fun onScroll(e1: MotionEvent, e2: MotionEvent, distanceX: Float, distanceY: Float): Boolean { + curPage?.contentTextView()?.setTextIsSelectable(false) if (!isMoved && abs(distanceX) > abs(distanceY)) { if (distanceX < 0) { //上一页的参数配置 From ce629e0dc348cc3330416f70e9726a3d67005dd7 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 20 Sep 2019 23:31:33 +0800 Subject: [PATCH 1576/1997] up --- .../legado/app/ui/widget/page/DataSource.kt | 2 +- .../io/legado/app/ui/widget/page/PageView.kt | 126 +++++++++--------- .../app/ui/widget/page/TextPageFactory.kt | 6 +- .../ui/widget/page/delegate/PageDelegate.kt | 36 ++++- app/src/main/res/layout/view_book_page.xml | 3 +- 5 files changed, 97 insertions(+), 76 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt b/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt index 6c43b1dee..fabb55a06 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt @@ -1,7 +1,7 @@ package io.legado.app.ui.widget.page interface DataSource { - fun isScroll(): Boolean + fun isScrollDelegate(): Boolean fun pageIndex(): Int diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 85d7be3d1..77cb77bd6 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -11,8 +11,10 @@ import io.legado.app.ui.widget.page.delegate.* import io.legado.app.utils.activity import io.legado.app.utils.getPrefInt -class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, attrs), - PageDelegate.PageInterface { +class PageView(context: Context, attrs: AttributeSet) : + FrameLayout(context, attrs), + PageDelegate.PageInterface, + DataSource { private var callback: CallBack? = null private var pageDelegate: PageDelegate? = null @@ -34,62 +36,8 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att setWillNotDraw(false) upPageAnim() - - setPageFactory(TextPageFactory.create(object : DataSource { - override fun isScroll(): Boolean { - return pageDelegate is ScrollPageDelegate - } - - override fun pageIndex(): Int { - return callback?.durChapterPos() ?: 0 - } - - override fun setPageIndex(pageIndex: Int) { - callback?.setPageIndex(pageIndex) - } - - override fun getChapterPosition(): Int { - return callback?.durChapterIndex() ?: 0 - } - - override fun getChapter(position: Int): TextChapter? { - return callback?.textChapter(position) - } - - override fun getCurrentChapter(): TextChapter? { - return callback?.textChapter(0) - } - - override fun getNextChapter(): TextChapter? { - return callback?.textChapter(1) - } - - override fun getPreviousChapter(): TextChapter? { - return callback?.textChapter(-1) - } - - override fun hasNextChapter(): Boolean { - callback?.let { - return it.durChapterIndex() < it.chapterSize() - 1 - } - return false - } - - override fun hasPrevChapter(): Boolean { - callback?.let { - return it.durChapterIndex() > 0 - } - return false - } - - override fun moveToNextChapter() { - callback?.moveToNextChapter() - } - - override fun moveToPrevChapter() { - callback?.moveToPrevChapter() - } - })) + this.pageFactory = TextPageFactory.create(this) + upContent() } override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { @@ -132,14 +80,8 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att upContent() } - private fun setPageFactory(factory: TextPageFactory) { - this.pageFactory = factory - - //可做成异步回调 - upContent() - } - fun upPageAnim() { + pageDelegate = null pageDelegate = when (context.getPrefInt("pageAnim")) { 0 -> CoverPageDelegate(this) 1 -> SlidePageDelegate(this) @@ -207,6 +149,60 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, att callback?.clickCenter() } + override fun isScrollDelegate(): Boolean { + return pageDelegate is ScrollPageDelegate + } + + override fun pageIndex(): Int { + return callback?.durChapterPos() ?: 0 + } + + override fun setPageIndex(pageIndex: Int) { + callback?.setPageIndex(pageIndex) + } + + override fun getChapterPosition(): Int { + return callback?.durChapterIndex() ?: 0 + } + + override fun getChapter(position: Int): TextChapter? { + return callback?.textChapter(position) + } + + override fun getCurrentChapter(): TextChapter? { + return callback?.textChapter(0) + } + + override fun getNextChapter(): TextChapter? { + return callback?.textChapter(1) + } + + override fun getPreviousChapter(): TextChapter? { + return callback?.textChapter(-1) + } + + override fun hasNextChapter(): Boolean { + callback?.let { + return it.durChapterIndex() < it.chapterSize() - 1 + } + return false + } + + override fun hasPrevChapter(): Boolean { + callback?.let { + return it.durChapterIndex() > 0 + } + return false + } + + override fun moveToNextChapter() { + callback?.moveToNextChapter() + } + + override fun moveToPrevChapter() { + callback?.moveToPrevChapter() + } + interface CallBack { fun chapterSize(): Int fun durChapterIndex(): Int diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt index b0eee5632..6882dcae0 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt @@ -62,7 +62,7 @@ class TextPageFactory private constructor(dataSource: DataSource) : } override fun currentPage(): TextPage? = dataSource.pageIndex().let { index -> - return if (dataSource.isScroll()) { + return if (dataSource.isScrollDelegate()) { dataSource.getCurrentChapter()?.scrollPage() } else { dataSource.getCurrentChapter()?.page(index) @@ -70,7 +70,7 @@ class TextPageFactory private constructor(dataSource: DataSource) : } override fun nextPage(): TextPage? = dataSource.pageIndex().let { index -> - if (dataSource.isScroll()) { + if (dataSource.isScrollDelegate()) { return dataSource.getNextChapter()?.scrollPage() ?: TextPage(index = index + 1, title = "index:${index + 1}") } @@ -85,7 +85,7 @@ class TextPageFactory private constructor(dataSource: DataSource) : } override fun previousPage(): TextPage? = dataSource.pageIndex().let { index -> - if (dataSource.isScroll()) { + if (dataSource.isScrollDelegate()) { return dataSource.getPreviousChapter()?.scrollPage() ?: TextPage(index = index + 1, title = "index:${index + 1}") } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt index ce4d4beab..00dc408e0 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt @@ -38,9 +38,19 @@ abstract class PageDelegate(protected val pageView: PageView) { protected var viewWidth: Int = pageView.width protected var viewHeight: Int = pageView.height - private val scroller: Scroller by lazy { Scroller(pageView.context, FastOutLinearInInterpolator()) } + private val scroller: Scroller by lazy { + Scroller( + pageView.context, + FastOutLinearInInterpolator() + ) + } - private val detector: GestureDetector by lazy { GestureDetector(pageView.context, GestureListener()) } + private val detector: GestureDetector by lazy { + GestureDetector( + pageView.context, + GestureListener() + ) + } private var isMoved = false private var noNext = true @@ -77,7 +87,13 @@ abstract class PageDelegate(protected val pageView: PageView) { } protected fun startScroll(startX: Int, startY: Int, dx: Int, dy: Int) { - scroller.startScroll(startX, startY, dx, dy, getDuration((if(dx !=0) dx else dy).toFloat())) + scroller.startScroll( + startX, + startY, + dx, + dy, + getDuration((if (dx != 0) dx else dy).toFloat()) + ) isRunning = true isStarted = true invalidate() @@ -243,8 +259,18 @@ abstract class PageDelegate(protected val pageView: PageView) { isLongPress = true } - override fun onScroll(e1: MotionEvent, e2: MotionEvent, distanceX: Float, distanceY: Float): Boolean { - curPage?.contentTextView()?.setTextIsSelectable(false) + override fun onScroll( + e1: MotionEvent, + e2: MotionEvent, + distanceX: Float, + distanceY: Float + ): Boolean { + if (pageView.isScrollDelegate()) { + curPage?.dispatchTouchEvent(e2) + return true + } else { + curPage?.contentTextView()?.setTextIsSelectable(false) + } if (!isMoved && abs(distanceX) > abs(distanceY)) { if (distanceX < 0) { //上一页的参数配置 diff --git a/app/src/main/res/layout/view_book_page.xml b/app/src/main/res/layout/view_book_page.xml index eb27614ad..59784756f 100644 --- a/app/src/main/res/layout/view_book_page.xml +++ b/app/src/main/res/layout/view_book_page.xml @@ -32,8 +32,7 @@ android:id="@+id/content_text_view" android:layout_width="match_parent" android:layout_height="0dp" - android:layout_weight="1" - android:textIsSelectable="true" /> + android:layout_weight="1" /> Date: Sat, 21 Sep 2019 12:17:12 +0800 Subject: [PATCH 1577/1997] up --- .../legado/app/ui/widget/page/ContentView.kt | 28 +++++--- .../app/ui/widget/page/PageScrollView.kt | 20 ++++++ .../main/res/layout/view_book_page_scroll.xml | 65 +++++++++++++++++++ 3 files changed, 103 insertions(+), 10 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/widget/page/PageScrollView.kt create mode 100644 app/src/main/res/layout/view_book_page_scroll.xml diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index 747f17497..c63ef5efe 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -19,27 +19,35 @@ import java.util.* class ContentView : FrameLayout { - + private var isScroll: Boolean = false private val bgImage: AppCompatImageView = AppCompatImageView(context) .apply { scaleType = ImageView.ScaleType.CENTER_CROP } - constructor(context: Context) : super(context) + constructor(context: Context) : super(context) { + this.isScroll = true + init() + } - constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { + init() + } - constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super( - context, - attrs, - defStyleAttr - ) + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : + super(context, attrs, defStyleAttr) { + init() + } - init { + fun init() { //设置背景防止切换背景时文字重叠 setBackgroundColor(context.getCompatColor(R.color.background)) addView(bgImage, LayoutParams(matchParent, matchParent)) - inflate(context, R.layout.view_book_page, this) + if (isScroll) { + inflate(context, R.layout.view_book_page_scroll, this) + } else { + inflate(context, R.layout.view_book_page, this) + } top_bar.layoutParams.height = context.getStatusBarHeight() upStyle() upTime() diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageScrollView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageScrollView.kt new file mode 100644 index 000000000..4ba6abb9b --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageScrollView.kt @@ -0,0 +1,20 @@ +package io.legado.app.ui.widget.page + +import android.content.Context +import android.util.AttributeSet +import android.widget.ScrollView + + +class PageScrollView : ScrollView { + constructor(context: Context) : super(context) + + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) + + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super( + context, + attrs, + defStyleAttr + ) + + +} \ No newline at end of file diff --git a/app/src/main/res/layout/view_book_page_scroll.xml b/app/src/main/res/layout/view_book_page_scroll.xml new file mode 100644 index 000000000..edbdad825 --- /dev/null +++ b/app/src/main/res/layout/view_book_page_scroll.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From c3166a16f4494d22bbcffb8bc725dee4a7e2659d Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 21 Sep 2019 12:42:36 +0800 Subject: [PATCH 1578/1997] up --- .../main/java/io/legado/app/ui/widget/page/ContentView.kt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index c63ef5efe..fcec1bd5a 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -34,11 +34,6 @@ class ContentView : FrameLayout { init() } - constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : - super(context, attrs, defStyleAttr) { - init() - } - fun init() { //设置背景防止切换背景时文字重叠 setBackgroundColor(context.getCompatColor(R.color.background)) From 48cf1c7e6db5b92e3c7cec24f2103d15209eaf24 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 21 Sep 2019 19:44:41 +0800 Subject: [PATCH 1579/1997] up --- .../app/ui/widget/page/ChapterProvider.kt | 6 +++++- .../app/ui/widget/page/ContentTextView.kt | 4 ++-- .../io/legado/app/ui/widget/page/ContentView.kt | 17 ++++++++++++++++- .../io/legado/app/ui/widget/page/PageView.kt | 10 +++++++--- .../io/legado/app/ui/widget/page/TextChapter.kt | 12 ++++++++++++ 5 files changed, 42 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt index 4e33bdd51..09fd9454a 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ChapterProvider.kt @@ -18,6 +18,7 @@ object ChapterProvider { content: String, chapterSize: Int ): TextChapter { val textPages = arrayListOf() + val pageLines = arrayListOf() val pageLengths = arrayListOf() var surplusText = content var pageIndex = 0 @@ -35,10 +36,12 @@ object ChapterProvider { } } textView.text = spannableStringBuilder - val lastCharNum = textView.getCharNum() + val lastLine = textView.getLineNum() + val lastCharNum = textView.getCharNum(lastLine) if (lastCharNum == 0) { break } else { + pageLines.add(lastLine) pageLengths.add(lastCharNum) textPages.add( TextPage( @@ -64,6 +67,7 @@ object ChapterProvider { bookChapter.title, bookChapter.url, textPages, + pageLines, pageLengths, chapterSize ) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt index 0e7a7bea8..485895497 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt @@ -16,8 +16,8 @@ class ContentTextView : AppCompatTextView { /** * 获取当前页总字数 */ - fun getCharNum(): Int { - return layout?.getLineEnd(getLineNum()) ?: 0 + fun getCharNum(lineNum: Int = getLineNum()): Int { + return layout?.getLineEnd(lineNum) ?: 0 } /** diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index fcec1bd5a..9383adb15 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -13,7 +13,14 @@ import io.legado.app.constant.AppConst.TIME_FORMAT import io.legado.app.help.ImageLoader import io.legado.app.help.ReadBookConfig import io.legado.app.utils.* -import kotlinx.android.synthetic.main.view_book_page.view.* +import kotlinx.android.synthetic.main.view_book_page.view.content_text_view +import kotlinx.android.synthetic.main.view_book_page.view.page_panel +import kotlinx.android.synthetic.main.view_book_page.view.top_bar +import kotlinx.android.synthetic.main.view_book_page.view.tv_bottom_left +import kotlinx.android.synthetic.main.view_book_page.view.tv_bottom_right +import kotlinx.android.synthetic.main.view_book_page.view.tv_top_left +import kotlinx.android.synthetic.main.view_book_page.view.tv_top_right +import kotlinx.android.synthetic.main.view_book_page_scroll.view.* import org.jetbrains.anko.matchParent import java.util.* @@ -111,4 +118,12 @@ class ContentView : FrameLayout { fun contentTextView(): ContentTextView? { return content_text_view } + + fun scrollTo(pos: Int?) { + if (pos != null) { + page_scroll_view?.post { + page_scroll_view?.scrollTo(0, content_text_view.layout.getLineTop(pos)) + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 77cb77bd6..7bf865314 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -34,10 +34,8 @@ class PageView(context: Context, attrs: AttributeSet) : addView(curPage) upBg() setWillNotDraw(false) - + pageFactory = TextPageFactory.create(this) upPageAnim() - this.pageFactory = TextPageFactory.create(this) - upContent() } override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { @@ -88,6 +86,7 @@ class PageView(context: Context, attrs: AttributeSet) : 2 -> ScrollPageDelegate(this) else -> NoAnimPageDelegate(this) } + upContent() } fun upContent() { @@ -96,6 +95,11 @@ class PageView(context: Context, attrs: AttributeSet) : curPage?.setContent(it.currentPage()) nextPage?.setContent(it.nextPage()) } + callback?.let { + if (isScrollDelegate()) { + curPage?.scrollTo(it.textChapter()?.getStartLine(it.durChapterPos())) + } + } } fun moveToPrevPage(noAnim: Boolean = true) { diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt index d9eff7009..72377e3cd 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt @@ -7,6 +7,7 @@ data class TextChapter( val title: String, val url: String, val pages: List, + val pageLines: List, val pageLengths: List, val chaptersSize: Int ) { @@ -64,5 +65,16 @@ data class TextChapter( } return stringBuilder.toString() } + + fun getStartLine(pageIndex: Int): Int { + if (pageLines.size > pageIndex) { + var lines = 0 + for (index: Int in 0 until pageIndex) { + lines += pageLines[index] + 1 + } + return lines + } + return 0 + } } From ef5fddf0efaca98401004945eeff394bfea19da4 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 21 Sep 2019 20:05:13 +0800 Subject: [PATCH 1580/1997] up --- .../java/io/legado/app/ui/widget/page/ContentView.kt | 12 ++++++++++++ .../io/legado/app/ui/widget/page/PageScrollView.kt | 10 ++++++++++ .../java/io/legado/app/ui/widget/page/PageView.kt | 6 ++++++ 3 files changed, 28 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index 9383adb15..441402562 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -27,6 +27,7 @@ import java.util.* class ContentView : FrameLayout { private var isScroll: Boolean = false + var callBack: CallBack? = null private val bgImage: AppCompatImageView = AppCompatImageView(context) .apply { scaleType = ImageView.ScaleType.CENTER_CROP @@ -55,6 +56,13 @@ class ContentView : FrameLayout { upTime() content_text_view.customSelectionActionModeCallback = ContentSelectActionCallback(content_text_view) + page_scroll_view?.scrollListener = object : PageScrollView.OnScrollListener { + override fun onScroll(scrollY: Int) { + content_text_view.layout?.getLineForVertical(scrollY)?.let { line -> + callBack?.scrollToLine(line) + } + } + } } fun upStyle() { @@ -126,4 +134,8 @@ class ContentView : FrameLayout { } } } + + interface CallBack { + fun scrollToLine(line: Int) + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageScrollView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageScrollView.kt index 4ba6abb9b..dc85416ed 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageScrollView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageScrollView.kt @@ -6,6 +6,7 @@ import android.widget.ScrollView class PageScrollView : ScrollView { + constructor(context: Context) : super(context) constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) @@ -16,5 +17,14 @@ class PageScrollView : ScrollView { defStyleAttr ) + var scrollListener: OnScrollListener? = null + + override fun onScrollChanged(l: Int, t: Int, oldl: Int, oldt: Int) { + super.onScrollChanged(l, t, oldl, oldt) + scrollListener?.onScroll(t) + } + interface OnScrollListener { + fun onScroll(scrollY: Int) + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 7bf865314..dd80a278c 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -14,6 +14,7 @@ import io.legado.app.utils.getPrefInt class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, attrs), PageDelegate.PageInterface, + ContentView.CallBack, DataSource { private var callback: CallBack? = null @@ -36,6 +37,7 @@ class PageView(context: Context, attrs: AttributeSet) : setWillNotDraw(false) pageFactory = TextPageFactory.create(this) upPageAnim() + curPage?.callBack = this } override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { @@ -207,6 +209,10 @@ class PageView(context: Context, attrs: AttributeSet) : callback?.moveToPrevChapter() } + override fun scrollToLine(line: Int) { + + } + interface CallBack { fun chapterSize(): Int fun durChapterIndex(): Int From 8e426101c2dc80386e1c0b3e45b788ceefe003b8 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 21 Sep 2019 21:28:09 +0800 Subject: [PATCH 1581/1997] up --- .../legado/app/ui/widget/page/ContentView.kt | 18 +++++++++++++----- .../io/legado/app/ui/widget/page/PageView.kt | 6 +++++- .../legado/app/ui/widget/page/TextChapter.kt | 13 ++++++++++++- 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index 441402562..368622cea 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -26,8 +26,9 @@ import java.util.* class ContentView : FrameLayout { - private var isScroll: Boolean = false var callBack: CallBack? = null + private var isScroll: Boolean = false + private var pageSize: Int = 0 private val bgImage: AppCompatImageView = AppCompatImageView(context) .apply { scaleType = ImageView.ScaleType.CENTER_CROP @@ -112,11 +113,18 @@ class ContentView : FrameLayout { tv_top_right.text = context.getString(R.string.battery_show, battery) } + fun setContent(textPage: TextPage?) { + content_text_view.text = textPage?.text + tv_bottom_left.text = textPage?.title + pageSize = textPage?.pageSize ?: 0 + setPageIndex(textPage?.index) + } + @SuppressLint("SetTextI18n") - fun setContent(page: TextPage?) { - content_text_view.text = page?.text - tv_bottom_left.text = page?.title - tv_bottom_right.text = "${page?.index?.plus(1)}/${page?.pageSize}" + fun setPageIndex(pageIndex: Int?) { + pageIndex?.let { + tv_bottom_right.text = "${pageIndex.plus(1)}/${pageSize}" + } } fun isTextSelected(): Boolean { diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index dd80a278c..2df6e694e 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -210,7 +210,11 @@ class PageView(context: Context, attrs: AttributeSet) : } override fun scrollToLine(line: Int) { - + callback?.textChapter()?.let { + val pageIndex = it.getPageIndex(line) + curPage?.setPageIndex(pageIndex) + callback?.setPageIndex(pageIndex) + } } interface CallBack { diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt index 72377e3cd..d7fbf375d 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt @@ -31,7 +31,7 @@ data class TextChapter( pages.forEach { spannableStringBuilder.append(it.text) } - return TextPage(0, spannableStringBuilder, title, position, chaptersSize) + return TextPage(0, spannableStringBuilder, title, position, pages.size) } return null } @@ -76,5 +76,16 @@ data class TextChapter( } return 0 } + + fun getPageIndex(line: Int): Int { + var lines = 0 + for (pageIndex in pageLines.indices) { + lines += pageLines[pageIndex] + 1 + if (line < lines) { + return pageIndex + } + } + return 0 + } } From c464f1cfecfdc2da545a8751eaca12023a20bfa8 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 21 Sep 2019 21:47:21 +0800 Subject: [PATCH 1582/1997] up --- .../io/legado/app/ui/book/read/ReadBookActivity.kt | 4 ++-- .../java/io/legado/app/ui/widget/page/PageView.kt | 14 ++++++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt index bfcebfff5..157aa7945 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt @@ -282,12 +282,12 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea viewModel.durChapterIndex - 1 -> launch { viewModel.prevTextChapter = ChapterProvider .getTextChapter(content_text_view, bookChapter, content, viewModel.chapterSize) - page_view.upContent() + page_view.upContent(-1) } viewModel.durChapterIndex + 1 -> launch { viewModel.nextTextChapter = ChapterProvider .getTextChapter(content_text_view, bookChapter, content, viewModel.chapterSize) - page_view.upContent() + page_view.upContent(1) } } } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 2df6e694e..ca4d9b633 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -91,11 +91,17 @@ class PageView(context: Context, attrs: AttributeSet) : upContent() } - fun upContent() { + fun upContent(position: Int = 0) { pageFactory?.let { - prevPage?.setContent(it.previousPage()) - curPage?.setContent(it.currentPage()) - nextPage?.setContent(it.nextPage()) + when (position) { + -1 -> prevPage?.setContent(it.previousPage()) + 1 -> nextPage?.setContent(it.nextPage()) + else -> { + curPage?.setContent(it.currentPage()) + nextPage?.setContent(it.nextPage()) + prevPage?.setContent(it.previousPage()) + } + } } callback?.let { if (isScrollDelegate()) { From 7d0bdd52d38dfd5cf197c3b2c9c6e99d1f631d80 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 21 Sep 2019 21:58:07 +0800 Subject: [PATCH 1583/1997] up --- .../main/java/io/legado/app/ui/widget/page/PageView.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index ca4d9b633..72aa4b4ef 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -100,14 +100,14 @@ class PageView(context: Context, attrs: AttributeSet) : curPage?.setContent(it.currentPage()) nextPage?.setContent(it.nextPage()) prevPage?.setContent(it.previousPage()) + callback?.let { callback -> + if (isScrollDelegate()) { + curPage?.scrollTo(callback.textChapter()?.getStartLine(callback.durChapterPos())) + } + } } } } - callback?.let { - if (isScrollDelegate()) { - curPage?.scrollTo(it.textChapter()?.getStartLine(it.durChapterPos())) - } - } } fun moveToPrevPage(noAnim: Boolean = true) { From 84efd785af1e6f76976e5c6c3895450f4fe082f9 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 21 Sep 2019 22:47:51 +0800 Subject: [PATCH 1584/1997] up --- .../io/legado/app/ui/book/read/ReadBookActivity.kt | 12 ++++++------ .../io/legado/app/ui/book/read/ReadBookViewModel.kt | 8 ++++---- .../main/java/io/legado/app/ui/book/read/ReadMenu.kt | 8 ++++---- .../java/io/legado/app/ui/widget/page/PageView.kt | 8 ++++---- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt index 157aa7945..b1d735117 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt @@ -375,10 +375,10 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea /** * 下一页 */ - override fun moveToNextChapter(): Boolean { + override fun moveToNextChapter(upContent: Boolean): Boolean { return if (viewModel.durChapterIndex < viewModel.chapterSize - 1) { viewModel.durPageIndex = 0 - viewModel.moveToNextChapter() + viewModel.moveToNextChapter(upContent) viewModel.saveRead() curChapterChanged() true @@ -390,10 +390,10 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea /** * 上一页 */ - override fun moveToPrevChapter(last: Boolean): Boolean { + override fun moveToPrevChapter(upContent: Boolean, last: Boolean): Boolean { return if (viewModel.durChapterIndex > 0) { viewModel.durPageIndex = if (last) viewModel.prevTextChapter?.lastIndex() ?: 0 else 0 - viewModel.moveToPrevChapter() + viewModel.moveToPrevChapter(upContent) viewModel.saveRead() curChapterChanged() true @@ -586,14 +586,14 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea page_view.upContent() viewModel.saveRead() } - 2 -> if (!moveToNextChapter()) ReadAloud.stop(this) + 2 -> if (!moveToNextChapter(true)) ReadAloud.stop(this) -1 -> { if (viewModel.durPageIndex > 0) { viewModel.durPageIndex = viewModel.durPageIndex - 1 page_view.upContent() viewModel.saveRead() } else { - moveToPrevChapter() + moveToPrevChapter(true) } } -2 -> moveToPrevChapter(false) diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt index 635deb97e..a0b02a402 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt @@ -108,7 +108,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } } - fun moveToNextChapter() { + fun moveToNextChapter(upContent: Boolean) { durChapterIndex++ prevTextChapter = curTextChapter curTextChapter = nextTextChapter @@ -116,7 +116,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { bookData.value?.let { if (curTextChapter == null) { loadContent(it, durChapterIndex) - } else { + } else if (upContent) { callBack?.upContent() } loadContent(it, durChapterIndex.plus(1)) @@ -131,7 +131,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } } - fun moveToPrevChapter() { + fun moveToPrevChapter(upContent: Boolean) { durChapterIndex-- nextTextChapter = curTextChapter curTextChapter = prevTextChapter @@ -139,7 +139,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { bookData.value?.let { if (curTextChapter == null) { loadContent(it, durChapterIndex) - } else { + } else if (upContent) { callBack?.upContent() } loadContent(it, durChapterIndex.minus(1)) diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadMenu.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadMenu.kt index af02fa16c..bb321fd65 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadMenu.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadMenu.kt @@ -153,10 +153,10 @@ class ReadMenu : FrameLayout { } //上一章 - tv_pre.onClick { callBack?.moveToPrevChapter(false) } + tv_pre.onClick { callBack?.moveToPrevChapter(upContent = true, last = false) } //下一章 - tv_next.onClick { callBack?.moveToNextChapter() } + tv_next.onClick { callBack?.moveToNextChapter(true) } //目录 ll_catalog.onClick { @@ -250,8 +250,8 @@ class ReadMenu : FrameLayout { interface CallBack { fun autoPage() fun skipToPage(page: Int) - fun moveToPrevChapter(last: Boolean): Boolean - fun moveToNextChapter(): Boolean + fun moveToPrevChapter(upContent: Boolean, last: Boolean): Boolean + fun moveToNextChapter(upContent: Boolean): Boolean fun openReplaceRule() fun openChapterList() fun showReadStyle() diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 72aa4b4ef..899937b37 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -208,11 +208,11 @@ class PageView(context: Context, attrs: AttributeSet) : } override fun moveToNextChapter() { - callback?.moveToNextChapter() + callback?.moveToNextChapter(false) } override fun moveToPrevChapter() { - callback?.moveToPrevChapter() + callback?.moveToPrevChapter(false) } override fun scrollToLine(line: Int) { @@ -241,12 +241,12 @@ class PageView(context: Context, attrs: AttributeSet) : /** * 下一章 */ - fun moveToNextChapter(): Boolean + fun moveToNextChapter(upContent: Boolean): Boolean /** * 上一章 */ - fun moveToPrevChapter(last: Boolean = true): Boolean + fun moveToPrevChapter(upContent: Boolean, last: Boolean = true): Boolean /** * 保存页数 From db112d74535e30cfa7ee26484500b8ab7dc6795e Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 21 Sep 2019 22:59:26 +0800 Subject: [PATCH 1585/1997] up --- .../main/java/io/legado/app/ui/widget/page/TextChapter.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt index d7fbf375d..0ab136b42 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextChapter.kt @@ -31,7 +31,10 @@ data class TextChapter( pages.forEach { spannableStringBuilder.append(it.text) } - return TextPage(0, spannableStringBuilder, title, position, pages.size) + return TextPage( + index = 0, text = spannableStringBuilder, title = title, + pageSize = pages.size, chapterSize = chaptersSize, chapterIndex = position + ) } return null } From 44a0a4467a7bce6f4346cf26f7d4328fdd836b7e Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 21 Sep 2019 23:25:47 +0800 Subject: [PATCH 1586/1997] up --- .../legado/app/ui/widget/page/ContentView.kt | 28 +++----- .../app/ui/widget/page/PageScrollView.kt | 30 --------- .../main/res/layout/view_book_page_scroll.xml | 65 ------------------- 3 files changed, 8 insertions(+), 115 deletions(-) delete mode 100644 app/src/main/java/io/legado/app/ui/widget/page/PageScrollView.kt delete mode 100644 app/src/main/res/layout/view_book_page_scroll.xml diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index 368622cea..258a7c928 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -13,15 +13,9 @@ import io.legado.app.constant.AppConst.TIME_FORMAT import io.legado.app.help.ImageLoader import io.legado.app.help.ReadBookConfig import io.legado.app.utils.* -import kotlinx.android.synthetic.main.view_book_page.view.content_text_view -import kotlinx.android.synthetic.main.view_book_page.view.page_panel -import kotlinx.android.synthetic.main.view_book_page.view.top_bar -import kotlinx.android.synthetic.main.view_book_page.view.tv_bottom_left -import kotlinx.android.synthetic.main.view_book_page.view.tv_bottom_right -import kotlinx.android.synthetic.main.view_book_page.view.tv_top_left -import kotlinx.android.synthetic.main.view_book_page.view.tv_top_right -import kotlinx.android.synthetic.main.view_book_page_scroll.view.* +import kotlinx.android.synthetic.main.view_book_page.view.* import org.jetbrains.anko.matchParent +import org.jetbrains.anko.sdk27.listeners.onScrollChange import java.util.* @@ -47,21 +41,15 @@ class ContentView : FrameLayout { //设置背景防止切换背景时文字重叠 setBackgroundColor(context.getCompatColor(R.color.background)) addView(bgImage, LayoutParams(matchParent, matchParent)) - if (isScroll) { - inflate(context, R.layout.view_book_page_scroll, this) - } else { - inflate(context, R.layout.view_book_page, this) - } + inflate(context, R.layout.view_book_page, this) top_bar.layoutParams.height = context.getStatusBarHeight() upStyle() upTime() content_text_view.customSelectionActionModeCallback = ContentSelectActionCallback(content_text_view) - page_scroll_view?.scrollListener = object : PageScrollView.OnScrollListener { - override fun onScroll(scrollY: Int) { - content_text_view.layout?.getLineForVertical(scrollY)?.let { line -> - callBack?.scrollToLine(line) - } + content_text_view.onScrollChange { _, _, scrollY, _, _ -> + content_text_view.layout?.getLineForVertical(scrollY)?.let { line -> + callBack?.scrollToLine(line) } } } @@ -137,8 +125,8 @@ class ContentView : FrameLayout { fun scrollTo(pos: Int?) { if (pos != null) { - page_scroll_view?.post { - page_scroll_view?.scrollTo(0, content_text_view.layout.getLineTop(pos)) + content_text_view.post { + content_text_view.scrollTo(0, content_text_view.layout.getLineTop(pos)) } } } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageScrollView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageScrollView.kt deleted file mode 100644 index dc85416ed..000000000 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageScrollView.kt +++ /dev/null @@ -1,30 +0,0 @@ -package io.legado.app.ui.widget.page - -import android.content.Context -import android.util.AttributeSet -import android.widget.ScrollView - - -class PageScrollView : ScrollView { - - constructor(context: Context) : super(context) - - constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) - - constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super( - context, - attrs, - defStyleAttr - ) - - var scrollListener: OnScrollListener? = null - - override fun onScrollChanged(l: Int, t: Int, oldl: Int, oldt: Int) { - super.onScrollChanged(l, t, oldl, oldt) - scrollListener?.onScroll(t) - } - - interface OnScrollListener { - fun onScroll(scrollY: Int) - } -} \ No newline at end of file diff --git a/app/src/main/res/layout/view_book_page_scroll.xml b/app/src/main/res/layout/view_book_page_scroll.xml deleted file mode 100644 index edbdad825..000000000 --- a/app/src/main/res/layout/view_book_page_scroll.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file From dcfea7b8eea456050c52a96c8c1092dadcaa9f98 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 21 Sep 2019 23:54:39 +0800 Subject: [PATCH 1587/1997] up --- .../ui/widget/page/delegate/CoverPageDelegate.kt | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/CoverPageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/CoverPageDelegate.kt index af4f368aa..8d1d05e3d 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/CoverPageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/CoverPageDelegate.kt @@ -42,7 +42,6 @@ class CoverPageDelegate(pageView: PageView) : PageDelegate(pageView) { override fun onScrollStop() { curPage?.x = 0.toFloat() - if (!isCancel) { pageView.fillPage(direction) } @@ -57,15 +56,11 @@ class CoverPageDelegate(pageView: PageView) : PageDelegate(pageView) { val distanceX = if (offsetX > 0) offsetX - viewWidth else offsetX + viewWidth bitmap?.let { - when (direction) { - Direction.PREV -> { - bitmapMatrix.setTranslate(distanceX, 0.toFloat()) - canvas.drawBitmap(it, bitmapMatrix, null) - } - Direction.NEXT -> { - curPage?.translationX = offsetX - } - Direction.NONE -> Unit + if (direction == Direction.PREV) { + bitmapMatrix.setTranslate(distanceX, 0.toFloat()) + canvas.drawBitmap(it, bitmapMatrix, null) + } else if (direction == Direction.NEXT) { + curPage?.translationX = offsetX } addShadow(distanceX.toInt(), canvas) } From 474ca2713fcdcb55810928dfd5018a6627fafcce Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 21 Sep 2019 23:56:00 +0800 Subject: [PATCH 1588/1997] up --- .../java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt index 00dc408e0..c2692c7d9 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt @@ -265,11 +265,10 @@ abstract class PageDelegate(protected val pageView: PageView) { distanceX: Float, distanceY: Float ): Boolean { + curPage?.contentTextView()?.setTextIsSelectable(false) if (pageView.isScrollDelegate()) { curPage?.dispatchTouchEvent(e2) return true - } else { - curPage?.contentTextView()?.setTextIsSelectable(false) } if (!isMoved && abs(distanceX) > abs(distanceY)) { if (distanceX < 0) { From 2a8f9e1db9aa0486a8ca5d631062697c892c8985 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 22 Sep 2019 00:11:33 +0800 Subject: [PATCH 1589/1997] up --- .../io/legado/app/ui/widget/page/delegate/PageDelegate.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt index c2692c7d9..996d0bfc2 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt @@ -3,6 +3,7 @@ package io.legado.app.ui.widget.page.delegate import android.graphics.Bitmap import android.graphics.Canvas import android.graphics.RectF +import android.text.method.ScrollingMovementMethod import android.view.GestureDetector import android.view.MotionEvent import android.widget.Scroller @@ -45,6 +46,10 @@ abstract class PageDelegate(protected val pageView: PageView) { ) } + private val scrollingMovementMethod: ScrollingMovementMethod by lazy { + ScrollingMovementMethod() + } + private val detector: GestureDetector by lazy { GestureDetector( pageView.context, @@ -266,6 +271,7 @@ abstract class PageDelegate(protected val pageView: PageView) { distanceY: Float ): Boolean { curPage?.contentTextView()?.setTextIsSelectable(false) + curPage?.contentTextView()?.movementMethod = scrollingMovementMethod if (pageView.isScrollDelegate()) { curPage?.dispatchTouchEvent(e2) return true From 1d70e381a8ea1f5907a435660a439e904c08b09b Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 22 Sep 2019 00:19:57 +0800 Subject: [PATCH 1590/1997] up --- .../io/legado/app/ui/widget/page/delegate/PageDelegate.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt index 996d0bfc2..17918285e 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt @@ -270,8 +270,10 @@ abstract class PageDelegate(protected val pageView: PageView) { distanceX: Float, distanceY: Float ): Boolean { - curPage?.contentTextView()?.setTextIsSelectable(false) - curPage?.contentTextView()?.movementMethod = scrollingMovementMethod + curPage?.contentTextView()?.let { + it.setTextIsSelectable(false) + it.movementMethod = scrollingMovementMethod + } if (pageView.isScrollDelegate()) { curPage?.dispatchTouchEvent(e2) return true From fae2ddd6bf9b9b60e665c0e995864845ac7231db Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 22 Sep 2019 10:03:34 +0800 Subject: [PATCH 1591/1997] up --- .../app/ui/widget/page/ContentTextView.kt | 190 ++++++++++++++++++ 1 file changed, 190 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt index 485895497..c2a9632ba 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt @@ -1,8 +1,16 @@ package io.legado.app.ui.widget.page +import android.annotation.SuppressLint import android.content.Context import android.util.AttributeSet +import android.view.MotionEvent +import android.view.VelocityTracker +import android.view.ViewConfiguration +import android.view.animation.Interpolator +import android.widget.OverScroller import androidx.appcompat.widget.AppCompatTextView +import androidx.core.view.ViewCompat +import kotlin.math.abs class ContentTextView : AppCompatTextView { @@ -13,6 +21,34 @@ class ContentTextView : AppCompatTextView { constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) + private val INVALID_POINTER = -1 + private val SCROLL_STATE_IDLE = 0 + private val SCROLL_STATE_DRAGGING = 1 + val SCROLL_STATE_SETTLING = 2 + + private var velocityTracker: VelocityTracker? = null + private var mScrollState = SCROLL_STATE_IDLE + private var mScrollPointerId = INVALID_POINTER + private var mLastTouchY: Int = 0 + private var mTouchSlop: Int = 0 + private var mMinFlingVelocity: Int = 0 + private var mMaxFlingVelocity: Int = 0 + private val mViewFling = ViewFling() + + //f(x) = (x-1)^5 + 1 + private val sQuinticInterpolator = Interpolator { + var t = it + t -= 1.0f + t * t * t * t * t + 1.0f + } + + init { + val vc = ViewConfiguration.get(context) + mTouchSlop = vc.scaledTouchSlop + mMinFlingVelocity = vc.scaledMinimumFlingVelocity + mMaxFlingVelocity = vc.scaledMaximumFlingVelocity + } + /** * 获取当前页总字数 */ @@ -27,4 +63,158 @@ class ContentTextView : AppCompatTextView { val topOfLastLine = height - paddingTop - paddingBottom - lineHeight return layout?.getLineForVertical(topOfLastLine) ?: 0 } + + @SuppressLint("ClickableViewAccessibility") + override fun onTouchEvent(event: MotionEvent?): Boolean { + event?.let { + val action = event.action + val actionIndex = event.actionIndex + val vtEvent = MotionEvent.obtain(event) + + if (velocityTracker == null) { + velocityTracker = VelocityTracker.obtain() + } + velocityTracker?.addMovement(it) + when (action) { + MotionEvent.ACTION_DOWN -> { + setScrollState(SCROLL_STATE_IDLE) + mScrollPointerId = event.getPointerId(0) + mLastTouchY = (event.y + 0.5f).toInt() + } + MotionEvent.ACTION_POINTER_DOWN -> { + mScrollPointerId = event.getPointerId(actionIndex) + mLastTouchY = (event.getY(actionIndex) + 0.5f).toInt() + } + MotionEvent.ACTION_MOVE -> { + val index = event.findPointerIndex(mScrollPointerId) + if (index < 0) { + return false + } + + val y = (event.getY(index) + 0.5f).toInt() + var dy = mLastTouchY - y + + if (mScrollState != SCROLL_STATE_DRAGGING) { + var startScroll = false + + if (abs(dy) > mTouchSlop) { + if (dy > 0) { + dy -= mTouchSlop + } else { + dy += mTouchSlop + } + startScroll = true + } + if (startScroll) { + setScrollState(SCROLL_STATE_DRAGGING) + } + } + + if (mScrollState == SCROLL_STATE_DRAGGING) { + mLastTouchY = y + } + } + MotionEvent.ACTION_POINTER_UP -> { + if (event.getPointerId(actionIndex) == mScrollPointerId) { + // Pick a new pointer to pick up the slack. + val newIndex = if (actionIndex == 0) 1 else 0 + mScrollPointerId = event.getPointerId(newIndex) + mLastTouchY = (event.getY(newIndex) + 0.5f).toInt() + } + } + MotionEvent.ACTION_UP -> { + velocityTracker?.computeCurrentVelocity(1000, mMaxFlingVelocity.toFloat()) + val yVelocity = velocityTracker?.getXVelocity(mScrollPointerId) ?: 0f + if (abs(yVelocity) > mMinFlingVelocity) { + mViewFling.fling(yVelocity.toInt()) + } else { + setScrollState(SCROLL_STATE_IDLE) + } + resetTouch() + } + MotionEvent.ACTION_CANCEL -> { + resetTouch() + } + } + vtEvent.recycle() + } + return super.onTouchEvent(event) + } + + private fun resetTouch() { + velocityTracker?.clear() + } + + private fun setScrollState(state: Int) { + if (state == mScrollState) { + return + } + mScrollState = state + if (state != SCROLL_STATE_SETTLING) { + mViewFling.stop() + } + } + + private inner class ViewFling : Runnable { + + private var mLastFlingY = 0 + private val mScroller: OverScroller = OverScroller(context, sQuinticInterpolator) + private var mEatRunOnAnimationRequest = false + private var mReSchedulePostAnimationCallback = false + + override fun run() { + disableRunOnAnimationRequests() + val scroller = mScroller + if (scroller.computeScrollOffset()) { + val y = scroller.currY + val dy = y - mLastFlingY + mLastFlingY = y + this@ContentTextView.scrollBy(0, dy) + postOnAnimation() + } + enableRunOnAnimationRequests() + } + + fun fling(velocityY: Int) { + mLastFlingY = 0 + setScrollState(SCROLL_STATE_SETTLING) + mScroller.fling( + 0, + 0, + 0, + velocityY, + Integer.MIN_VALUE, + Integer.MAX_VALUE, + Integer.MIN_VALUE, + Integer.MAX_VALUE + ) + postOnAnimation() + } + + fun stop() { + removeCallbacks(this) + mScroller.abortAnimation() + } + + private fun disableRunOnAnimationRequests() { + mReSchedulePostAnimationCallback = false + mEatRunOnAnimationRequest = true + } + + private fun enableRunOnAnimationRequests() { + mEatRunOnAnimationRequest = false + if (mReSchedulePostAnimationCallback) { + postOnAnimation() + } + } + + internal fun postOnAnimation() { + if (mEatRunOnAnimationRequest) { + mReSchedulePostAnimationCallback = true + } else { + removeCallbacks(this) + ViewCompat.postOnAnimation(this@ContentTextView, this) + } + } + } } From 52381371935adab6e9fe741018241e78801ebede Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 22 Sep 2019 10:11:18 +0800 Subject: [PATCH 1592/1997] up --- .../main/java/io/legado/app/ui/widget/page/ContentTextView.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt index c2a9632ba..ff8fd1dc9 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt @@ -124,9 +124,9 @@ class ContentTextView : AppCompatTextView { } MotionEvent.ACTION_UP -> { velocityTracker?.computeCurrentVelocity(1000, mMaxFlingVelocity.toFloat()) - val yVelocity = velocityTracker?.getXVelocity(mScrollPointerId) ?: 0f + val yVelocity = velocityTracker?.getYVelocity(mScrollPointerId) ?: 0f if (abs(yVelocity) > mMinFlingVelocity) { - mViewFling.fling(yVelocity.toInt()) + mViewFling.fling(-yVelocity.toInt()) } else { setScrollState(SCROLL_STATE_IDLE) } From 7682cbdf021682971e0837c2b10d74c5968b5362 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 22 Sep 2019 10:17:26 +0800 Subject: [PATCH 1593/1997] up --- .../app/ui/widget/page/ContentTextView.kt | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt index ff8fd1dc9..873b48ea7 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt @@ -21,14 +21,13 @@ class ContentTextView : AppCompatTextView { constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) - private val INVALID_POINTER = -1 - private val SCROLL_STATE_IDLE = 0 - private val SCROLL_STATE_DRAGGING = 1 - val SCROLL_STATE_SETTLING = 2 + private val scrollStateIdle = 0 + private val scrollStateDragging = 1 + val scrollStateSettling = 2 private var velocityTracker: VelocityTracker? = null - private var mScrollState = SCROLL_STATE_IDLE - private var mScrollPointerId = INVALID_POINTER + private var mScrollState = scrollStateIdle + private var mScrollPointerId = -1 private var mLastTouchY: Int = 0 private var mTouchSlop: Int = 0 private var mMinFlingVelocity: Int = 0 @@ -77,7 +76,7 @@ class ContentTextView : AppCompatTextView { velocityTracker?.addMovement(it) when (action) { MotionEvent.ACTION_DOWN -> { - setScrollState(SCROLL_STATE_IDLE) + setScrollState(scrollStateIdle) mScrollPointerId = event.getPointerId(0) mLastTouchY = (event.y + 0.5f).toInt() } @@ -94,7 +93,7 @@ class ContentTextView : AppCompatTextView { val y = (event.getY(index) + 0.5f).toInt() var dy = mLastTouchY - y - if (mScrollState != SCROLL_STATE_DRAGGING) { + if (mScrollState != scrollStateDragging) { var startScroll = false if (abs(dy) > mTouchSlop) { @@ -106,11 +105,11 @@ class ContentTextView : AppCompatTextView { startScroll = true } if (startScroll) { - setScrollState(SCROLL_STATE_DRAGGING) + setScrollState(scrollStateDragging) } } - if (mScrollState == SCROLL_STATE_DRAGGING) { + if (mScrollState == scrollStateDragging) { mLastTouchY = y } } @@ -128,7 +127,7 @@ class ContentTextView : AppCompatTextView { if (abs(yVelocity) > mMinFlingVelocity) { mViewFling.fling(-yVelocity.toInt()) } else { - setScrollState(SCROLL_STATE_IDLE) + setScrollState(scrollStateIdle) } resetTouch() } @@ -150,7 +149,7 @@ class ContentTextView : AppCompatTextView { return } mScrollState = state - if (state != SCROLL_STATE_SETTLING) { + if (state != scrollStateSettling) { mViewFling.stop() } } @@ -177,7 +176,7 @@ class ContentTextView : AppCompatTextView { fun fling(velocityY: Int) { mLastFlingY = 0 - setScrollState(SCROLL_STATE_SETTLING) + setScrollState(scrollStateSettling) mScroller.fling( 0, 0, From 05033bd7b10905ec049a7f79e11620473cd8e15d Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 22 Sep 2019 12:49:38 +0800 Subject: [PATCH 1594/1997] up --- .../app/ui/widget/page/ContentTextView.kt | 45 ++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt index 873b48ea7..ed4ff6849 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt @@ -11,6 +11,8 @@ import android.widget.OverScroller import androidx.appcompat.widget.AppCompatTextView import androidx.core.view.ViewCompat import kotlin.math.abs +import kotlin.math.max +import kotlin.math.min class ContentTextView : AppCompatTextView { @@ -33,6 +35,8 @@ class ContentTextView : AppCompatTextView { private var mMinFlingVelocity: Int = 0 private var mMaxFlingVelocity: Int = 0 private val mViewFling = ViewFling() + //滑动距离的最大边界 + private var mOffsetHeight: Int = 0 //f(x) = (x-1)^5 + 1 private val sQuinticInterpolator = Interpolator { @@ -48,6 +52,14 @@ class ContentTextView : AppCompatTextView { mMaxFlingVelocity = vc.scaledMaximumFlingVelocity } + fun atTop(): Boolean { + return scrollY <= 0 + } + + fun atBottom(): Boolean { + return scrollY >= mOffsetHeight + } + /** * 获取当前页总字数 */ @@ -63,6 +75,33 @@ class ContentTextView : AppCompatTextView { return layout?.getLineForVertical(topOfLastLine) ?: 0 } + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + initOffsetHeight() + } + + override fun onTextChanged( + text: CharSequence, + start: Int, + lengthBefore: Int, + lengthAfter: Int + ) { + super.onTextChanged(text, start, lengthBefore, lengthAfter) + initOffsetHeight() + } + + private fun initOffsetHeight() { + val mLayoutHeight: Int + + //获得内容面板 + val mLayout = layout ?: return + //获得内容面板的高度 + mLayoutHeight = mLayout.height + + //计算滑动距离的边界 + mOffsetHeight = mLayoutHeight + totalPaddingTop + totalPaddingBottom - measuredHeight + } + @SuppressLint("ClickableViewAccessibility") override fun onTouchEvent(event: MotionEvent?): Boolean { event?.let { @@ -168,7 +207,11 @@ class ContentTextView : AppCompatTextView { val y = scroller.currY val dy = y - mLastFlingY mLastFlingY = y - this@ContentTextView.scrollBy(0, dy) + if (dy < 0 && scrollY > 0) { + scrollBy(0, max(dy, -scrollY)) + } else if (dy > 0 && scrollY < mOffsetHeight) { + scrollBy(0, min(dy, mOffsetHeight - scrollY)) + } postOnAnimation() } enableRunOnAnimationRequests() From e7d301181f97cb2f593abb15e8893271374ddde2 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 22 Sep 2019 12:50:26 +0800 Subject: [PATCH 1595/1997] up --- .../main/java/io/legado/app/ui/widget/page/ContentTextView.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt index ed4ff6849..fd406ea57 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt @@ -193,6 +193,9 @@ class ContentTextView : AppCompatTextView { } } + /** + * 惯性滚动 + */ private inner class ViewFling : Runnable { private var mLastFlingY = 0 From 000f165038e88d16d3392152ed9653898e125d9e Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 22 Sep 2019 12:55:57 +0800 Subject: [PATCH 1596/1997] up --- .../app/ui/widget/page/delegate/PageDelegate.kt | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt index 17918285e..7f9ea1292 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt @@ -65,7 +65,6 @@ abstract class PageDelegate(protected val pageView: PageView) { var isCancel = false var isRunning = false var isStarted = false - var isLongPress = false protected fun setStartPoint(x: Float, y: Float, invalidate: Boolean = true) { startX = x @@ -211,7 +210,6 @@ abstract class PageDelegate(protected val pageView: PageView) { private inner class GestureListener : GestureDetector.SimpleOnGestureListener() { override fun onDown(e: MotionEvent): Boolean { - isLongPress = false // abort() //是否移动 isMoved = false @@ -259,11 +257,6 @@ abstract class PageDelegate(protected val pageView: PageView) { return true } - override fun onLongPress(e: MotionEvent?) { - curPage?.dispatchTouchEvent(e) - isLongPress = true - } - override fun onScroll( e1: MotionEvent, e2: MotionEvent, @@ -271,10 +264,14 @@ abstract class PageDelegate(protected val pageView: PageView) { distanceY: Float ): Boolean { curPage?.contentTextView()?.let { - it.setTextIsSelectable(false) - it.movementMethod = scrollingMovementMethod + //滑动时禁止选择文字 + if (it.isTextSelectable) { + it.setTextIsSelectable(false) + it.movementMethod = scrollingMovementMethod + } } if (pageView.isScrollDelegate()) { + //传递触摸事件到textView curPage?.dispatchTouchEvent(e2) return true } From 0cadd39f42abb4e7b1d7d17e02a872c76ecd1ae2 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 22 Sep 2019 13:04:03 +0800 Subject: [PATCH 1597/1997] up --- .../io/legado/app/ui/widget/page/delegate/PageDelegate.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt index 7f9ea1292..c40802d74 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt @@ -173,6 +173,9 @@ abstract class PageDelegate(protected val pageView: PageView) { onScrollStart() } + /** + * 触摸事件处理 + */ fun onTouch(event: MotionEvent): Boolean { if (isStarted) return false if (curPage?.isTextSelected() == true) { @@ -206,7 +209,9 @@ abstract class PageDelegate(protected val pageView: PageView) { NONE, PREV, NEXT } - + /** + * 触摸事件处理 + */ private inner class GestureListener : GestureDetector.SimpleOnGestureListener() { override fun onDown(e: MotionEvent): Boolean { From aea04f9912522ceefc279441a275f2f899f4be12 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 22 Sep 2019 13:13:42 +0800 Subject: [PATCH 1598/1997] up --- .../java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt index c40802d74..a3352af33 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt @@ -278,7 +278,6 @@ abstract class PageDelegate(protected val pageView: PageView) { if (pageView.isScrollDelegate()) { //传递触摸事件到textView curPage?.dispatchTouchEvent(e2) - return true } if (!isMoved && abs(distanceX) > abs(distanceY)) { if (distanceX < 0) { From 6561e3c7bdd33eb6d1f7444acef0e512c27d76c7 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 22 Sep 2019 13:21:30 +0800 Subject: [PATCH 1599/1997] up --- app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index 258a7c928..8b5185bd9 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -51,6 +51,9 @@ class ContentView : FrameLayout { content_text_view.layout?.getLineForVertical(scrollY)?.let { line -> callBack?.scrollToLine(line) } + if (content_text_view.atBottom()) { + setPageIndex(pageSize - 1) + } } } From 09bf55bcf4ae484abe03e9377a6158984ecb72bd Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 22 Sep 2019 13:57:19 +0800 Subject: [PATCH 1600/1997] up --- .../io/legado/app/ui/widget/page/ContentTextView.kt | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt index fd406ea57..7b6665219 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt @@ -27,6 +27,7 @@ class ContentTextView : AppCompatTextView { private val scrollStateDragging = 1 val scrollStateSettling = 2 + private val mViewFling: ViewFling by lazy { ViewFling() } private var velocityTracker: VelocityTracker? = null private var mScrollState = scrollStateIdle private var mScrollPointerId = -1 @@ -34,7 +35,7 @@ class ContentTextView : AppCompatTextView { private var mTouchSlop: Int = 0 private var mMinFlingVelocity: Int = 0 private var mMaxFlingVelocity: Int = 0 - private val mViewFling = ViewFling() + //滑动距离的最大边界 private var mOffsetHeight: Int = 0 @@ -80,13 +81,8 @@ class ContentTextView : AppCompatTextView { initOffsetHeight() } - override fun onTextChanged( - text: CharSequence, - start: Int, - lengthBefore: Int, - lengthAfter: Int - ) { - super.onTextChanged(text, start, lengthBefore, lengthAfter) + override fun setText(text: CharSequence?, type: BufferType?) { + super.setText(text, type) initOffsetHeight() } From a2f49c7c0b2c17bb67ba9055e57033088f769b0c Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 22 Sep 2019 17:05:52 +0800 Subject: [PATCH 1601/1997] up --- .../app/ui/widget/page/TextPageFactory.kt | 10 +-- .../ui/widget/page/delegate/PageDelegate.kt | 39 ++++++++++-- .../page/delegate/ScrollPageDelegate.kt | 61 ++++++++++++++++++- 3 files changed, 100 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt index 6882dcae0..a69e37147 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt @@ -39,7 +39,9 @@ class TextPageFactory private constructor(dataSource: DataSource) : override fun moveToNext(): Boolean = dataSource.pageIndex().let { index -> return if (hasNext()) { - if (dataSource.getCurrentChapter()?.isLastIndex(index) == true) { + if (dataSource.getCurrentChapter()?.isLastIndex(index) == true + || dataSource.isScrollDelegate() + ) { dataSource.moveToNextChapter() } else { dataSource.setPageIndex(index.plus(1)) @@ -51,10 +53,10 @@ class TextPageFactory private constructor(dataSource: DataSource) : override fun moveToPrevious(): Boolean = dataSource.pageIndex().let { index -> return if (hasPrev()) { - if (index > 0) { - dataSource.setPageIndex(index.minus(1)) - } else { + if (index <= 0 || dataSource.isScrollDelegate()) { dataSource.moveToPrevChapter() + } else { + dataSource.setPageIndex(index.minus(1)) } true } else diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt index a3352af33..5a51d580c 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt @@ -176,7 +176,7 @@ abstract class PageDelegate(protected val pageView: PageView) { /** * 触摸事件处理 */ - fun onTouch(event: MotionEvent): Boolean { + open fun onTouch(event: MotionEvent): Boolean { if (isStarted) return false if (curPage?.isTextSelected() == true) { curPage?.dispatchTouchEvent(event) @@ -278,8 +278,35 @@ abstract class PageDelegate(protected val pageView: PageView) { if (pageView.isScrollDelegate()) { //传递触摸事件到textView curPage?.dispatchTouchEvent(e2) - } - if (!isMoved && abs(distanceX) > abs(distanceY)) { + if (!isMoved && abs(distanceX) < abs(distanceY)) { + if (distanceY < 0) { + //上一页的参数配置 + direction = Direction.PREV + //判断是否上一页存在 + val hasPrev = pageView.hasPrev() + //如果上一页不存在 + if (!hasPrev) { + noNext = true + return true + } + //上一页截图 + bitmap = prevPage?.screenshot() + } else { + //进行下一页的配置 + direction = Direction.NEXT + //判断是否下一页存在 + val hasNext = pageView.hasNext() + //如果不存在表示没有下一页了 + if (!hasNext) { + noNext = true + return true + } + //下一页截图 + bitmap = nextPage?.screenshot() + } + isMoved = true + } + } else if (!isMoved && abs(distanceX) > abs(distanceY)) { if (distanceX < 0) { //上一页的参数配置 direction = Direction.PREV @@ -308,7 +335,11 @@ abstract class PageDelegate(protected val pageView: PageView) { isMoved = true } if (isMoved) { - isCancel = if (direction == Direction.NEXT) distanceX < 0 else distanceX > 0 + isCancel = if (pageView.isScrollDelegate()) { + if (direction == Direction.NEXT) distanceY < 0 else distanceY > 0 + } else { + if (direction == Direction.NEXT) distanceX < 0 else distanceX > 0 + } isRunning = true //设置触摸点 setTouchPoint(e2.x, e2.y) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/ScrollPageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/ScrollPageDelegate.kt index 2da678320..0551673fb 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/ScrollPageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/ScrollPageDelegate.kt @@ -1,21 +1,78 @@ package io.legado.app.ui.widget.page.delegate import android.graphics.Canvas +import android.graphics.Matrix +import android.view.MotionEvent import io.legado.app.ui.widget.page.PageView class ScrollPageDelegate(pageView: PageView) : PageDelegate(pageView) { + private var atTop: Boolean = false + private var atBottom: Boolean = false + private val bitmapMatrix = Matrix() + + override fun onTouch(event: MotionEvent): Boolean { + if (event.action == MotionEvent.ACTION_DOWN) { + curPage?.contentTextView()?.let { + atTop = it.atTop() + atBottom = it.atBottom() + } + } + return super.onTouch(event) + } override fun onScrollStart() { + if (!atTop && !atBottom) { + stopScroll() + return + } + val distanceY: Float + when (direction) { + Direction.NEXT -> if (isCancel) { + var dis = viewHeight - startY + touchY + if (dis > viewHeight) { + dis = viewHeight.toFloat() + } + distanceY = viewHeight - dis + } else { + distanceY = -(touchY + (viewHeight - startY)) + } + else -> distanceY = if (isCancel) { + -(touchY - startY) + } else { + viewWidth - (touchY - startY) + } + } + startScroll(0, touchY.toInt(), 0, distanceY.toInt()) } override fun onDraw(canvas: Canvas) { + if (atTop || atBottom) { + val offsetY = touchY - startY + + if ((direction == Direction.NEXT && offsetY > 0) + || (direction == Direction.PREV && offsetY < 0) + ) return + val distanceY = if (offsetY > 0) offsetY - viewHeight else offsetY + viewHeight + if (atTop && direction == Direction.PREV) { + bitmap?.let { + bitmapMatrix.setTranslate(0.toFloat(), distanceY) + canvas.drawBitmap(it, bitmapMatrix, null) + } + } else if (atBottom && direction == Direction.NEXT) { + bitmap?.let { + bitmapMatrix.setTranslate(0.toFloat(), distanceY) + canvas.drawBitmap(it, bitmapMatrix, null) + } + } + } } override fun onScrollStop() { - + if (!isCancel) { + pageView.fillPage(direction) + } } - } \ No newline at end of file From 22f25494d60e15e691e960b77253bebfac0d625b Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 22 Sep 2019 17:45:04 +0800 Subject: [PATCH 1602/1997] up --- .../java/io/legado/app/ui/widget/page/ContentTextView.kt | 5 +++++ .../java/io/legado/app/ui/widget/page/ContentView.kt | 9 +++++++++ .../main/java/io/legado/app/ui/widget/page/PageView.kt | 5 ++++- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt index 7b6665219..7136d6b79 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt @@ -98,6 +98,11 @@ class ContentTextView : AppCompatTextView { mOffsetHeight = mLayoutHeight + totalPaddingTop + totalPaddingBottom - measuredHeight } + override fun scrollTo(x: Int, y: Int) { + setScrollState(scrollStateIdle) + super.scrollTo(x, min(y, mOffsetHeight)) + } + @SuppressLint("ClickableViewAccessibility") override fun onTouchEvent(event: MotionEvent?): Boolean { event?.let { diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index 8b5185bd9..118bcfa97 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -134,6 +134,15 @@ class ContentView : FrameLayout { } } + fun scrollToBottom() { + content_text_view.post { + content_text_view.scrollTo( + 0, + content_text_view.layout.getLineTop(content_text_view.lineCount) + ) + } + } + interface CallBack { fun scrollToLine(line: Int) } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 899937b37..114417973 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -70,14 +70,17 @@ class PageView(context: Context, attrs: AttributeSet) : when (direction) { PageDelegate.Direction.PREV -> { it.moveToPrevious() + upContent() + curPage?.scrollToBottom() } PageDelegate.Direction.NEXT -> { it.moveToNext() + upContent() + curPage?.scrollTo(0) } else -> return } } - upContent() } fun upPageAnim() { From 3a30ee98477877410bd343a76d636e95a946dd0c Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 22 Sep 2019 17:48:15 +0800 Subject: [PATCH 1603/1997] up --- .../main/java/io/legado/app/ui/widget/page/ContentTextView.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt index 7136d6b79..986fbeefd 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt @@ -99,7 +99,6 @@ class ContentTextView : AppCompatTextView { } override fun scrollTo(x: Int, y: Int) { - setScrollState(scrollStateIdle) super.scrollTo(x, min(y, mOffsetHeight)) } From 195841d94fc7bfa0b427933bfe0734efbd1abf2c Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 22 Sep 2019 18:34:26 +0800 Subject: [PATCH 1604/1997] up --- .../ui/widget/page/delegate/PageDelegate.kt | 65 ++++++++++++------- .../page/delegate/ScrollPageDelegate.kt | 14 +--- 2 files changed, 41 insertions(+), 38 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt index 5a51d580c..4e21d5bf5 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt @@ -38,6 +38,9 @@ abstract class PageDelegate(protected val pageView: PageView) { protected var viewWidth: Int = pageView.width protected var viewHeight: Int = pageView.height + //textView在顶端或低端 + protected var atTop: Boolean = false + protected var atBottom: Boolean = false private val scroller: Scroller by lazy { Scroller( @@ -176,15 +179,21 @@ abstract class PageDelegate(protected val pageView: PageView) { /** * 触摸事件处理 */ - open fun onTouch(event: MotionEvent): Boolean { + fun onTouch(event: MotionEvent): Boolean { if (isStarted) return false if (curPage?.isTextSelected() == true) { curPage?.dispatchTouchEvent(event) return true } if (event.action == MotionEvent.ACTION_DOWN) { - curPage?.contentTextView()?.setTextIsSelectable(true) - curPage?.dispatchTouchEvent(event) + curPage?.let { + it.contentTextView()?.let { contentTextView -> + contentTextView.setTextIsSelectable(true) + atTop = contentTextView.atTop() + atBottom = contentTextView.atBottom() + } + it.dispatchTouchEvent(event) + } } else if (event.action == MotionEvent.ACTION_UP) { curPage?.dispatchTouchEvent(event) if (isMoved) { @@ -276,36 +285,42 @@ abstract class PageDelegate(protected val pageView: PageView) { } } if (pageView.isScrollDelegate()) { - //传递触摸事件到textView - curPage?.dispatchTouchEvent(e2) if (!isMoved && abs(distanceX) < abs(distanceY)) { if (distanceY < 0) { - //上一页的参数配置 - direction = Direction.PREV - //判断是否上一页存在 - val hasPrev = pageView.hasPrev() - //如果上一页不存在 - if (!hasPrev) { - noNext = true - return true + if (atTop) { + //上一页的参数配置 + direction = Direction.PREV + //判断是否上一页存在 + val hasPrev = pageView.hasPrev() + //如果上一页不存在 + if (!hasPrev) { + noNext = true + return true + } + //上一页截图 + bitmap = prevPage?.screenshot() } - //上一页截图 - bitmap = prevPage?.screenshot() } else { - //进行下一页的配置 - direction = Direction.NEXT - //判断是否下一页存在 - val hasNext = pageView.hasNext() - //如果不存在表示没有下一页了 - if (!hasNext) { - noNext = true - return true + if (atBottom) { + //进行下一页的配置 + direction = Direction.NEXT + //判断是否下一页存在 + val hasNext = pageView.hasNext() + //如果不存在表示没有下一页了 + if (!hasNext) { + noNext = true + return true + } + //下一页截图 + bitmap = nextPage?.screenshot() } - //下一页截图 - bitmap = nextPage?.screenshot() } isMoved = true } + if ((atTop && direction != Direction.PREV) || (atBottom && direction != Direction.NEXT) || direction == Direction.NONE) { + //传递触摸事件到textView + curPage?.dispatchTouchEvent(e2) + } } else if (!isMoved && abs(distanceX) > abs(distanceY)) { if (distanceX < 0) { //上一页的参数配置 diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/ScrollPageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/ScrollPageDelegate.kt index 0551673fb..b7afc58b6 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/ScrollPageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/ScrollPageDelegate.kt @@ -2,23 +2,11 @@ package io.legado.app.ui.widget.page.delegate import android.graphics.Canvas import android.graphics.Matrix -import android.view.MotionEvent import io.legado.app.ui.widget.page.PageView class ScrollPageDelegate(pageView: PageView) : PageDelegate(pageView) { - private var atTop: Boolean = false - private var atBottom: Boolean = false - private val bitmapMatrix = Matrix() - override fun onTouch(event: MotionEvent): Boolean { - if (event.action == MotionEvent.ACTION_DOWN) { - curPage?.contentTextView()?.let { - atTop = it.atTop() - atBottom = it.atBottom() - } - } - return super.onTouch(event) - } + private val bitmapMatrix = Matrix() override fun onScrollStart() { if (!atTop && !atBottom) { From 7cba4b5152ebde296f4bbdab12d1abb1223e16a2 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 22 Sep 2019 19:07:26 +0800 Subject: [PATCH 1605/1997] up --- .../app/ui/widget/page/TextPageFactory.kt | 94 ++++++++++--------- 1 file changed, 51 insertions(+), 43 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt index a69e37147..aa8c1fcca 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt @@ -9,13 +9,21 @@ class TextPageFactory private constructor(dataSource: DataSource) : } } - override fun hasPrev(): Boolean { - return dataSource.hasPrevChapter() || dataSource.pageIndex() > 0 + override fun hasPrev(): Boolean = with(dataSource) { + return if (isScrollDelegate()) { + hasPrevChapter() + } else { + hasPrevChapter() || pageIndex() > 0 + } } - override fun hasNext(): Boolean { - return dataSource.hasNextChapter() - || dataSource.getCurrentChapter()?.isLastIndex(dataSource.pageIndex()) != true + override fun hasNext(): Boolean = with(dataSource) { + return if (isScrollDelegate()) { + hasNextChapter() + } else { + hasNextChapter() + || getCurrentChapter()?.isLastIndex(pageIndex()) != true + } } override fun pageAt(index: Int): TextPage { @@ -27,76 +35,76 @@ class TextPageFactory private constructor(dataSource: DataSource) : dataSource.setPageIndex(0) } - override fun moveToLast() { - dataSource.getCurrentChapter()?.let { + override fun moveToLast() = with(dataSource) { + getCurrentChapter()?.let { if (it.pageSize() == 0) { - dataSource.setPageIndex(0) + setPageIndex(0) } else { - dataSource.setPageIndex(it.pageSize().minus(1)) + setPageIndex(it.pageSize().minus(1)) } - } ?: dataSource.setPageIndex(0) + } ?: setPageIndex(0) } - override fun moveToNext(): Boolean = dataSource.pageIndex().let { index -> + override fun moveToNext(): Boolean = with(dataSource) { return if (hasNext()) { - if (dataSource.getCurrentChapter()?.isLastIndex(index) == true - || dataSource.isScrollDelegate() + if (getCurrentChapter()?.isLastIndex(pageIndex()) == true + || isScrollDelegate() ) { - dataSource.moveToNextChapter() + moveToNextChapter() } else { - dataSource.setPageIndex(index.plus(1)) + setPageIndex(pageIndex().plus(1)) } true } else false } - override fun moveToPrevious(): Boolean = dataSource.pageIndex().let { index -> + override fun moveToPrevious(): Boolean = with(dataSource) { return if (hasPrev()) { - if (index <= 0 || dataSource.isScrollDelegate()) { - dataSource.moveToPrevChapter() + if (pageIndex() <= 0 || isScrollDelegate()) { + moveToPrevChapter() } else { - dataSource.setPageIndex(index.minus(1)) + setPageIndex(pageIndex().minus(1)) } true } else false } - override fun currentPage(): TextPage? = dataSource.pageIndex().let { index -> - return if (dataSource.isScrollDelegate()) { - dataSource.getCurrentChapter()?.scrollPage() + override fun currentPage(): TextPage? = with(dataSource) { + return if (isScrollDelegate()) { + getCurrentChapter()?.scrollPage() } else { - dataSource.getCurrentChapter()?.page(index) - } ?: TextPage(index = index, title = "index:$index") + getCurrentChapter()?.page(pageIndex()) + } ?: TextPage(index = pageIndex(), title = "index:${pageIndex()}") } - override fun nextPage(): TextPage? = dataSource.pageIndex().let { index -> - if (dataSource.isScrollDelegate()) { - return dataSource.getNextChapter()?.scrollPage() - ?: TextPage(index = index + 1, title = "index:${index + 1}") + override fun nextPage(): TextPage? = with(dataSource) { + if (isScrollDelegate()) { + return getNextChapter()?.scrollPage() + ?: TextPage(index = pageIndex() + 1, title = "index:${pageIndex() + 1}") } - dataSource.getCurrentChapter()?.let { - if (index < it.pageSize() - 1) { - return dataSource.getCurrentChapter()?.page(index + 1)?.removePageAloudSpan() - ?: TextPage(index = index + 1, title = "index:${index + 1}") + getCurrentChapter()?.let { + if (pageIndex() < it.pageSize() - 1) { + return getCurrentChapter()?.page(pageIndex() + 1)?.removePageAloudSpan() + ?: TextPage(index = pageIndex() + 1, title = "index:${pageIndex() + 1}") } } - return dataSource.getNextChapter()?.page(0)?.removePageAloudSpan() - ?: TextPage(index = index + 1, title = "index:${index + 1}") + return getNextChapter()?.page(0)?.removePageAloudSpan() + ?: TextPage(index = pageIndex() + 1, title = "index:${pageIndex() + 1}") } - override fun previousPage(): TextPage? = dataSource.pageIndex().let { index -> - if (dataSource.isScrollDelegate()) { - return dataSource.getPreviousChapter()?.scrollPage() - ?: TextPage(index = index + 1, title = "index:${index + 1}") + override fun previousPage(): TextPage? = with(dataSource) { + if (isScrollDelegate()) { + return getPreviousChapter()?.scrollPage() + ?: TextPage(index = pageIndex() + 1, title = "index:${pageIndex() + 1}") } - if (index > 0) { - return dataSource.getCurrentChapter()?.page(index - 1)?.removePageAloudSpan() - ?: TextPage(index = index - 1, title = "index:${index - 1}") + if (pageIndex() > 0) { + return getCurrentChapter()?.page(pageIndex() - 1)?.removePageAloudSpan() + ?: TextPage(index = pageIndex() - 1, title = "index:${pageIndex() - 1}") } - return dataSource.getPreviousChapter()?.lastPage()?.removePageAloudSpan() - ?: TextPage(index = index - 1, title = "index:${index - 1}") + return getPreviousChapter()?.lastPage()?.removePageAloudSpan() + ?: TextPage(index = pageIndex() - 1, title = "index:${pageIndex() - 1}") } From 0c0d81c14b9b9b75ef03c2235e2255e4aea060bd Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 22 Sep 2019 19:09:47 +0800 Subject: [PATCH 1606/1997] up --- .../main/java/io/legado/app/ui/widget/page/PageView.kt | 2 +- .../java/io/legado/app/ui/widget/page/TextPageFactory.kt | 9 +-------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 114417973..474f74887 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -35,7 +35,7 @@ class PageView(context: Context, attrs: AttributeSet) : addView(curPage) upBg() setWillNotDraw(false) - pageFactory = TextPageFactory.create(this) + pageFactory = TextPageFactory(this) upPageAnim() curPage?.callBack = this } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt index aa8c1fcca..cfadbf7aa 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt @@ -1,13 +1,6 @@ package io.legado.app.ui.widget.page -class TextPageFactory private constructor(dataSource: DataSource) : - PageFactory(dataSource) { - - companion object { - fun create(dataSource: DataSource): TextPageFactory { - return TextPageFactory(dataSource) - } - } +class TextPageFactory(dataSource: DataSource) : PageFactory(dataSource) { override fun hasPrev(): Boolean = with(dataSource) { return if (isScrollDelegate()) { From c6b5ec21f22b1170846f52781c712956ce8e6247 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 22 Sep 2019 19:55:30 +0800 Subject: [PATCH 1607/1997] up --- .../app/ui/widget/page/ContentTextView.kt | 42 +++++++++---------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt index 986fbeefd..de0027c8f 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt @@ -125,31 +125,29 @@ class ContentTextView : AppCompatTextView { } MotionEvent.ACTION_MOVE -> { val index = event.findPointerIndex(mScrollPointerId) - if (index < 0) { - return false - } - - val y = (event.getY(index) + 0.5f).toInt() - var dy = mLastTouchY - y - - if (mScrollState != scrollStateDragging) { - var startScroll = false - - if (abs(dy) > mTouchSlop) { - if (dy > 0) { - dy -= mTouchSlop - } else { - dy += mTouchSlop + if (index > 0) { + val y = (event.getY(index) + 0.5f).toInt() + var dy = mLastTouchY - y + + if (mScrollState != scrollStateDragging) { + var startScroll = false + + if (abs(dy) > mTouchSlop) { + if (dy > 0) { + dy -= mTouchSlop + } else { + dy += mTouchSlop + } + startScroll = true + } + if (startScroll) { + setScrollState(scrollStateDragging) } - startScroll = true - } - if (startScroll) { - setScrollState(scrollStateDragging) } - } - if (mScrollState == scrollStateDragging) { - mLastTouchY = y + if (mScrollState == scrollStateDragging) { + mLastTouchY = y + } } } MotionEvent.ACTION_POINTER_UP -> { From f729531dacaa0d6df45f7b6d01efce43f1b331b2 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 22 Sep 2019 19:57:08 +0800 Subject: [PATCH 1608/1997] up --- .../java/io/legado/app/ui/widget/page/ContentTextView.kt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt index de0027c8f..5434744db 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt @@ -81,8 +81,13 @@ class ContentTextView : AppCompatTextView { initOffsetHeight() } - override fun setText(text: CharSequence?, type: BufferType?) { - super.setText(text, type) + override fun onTextChanged( + text: CharSequence?, + start: Int, + lengthBefore: Int, + lengthAfter: Int + ) { + super.onTextChanged(text, start, lengthBefore, lengthAfter) initOffsetHeight() } From 4247a573e02de9200c0b54b3fdd3d12c5400eabd Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 22 Sep 2019 20:21:46 +0800 Subject: [PATCH 1609/1997] up --- .../io/legado/app/ui/widget/page/delegate/PageDelegate.kt | 4 +++- app/src/main/res/layout/view_book_page.xml | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt index 4e21d5bf5..1017b2314 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt @@ -188,7 +188,9 @@ abstract class PageDelegate(protected val pageView: PageView) { if (event.action == MotionEvent.ACTION_DOWN) { curPage?.let { it.contentTextView()?.let { contentTextView -> - contentTextView.setTextIsSelectable(true) + if (!contentTextView.isTextSelectable) { + contentTextView.setTextIsSelectable(true) + } atTop = contentTextView.atTop() atBottom = contentTextView.atBottom() } diff --git a/app/src/main/res/layout/view_book_page.xml b/app/src/main/res/layout/view_book_page.xml index 59784756f..eb27614ad 100644 --- a/app/src/main/res/layout/view_book_page.xml +++ b/app/src/main/res/layout/view_book_page.xml @@ -32,7 +32,8 @@ android:id="@+id/content_text_view" android:layout_width="match_parent" android:layout_height="0dp" - android:layout_weight="1" /> + android:layout_weight="1" + android:textIsSelectable="true" /> Date: Sun, 22 Sep 2019 21:14:51 +0800 Subject: [PATCH 1610/1997] up --- .../java/io/legado/app/ui/widget/page/PageView.kt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 474f74887..f37622f4b 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -71,14 +71,19 @@ class PageView(context: Context, attrs: AttributeSet) : PageDelegate.Direction.PREV -> { it.moveToPrevious() upContent() - curPage?.scrollToBottom() } PageDelegate.Direction.NEXT -> { it.moveToNext() upContent() - curPage?.scrollTo(0) } - else -> return + else -> Unit + } + } + if (isScrollDelegate()) { + when (direction) { + PageDelegate.Direction.PREV -> curPage?.scrollToBottom() + PageDelegate.Direction.NEXT -> curPage?.scrollTo(0) + else -> Unit } } } From 3fe160100f73d4eb775f34de1b0cc073c21e6501 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 22 Sep 2019 21:18:22 +0800 Subject: [PATCH 1611/1997] up --- .../io/legado/app/ui/widget/page/PageView.kt | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index f37622f4b..5a1a9e78b 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -66,25 +66,22 @@ class PageView(context: Context, attrs: AttributeSet) : } fun fillPage(direction: PageDelegate.Direction) { - pageFactory?.let { - when (direction) { - PageDelegate.Direction.PREV -> { - it.moveToPrevious() - upContent() - } - PageDelegate.Direction.NEXT -> { - it.moveToNext() - upContent() + when (direction) { + PageDelegate.Direction.PREV -> { + pageFactory?.moveToPrevious() + upContent() + if (isScrollDelegate()) { + curPage?.scrollToBottom() } - else -> Unit } - } - if (isScrollDelegate()) { - when (direction) { - PageDelegate.Direction.PREV -> curPage?.scrollToBottom() - PageDelegate.Direction.NEXT -> curPage?.scrollTo(0) - else -> Unit + PageDelegate.Direction.NEXT -> { + pageFactory?.moveToNext() + upContent() + if (isScrollDelegate()) { + curPage?.scrollTo(0) + } } + else -> Unit } } From 2941f0ee371c0c5269a9f81ff9b02affb3a8379c Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 23 Sep 2019 08:14:32 +0800 Subject: [PATCH 1612/1997] up --- .../widget/page/delegate/EventExtensions.kt | 20 +++++++++++++++++++ .../ui/widget/page/delegate/PageDelegate.kt | 13 +++--------- 2 files changed, 23 insertions(+), 10 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/widget/page/delegate/EventExtensions.kt diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/EventExtensions.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/EventExtensions.kt new file mode 100644 index 000000000..99916e27a --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/EventExtensions.kt @@ -0,0 +1,20 @@ +package io.legado.app.ui.widget.page.delegate + +import android.view.MotionEvent + +fun MotionEvent.toAction(action: Int): MotionEvent { + return MotionEvent.obtain( + downTime, + eventTime, + action, + x, + y, + pressure, + size, + metaState, + xPrecision, + yPrecision, + deviceId, + edgeFlags + ) +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt index 1017b2314..96483e499 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt @@ -188,9 +188,6 @@ abstract class PageDelegate(protected val pageView: PageView) { if (event.action == MotionEvent.ACTION_DOWN) { curPage?.let { it.contentTextView()?.let { contentTextView -> - if (!contentTextView.isTextSelectable) { - contentTextView.setTextIsSelectable(true) - } atTop = contentTextView.atTop() atBottom = contentTextView.atBottom() } @@ -279,17 +276,11 @@ abstract class PageDelegate(protected val pageView: PageView) { distanceX: Float, distanceY: Float ): Boolean { - curPage?.contentTextView()?.let { - //滑动时禁止选择文字 - if (it.isTextSelectable) { - it.setTextIsSelectable(false) - it.movementMethod = scrollingMovementMethod - } - } if (pageView.isScrollDelegate()) { if (!isMoved && abs(distanceX) < abs(distanceY)) { if (distanceY < 0) { if (atTop) { + curPage?.dispatchTouchEvent(e1.toAction(MotionEvent.ACTION_UP)) //上一页的参数配置 direction = Direction.PREV //判断是否上一页存在 @@ -304,6 +295,7 @@ abstract class PageDelegate(protected val pageView: PageView) { } } else { if (atBottom) { + curPage?.dispatchTouchEvent(e1.toAction(MotionEvent.ACTION_UP)) //进行下一页的配置 direction = Direction.NEXT //判断是否下一页存在 @@ -324,6 +316,7 @@ abstract class PageDelegate(protected val pageView: PageView) { curPage?.dispatchTouchEvent(e2) } } else if (!isMoved && abs(distanceX) > abs(distanceY)) { + curPage?.dispatchTouchEvent(e1.toAction(MotionEvent.ACTION_UP)) if (distanceX < 0) { //上一页的参数配置 direction = Direction.PREV From 1b9449b622be7ebcb66fe6552ef53edda448c743 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 23 Sep 2019 08:15:22 +0800 Subject: [PATCH 1613/1997] up --- .../io/legado/app/ui/widget/page/delegate/PageDelegate.kt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt index 96483e499..b83e4bc88 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt @@ -3,7 +3,6 @@ package io.legado.app.ui.widget.page.delegate import android.graphics.Bitmap import android.graphics.Canvas import android.graphics.RectF -import android.text.method.ScrollingMovementMethod import android.view.GestureDetector import android.view.MotionEvent import android.widget.Scroller @@ -49,10 +48,6 @@ abstract class PageDelegate(protected val pageView: PageView) { ) } - private val scrollingMovementMethod: ScrollingMovementMethod by lazy { - ScrollingMovementMethod() - } - private val detector: GestureDetector by lazy { GestureDetector( pageView.context, From a3a86fb0442a71bf1a71bc0635dc8fee69d83aba Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 23 Sep 2019 08:49:11 +0800 Subject: [PATCH 1614/1997] up --- .../io/legado/app/ui/widget/page/delegate/PageDelegate.kt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt index b83e4bc88..9ce140145 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt @@ -94,7 +94,7 @@ abstract class PageDelegate(protected val pageView: PageView) { startY, dx, dy, - getDuration((if (dx != 0) dx else dy).toFloat()) + if (dx != 0) getDuration(dx, viewWidth) else getDuration(dy, viewHeight) ) isRunning = true isStarted = true @@ -109,9 +109,8 @@ abstract class PageDelegate(protected val pageView: PageView) { invalidate() } - protected fun getDuration(distance: Float): Int { - val duration = 300 * abs(distance) / viewWidth - return duration.toInt() + private fun getDuration(distance: Int, len: Int): Int { + return (300f * abs(distance) / len).toInt() } fun setViewSize(width: Int, height: Int) { From 0dffb04e353f6bf7e4b9031391b12c8e4b3fa302 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 23 Sep 2019 08:57:06 +0800 Subject: [PATCH 1615/1997] up --- .../main/java/io/legado/app/ui/widget/page/ContentView.kt | 1 + app/src/main/java/io/legado/app/ui/widget/page/PageView.kt | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index 118bcfa97..bcde1f376 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -145,5 +145,6 @@ class ContentView : FrameLayout { interface CallBack { fun scrollToLine(line: Int) + fun scrollToLast() } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 5a1a9e78b..447b6b1e6 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -228,6 +228,12 @@ class PageView(context: Context, attrs: AttributeSet) : } } + override fun scrollToLast() { + callback?.textChapter()?.let { + callback?.setPageIndex(it.lastIndex()) + } + } + interface CallBack { fun chapterSize(): Int fun durChapterIndex(): Int From 4cd983f331efa19c6dcb1051eccb0ee456d92070 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 23 Sep 2019 09:06:49 +0800 Subject: [PATCH 1616/1997] up --- .../io/legado/app/ui/widget/page/ContentView.kt | 1 + .../io/legado/app/ui/widget/page/PageView.kt | 16 ++++++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index bcde1f376..a3a9639b9 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -53,6 +53,7 @@ class ContentView : FrameLayout { } if (content_text_view.atBottom()) { setPageIndex(pageSize - 1) + callBack?.scrollToLast() } } } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 447b6b1e6..12b90dae2 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -221,16 +221,20 @@ class PageView(context: Context, attrs: AttributeSet) : } override fun scrollToLine(line: Int) { - callback?.textChapter()?.let { - val pageIndex = it.getPageIndex(line) - curPage?.setPageIndex(pageIndex) - callback?.setPageIndex(pageIndex) + if (isScrollDelegate()) { + callback?.textChapter()?.let { + val pageIndex = it.getPageIndex(line) + curPage?.setPageIndex(pageIndex) + callback?.setPageIndex(pageIndex) + } } } override fun scrollToLast() { - callback?.textChapter()?.let { - callback?.setPageIndex(it.lastIndex()) + if (isScrollDelegate()) { + callback?.textChapter()?.let { + callback?.setPageIndex(it.lastIndex()) + } } } From e16cb8df0a054f26f0cae04df3f930edcf353028 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 23 Sep 2019 09:41:40 +0800 Subject: [PATCH 1617/1997] up --- .../app/ui/book/read/ReadBookActivity.kt | 20 +++++--- .../legado/app/ui/widget/page/DataSource.kt | 4 +- .../io/legado/app/ui/widget/page/PageView.kt | 36 +++++++++----- .../app/ui/widget/page/TextPageFactory.kt | 48 +++++++++---------- .../ui/widget/page/delegate/PageDelegate.kt | 4 +- 5 files changed, 65 insertions(+), 47 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt index b1d735117..dbcc05184 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt @@ -582,16 +582,24 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea observeEvent(Bus.TTS_TURN_PAGE) { when (it) { 1 -> { - viewModel.durPageIndex = viewModel.durPageIndex + 1 - page_view.upContent() - viewModel.saveRead() + if (page_view.isScrollDelegate) { + page_view.moveToNextPage() + } else { + viewModel.durPageIndex = viewModel.durPageIndex + 1 + page_view.upContent() + viewModel.saveRead() + } } 2 -> if (!moveToNextChapter(true)) ReadAloud.stop(this) -1 -> { if (viewModel.durPageIndex > 0) { - viewModel.durPageIndex = viewModel.durPageIndex - 1 - page_view.upContent() - viewModel.saveRead() + if (page_view.isScrollDelegate) { + page_view.moveToPrevPage() + } else { + viewModel.durPageIndex = viewModel.durPageIndex - 1 + page_view.upContent() + viewModel.saveRead() + } } else { moveToPrevChapter(true) } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt b/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt index fabb55a06..01c84da91 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/DataSource.kt @@ -1,9 +1,9 @@ package io.legado.app.ui.widget.page interface DataSource { - fun isScrollDelegate(): Boolean + val isScrollDelegate: Boolean - fun pageIndex(): Int + val pageIndex: Int fun setPageIndex(pageIndex: Int) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 12b90dae2..50d6ff59c 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -70,14 +70,14 @@ class PageView(context: Context, attrs: AttributeSet) : PageDelegate.Direction.PREV -> { pageFactory?.moveToPrevious() upContent() - if (isScrollDelegate()) { + if (isScrollDelegate) { curPage?.scrollToBottom() } } PageDelegate.Direction.NEXT -> { pageFactory?.moveToNext() upContent() - if (isScrollDelegate()) { + if (isScrollDelegate) { curPage?.scrollTo(0) } } @@ -106,7 +106,7 @@ class PageView(context: Context, attrs: AttributeSet) : nextPage?.setContent(it.nextPage()) prevPage?.setContent(it.previousPage()) callback?.let { callback -> - if (isScrollDelegate()) { + if (isScrollDelegate) { curPage?.scrollTo(callback.textChapter()?.getStartLine(callback.durChapterPos())) } } @@ -117,13 +117,25 @@ class PageView(context: Context, attrs: AttributeSet) : fun moveToPrevPage(noAnim: Boolean = true) { if (noAnim) { - fillPage(PageDelegate.Direction.PREV) + if (isScrollDelegate) { + callback?.textChapter()?.let { + curPage?.scrollTo(it.getStartLine(pageIndex - 1)) + } + } else { + fillPage(PageDelegate.Direction.PREV) + } } } fun moveToNextPage(noAnim: Boolean = true) { if (noAnim) { - fillPage(PageDelegate.Direction.NEXT) + if (isScrollDelegate) { + callback?.textChapter()?.let { + curPage?.scrollTo(it.getStartLine(pageIndex + 1)) + } + } else { + fillPage(PageDelegate.Direction.NEXT) + } } } @@ -166,13 +178,11 @@ class PageView(context: Context, attrs: AttributeSet) : callback?.clickCenter() } - override fun isScrollDelegate(): Boolean { - return pageDelegate is ScrollPageDelegate - } + override val isScrollDelegate: Boolean + get() = pageDelegate is ScrollPageDelegate - override fun pageIndex(): Int { - return callback?.durChapterPos() ?: 0 - } + override val pageIndex: Int + get() = callback?.durChapterPos() ?: 0 override fun setPageIndex(pageIndex: Int) { callback?.setPageIndex(pageIndex) @@ -221,7 +231,7 @@ class PageView(context: Context, attrs: AttributeSet) : } override fun scrollToLine(line: Int) { - if (isScrollDelegate()) { + if (isScrollDelegate) { callback?.textChapter()?.let { val pageIndex = it.getPageIndex(line) curPage?.setPageIndex(pageIndex) @@ -231,7 +241,7 @@ class PageView(context: Context, attrs: AttributeSet) : } override fun scrollToLast() { - if (isScrollDelegate()) { + if (isScrollDelegate) { callback?.textChapter()?.let { callback?.setPageIndex(it.lastIndex()) } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt index cfadbf7aa..544049bdc 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt @@ -3,19 +3,19 @@ package io.legado.app.ui.widget.page class TextPageFactory(dataSource: DataSource) : PageFactory(dataSource) { override fun hasPrev(): Boolean = with(dataSource) { - return if (isScrollDelegate()) { + return if (isScrollDelegate) { hasPrevChapter() } else { - hasPrevChapter() || pageIndex() > 0 + hasPrevChapter() || pageIndex > 0 } } override fun hasNext(): Boolean = with(dataSource) { - return if (isScrollDelegate()) { + return if (isScrollDelegate) { hasNextChapter() } else { hasNextChapter() - || getCurrentChapter()?.isLastIndex(pageIndex()) != true + || getCurrentChapter()?.isLastIndex(pageIndex) != true } } @@ -40,12 +40,12 @@ class TextPageFactory(dataSource: DataSource) : PageFactory(dataSource override fun moveToNext(): Boolean = with(dataSource) { return if (hasNext()) { - if (getCurrentChapter()?.isLastIndex(pageIndex()) == true - || isScrollDelegate() + if (getCurrentChapter()?.isLastIndex(pageIndex) == true + || isScrollDelegate ) { moveToNextChapter() } else { - setPageIndex(pageIndex().plus(1)) + setPageIndex(pageIndex.plus(1)) } true } else @@ -54,10 +54,10 @@ class TextPageFactory(dataSource: DataSource) : PageFactory(dataSource override fun moveToPrevious(): Boolean = with(dataSource) { return if (hasPrev()) { - if (pageIndex() <= 0 || isScrollDelegate()) { + if (pageIndex <= 0 || isScrollDelegate) { moveToPrevChapter() } else { - setPageIndex(pageIndex().minus(1)) + setPageIndex(pageIndex.minus(1)) } true } else @@ -65,39 +65,39 @@ class TextPageFactory(dataSource: DataSource) : PageFactory(dataSource } override fun currentPage(): TextPage? = with(dataSource) { - return if (isScrollDelegate()) { + return if (isScrollDelegate) { getCurrentChapter()?.scrollPage() } else { - getCurrentChapter()?.page(pageIndex()) - } ?: TextPage(index = pageIndex(), title = "index:${pageIndex()}") + getCurrentChapter()?.page(pageIndex) + } ?: TextPage(index = pageIndex, title = "index:${pageIndex}") } override fun nextPage(): TextPage? = with(dataSource) { - if (isScrollDelegate()) { + if (isScrollDelegate) { return getNextChapter()?.scrollPage() - ?: TextPage(index = pageIndex() + 1, title = "index:${pageIndex() + 1}") + ?: TextPage(index = pageIndex + 1, title = "index:${pageIndex + 1}") } getCurrentChapter()?.let { - if (pageIndex() < it.pageSize() - 1) { - return getCurrentChapter()?.page(pageIndex() + 1)?.removePageAloudSpan() - ?: TextPage(index = pageIndex() + 1, title = "index:${pageIndex() + 1}") + if (pageIndex < it.pageSize() - 1) { + return getCurrentChapter()?.page(pageIndex + 1)?.removePageAloudSpan() + ?: TextPage(index = pageIndex + 1, title = "index:${pageIndex + 1}") } } return getNextChapter()?.page(0)?.removePageAloudSpan() - ?: TextPage(index = pageIndex() + 1, title = "index:${pageIndex() + 1}") + ?: TextPage(index = pageIndex + 1, title = "index:${pageIndex + 1}") } override fun previousPage(): TextPage? = with(dataSource) { - if (isScrollDelegate()) { + if (isScrollDelegate) { return getPreviousChapter()?.scrollPage() - ?: TextPage(index = pageIndex() + 1, title = "index:${pageIndex() + 1}") + ?: TextPage(index = pageIndex + 1, title = "index:${pageIndex + 1}") } - if (pageIndex() > 0) { - return getCurrentChapter()?.page(pageIndex() - 1)?.removePageAloudSpan() - ?: TextPage(index = pageIndex() - 1, title = "index:${pageIndex() - 1}") + if (pageIndex > 0) { + return getCurrentChapter()?.page(pageIndex - 1)?.removePageAloudSpan() + ?: TextPage(index = pageIndex - 1, title = "index:${pageIndex - 1}") } return getPreviousChapter()?.lastPage()?.removePageAloudSpan() - ?: TextPage(index = pageIndex() - 1, title = "index:${pageIndex() - 1}") + ?: TextPage(index = pageIndex - 1, title = "index:${pageIndex - 1}") } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt index 9ce140145..deae2f920 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt @@ -270,7 +270,7 @@ abstract class PageDelegate(protected val pageView: PageView) { distanceX: Float, distanceY: Float ): Boolean { - if (pageView.isScrollDelegate()) { + if (pageView.isScrollDelegate) { if (!isMoved && abs(distanceX) < abs(distanceY)) { if (distanceY < 0) { if (atTop) { @@ -339,7 +339,7 @@ abstract class PageDelegate(protected val pageView: PageView) { isMoved = true } if (isMoved) { - isCancel = if (pageView.isScrollDelegate()) { + isCancel = if (pageView.isScrollDelegate) { if (direction == Direction.NEXT) distanceY < 0 else distanceY > 0 } else { if (direction == Direction.NEXT) distanceX < 0 else distanceX > 0 From 975bd42526fbb4a5f6d0d80f55df2c68cad56ee7 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 23 Sep 2019 10:39:20 +0800 Subject: [PATCH 1618/1997] up --- app/src/main/java/io/legado/app/model/WebBook.kt | 1 + .../java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt | 2 +- .../java/io/legado/app/model/webbook/BookChapterList.kt | 9 +++++++-- .../main/java/io/legado/app/model/webbook/BookContent.kt | 5 +++-- .../main/java/io/legado/app/model/webbook/BookInfo.kt | 4 ++-- .../main/java/io/legado/app/model/webbook/BookList.kt | 4 ++-- 6 files changed, 16 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/WebBook.kt b/app/src/main/java/io/legado/app/model/WebBook.kt index 6e00a80bc..a09e9f326 100644 --- a/app/src/main/java/io/legado/app/model/WebBook.kt +++ b/app/src/main/java/io/legado/app/model/WebBook.kt @@ -114,6 +114,7 @@ class WebBook(val bookSource: BookSource) { book, bookChapter, bookSource, + analyzeUrl, nextChapterUrl ) } diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt index 080345ab1..654882cc2 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt @@ -30,7 +30,7 @@ import javax.script.SimpleBindings @Keep @SuppressLint("DefaultLocale") class AnalyzeUrl( - private var ruleUrl: String, + var ruleUrl: String, key: String? = null, page: Int? = null, headerMapF: Map? = null, diff --git a/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt b/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt index 3557ea844..13c4ab54b 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt @@ -26,8 +26,13 @@ object BookChapterList { var chapterList = arrayListOf() val baseUrl: String = NetworkUtils.getUrl(response) val body: String? = response.body() - body ?: throw Exception(App.INSTANCE.getString(R.string.error_get_web_content, baseUrl)) - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取成功:$baseUrl") + body ?: throw Exception( + App.INSTANCE.getString( + R.string.error_get_web_content, + analyzeUrl.ruleUrl + ) + ) + SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取成功:${analyzeUrl.ruleUrl}") val tocRule = bookSource.getTocRule() val nextUrlList = arrayListOf(baseUrl) var reverse = false diff --git a/app/src/main/java/io/legado/app/model/webbook/BookContent.kt b/app/src/main/java/io/legado/app/model/webbook/BookContent.kt index 0f78b9d4a..fc5178104 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookContent.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookContent.kt @@ -23,6 +23,7 @@ object BookContent { book: Book, bookChapter: BookChapter, bookSource: BookSource, + analyzeUrl: AnalyzeUrl, nextChapterUrlF: String? = null ): String { val baseUrl: String = NetworkUtils.getUrl(response) @@ -30,10 +31,10 @@ object BookContent { body ?: throw Exception( App.INSTANCE.getString( R.string.error_get_web_content, - baseUrl + analyzeUrl.ruleUrl ) ) - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取成功:$baseUrl") + SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取成功:${analyzeUrl.ruleUrl}") val content = StringBuilder() val nextUrlList = arrayListOf(baseUrl) val contentRule = bookSource.getContentRule() diff --git a/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt b/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt index 1a7c5051c..c80ce8c55 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt @@ -21,10 +21,10 @@ object BookInfo { body ?: throw Exception( App.INSTANCE.getString( R.string.error_get_web_content, - baseUrl + analyzeUrl.ruleUrl ) ) - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取成功:$baseUrl") + SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取成功:${analyzeUrl.ruleUrl}") val infoRule = bookSource.getBookInfoRule() val analyzeRule = AnalyzeRule(book) analyzeRule.setContent(body, baseUrl) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookList.kt b/app/src/main/java/io/legado/app/model/webbook/BookList.kt index 1e2bfb6c9..8d953c342 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookList.kt @@ -25,10 +25,10 @@ object BookList { body ?: throw Exception( App.INSTANCE.getString( R.string.error_get_web_content, - baseUrl + analyzeUrl.ruleUrl ) ) - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取成功:$baseUrl") + SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取成功:${analyzeUrl.ruleUrl}") val analyzeRule = AnalyzeRule(null) analyzeRule.setContent(body, baseUrl) bookSource.bookUrlPattern?.let { From a7325b1e12dd5b216026b43072895409cdf4a80d Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 23 Sep 2019 10:56:20 +0800 Subject: [PATCH 1619/1997] up --- app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt b/app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt index 8c624a7e8..128fb6078 100644 --- a/app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt +++ b/app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt @@ -18,7 +18,7 @@ import kotlin.math.min object WebDavHelp { private val zipFilePath = FileHelp.getCachePath() + "/backup" + ".zip" - fun getWebDavUrl(): String? { + private fun getWebDavUrl(): String? { var url = App.INSTANCE.getPrefString("web_dav_url") if (url.isNullOrBlank()) return null if (!url.endsWith("/")) url += "/" From 71c95a37fb016f18a40a6e84b7c505fc527895ca Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 23 Sep 2019 11:40:04 +0800 Subject: [PATCH 1620/1997] up --- .../main/java/io/legado/app/lib/webdav/WebDav.kt | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt b/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt index 29229bbbb..d7aa3c137 100644 --- a/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt +++ b/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt @@ -20,9 +20,9 @@ import java.net.URLEncoder import java.util.* class WebDav @Throws(MalformedURLException::class) -constructor(url: String) { +constructor(urlStr: String) { private val okHttpClient = HttpHelper.client - private val url: URL = URL(null, url, Handler) + private val url: URL = URL(null, urlStr, Handler) private var httpUrl: String? = null var displayName: String? = null @@ -32,9 +32,10 @@ constructor(url: String) { var urlName = "" get() { if (field.isEmpty()) { - this.urlName = (if (parent.isEmpty()) url.file else url.toString() - .replace(parent, "")) - .replace("/", "") + this.urlName = ( + if (parent.isEmpty()) url.file + else url.toString().replace(parent, "") + ).replace("/", "") } return field } @@ -140,9 +141,7 @@ constructor(url: String) { Credentials.basic(it.user, it.pass) ) } - request.header("Depth", if (depth < 0) "infinity" else depth.toString()) - return okHttpClient.newCall(request.build()).execute() } return null @@ -238,7 +237,6 @@ constructor(url: String) { Credentials.basic(it.user, it.pass) ) } - val response = okHttpClient.newCall(requestBuilder.build()).execute() return response.isSuccessful } From 3fb3a0e02424e83d8cb4610b318cc36a162489de Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 23 Sep 2019 11:48:54 +0800 Subject: [PATCH 1621/1997] up --- .../java/io/legado/app/lib/webdav/WebDav.kt | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt b/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt index d7aa3c137..904c143db 100644 --- a/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt +++ b/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt @@ -1,10 +1,10 @@ package io.legado.app.lib.webdav -import io.legado.app.help.http.HttpHelper import io.legado.app.lib.webdav.http.Handler import io.legado.app.lib.webdav.http.HttpAuth import okhttp3.Credentials import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.RequestBody.Companion.asRequestBody import okhttp3.RequestBody.Companion.toRequestBody @@ -21,7 +21,19 @@ import java.util.* class WebDav @Throws(MalformedURLException::class) constructor(urlStr: String) { - private val okHttpClient = HttpHelper.client + companion object { + private val okHttpClient by lazy { + OkHttpClient.Builder().build() + } + // 指定返回哪些属性 + private const val DIR = """\n + \n + \n + \n\n\n\n\n%s + \n + """ + + } private val url: URL = URL(null, urlStr, Handler) private var httpUrl: String? = null @@ -257,15 +269,4 @@ constructor(urlStr: String) { this.exists = exists } - companion object { - - // 指定返回哪些属性 - private const val DIR = """\n - \n - \n - \n\n\n\n\n%s - \n - """ - - } } \ No newline at end of file From eea45d86f816faaae656979367001da49a9bfd8d Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 23 Sep 2019 12:18:56 +0800 Subject: [PATCH 1622/1997] up --- .../java/io/legado/app/lib/webdav/WebDav.kt | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt b/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt index 904c143db..ed73e649d 100644 --- a/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt +++ b/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt @@ -1,10 +1,10 @@ package io.legado.app.lib.webdav +import io.legado.app.help.http.HttpHelper import io.legado.app.lib.webdav.http.Handler import io.legado.app.lib.webdav.http.HttpAuth import okhttp3.Credentials import okhttp3.MediaType.Companion.toMediaTypeOrNull -import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.RequestBody.Companion.asRequestBody import okhttp3.RequestBody.Companion.toRequestBody @@ -22,17 +22,13 @@ import java.util.* class WebDav @Throws(MalformedURLException::class) constructor(urlStr: String) { companion object { - private val okHttpClient by lazy { - OkHttpClient.Builder().build() - } // 指定返回哪些属性 - private const val DIR = """\n - \n - \n - \n\n\n\n\n%s - \n - """ - + private const val DIR = "\n" + + "\n" + + "\n" + + "\n\n\n\n\n%s" + + "\n" + + "" } private val url: URL = URL(null, urlStr, Handler) private var httpUrl: String? = null @@ -64,7 +60,7 @@ constructor(urlStr: String) { } try { - return okHttpClient.newCall(request.build()).execute().body?.byteStream() + return HttpHelper.client.newCall(request.build()).execute().body?.byteStream() } catch (e: IOException) { e.printStackTrace() } catch (e: IllegalArgumentException) { @@ -154,7 +150,7 @@ constructor(urlStr: String) { ) } request.header("Depth", if (depth < 0) "infinity" else depth.toString()) - return okHttpClient.newCall(request.build()).execute() + return HttpHelper.client.newCall(request.build()).execute() } return null } @@ -249,7 +245,7 @@ constructor(urlStr: String) { Credentials.basic(it.user, it.pass) ) } - val response = okHttpClient.newCall(requestBuilder.build()).execute() + val response = HttpHelper.client.newCall(requestBuilder.build()).execute() return response.isSuccessful } From d91e5bfa27718f4f27e0f423d11e2fa8c42b06f9 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 23 Sep 2019 12:35:45 +0800 Subject: [PATCH 1623/1997] up --- .../java/io/legado/app/lib/webdav/WebDav.kt | 72 +++++++++---------- 1 file changed, 34 insertions(+), 38 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt b/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt index ed73e649d..cdd53bf55 100644 --- a/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt +++ b/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt @@ -31,7 +31,18 @@ constructor(urlStr: String) { "" } private val url: URL = URL(null, urlStr, Handler) - private var httpUrl: String? = null + private val httpUrl: String? by lazy { + val raw = url.toString().replace("davs://", "https://").replace("dav://", "http://") + try { + return@lazy URLEncoder.encode(raw, "UTF-8") + .replace("\\+".toRegex(), "%20") + .replace("%3A".toRegex(), ":") + .replace("%2F".toRegex(), "/") + } catch (e: UnsupportedEncodingException) { + e.printStackTrace() + return@lazy null + } + } var displayName: String? = null var size: Long = 0 @@ -52,38 +63,6 @@ constructor(urlStr: String) { fun getHost() = url.host - private val inputStream: InputStream? - get() = getUrl()?.let { url -> - val request = Request.Builder().url(url) - HttpAuth.auth?.let { - request.header("Authorization", Credentials.basic(it.user, it.pass)) - } - - try { - return HttpHelper.client.newCall(request.build()).execute().body?.byteStream() - } catch (e: IOException) { - e.printStackTrace() - } catch (e: IllegalArgumentException) { - e.printStackTrace() - } - return null - } - - private fun getUrl(): String? { - if (httpUrl == null) { - val raw = url.toString().replace("davs://", "https://").replace("dav://", "http://") - try { - httpUrl = URLEncoder.encode(raw, "UTF-8") - .replace("\\+".toRegex(), "%20") - .replace("%3A".toRegex(), ":") - .replace("%2F".toRegex(), "/") - } catch (e: UnsupportedEncodingException) { - e.printStackTrace() - } - } - return httpUrl - } - /** * 填充文件信息。实例化WebDAVFile对象时,并没有将远程文件的信息填充到实例中。需要手动填充! * @@ -136,7 +115,7 @@ constructor(urlStr: String) { } else { String.format(DIR, requestProps.toString() + "\n") } - getUrl()?.let { url -> + httpUrl?.let { url -> val request = Request.Builder() .url(url) // 添加RequestBody对象,可以只返回的属性。如果设为null,则会返回全部属性 @@ -159,7 +138,7 @@ constructor(urlStr: String) { val list = ArrayList() val document = Jsoup.parse(s) val elements = document.getElementsByTag("d:response") - getUrl()?.let { url -> + httpUrl?.let { url -> val baseUrl = if (url.endsWith("/")) url else "$url/" for (element in elements) { val href = element.getElementsByTag("d:href")[0].text() @@ -187,7 +166,7 @@ constructor(urlStr: String) { */ @Throws(IOException::class) fun makeAsDir(): Boolean { - getUrl()?.let { url -> + httpUrl?.let { url -> val request = Request.Builder() .url(url) .method("MKCOL", null) @@ -207,7 +186,7 @@ constructor(urlStr: String) { if (File(savedPath).exists()) { if (!replaceExisting) return false } - val inputS = inputStream ?: return false + val inputS = getInputStream() ?: return false File(savedPath).writeBytes(inputS.readBytes()) return true } @@ -223,7 +202,7 @@ constructor(urlStr: String) { val mediaType = contentType?.toMediaTypeOrNull() // 务必注意RequestBody不要嵌套,不然上传时内容可能会被追加多余的文件信息 val fileBody = file.asRequestBody(mediaType) - getUrl()?.let { + httpUrl?.let { val request = Request.Builder() .url(it) .put(fileBody) @@ -249,6 +228,23 @@ constructor(urlStr: String) { return response.isSuccessful } + private fun getInputStream(): InputStream? { + httpUrl?.let { url -> + val request = Request.Builder().url(url) + HttpAuth.auth?.let { + request.header("Authorization", Credentials.basic(it.user, it.pass)) + } + try { + return HttpHelper.client.newCall(request.build()).execute().body?.byteStream() + } catch (e: IOException) { + e.printStackTrace() + } catch (e: IllegalArgumentException) { + e.printStackTrace() + } + } + return null + } + fun canRead(): Boolean { return true } From 1c5f40e0bf857a5c4949090d8e9cecc7e0307381 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 23 Sep 2019 12:36:52 +0800 Subject: [PATCH 1624/1997] up --- app/src/main/java/io/legado/app/lib/webdav/WebDav.kt | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt b/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt index cdd53bf55..35f43a441 100644 --- a/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt +++ b/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt @@ -46,7 +46,7 @@ constructor(urlStr: String) { var displayName: String? = null var size: Long = 0 - private var exists = false + var exists = false var parent = "" var urlName = "" get() { @@ -253,12 +253,4 @@ constructor(urlStr: String) { return false } - fun exists(): Boolean { - return exists - } - - fun exists(exists: Boolean) { - this.exists = exists - } - } \ No newline at end of file From 8a653f17ac995ee792525138494f409085bd5079 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 23 Sep 2019 12:37:27 +0800 Subject: [PATCH 1625/1997] up --- app/src/main/java/io/legado/app/lib/webdav/WebDav.kt | 8 -------- 1 file changed, 8 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt b/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt index 35f43a441..8cf806786 100644 --- a/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt +++ b/app/src/main/java/io/legado/app/lib/webdav/WebDav.kt @@ -245,12 +245,4 @@ constructor(urlStr: String) { return null } - fun canRead(): Boolean { - return true - } - - fun canWrite(): Boolean { - return false - } - } \ No newline at end of file From ff717c16d236c632ba035a75b694acb5d1be2e05 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 23 Sep 2019 14:02:46 +0800 Subject: [PATCH 1626/1997] up --- .../ui/widget/page/delegate/PageDelegate.kt | 64 +++++++++++-------- 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt index deae2f920..05692299c 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt @@ -274,7 +274,9 @@ abstract class PageDelegate(protected val pageView: PageView) { if (!isMoved && abs(distanceX) < abs(distanceY)) { if (distanceY < 0) { if (atTop) { - curPage?.dispatchTouchEvent(e1.toAction(MotionEvent.ACTION_UP)) + val event = e1.toAction(MotionEvent.ACTION_UP) + curPage?.dispatchTouchEvent(event) + event.recycle() //上一页的参数配置 direction = Direction.PREV //判断是否上一页存在 @@ -289,7 +291,9 @@ abstract class PageDelegate(protected val pageView: PageView) { } } else { if (atBottom) { - curPage?.dispatchTouchEvent(e1.toAction(MotionEvent.ACTION_UP)) + val event = e1.toAction(MotionEvent.ACTION_UP) + curPage?.dispatchTouchEvent(event) + event.recycle() //进行下一页的配置 direction = Direction.NEXT //判断是否下一页存在 @@ -309,34 +313,38 @@ abstract class PageDelegate(protected val pageView: PageView) { //传递触摸事件到textView curPage?.dispatchTouchEvent(e2) } - } else if (!isMoved && abs(distanceX) > abs(distanceY)) { - curPage?.dispatchTouchEvent(e1.toAction(MotionEvent.ACTION_UP)) - if (distanceX < 0) { - //上一页的参数配置 - direction = Direction.PREV - //判断是否上一页存在 - val hasPrev = pageView.hasPrev() - //如果上一页不存在 - if (!hasPrev) { - noNext = true - return true - } - //上一页截图 - bitmap = prevPage?.screenshot() - } else { - //进行下一页的配置 - direction = Direction.NEXT - //判断是否下一页存在 - val hasNext = pageView.hasNext() - //如果不存在表示没有下一页了 - if (!hasNext) { - noNext = true - return true + } else if (!isMoved) { + val event = e1.toAction(MotionEvent.ACTION_UP) + curPage?.dispatchTouchEvent(event) + event.recycle() + if (abs(distanceX) > abs(distanceY)) { + if (distanceX < 0) { + //上一页的参数配置 + direction = Direction.PREV + //判断是否上一页存在 + val hasPrev = pageView.hasPrev() + //如果上一页不存在 + if (!hasPrev) { + noNext = true + return true + } + //上一页截图 + bitmap = prevPage?.screenshot() + } else { + //进行下一页的配置 + direction = Direction.NEXT + //判断是否下一页存在 + val hasNext = pageView.hasNext() + //如果不存在表示没有下一页了 + if (!hasNext) { + noNext = true + return true + } + //下一页截图 + bitmap = nextPage?.screenshot() } - //下一页截图 - bitmap = nextPage?.screenshot() + isMoved = true } - isMoved = true } if (isMoved) { isCancel = if (pageView.isScrollDelegate) { From 4e0ff507771dbb5d71f36bac44cf95b4d471a856 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 23 Sep 2019 14:14:49 +0800 Subject: [PATCH 1627/1997] up --- app/src/main/java/io/legado/app/ui/widget/page/PageView.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 50d6ff59c..e2eadce31 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -108,6 +108,7 @@ class PageView(context: Context, attrs: AttributeSet) : callback?.let { callback -> if (isScrollDelegate) { curPage?.scrollTo(callback.textChapter()?.getStartLine(callback.durChapterPos())) + prevPage?.scrollToBottom() } } } From 1a619e6b6ec6107c2767e7559f95aa607a466ba6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 23 Sep 2019 14:38:54 +0800 Subject: [PATCH 1628/1997] up --- .../widget/page/delegate/CoverPageDelegate.kt | 28 ++++++++++--------- .../ui/widget/page/delegate/PageDelegate.kt | 6 +--- .../page/delegate/ScrollPageDelegate.kt | 28 ++++++++++--------- .../widget/page/delegate/SlidePageDelegate.kt | 28 ++++++++++--------- 4 files changed, 46 insertions(+), 44 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/CoverPageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/CoverPageDelegate.kt index 8d1d05e3d..dd4f8d185 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/CoverPageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/CoverPageDelegate.kt @@ -21,20 +21,22 @@ class CoverPageDelegate(pageView: PageView) : PageDelegate(pageView) { override fun onScrollStart() { val distanceX: Float when (direction) { - Direction.NEXT -> if (isCancel) { - var dis = viewWidth - startX + touchX - if (dis > viewWidth) { - dis = viewWidth.toFloat() + Direction.NEXT -> distanceX = + if (isCancel) { + var dis = viewWidth - startX + touchX + if (dis > viewWidth) { + dis = viewWidth.toFloat() + } + viewWidth - dis + } else { + -(touchX + (viewWidth - startX)) + } + else -> distanceX = + if (isCancel) { + -(touchX - startX) + } else { + viewWidth - (touchX - startX) } - distanceX = viewWidth - dis - } else { - distanceX = -(touchX + (viewWidth - startX)) - } - else -> distanceX = if (isCancel) { - -(touchX - startX) - } else { - viewWidth - (touchX - startX) - } } startScroll(touchX.toInt(), 0, distanceX.toInt(), 0) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt index 05692299c..56a61ba71 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt @@ -94,7 +94,7 @@ abstract class PageDelegate(protected val pageView: PageView) { startY, dx, dy, - if (dx != 0) getDuration(dx, viewWidth) else getDuration(dy, viewHeight) + if (dx != 0) (dx * 0.3).toInt() else (dy * 0.3).toInt() ) isRunning = true isStarted = true @@ -109,10 +109,6 @@ abstract class PageDelegate(protected val pageView: PageView) { invalidate() } - private fun getDuration(distance: Int, len: Int): Int { - return (300f * abs(distance) / len).toInt() - } - fun setViewSize(width: Int, height: Int) { viewWidth = width viewHeight = height diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/ScrollPageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/ScrollPageDelegate.kt index b7afc58b6..a2d900529 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/ScrollPageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/ScrollPageDelegate.kt @@ -15,20 +15,22 @@ class ScrollPageDelegate(pageView: PageView) : PageDelegate(pageView) { } val distanceY: Float when (direction) { - Direction.NEXT -> if (isCancel) { - var dis = viewHeight - startY + touchY - if (dis > viewHeight) { - dis = viewHeight.toFloat() + Direction.NEXT -> distanceY = + if (isCancel) { + var dis = viewHeight - startY + touchY + if (dis > viewHeight) { + dis = viewHeight.toFloat() + } + viewHeight - dis + } else { + -(touchY + (viewHeight - startY)) + } + else -> distanceY = + if (isCancel) { + -(touchY - startY) + } else { + viewHeight - (touchY - startY) } - distanceY = viewHeight - dis - } else { - distanceY = -(touchY + (viewHeight - startY)) - } - else -> distanceY = if (isCancel) { - -(touchY - startY) - } else { - viewWidth - (touchY - startY) - } } startScroll(0, touchY.toInt(), 0, distanceY.toInt()) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/SlidePageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/SlidePageDelegate.kt index 584a4aa2e..60cc351f6 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/SlidePageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/SlidePageDelegate.kt @@ -11,20 +11,22 @@ class SlidePageDelegate(pageView: PageView) : PageDelegate(pageView) { override fun onScrollStart() { val distanceX: Float when (direction) { - Direction.NEXT -> if (isCancel) { - var dis = viewWidth - startX + touchX - if (dis > viewWidth) { - dis = viewWidth.toFloat() + Direction.NEXT -> distanceX = + if (isCancel) { + var dis = viewWidth - startX + touchX + if (dis > viewWidth) { + dis = viewWidth.toFloat() + } + viewWidth - dis + } else { + -(touchX + (viewWidth - startX)) + } + else -> distanceX = + if (isCancel) { + -(touchX - startX) + } else { + viewWidth - (touchX - startX) } - distanceX = viewWidth - dis - } else { - distanceX = -(touchX + (viewWidth - startX)) - } - else -> distanceX = if (isCancel) { - -(touchX - startX) - } else { - viewWidth - (touchX - startX) - } } startScroll(touchX.toInt(), 0, distanceX.toInt(), 0) From aad8c3cf54c9189fa562d27a26174b8025c26b80 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 23 Sep 2019 14:46:36 +0800 Subject: [PATCH 1629/1997] up --- .../java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt index 56a61ba71..387d8c9b2 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt @@ -94,7 +94,7 @@ abstract class PageDelegate(protected val pageView: PageView) { startY, dx, dy, - if (dx != 0) (dx * 0.3).toInt() else (dy * 0.3).toInt() + if (dx != 0) (abs(dx) * 0.3).toInt() else (abs(dy) * 0.3).toInt() ) isRunning = true isStarted = true From d1cbf843bcd31e2cf7724f177840f2ea3468c8e6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 23 Sep 2019 16:13:15 +0800 Subject: [PATCH 1630/1997] up --- .../java/io/legado/app/ui/widget/page/PageView.kt | 4 +++- .../app/ui/widget/page/delegate/PageDelegate.kt | 11 +++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index e2eadce31..dce8a906f 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -108,11 +108,13 @@ class PageView(context: Context, attrs: AttributeSet) : callback?.let { callback -> if (isScrollDelegate) { curPage?.scrollTo(callback.textChapter()?.getStartLine(callback.durChapterPos())) - prevPage?.scrollToBottom() } } } } + if (isScrollDelegate) { + prevPage?.scrollToBottom() + } } } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt index 387d8c9b2..e7d8581ed 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt @@ -104,8 +104,15 @@ abstract class PageDelegate(protected val pageView: PageView) { protected fun stopScroll() { isRunning = false isStarted = false - bitmap?.recycle() - bitmap = null + if (pageView.isScrollDelegate) { + pageView.postDelayed({ + bitmap?.recycle() + bitmap = null + }, 100) + } else { + bitmap?.recycle() + bitmap = null + } invalidate() } From e846858488c42ace8d4dce396e9036186fca5404 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 23 Sep 2019 17:42:46 +0800 Subject: [PATCH 1631/1997] up --- app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt | 1 - app/src/main/java/io/legado/app/ui/widget/page/PageView.kt | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index a3a9639b9..719129a03 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -52,7 +52,6 @@ class ContentView : FrameLayout { callBack?.scrollToLine(line) } if (content_text_view.atBottom()) { - setPageIndex(pageSize - 1) callBack?.scrollToLast() } } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index dce8a906f..69ce82b33 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -247,6 +247,7 @@ class PageView(context: Context, attrs: AttributeSet) : if (isScrollDelegate) { callback?.textChapter()?.let { callback?.setPageIndex(it.lastIndex()) + curPage?.setPageIndex(it.lastIndex()) } } } From 438be8a1c17f03ead7b6cafe0a1b2a2bb2f813f9 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 23 Sep 2019 18:04:29 +0800 Subject: [PATCH 1632/1997] up --- .../io/legado/app/ui/widget/page/PageView.kt | 17 +---- .../ui/widget/page/delegate/PageDelegate.kt | 63 +++++++------------ 2 files changed, 25 insertions(+), 55 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 69ce82b33..8b348d310 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -13,13 +13,12 @@ import io.legado.app.utils.getPrefInt class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, attrs), - PageDelegate.PageInterface, ContentView.CallBack, DataSource { - private var callback: CallBack? = null + var callback: CallBack? = null + var pageFactory: TextPageFactory? = null private var pageDelegate: PageDelegate? = null - private var pageFactory: TextPageFactory? = null var prevPage: ContentView? = null var curPage: ContentView? = null @@ -169,18 +168,6 @@ class PageView(context: Context, attrs: AttributeSet) : nextPage?.upBattery(battery) } - override fun hasNext(): Boolean { - return pageFactory?.hasNext() == true - } - - override fun hasPrev(): Boolean { - return pageFactory?.hasPrev() == true - } - - override fun clickCenter() { - callback?.clickCenter() - } - override val isScrollDelegate: Boolean get() = pageDelegate is ScrollPageDelegate diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt index e7d8581ed..a7f690890 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt @@ -104,6 +104,7 @@ abstract class PageDelegate(protected val pageView: PageView) { protected fun stopScroll() { isRunning = false isStarted = false + invalidate() if (pageView.isScrollDelegate) { pageView.postDelayed({ bitmap?.recycle() @@ -113,7 +114,6 @@ abstract class PageDelegate(protected val pageView: PageView) { bitmap?.recycle() bitmap = null } - invalidate() } fun setViewSize(width: Int, height: Int) { @@ -144,7 +144,6 @@ abstract class PageDelegate(protected val pageView: PageView) { fun start(direction: Direction) { if (isStarted) return - this.direction = direction if (direction === Direction.NEXT) { val x = viewWidth.toFloat() val y = viewHeight.toFloat() @@ -153,8 +152,7 @@ abstract class PageDelegate(protected val pageView: PageView) { //设置点击点 setTouchPoint(x, y, false) //设置方向 - val hasNext = pageView.hasNext() - if (!hasNext) { + if (!hasNext()) { return } } else { @@ -165,8 +163,7 @@ abstract class PageDelegate(protected val pageView: PageView) { //设置点击点 setTouchPoint(x, y, false) //设置方向方向 - val hashPrev = pageView.hasPrev() - if (!hashPrev) { + if (!hasPrev()) { return } } @@ -240,26 +237,22 @@ abstract class PageDelegate(protected val pageView: PageView) { val x = e.x val y = e.y if (centerRectF.contains(x, y)) { - pageView.clickCenter() + pageView.callback?.clickCenter() setTouchPoint(x, y) } else { - direction = if (x > viewWidth / 2) Direction.NEXT else Direction.PREV - if (direction == Direction.NEXT) { - //判断是否下一页存在 - val hasNext = pageView.hasNext() + bitmap = if (x > viewWidth / 2) { //设置动画方向 - if (!hasNext) { + if (!hasNext()) { return true } //下一页截图 - bitmap = nextPage?.screenshot() + nextPage?.screenshot() } else { - val hasPrev = pageView.hasPrev() - if (!hasPrev) { + if (!hasPrev()) { return true } //上一页截图 - bitmap = prevPage?.screenshot() + prevPage?.screenshot() } setTouchPoint(x, y) onScrollStart() @@ -280,12 +273,8 @@ abstract class PageDelegate(protected val pageView: PageView) { val event = e1.toAction(MotionEvent.ACTION_UP) curPage?.dispatchTouchEvent(event) event.recycle() - //上一页的参数配置 - direction = Direction.PREV - //判断是否上一页存在 - val hasPrev = pageView.hasPrev() //如果上一页不存在 - if (!hasPrev) { + if (!hasPrev()) { noNext = true return true } @@ -297,12 +286,8 @@ abstract class PageDelegate(protected val pageView: PageView) { val event = e1.toAction(MotionEvent.ACTION_UP) curPage?.dispatchTouchEvent(event) event.recycle() - //进行下一页的配置 - direction = Direction.NEXT - //判断是否下一页存在 - val hasNext = pageView.hasNext() //如果不存在表示没有下一页了 - if (!hasNext) { + if (!hasNext()) { noNext = true return true } @@ -322,24 +307,16 @@ abstract class PageDelegate(protected val pageView: PageView) { event.recycle() if (abs(distanceX) > abs(distanceY)) { if (distanceX < 0) { - //上一页的参数配置 - direction = Direction.PREV - //判断是否上一页存在 - val hasPrev = pageView.hasPrev() //如果上一页不存在 - if (!hasPrev) { + if (!hasPrev()) { noNext = true return true } //上一页截图 bitmap = prevPage?.screenshot() } else { - //进行下一页的配置 - direction = Direction.NEXT - //判断是否下一页存在 - val hasNext = pageView.hasNext() //如果不存在表示没有下一页了 - if (!hasNext) { + if (!hasNext()) { noNext = true return true } @@ -363,9 +340,15 @@ abstract class PageDelegate(protected val pageView: PageView) { } } - interface PageInterface { - fun hasNext(): Boolean - fun hasPrev(): Boolean - fun clickCenter() + private fun hasPrev(): Boolean { + //上一页的参数配置 + direction = Direction.PREV + return pageView.pageFactory?.hasPrev() == true + } + + private fun hasNext(): Boolean { + //进行下一页的配置 + direction = Direction.NEXT + return pageView.pageFactory?.hasNext() == true } } \ No newline at end of file From fd7f61f7b3c71a45472b27c1b2a1d0c272bef2a1 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 24 Sep 2019 10:35:42 +0800 Subject: [PATCH 1633/1997] up --- .../main/java/io/legado/app/receiver/MediaButtonReceiver.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt index ea4e91d4e..17eba6b18 100644 --- a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt +++ b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt @@ -7,7 +7,6 @@ import android.view.KeyEvent import io.legado.app.constant.Bus import io.legado.app.help.ActivityHelp import io.legado.app.ui.book.read.ReadBookActivity -import io.legado.app.utils.LogUtils import io.legado.app.utils.postEvent @@ -23,7 +22,7 @@ class MediaButtonReceiver : BroadcastReceiver() { fun handleIntent(context: Context, intent: Intent): Boolean { val intentAction = intent.action val keyEventAction = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT)?.action - LogUtils.log("耳机按键: $intentAction $keyEventAction") +// LogUtils.log("耳机按键: $intentAction $keyEventAction") if (Intent.ACTION_MEDIA_BUTTON == intentAction) { if (keyEventAction == KeyEvent.ACTION_DOWN) { readAloud(context) From 5907da9b3076d31638edd86bc32387268aaf7215 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 24 Sep 2019 16:00:33 +0800 Subject: [PATCH 1634/1997] up --- .../app/lib/theme/view/ATEAutoCompleteTextView.kt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt index 4e6d04b2f..b5d7337ff 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt @@ -1,8 +1,10 @@ package io.legado.app.lib.theme.view import android.content.Context +import android.graphics.Rect import android.os.Build import android.util.AttributeSet +import android.view.KeyEvent import androidx.appcompat.widget.AppCompatAutoCompleteTextView import io.legado.app.lib.theme.Selector import io.legado.app.lib.theme.ThemeStore @@ -19,4 +21,14 @@ class ATEAutoCompleteTextView(context: Context, attrs: AttributeSet) : .create() } } + + override fun enoughToFilter(): Boolean { + return true + } + + override fun onFocusChanged(focused: Boolean, direction: Int, previouslyFocusedRect: Rect?) { + super.onFocusChanged(focused, direction, previouslyFocusedRect) + + performFiltering(text, KeyEvent.KEYCODE_UNKNOWN) + } } From 02462cce82db383122267fc7fdd8bf89f427833c Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 24 Sep 2019 17:35:24 +0800 Subject: [PATCH 1635/1997] up --- app/src/main/assets/updateLog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/assets/updateLog.md b/app/src/main/assets/updateLog.md index 8038b0c77..93e1287fd 100644 --- a/app/src/main/assets/updateLog.md +++ b/app/src/main/assets/updateLog.md @@ -1,5 +1,5 @@ ## 本软件为开源软件,没有上架Google Play,请不要在任何地方购买! -### 关注公众号[开源阅读软件]可获取书源,点击广告可支持作者! +### 关注公众号[开源阅读软件]点击广告可支持作者! ### 捐赠里点击红包搜索码可开启高级功能! ## 更新日志 From 06e7e5027bc5ccdc72b1aafb5502824164e8c155 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 25 Sep 2019 11:55:54 +0800 Subject: [PATCH 1636/1997] up --- .../lib/theme/view/ATEAutoCompleteTextView.kt | 49 +++++++++++++++++++ .../res/layout/item_1line_text_and_del.xml | 23 +++++++++ 2 files changed, 72 insertions(+) create mode 100644 app/src/main/res/layout/item_1line_text_and_del.xml diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt index b5d7337ff..b42587aae 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt @@ -5,14 +5,26 @@ import android.graphics.Rect import android.os.Build import android.util.AttributeSet import android.view.KeyEvent +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ArrayAdapter import androidx.appcompat.widget.AppCompatAutoCompleteTextView +import io.legado.app.R import io.legado.app.lib.theme.Selector import io.legado.app.lib.theme.ThemeStore +import io.legado.app.utils.gone +import io.legado.app.utils.visible +import kotlinx.android.synthetic.main.item_1line_text_and_del.view.* +import org.jetbrains.anko.sdk27.listeners.onClick class ATEAutoCompleteTextView(context: Context, attrs: AttributeSet) : AppCompatAutoCompleteTextView(context, attrs) { + var callBack: CallBack? = null + var showDel: Boolean = false + init { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { backgroundTintList = Selector.colorBuild() @@ -29,6 +41,43 @@ class ATEAutoCompleteTextView(context: Context, attrs: AttributeSet) : override fun onFocusChanged(focused: Boolean, direction: Int, previouslyFocusedRect: Rect?) { super.onFocusChanged(focused, direction, previouslyFocusedRect) + performFiltering() + } + + fun performFiltering() { performFiltering(text, KeyEvent.KEYCODE_UNKNOWN) } + + fun setSelectValues(values: List, showDel: Boolean = false) { + this.showDel = showDel + setAdapter(MyAdapter(context, values)) + } + + fun setSelectValues(vararg value: String, showDel: Boolean = false) { + this.showDel = showDel + setAdapter(MyAdapter(context, value.toMutableList())) + } + + inner class MyAdapter(context: Context, values: List) : + ArrayAdapter(context, android.R.layout.simple_dropdown_item_1line, values) { + + override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { + val view = convertView ?: LayoutInflater.from(context) + .inflate(R.layout.item_1line_text_and_del, parent, false) + view.text_view.text = getItem(position) + if (showDel) view.iv_delete.visible() else view.iv_delete.gone() + view.iv_delete.onClick { + getItem(position)?.let { + remove(it) + callBack?.delete(it) + performFiltering() + } + } + return view + } + } + + interface CallBack { + fun delete(value: String) + } } diff --git a/app/src/main/res/layout/item_1line_text_and_del.xml b/app/src/main/res/layout/item_1line_text_and_del.xml new file mode 100644 index 000000000..cb08c99f8 --- /dev/null +++ b/app/src/main/res/layout/item_1line_text_and_del.xml @@ -0,0 +1,23 @@ + + + + + + + + \ No newline at end of file From 43ff120e6e58eeaaea160dc0ce8bce225cf47915 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 25 Sep 2019 11:56:39 +0800 Subject: [PATCH 1637/1997] up --- app/src/main/res/layout/item_1line_text_and_del.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/layout/item_1line_text_and_del.xml b/app/src/main/res/layout/item_1line_text_and_del.xml index cb08c99f8..b30b387d2 100644 --- a/app/src/main/res/layout/item_1line_text_and_del.xml +++ b/app/src/main/res/layout/item_1line_text_and_del.xml @@ -4,6 +4,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" + android:padding="6dp" tools:ignore="UseCompoundDrawables"> Date: Wed, 25 Sep 2019 12:17:03 +0800 Subject: [PATCH 1638/1997] up --- .../app/lib/theme/view/ATEAutoCompleteTextView.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt index b42587aae..855d82720 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt @@ -22,7 +22,7 @@ import org.jetbrains.anko.sdk27.listeners.onClick class ATEAutoCompleteTextView(context: Context, attrs: AttributeSet) : AppCompatAutoCompleteTextView(context, attrs) { - var callBack: CallBack? = null + var delCallBack: DelCallBack? = null var showDel: Boolean = false init { @@ -48,12 +48,12 @@ class ATEAutoCompleteTextView(context: Context, attrs: AttributeSet) : performFiltering(text, KeyEvent.KEYCODE_UNKNOWN) } - fun setSelectValues(values: List, showDel: Boolean = false) { + fun setFilterValues(values: List, showDel: Boolean = false) { this.showDel = showDel setAdapter(MyAdapter(context, values)) } - fun setSelectValues(vararg value: String, showDel: Boolean = false) { + fun setFilterValues(vararg value: String, showDel: Boolean = false) { this.showDel = showDel setAdapter(MyAdapter(context, value.toMutableList())) } @@ -69,7 +69,7 @@ class ATEAutoCompleteTextView(context: Context, attrs: AttributeSet) : view.iv_delete.onClick { getItem(position)?.let { remove(it) - callBack?.delete(it) + delCallBack?.delete(it) performFiltering() } } @@ -77,7 +77,7 @@ class ATEAutoCompleteTextView(context: Context, attrs: AttributeSet) : } } - interface CallBack { + interface DelCallBack { fun delete(value: String) } } From 4c72a094a557dd643969278f4258be9e827b6312 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 25 Sep 2019 14:22:06 +0800 Subject: [PATCH 1639/1997] up --- .../legado/app/lib/dialogs/AndroidDialogs.kt | 2 +- .../lib/theme/view/ATEAutoCompleteTextView.kt | 27 +++++++------------ .../book/source/manage/BookSourceActivity.kt | 24 +++++++++++++++++ .../book/source/manage/GroupManageDialog.kt | 9 +++---- .../ui/main/bookshelf/BookshelfFragment.kt | 5 ++-- .../app/ui/replacerule/GroupManageDialog.kt | 9 +++---- ...alog_edittext.xml => dialog_edit_text.xml} | 2 +- 7 files changed, 43 insertions(+), 35 deletions(-) rename app/src/main/res/layout/{dialog_edittext.xml => dialog_edit_text.xml} (90%) diff --git a/app/src/main/java/io/legado/app/lib/dialogs/AndroidDialogs.kt b/app/src/main/java/io/legado/app/lib/dialogs/AndroidDialogs.kt index 10716da17..0d40174f4 100644 --- a/app/src/main/java/io/legado/app/lib/dialogs/AndroidDialogs.kt +++ b/app/src/main/java/io/legado/app/lib/dialogs/AndroidDialogs.kt @@ -57,7 +57,7 @@ fun Context.alert( titleResource: Int? = null, messageResource: Int? = null, init: (AlertBuilder.() -> Unit)? = null -): AlertBuilder { +): AlertBuilder { return AndroidAlertBuilder(this).apply { if (titleResource != null) { this.titleResource = titleResource diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt index 855d82720..92e5ce110 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt @@ -2,36 +2,31 @@ package io.legado.app.lib.theme.view import android.content.Context import android.graphics.Rect -import android.os.Build import android.util.AttributeSet -import android.view.KeyEvent import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.ArrayAdapter import androidx.appcompat.widget.AppCompatAutoCompleteTextView import io.legado.app.R -import io.legado.app.lib.theme.Selector -import io.legado.app.lib.theme.ThemeStore +import io.legado.app.lib.theme.ATH import io.legado.app.utils.gone import io.legado.app.utils.visible import kotlinx.android.synthetic.main.item_1line_text_and_del.view.* import org.jetbrains.anko.sdk27.listeners.onClick -class ATEAutoCompleteTextView(context: Context, attrs: AttributeSet) : - AppCompatAutoCompleteTextView(context, attrs) { +class ATEAutoCompleteTextView : AppCompatAutoCompleteTextView { + + constructor(context: Context) : super(context) + + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) var delCallBack: DelCallBack? = null var showDel: Boolean = false init { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - backgroundTintList = Selector.colorBuild() - .setFocusedColor(ThemeStore.accentColor(context)) - .setDefaultColor(ThemeStore.textColorPrimary(context)) - .create() - } + ATH.applyAccentTint(this) } override fun enoughToFilter(): Boolean { @@ -41,11 +36,7 @@ class ATEAutoCompleteTextView(context: Context, attrs: AttributeSet) : override fun onFocusChanged(focused: Boolean, direction: Int, previouslyFocusedRect: Rect?) { super.onFocusChanged(focused, direction, previouslyFocusedRect) - performFiltering() - } - - fun performFiltering() { - performFiltering(text, KeyEvent.KEYCODE_UNKNOWN) + showDropDown() } fun setFilterValues(values: List, showDel: Boolean = false) { @@ -70,7 +61,7 @@ class ATEAutoCompleteTextView(context: Context, attrs: AttributeSet) : getItem(position)?.let { remove(it) delCallBack?.delete(it) - performFiltering() + showDropDown() } } return view diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt index 32510192b..0e75a00f0 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt @@ -19,14 +19,21 @@ import io.legado.app.base.VMBaseActivity import io.legado.app.data.entities.BookSource import io.legado.app.help.ItemTouchCallback import io.legado.app.help.storage.Restore +import io.legado.app.lib.dialogs.alert +import io.legado.app.lib.dialogs.cancelButton +import io.legado.app.lib.dialogs.customView +import io.legado.app.lib.dialogs.okButton import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.primaryTextColor +import io.legado.app.lib.theme.view.ATEAutoCompleteTextView import io.legado.app.service.CheckSourceService import io.legado.app.ui.book.source.edit.SourceEditActivity import io.legado.app.ui.qrcode.QrCodeActivity +import io.legado.app.utils.applyTint import io.legado.app.utils.getViewModel import io.legado.app.utils.splitNotBlank import kotlinx.android.synthetic.main.activity_book_source.* +import kotlinx.android.synthetic.main.dialog_edit_text.view.* import kotlinx.android.synthetic.main.view_search.* import kotlinx.android.synthetic.main.view_title_bar.* import org.jetbrains.anko.startActivity @@ -84,6 +91,7 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity R.id.menu_del_selection -> viewModel.delSelection(adapter.getSelectionIds()) R.id.menu_check_book_source -> startService(Pair("data", adapter.getSelectionIds())) + R.id.menu_import_book_source_onLine -> showImportDialog() } if (item.groupId == R.id.source_group) { search_view.setQuery(item.title, true) @@ -153,6 +161,22 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity } } + private fun showImportDialog() { + alert(titleResource = R.string.import_book_source_on_line) { + var editText: ATEAutoCompleteTextView? = null + customView { + layoutInflater.inflate(R.layout.dialog_edit_text, null).apply { + editText = edit_view + } + } + okButton { + editText?.text + } + cancelButton() + }.show().applyTint() + } + + override fun onQueryTextChange(newText: String?): Boolean { newText?.let { initLiveDataBookSource(it) diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/GroupManageDialog.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/GroupManageDialog.kt index bf44c56a5..1cdcccd45 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/manage/GroupManageDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/GroupManageDialog.kt @@ -23,12 +23,11 @@ import io.legado.app.lib.dialogs.alert import io.legado.app.lib.dialogs.customView import io.legado.app.lib.dialogs.noButton import io.legado.app.lib.dialogs.yesButton -import io.legado.app.lib.theme.ATH import io.legado.app.utils.applyTint import io.legado.app.utils.getViewModelOfActivity import io.legado.app.utils.requestInputMethod import io.legado.app.utils.splitNotBlank -import kotlinx.android.synthetic.main.dialog_edittext.view.* +import kotlinx.android.synthetic.main.dialog_edit_text.view.* import kotlinx.android.synthetic.main.dialog_recycler_view.* import kotlinx.android.synthetic.main.item_book_group.view.tv_group import kotlinx.android.synthetic.main.item_group_manage.view.* @@ -91,9 +90,8 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { alert(title = getString(R.string.add_group)) { var editText: EditText? = null customView { - layoutInflater.inflate(R.layout.dialog_edittext, null).apply { + layoutInflater.inflate(R.layout.dialog_edit_text, null).apply { editText = edit_view.apply { - ATH.applyAccentTint(this) hint = "分组名称" } } @@ -114,9 +112,8 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { alert(title = getString(R.string.group_edit)) { var editText: EditText? = null customView { - layoutInflater.inflate(R.layout.dialog_edittext, null).apply { + layoutInflater.inflate(R.layout.dialog_edit_text, null).apply { editText = edit_view.apply { - ATH.applyAccentTint(this) hint = "分组名称" setText(group) } diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index 8e8a581a0..60bccd39f 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -27,7 +27,7 @@ import io.legado.app.ui.book.read.ReadBookActivity import io.legado.app.ui.book.search.SearchActivity import io.legado.app.ui.bookshelf.BookshelfActivity import io.legado.app.utils.* -import kotlinx.android.synthetic.main.dialog_edittext.view.* +import kotlinx.android.synthetic.main.dialog_edit_text.view.* import kotlinx.android.synthetic.main.fragment_bookshelf.* import kotlinx.android.synthetic.main.view_title_bar.* import org.jetbrains.anko.startActivity @@ -135,9 +135,8 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b alert(title = "新建分组") { var editText: EditText? = null customView { - layoutInflater.inflate(R.layout.dialog_edittext, null).apply { + layoutInflater.inflate(R.layout.dialog_edit_text, null).apply { editText = edit_view.apply { - ATH.applyAccentTint(this) hint = "分组名称" } } diff --git a/app/src/main/java/io/legado/app/ui/replacerule/GroupManageDialog.kt b/app/src/main/java/io/legado/app/ui/replacerule/GroupManageDialog.kt index e653947f8..49fb8c3e6 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/GroupManageDialog.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/GroupManageDialog.kt @@ -23,12 +23,11 @@ import io.legado.app.lib.dialogs.alert import io.legado.app.lib.dialogs.customView import io.legado.app.lib.dialogs.noButton import io.legado.app.lib.dialogs.yesButton -import io.legado.app.lib.theme.ATH import io.legado.app.utils.applyTint import io.legado.app.utils.getViewModelOfActivity import io.legado.app.utils.requestInputMethod import io.legado.app.utils.splitNotBlank -import kotlinx.android.synthetic.main.dialog_edittext.view.* +import kotlinx.android.synthetic.main.dialog_edit_text.view.* import kotlinx.android.synthetic.main.dialog_recycler_view.* import kotlinx.android.synthetic.main.item_book_group.view.tv_group import kotlinx.android.synthetic.main.item_group_manage.view.* @@ -91,9 +90,8 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { alert(title = getString(R.string.add_group)) { var editText: EditText? = null customView { - layoutInflater.inflate(R.layout.dialog_edittext, null).apply { + layoutInflater.inflate(R.layout.dialog_edit_text, null).apply { editText = edit_view.apply { - ATH.applyAccentTint(this) hint = "分组名称" } } @@ -114,9 +112,8 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { alert(title = getString(R.string.group_edit)) { var editText: EditText? = null customView { - layoutInflater.inflate(R.layout.dialog_edittext, null).apply { + layoutInflater.inflate(R.layout.dialog_edit_text, null).apply { editText = edit_view.apply { - ATH.applyAccentTint(this) hint = "分组名称" setText(group) } diff --git a/app/src/main/res/layout/dialog_edittext.xml b/app/src/main/res/layout/dialog_edit_text.xml similarity index 90% rename from app/src/main/res/layout/dialog_edittext.xml rename to app/src/main/res/layout/dialog_edit_text.xml index 04dd314d0..2cf3da5dd 100644 --- a/app/src/main/res/layout/dialog_edittext.xml +++ b/app/src/main/res/layout/dialog_edit_text.xml @@ -7,7 +7,7 @@ android:layout_marginBottom="48dp" android:overScrollMode="ifContentScrolls"> - Date: Wed, 25 Sep 2019 15:19:39 +0800 Subject: [PATCH 1640/1997] up --- .../lib/theme/view/ATEAutoCompleteTextView.kt | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt index 92e5ce110..c88327109 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt @@ -22,8 +22,7 @@ class ATEAutoCompleteTextView : AppCompatAutoCompleteTextView { constructor(context: Context, attrs: AttributeSet) : super(context, attrs) - var delCallBack: DelCallBack? = null - var showDel: Boolean = false + var delCallBack: ((value: String) -> Unit)? = null init { ATH.applyAccentTint(this) @@ -39,13 +38,13 @@ class ATEAutoCompleteTextView : AppCompatAutoCompleteTextView { showDropDown() } - fun setFilterValues(values: List, showDel: Boolean = false) { - this.showDel = showDel + fun setFilterValues(values: List, delCallBack: ((value: String) -> Unit)? = null) { + this.delCallBack = delCallBack setAdapter(MyAdapter(context, values)) } - fun setFilterValues(vararg value: String, showDel: Boolean = false) { - this.showDel = showDel + fun setFilterValues(vararg value: String, delCallBack: ((value: String) -> Unit)? = null) { + this.delCallBack = delCallBack setAdapter(MyAdapter(context, value.toMutableList())) } @@ -56,11 +55,11 @@ class ATEAutoCompleteTextView : AppCompatAutoCompleteTextView { val view = convertView ?: LayoutInflater.from(context) .inflate(R.layout.item_1line_text_and_del, parent, false) view.text_view.text = getItem(position) - if (showDel) view.iv_delete.visible() else view.iv_delete.gone() + if (delCallBack != null) view.iv_delete.visible() else view.iv_delete.gone() view.iv_delete.onClick { getItem(position)?.let { remove(it) - delCallBack?.delete(it) + delCallBack?.invoke(it) showDropDown() } } @@ -68,7 +67,4 @@ class ATEAutoCompleteTextView : AppCompatAutoCompleteTextView { } } - interface DelCallBack { - fun delete(value: String) - } } From ac537b312c511c4565880b4ccf77c85607039b68 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 25 Sep 2019 16:18:12 +0800 Subject: [PATCH 1641/1997] up --- .../legado/app/ui/book/source/manage/BookSourceActivity.kt | 7 +++++++ app/src/main/java/io/legado/app/utils/ACache.java | 7 ++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt index 0e75a00f0..95fa8f635 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt @@ -1,5 +1,6 @@ package io.legado.app.ui.book.source.manage +import android.annotation.SuppressLint import android.content.Intent import android.os.Bundle import android.view.Menu @@ -29,6 +30,7 @@ import io.legado.app.lib.theme.view.ATEAutoCompleteTextView import io.legado.app.service.CheckSourceService import io.legado.app.ui.book.source.edit.SourceEditActivity import io.legado.app.ui.qrcode.QrCodeActivity +import io.legado.app.utils.ACache import io.legado.app.utils.applyTint import io.legado.app.utils.getViewModel import io.legado.app.utils.splitNotBlank @@ -161,12 +163,17 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity } } + @SuppressLint("InflateParams") private fun showImportDialog() { + val cacheUrls = ACache.get(this, "cacheUrls") alert(titleResource = R.string.import_book_source_on_line) { var editText: ATEAutoCompleteTextView? = null customView { layoutInflater.inflate(R.layout.dialog_edit_text, null).apply { editText = edit_view + edit_view.setFilterValues("") { + + } } } okButton { diff --git a/app/src/main/java/io/legado/app/utils/ACache.java b/app/src/main/java/io/legado/app/utils/ACache.java index 381c093b6..908460896 100644 --- a/app/src/main/java/io/legado/app/utils/ACache.java +++ b/app/src/main/java/io/legado/app/utils/ACache.java @@ -514,7 +514,7 @@ public class ACache { /** * @author 杨福海(michael) www.yangfuhai.com * @version 1.0 - * @title 时间计算工具类 + * title 时间计算工具类 */ private static class Utils { @@ -685,7 +685,7 @@ public class ACache { /** * @author 杨福海(michael) www.yangfuhai.com * @version 1.0 - * @title 缓存管理器 + * title 缓存管理器 */ public class ACacheManager { private final AtomicLong cacheSize; @@ -758,7 +758,6 @@ public class ACache { } catch (Exception e) { e.printStackTrace(); } - } private File get(String key) { @@ -834,8 +833,6 @@ public class ACache { e.printStackTrace(); return 0; } - - } private long calculateSize(File file) { From c0ee91f8f4f2ceafd191b56381bd9423139ba011 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 25 Sep 2019 17:13:05 +0800 Subject: [PATCH 1642/1997] up --- .../main/java/io/legado/app/utils/ACache.java | 843 ------------------ .../main/java/io/legado/app/utils/ACache.kt | 810 +++++++++++++++++ 2 files changed, 810 insertions(+), 843 deletions(-) delete mode 100644 app/src/main/java/io/legado/app/utils/ACache.java create mode 100644 app/src/main/java/io/legado/app/utils/ACache.kt diff --git a/app/src/main/java/io/legado/app/utils/ACache.java b/app/src/main/java/io/legado/app/utils/ACache.java deleted file mode 100644 index 908460896..000000000 --- a/app/src/main/java/io/legado/app/utils/ACache.java +++ /dev/null @@ -1,843 +0,0 @@ -//Copyright (c) 2017. 章钦豪. All rights reserved. -package io.legado.app.utils; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Canvas; -import android.graphics.PixelFormat; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.util.Log; - -import androidx.annotation.Nullable; - -import org.json.JSONArray; -import org.json.JSONObject; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.RandomAccessFile; -import java.io.Serializable; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; - - -/** - * 本地缓存 - */ -@SuppressWarnings({"unused", "ResultOfMethodCallIgnored", "WeakerAccess"}) -public class ACache { - public static final int TIME_HOUR = 60 * 60; - public static final int TIME_DAY = TIME_HOUR * 24; - private static final int MAX_SIZE = 1000 * 1000 * 50; // 50 mb - private static final int MAX_COUNT = Integer.MAX_VALUE; // 不限制存放数据的数量 - private static Map mInstanceMap = new HashMap<>(); - private ACacheManager mCache; - - private ACache(File cacheDir, long max_size, int max_count) { - try { - if (!cacheDir.exists() && !cacheDir.mkdirs()) { - Log.i("ACache", "can't make dirs in %s" + cacheDir.getAbsolutePath()); - } - mCache = new ACacheManager(cacheDir, max_size, max_count); - } catch (Exception ignored) { - } - } - - public static ACache get(Context ctx) { - return get(ctx, "ACache"); - } - - public static ACache get(Context ctx, String cacheName) { - File f = new File(ctx.getCacheDir(), cacheName); - return get(f, MAX_SIZE, MAX_COUNT); - } - - public static ACache get(File cacheDir) { - return get(cacheDir, MAX_SIZE, MAX_COUNT); - } - - public static ACache get(Context ctx, long max_zise, int max_count) { - try { - File f = new File(ctx.getCacheDir(), "ACache"); - return get(f, max_zise, max_count); - } catch (Exception ignored) { - } - - return null; - } - - public static ACache get(File cacheDir, long max_zise, int max_count) { - try { - ACache manager = mInstanceMap.get(cacheDir.getAbsoluteFile() + myPid()); - if (manager == null) { - manager = new ACache(cacheDir, max_zise, max_count); - mInstanceMap.put(cacheDir.getAbsolutePath() + myPid(), manager); - } - return manager; - } catch (Exception ignored) { - } - - return null; - } - - private static String myPid() { - return "_" + android.os.Process.myPid(); - } - - // ======================================= - // ============ String数据 读写 ============== - // ======================================= - - /** - * 保存 String数据 到 缓存中 - * - * @param key 保存的key - * @param value 保存的String数据 - */ - public void put(String key, String value) { - try { - File file = mCache.newFile(key); - BufferedWriter out = null; - try { - out = new BufferedWriter(new FileWriter(file), 1024); - out.write(value); - } catch (IOException ignored) { - } finally { - if (out != null) { - try { - out.flush(); - out.close(); - } catch (IOException ignored) { - } - } - mCache.put(file); - } - } catch (Exception ignored) { - } - - } - - /** - * 保存 String数据 到 缓存中 - * - * @param key 保存的key - * @param value 保存的String数据 - * @param saveTime 保存的时间,单位:秒 - */ - public void put(String key, String value, int saveTime) { - put(key, Utils.newStringWithDateInfo(saveTime, value)); - } - - /** - * 读取 String数据 - * - * @return String 数据 - */ - @Nullable - public String getAsString(String key) { - File file = mCache.get(key); - if (!file.exists()) - return null; - boolean removeFile = false; - try (BufferedReader in = new BufferedReader(new FileReader(file))) { - StringBuilder readString = new StringBuilder(); - String currentLine; - while ((currentLine = in.readLine()) != null) { - readString.append(currentLine); - } - if (!Utils.isDue(readString.toString())) { - return Utils.clearDateInfo(readString.toString()); - } else { - removeFile = true; - return null; - } - } catch (IOException e) { - return null; - } finally { - if (removeFile) - remove(key); - } - } - - // ======================================= - // ========== JSONObject 数据 读写 ========= - // ======================================= - - /** - * 保存 JSONObject数据 到 缓存中 - * - * @param key 保存的key - * @param value 保存的JSON数据 - */ - public void put(String key, JSONObject value) { - put(key, value.toString()); - } - - /** - * 保存 JSONObject数据 到 缓存中 - * - * @param key 保存的key - * @param value 保存的JSONObject数据 - * @param saveTime 保存的时间,单位:秒 - */ - public void put(String key, JSONObject value, int saveTime) { - put(key, value.toString(), saveTime); - } - - /** - * 读取JSONObject数据 - * - * @return JSONObject数据 - */ - public JSONObject getAsJSONObject(String key) { - String JSONString = getAsString(key); - try { - return new JSONObject(JSONString); - } catch (Exception e) { - return null; - } - } - - // ======================================= - // ============ JSONArray 数据 读写 ============= - // ======================================= - - /** - * 保存 JSONArray数据 到 缓存中 - * - * @param key 保存的key - * @param value 保存的JSONArray数据 - */ - public void put(String key, JSONArray value) { - put(key, value.toString()); - } - - /** - * 保存 JSONArray数据 到 缓存中 - * - * @param key 保存的key - * @param value 保存的JSONArray数据 - * @param saveTime 保存的时间,单位:秒 - */ - public void put(String key, JSONArray value, int saveTime) { - put(key, value.toString(), saveTime); - } - - /** - * 读取JSONArray数据 - * - * @return JSONArray数据 - */ - public JSONArray getAsJSONArray(String key) { - String JSONString = getAsString(key); - try { - return new JSONArray(JSONString); - } catch (Exception e) { - return null; - } - } - - // ======================================= - // ============== byte 数据 读写 ============= - // ======================================= - - /** - * 保存 byte数据 到 缓存中 - * - * @param key 保存的key - * @param value 保存的数据 - */ - public void put(String key, byte[] value) { - File file = mCache.newFile(key); - FileOutputStream out = null; - try { - out = new FileOutputStream(file); - out.write(value); - } catch (Exception ignored) { - } finally { - if (out != null) { - try { - out.flush(); - out.close(); - } catch (IOException ignored) { - } - } - mCache.put(file); - } - } - - /** - * 保存 byte数据 到 缓存中 - * - * @param key 保存的key - * @param value 保存的数据 - * @param saveTime 保存的时间,单位:秒 - */ - public void put(String key, byte[] value, int saveTime) { - put(key, Utils.newByteArrayWithDateInfo(saveTime, value)); - } - - /** - * 获取 byte 数据 - * - * @return byte 数据 - */ - public byte[] getAsBinary(String key) { - RandomAccessFile RAFile = null; - boolean removeFile = false; - try { - File file = mCache.get(key); - if (!file.exists()) - return null; - RAFile = new RandomAccessFile(file, "r"); - byte[] byteArray = new byte[(int) RAFile.length()]; - RAFile.read(byteArray); - if (!Utils.isDue(byteArray)) { - return Utils.clearDateInfo(byteArray); - } else { - removeFile = true; - return null; - } - } catch (Exception e) { - e.printStackTrace(); - return null; - } finally { - if (RAFile != null) { - try { - RAFile.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - if (removeFile) - remove(key); - } - } - - // ======================================= - // ============= 序列化 数据 读写 =============== - // ======================================= - - /** - * 保存 Serializable数据 到 缓存中 - * - * @param key 保存的key - * @param value 保存的value - */ - public void put(String key, Serializable value) { - put(key, value, -1); - } - - /** - * 保存 Serializable数据到 缓存中 - * - * @param key 保存的key - * @param value 保存的value - * @param saveTime 保存的时间,单位:秒 - */ - public void put(String key, Serializable value, int saveTime) { - ByteArrayOutputStream baos; - baos = new ByteArrayOutputStream(); - try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { - oos.writeObject(value); - byte[] data = baos.toByteArray(); - if (saveTime != -1) { - put(key, data, saveTime); - } else { - put(key, data); - } - } catch (Exception e) { - e.printStackTrace(); - } - } - - /** - * 读取 Serializable数据 - * - * @return Serializable 数据 - */ - public Object getAsObject(String key) { - byte[] data = getAsBinary(key); - if (data != null) { - ByteArrayInputStream bais = null; - ObjectInputStream ois = null; - try { - bais = new ByteArrayInputStream(data); - ois = new ObjectInputStream(bais); - return ois.readObject(); - } catch (Exception e) { - e.printStackTrace(); - return null; - } finally { - try { - if (bais != null) - bais.close(); - } catch (IOException e) { - e.printStackTrace(); - } - try { - if (ois != null) - ois.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - return null; - - } - - // ======================================= - // ============== bitmap 数据 读写 ============= - // ======================================= - - /** - * 保存 bitmap 到 缓存中 - * - * @param key 保存的key - * @param value 保存的bitmap数据 - */ - public void put(String key, Bitmap value) { - put(key, Utils.Bitmap2Bytes(value)); - } - - /** - * 保存 bitmap 到 缓存中 - * - * @param key 保存的key - * @param value 保存的 bitmap 数据 - * @param saveTime 保存的时间,单位:秒 - */ - public void put(String key, Bitmap value, int saveTime) { - put(key, Utils.Bitmap2Bytes(value), saveTime); - } - - /** - * 读取 bitmap 数据 - * - * @return bitmap 数据 - */ - public Bitmap getAsBitmap(String key) { - if (getAsBinary(key) == null) { - return null; - } - return Utils.Bytes2Bimap(getAsBinary(key)); - } - - // ======================================= - // ============= drawable 数据 读写 ============= - // ======================================= - - /** - * 保存 drawable 到 缓存中 - * - * @param key 保存的key - * @param value 保存的drawable数据 - */ - public void put(String key, Drawable value) { - put(key, Utils.drawable2Bitmap(value)); - } - - /** - * 保存 drawable 到 缓存中 - * - * @param key 保存的key - * @param value 保存的 drawable 数据 - * @param saveTime 保存的时间,单位:秒 - */ - public void put(String key, Drawable value, int saveTime) { - put(key, Utils.drawable2Bitmap(value), saveTime); - } - - /** - * 读取 Drawable 数据 - * - * @return Drawable 数据 - */ - public Drawable getAsDrawable(String key) { - if (getAsBinary(key) == null) { - return null; - } - return Utils.bitmap2Drawable(Utils.Bytes2Bimap(getAsBinary(key))); - } - - /** - * 获取缓存文件 - * - * @return value 缓存的文件 - */ - public File file(String key) { - try { - File f = mCache.newFile(key); - if (f.exists()) { - return f; - } - } catch (Exception e) { - e.printStackTrace(); - } - - return null; - } - - /** - * 移除某个key - * - * @return 是否移除成功 - */ - public boolean remove(String key) { - return mCache.remove(key); - } - - /** - * 清除所有数据 - */ - public void clear() { - mCache.clear(); - } - - /** - * @author 杨福海(michael) www.yangfuhai.com - * @version 1.0 - * title 时间计算工具类 - */ - private static class Utils { - - private static final char mSeparator = ' '; - - /** - * 判断缓存的String数据是否到期 - * - * @return true:到期了 false:还没有到期 - */ - private static boolean isDue(String str) { - return isDue(str.getBytes()); - } - - /** - * 判断缓存的byte数据是否到期 - * - * @return true:到期了 false:还没有到期 - */ - private static boolean isDue(byte[] data) { - try { - String[] strs = getDateInfoFromDate(data); - if (strs != null && strs.length == 2) { - String saveTimeStr = strs[0]; - while (saveTimeStr.startsWith("0")) { - saveTimeStr = saveTimeStr - .substring(1); - } - long saveTime = Long.valueOf(saveTimeStr); - long deleteAfter = Long.valueOf(strs[1]); - if (System.currentTimeMillis() > saveTime + deleteAfter * 1000) { - return true; - } - } - } catch (Exception e) { - e.printStackTrace(); - } - - return false; - } - - private static String newStringWithDateInfo(int second, String strInfo) { - return createDateInfo(second) + strInfo; - } - - private static byte[] newByteArrayWithDateInfo(int second, byte[] data2) { - byte[] data1 = createDateInfo(second).getBytes(); - byte[] retdata = new byte[data1.length + data2.length]; - System.arraycopy(data1, 0, retdata, 0, data1.length); - System.arraycopy(data2, 0, retdata, data1.length, data2.length); - return retdata; - } - - private static String clearDateInfo(String strInfo) { - if (strInfo != null && hasDateInfo(strInfo.getBytes())) { - strInfo = strInfo.substring(strInfo.indexOf(mSeparator) + 1); - } - return strInfo; - } - - private static byte[] clearDateInfo(byte[] data) { - if (hasDateInfo(data)) { - return copyOfRange(data, indexOf(data, mSeparator) + 1, - data.length); - } - return data; - } - - private static boolean hasDateInfo(byte[] data) { - return data != null && data.length > 15 && data[13] == '-' - && indexOf(data, mSeparator) > 14; - } - - private static String[] getDateInfoFromDate(byte[] data) { - if (hasDateInfo(data)) { - String saveDate = new String(copyOfRange(data, 0, 13)); - String deleteAfter = new String(copyOfRange(data, 14, - indexOf(data, mSeparator))); - return new String[]{saveDate, deleteAfter}; - } - return null; - } - - private static int indexOf(byte[] data, char c) { - for (int i = 0; i < data.length; i++) { - if (data[i] == c) { - return i; - } - } - return -1; - } - - private static byte[] copyOfRange(byte[] original, int from, int to) { - int newLength = to - from; - if (newLength < 0) - throw new IllegalArgumentException(from + " > " + to); - byte[] copy = new byte[newLength]; - System.arraycopy(original, from, copy, 0, - Math.min(original.length - from, newLength)); - return copy; - } - - private static String createDateInfo(int second) { - StringBuilder currentTime = new StringBuilder(System.currentTimeMillis() + ""); - while (currentTime.length() < 13) { - currentTime.insert(0, "0"); - } - return currentTime + "-" + second + mSeparator; - } - - /* - * Bitmap → byte[] - */ - private static byte[] Bitmap2Bytes(Bitmap bm) { - if (bm == null) { - return null; - } - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - bm.compress(Bitmap.CompressFormat.PNG, 100, baos); - return baos.toByteArray(); - } - - /* - * byte[] → Bitmap - */ - private static Bitmap Bytes2Bimap(byte[] b) { - if (b.length == 0) { - return null; - } - return BitmapFactory.decodeByteArray(b, 0, b.length); - } - - /* - * Drawable → Bitmap - */ - private static Bitmap drawable2Bitmap(Drawable drawable) { - if (drawable == null) { - return null; - } - // 取 drawable 的长宽 - int w = drawable.getIntrinsicWidth(); - int h = drawable.getIntrinsicHeight(); - // 取 drawable 的颜色格式 - Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 - : Bitmap.Config.RGB_565; - // 建立对应 bitmap - Bitmap bitmap = Bitmap.createBitmap(w, h, config); - // 建立对应 bitmap 的画布 - Canvas canvas = new Canvas(bitmap); - drawable.setBounds(0, 0, w, h); - // 把 drawable 内容画到画布中 - drawable.draw(canvas); - return bitmap; - } - - /* - * Bitmap → Drawable - */ - @SuppressWarnings("deprecation") - private static Drawable bitmap2Drawable(Bitmap bm) { - if (bm == null) { - return null; - } - return new BitmapDrawable(bm); - } - } - - /** - * @author 杨福海(michael) www.yangfuhai.com - * @version 1.0 - * title 缓存管理器 - */ - public class ACacheManager { - private final AtomicLong cacheSize; - private final AtomicInteger cacheCount; - private final long sizeLimit; - private final int countLimit; - private final Map lastUsageDates = Collections - .synchronizedMap(new HashMap<>()); - protected File cacheDir; - - private ACacheManager(File cacheDir, long sizeLimit, int countLimit) { - this.cacheDir = cacheDir; - this.sizeLimit = sizeLimit; - this.countLimit = countLimit; - cacheSize = new AtomicLong(); - cacheCount = new AtomicInteger(); - calculateCacheSizeAndCacheCount(); - } - - /** - * 计算 cacheSize和cacheCount - */ - private void calculateCacheSizeAndCacheCount() { - new Thread(() -> { - - try { - int size = 0; - int count = 0; - File[] cachedFiles = cacheDir.listFiles(); - if (cachedFiles != null) { - for (File cachedFile : cachedFiles) { - size += calculateSize(cachedFile); - count += 1; - lastUsageDates.put(cachedFile, - cachedFile.lastModified()); - } - cacheSize.set(size); - cacheCount.set(count); - } - } catch (Exception e) { - e.printStackTrace(); - } - - }).start(); - } - - private void put(File file) { - - try { - int curCacheCount = cacheCount.get(); - while (curCacheCount + 1 > countLimit) { - long freedSize = removeNext(); - cacheSize.addAndGet(-freedSize); - - curCacheCount = cacheCount.addAndGet(-1); - } - cacheCount.addAndGet(1); - - long valueSize = calculateSize(file); - long curCacheSize = cacheSize.get(); - while (curCacheSize + valueSize > sizeLimit) { - long freedSize = removeNext(); - curCacheSize = cacheSize.addAndGet(-freedSize); - } - cacheSize.addAndGet(valueSize); - - long currentTime = System.currentTimeMillis(); - file.setLastModified(currentTime); - lastUsageDates.put(file, currentTime); - } catch (Exception e) { - e.printStackTrace(); - } - } - - private File get(String key) { - File file = newFile(key); - long currentTime = System.currentTimeMillis(); - file.setLastModified(currentTime); - lastUsageDates.put(file, currentTime); - - return file; - } - - private File newFile(String key) { - return new File(cacheDir, key.hashCode() + ""); - } - - private boolean remove(String key) { - File image = get(key); - return image.delete(); - } - - private void clear() { - try { - lastUsageDates.clear(); - cacheSize.set(0); - File[] files = cacheDir.listFiles(); - if (files != null) { - for (File f : files) { - f.delete(); - } - } - } catch (Exception e) { - e.printStackTrace(); - } - - } - - /** - * 移除旧的文件 - */ - private long removeNext() { - try { - if (lastUsageDates.isEmpty()) { - return 0; - } - - Long oldestUsage = null; - File mostLongUsedFile = null; - Set> entries = lastUsageDates.entrySet(); - synchronized (lastUsageDates) { - for (Entry entry : entries) { - if (mostLongUsedFile == null) { - mostLongUsedFile = entry.getKey(); - oldestUsage = entry.getValue(); - } else { - Long lastValueUsage = entry.getValue(); - if (lastValueUsage < oldestUsage) { - oldestUsage = lastValueUsage; - mostLongUsedFile = entry.getKey(); - } - } - } - } - - long fileSize = 0; - if (mostLongUsedFile != null) { - fileSize = calculateSize(mostLongUsedFile); - if (mostLongUsedFile.delete()) { - lastUsageDates.remove(mostLongUsedFile); - } - } - return fileSize; - } catch (Exception e) { - e.printStackTrace(); - return 0; - } - } - - private long calculateSize(File file) { - return file.length(); - } - } - -} diff --git a/app/src/main/java/io/legado/app/utils/ACache.kt b/app/src/main/java/io/legado/app/utils/ACache.kt new file mode 100644 index 000000000..f40fac7f2 --- /dev/null +++ b/app/src/main/java/io/legado/app/utils/ACache.kt @@ -0,0 +1,810 @@ +//Copyright (c) 2017. 章钦豪. All rights reserved. +package io.legado.app.utils + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.Canvas +import android.graphics.PixelFormat +import android.graphics.drawable.BitmapDrawable +import android.graphics.drawable.Drawable +import android.util.Log +import org.json.JSONArray +import org.json.JSONObject +import java.io.* +import java.util.* +import java.util.concurrent.atomic.AtomicInteger +import java.util.concurrent.atomic.AtomicLong + + +/** + * 本地缓存 + */ +class ACache private constructor(cacheDir: File, max_size: Long, max_count: Int) { + private lateinit var mCache: ACacheManager + + init { + try { + if (!cacheDir.exists() && !cacheDir.mkdirs()) { + Log.i("ACache", "can't make dirs in %s" + cacheDir.absolutePath) + } + mCache = ACacheManager(cacheDir, max_size, max_count) + } catch (ignored: Exception) { + } + + } + + // ======================================= + // ============ String数据 读写 ============== + // ======================================= + + /** + * 保存 String数据 到 缓存中 + * + * @param key 保存的key + * @param value 保存的String数据 + */ + fun put(key: String, value: String) { + try { + val file = mCache.newFile(key) + var out: BufferedWriter? = null + try { + out = BufferedWriter(FileWriter(file), 1024) + out.write(value) + } catch (ignored: IOException) { + } finally { + if (out != null) { + try { + out.flush() + out.close() + } catch (ignored: IOException) { + } + + } + mCache.put(file) + } + } catch (ignored: Exception) { + } + + } + + /** + * 保存 String数据 到 缓存中 + * + * @param key 保存的key + * @param value 保存的String数据 + * @param saveTime 保存的时间,单位:秒 + */ + fun put(key: String, value: String, saveTime: Int) { + put(key, Utils.newStringWithDateInfo(saveTime, value)) + } + + /** + * 读取 String数据 + * + * @return String 数据 + */ + fun getAsString(key: String): String? { + val file = mCache[key] + if (!file.exists()) + return null + var removeFile = false + return try { + val text = file.readText() + if (!Utils.isDue(text)) { + Utils.clearDateInfo(text) + } else { + removeFile = true + null + } + } catch (e: IOException) { + null + } finally { + if (removeFile) + remove(key) + } + } + + // ======================================= + // ========== JSONObject 数据 读写 ========= + // ======================================= + + /** + * 保存 JSONObject数据 到 缓存中 + * + * @param key 保存的key + * @param value 保存的JSON数据 + */ + fun put(key: String, value: JSONObject) { + put(key, value.toString()) + } + + /** + * 保存 JSONObject数据 到 缓存中 + * + * @param key 保存的key + * @param value 保存的JSONObject数据 + * @param saveTime 保存的时间,单位:秒 + */ + fun put(key: String, value: JSONObject, saveTime: Int) { + put(key, value.toString(), saveTime) + } + + /** + * 读取JSONObject数据 + * + * @return JSONObject数据 + */ + fun getAsJSONObject(key: String): JSONObject? { + val json = getAsString(key) + return try { + JSONObject(json) + } catch (e: Exception) { + null + } + + } + + // ======================================= + // ============ JSONArray 数据 读写 ============= + // ======================================= + + /** + * 保存 JSONArray数据 到 缓存中 + * + * @param key 保存的key + * @param value 保存的JSONArray数据 + */ + fun put(key: String, value: JSONArray) { + put(key, value.toString()) + } + + /** + * 保存 JSONArray数据 到 缓存中 + * + * @param key 保存的key + * @param value 保存的JSONArray数据 + * @param saveTime 保存的时间,单位:秒 + */ + fun put(key: String, value: JSONArray, saveTime: Int) { + put(key, value.toString(), saveTime) + } + + /** + * 读取JSONArray数据 + * + * @return JSONArray数据 + */ + fun getAsJSONArray(key: String): JSONArray? { + val json = getAsString(key) + return try { + JSONArray(json) + } catch (e: Exception) { + null + } + + } + + // ======================================= + // ============== byte 数据 读写 ============= + // ======================================= + + /** + * 保存 byte数据 到 缓存中 + * + * @param key 保存的key + * @param value 保存的数据 + */ + fun put(key: String, value: ByteArray) { + val file = mCache.newFile(key) + var out: FileOutputStream? = null + try { + out = FileOutputStream(file) + out.write(value) + } catch (ignored: Exception) { + } finally { + if (out != null) { + try { + out.flush() + out.close() + } catch (ignored: IOException) { + } + + } + mCache.put(file) + } + } + + /** + * 保存 byte数据 到 缓存中 + * + * @param key 保存的key + * @param value 保存的数据 + * @param saveTime 保存的时间,单位:秒 + */ + fun put(key: String, value: ByteArray, saveTime: Int) { + put(key, Utils.newByteArrayWithDateInfo(saveTime, value)) + } + + /** + * 获取 byte 数据 + * + * @return byte 数据 + */ + fun getAsBinary(key: String): ByteArray? { + var raf: RandomAccessFile? = null + var removeFile = false + try { + val file = mCache[key] + if (!file.exists()) + return null + raf = RandomAccessFile(file, "r") + val byteArray = ByteArray(raf.length().toInt()) + raf.read(byteArray) + return if (!Utils.isDue(byteArray)) { + Utils.clearDateInfo(byteArray) + } else { + removeFile = true + null + } + } catch (e: Exception) { + e.printStackTrace() + return null + } finally { + if (raf != null) { + try { + raf.close() + } catch (e: IOException) { + e.printStackTrace() + } + + } + if (removeFile) + remove(key) + } + } + + /** + * 保存 Serializable数据到 缓存中 + * + * @param key 保存的key + * @param value 保存的value + * @param saveTime 保存的时间,单位:秒 + */ + @JvmOverloads + fun put(key: String, value: Serializable, saveTime: Int = -1) { + try { + val baos = ByteArrayOutputStream() + ObjectOutputStream(baos).use { oos -> + oos.writeObject(value) + val data = baos.toByteArray() + if (saveTime != -1) { + put(key, data, saveTime) + } else { + put(key, data) + } + } + } catch (e: Exception) { + e.printStackTrace() + } + } + + /** + * 读取 Serializable数据 + * + * @return Serializable 数据 + */ + fun getAsObject(key: String): Any? { + val data = getAsBinary(key) + if (data != null) { + var bais: ByteArrayInputStream? = null + var ois: ObjectInputStream? = null + try { + bais = ByteArrayInputStream(data) + ois = ObjectInputStream(bais) + return ois.readObject() + } catch (e: Exception) { + e.printStackTrace() + return null + } finally { + try { + bais?.close() + } catch (e: IOException) { + e.printStackTrace() + } + + try { + ois?.close() + } catch (e: IOException) { + e.printStackTrace() + } + + } + } + return null + + } + + // ======================================= + // ============== bitmap 数据 读写 ============= + // ======================================= + + /** + * 保存 bitmap 到 缓存中 + * + * @param key 保存的key + * @param value 保存的bitmap数据 + */ + fun put(key: String, value: Bitmap) { + put(key, Utils.Bitmap2Bytes(value)) + } + + /** + * 保存 bitmap 到 缓存中 + * + * @param key 保存的key + * @param value 保存的 bitmap 数据 + * @param saveTime 保存的时间,单位:秒 + */ + fun put(key: String, value: Bitmap, saveTime: Int) { + put(key, Utils.Bitmap2Bytes(value), saveTime) + } + + /** + * 读取 bitmap 数据 + * + * @return bitmap 数据 + */ + fun getAsBitmap(key: String): Bitmap? { + return if (getAsBinary(key) == null) { + null + } else Utils.Bytes2Bimap(getAsBinary(key)!!) + } + + // ======================================= + // ============= drawable 数据 读写 ============= + // ======================================= + + /** + * 保存 drawable 到 缓存中 + * + * @param key 保存的key + * @param value 保存的drawable数据 + */ + fun put(key: String, value: Drawable) { + put(key, Utils.drawable2Bitmap(value)) + } + + /** + * 保存 drawable 到 缓存中 + * + * @param key 保存的key + * @param value 保存的 drawable 数据 + * @param saveTime 保存的时间,单位:秒 + */ + fun put(key: String, value: Drawable, saveTime: Int) { + put(key, Utils.drawable2Bitmap(value), saveTime) + } + + /** + * 读取 Drawable 数据 + * + * @return Drawable 数据 + */ + fun getAsDrawable(key: String): Drawable? { + return if (getAsBinary(key) == null) { + null + } else Utils.bitmap2Drawable( + Utils.Bytes2Bimap( + getAsBinary(key)!! + ) + ) + } + + /** + * 获取缓存文件 + * + * @return value 缓存的文件 + */ + fun file(key: String): File? { + try { + val f = mCache.newFile(key) + if (f.exists()) { + return f + } + } catch (e: Exception) { + e.printStackTrace() + } + + return null + } + + /** + * 移除某个key + * + * @return 是否移除成功 + */ + fun remove(key: String): Boolean { + return mCache.remove(key) + } + + /** + * 清除所有数据 + */ + fun clear() { + mCache.clear() + } + + /** + * @author 杨福海(michael) www.yangfuhai.com + * @version 1.0 + * title 时间计算工具类 + */ + private object Utils { + + private val mSeparator = ' ' + + /** + * 判断缓存的String数据是否到期 + * + * @return true:到期了 false:还没有到期 + */ + fun isDue(str: String): Boolean { + return isDue(str.toByteArray()) + } + + /** + * 判断缓存的byte数据是否到期 + * + * @return true:到期了 false:还没有到期 + */ + fun isDue(data: ByteArray): Boolean { + try { + val strs = getDateInfoFromDate(data) + if (strs != null && strs.size == 2) { + var saveTimeStr = strs[0] + while (saveTimeStr.startsWith("0")) { + saveTimeStr = saveTimeStr + .substring(1) + } + val saveTime = java.lang.Long.valueOf(saveTimeStr) + val deleteAfter = java.lang.Long.valueOf(strs[1]) + if (System.currentTimeMillis() > saveTime + deleteAfter * 1000) { + return true + } + } + } catch (e: Exception) { + e.printStackTrace() + } + + return false + } + + fun newStringWithDateInfo(second: Int, strInfo: String): String { + return createDateInfo(second) + strInfo + } + + fun newByteArrayWithDateInfo(second: Int, data2: ByteArray): ByteArray { + val data1 = createDateInfo(second).toByteArray() + val retdata = ByteArray(data1.size + data2.size) + System.arraycopy(data1, 0, retdata, 0, data1.size) + System.arraycopy(data2, 0, retdata, data1.size, data2.size) + return retdata + } + + fun clearDateInfo(strInfo: String?): String? { + var strInfo = strInfo + if (strInfo != null && hasDateInfo(strInfo.toByteArray())) { + strInfo = strInfo.substring(strInfo.indexOf(mSeparator) + 1) + } + return strInfo + } + + fun clearDateInfo(data: ByteArray): ByteArray { + return if (hasDateInfo(data)) { + copyOfRange( + data, indexOf(data, mSeparator) + 1, + data.size + ) + } else data + } + + fun hasDateInfo(data: ByteArray?): Boolean { + return (data != null && data.size > 15 && data[13] == '-'.toByte() + && indexOf(data, mSeparator) > 14) + } + + fun getDateInfoFromDate(data: ByteArray): Array? { + if (hasDateInfo(data)) { + val saveDate = String(copyOfRange(data, 0, 13)) + val deleteAfter = String( + copyOfRange( + data, 14, + indexOf(data, mSeparator) + ) + ) + return arrayOf(saveDate, deleteAfter) + } + return null + } + + private fun indexOf(data: ByteArray, c: Char): Int { + for (i in data.indices) { + if (data[i] == c.toByte()) { + return i + } + } + return -1 + } + + private fun copyOfRange(original: ByteArray, from: Int, to: Int): ByteArray { + val newLength = to - from + require(newLength >= 0) { "$from > $to" } + val copy = ByteArray(newLength) + System.arraycopy( + original, from, copy, 0, + Math.min(original.size - from, newLength) + ) + return copy + } + + private fun createDateInfo(second: Int): String { + val currentTime = StringBuilder(System.currentTimeMillis().toString() + "") + while (currentTime.length < 13) { + currentTime.insert(0, "0") + } + return "$currentTime-$second$mSeparator" + } + + /* + * Bitmap → byte[] + */ + fun Bitmap2Bytes(bm: Bitmap): ByteArray { + val baos = ByteArrayOutputStream() + bm.compress(Bitmap.CompressFormat.PNG, 100, baos) + return baos.toByteArray() + } + + /* + * byte[] → Bitmap + */ + fun Bytes2Bimap(b: ByteArray): Bitmap? { + return if (b.size == 0) { + null + } else BitmapFactory.decodeByteArray(b, 0, b.size) + } + + /* + * Drawable → Bitmap + */ + fun drawable2Bitmap(drawable: Drawable): Bitmap { + // 取 drawable 的长宽 + val w = drawable.intrinsicWidth + val h = drawable.intrinsicHeight + // 取 drawable 的颜色格式 + val config = if (drawable.opacity != PixelFormat.OPAQUE) + Bitmap.Config.ARGB_8888 + else + Bitmap.Config.RGB_565 + // 建立对应 bitmap + val bitmap = Bitmap.createBitmap(w, h, config) + // 建立对应 bitmap 的画布 + val canvas = Canvas(bitmap) + drawable.setBounds(0, 0, w, h) + // 把 drawable 内容画到画布中 + drawable.draw(canvas) + return bitmap + } + + /* + * Bitmap → Drawable + */ + fun bitmap2Drawable(bm: Bitmap?): Drawable? { + return if (bm == null) { + null + } else BitmapDrawable(bm) + } + } + + /** + * @author 杨福海(michael) www.yangfuhai.com + * @version 1.0 + * title 缓存管理器 + */ + open inner class ACacheManager( + private var cacheDir: File, + private val sizeLimit: Long, + private val countLimit: Int + ) { + private val cacheSize: AtomicLong = AtomicLong() + private val cacheCount: AtomicInteger = AtomicInteger() + private val lastUsageDates = Collections + .synchronizedMap(HashMap()) + + init { + calculateCacheSizeAndCacheCount() + } + + /** + * 计算 cacheSize和cacheCount + */ + private fun calculateCacheSizeAndCacheCount() { + Thread { + + try { + var size = 0 + var count = 0 + val cachedFiles = cacheDir.listFiles() + if (cachedFiles != null) { + for (cachedFile in cachedFiles) { + size += calculateSize(cachedFile).toInt() + count += 1 + lastUsageDates[cachedFile] = cachedFile.lastModified() + } + cacheSize.set(size.toLong()) + cacheCount.set(count) + } + } catch (e: Exception) { + e.printStackTrace() + } + + + }.start() + } + + fun put(file: File) { + + try { + var curCacheCount = cacheCount.get() + while (curCacheCount + 1 > countLimit) { + val freedSize = removeNext() + cacheSize.addAndGet(-freedSize) + + curCacheCount = cacheCount.addAndGet(-1) + } + cacheCount.addAndGet(1) + + val valueSize = calculateSize(file) + var curCacheSize = cacheSize.get() + while (curCacheSize + valueSize > sizeLimit) { + val freedSize = removeNext() + curCacheSize = cacheSize.addAndGet(-freedSize) + } + cacheSize.addAndGet(valueSize) + + val currentTime = System.currentTimeMillis() + file.setLastModified(currentTime) + lastUsageDates[file] = currentTime + } catch (e: Exception) { + e.printStackTrace() + } + + } + + operator fun get(key: String): File { + val file = newFile(key) + val currentTime = System.currentTimeMillis() + file.setLastModified(currentTime) + lastUsageDates[file] = currentTime + + return file + } + + fun newFile(key: String): File { + return File(cacheDir, key.hashCode().toString() + "") + } + + fun remove(key: String): Boolean { + val image = get(key) + return image.delete() + } + + fun clear() { + try { + lastUsageDates.clear() + cacheSize.set(0) + val files = cacheDir.listFiles() + if (files != null) { + for (f in files) { + f.delete() + } + } + } catch (e: Exception) { + e.printStackTrace() + } + + } + + /** + * 移除旧的文件 + */ + private fun removeNext(): Long { + try { + if (lastUsageDates.isEmpty()) { + return 0 + } + + var oldestUsage: Long? = null + var mostLongUsedFile: File? = null + val entries = lastUsageDates.entries + synchronized(lastUsageDates) { + for ((key, lastValueUsage) in entries) { + if (mostLongUsedFile == null) { + mostLongUsedFile = key + oldestUsage = lastValueUsage + } else { + if (lastValueUsage < oldestUsage!!) { + oldestUsage = lastValueUsage + mostLongUsedFile = key + } + } + } + } + + var fileSize: Long = 0 + if (mostLongUsedFile != null) { + fileSize = calculateSize(mostLongUsedFile!!) + if (mostLongUsedFile!!.delete()) { + lastUsageDates.remove(mostLongUsedFile) + } + } + return fileSize + } catch (e: Exception) { + e.printStackTrace() + return 0 + } + + } + + private fun calculateSize(file: File): Long { + return file.length() + } + } + + companion object { + const val TIME_HOUR = 60 * 60 + const val TIME_DAY = TIME_HOUR * 24 + private const val MAX_SIZE = 1000 * 1000 * 50 // 50 mb + private const val MAX_COUNT = Integer.MAX_VALUE // 不限制存放数据的数量 + private val mInstanceMap = HashMap() + + @JvmOverloads + operator fun get(ctx: Context, cacheName: String = "ACache"): ACache? { + val f = File(ctx.cacheDir, cacheName) + return get(f, MAX_SIZE.toLong(), MAX_COUNT) + } + + operator fun get(ctx: Context, max_zise: Long, max_count: Int): ACache? { + try { + val f = File(ctx.cacheDir, "ACache") + return get(f, max_zise, max_count) + } catch (ignored: Exception) { + } + + return null + } + + @JvmOverloads + operator fun get( + cacheDir: File, + max_zise: Long = MAX_SIZE.toLong(), + max_count: Int = MAX_COUNT + ): ACache? { + try { + var manager = mInstanceMap[cacheDir.absoluteFile.toString() + myPid()] + if (manager == null) { + manager = ACache(cacheDir, max_zise, max_count) + mInstanceMap[cacheDir.absolutePath + myPid()] = manager + } + return manager + } catch (ignored: Exception) { + } + return null + } + + private fun myPid(): String { + return "_" + android.os.Process.myPid() + } + } + +} \ No newline at end of file From cab4193ea1a1e9241c920d36146f48087acc2964 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 25 Sep 2019 18:04:43 +0800 Subject: [PATCH 1643/1997] up --- .../lib/theme/view/ATEAutoCompleteTextView.kt | 6 ++-- .../book/source/manage/BookSourceActivity.kt | 8 +++-- .../main/java/io/legado/app/utils/ACache.kt | 30 ++++++++----------- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt index c88327109..8fb7063e0 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt @@ -38,9 +38,11 @@ class ATEAutoCompleteTextView : AppCompatAutoCompleteTextView { showDropDown() } - fun setFilterValues(values: List, delCallBack: ((value: String) -> Unit)? = null) { + fun setFilterValues(values: List?, delCallBack: ((value: String) -> Unit)? = null) { this.delCallBack = delCallBack - setAdapter(MyAdapter(context, values)) + values?.let { + setAdapter(MyAdapter(context, values)) + } } fun setFilterValues(vararg value: String, delCallBack: ((value: String) -> Unit)? = null) { diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt index 95fa8f635..c00d4167f 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt @@ -165,13 +165,17 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity @SuppressLint("InflateParams") private fun showImportDialog() { - val cacheUrls = ACache.get(this, "cacheUrls") + val cacheUrls: List? = ACache + .get(this, "cacheUrls", cacheDir = false) + ?.getAsString("sourceUrl") + ?.splitNotBlank(";") + ?.toMutableList() alert(titleResource = R.string.import_book_source_on_line) { var editText: ATEAutoCompleteTextView? = null customView { layoutInflater.inflate(R.layout.dialog_edit_text, null).apply { editText = edit_view - edit_view.setFilterValues("") { + edit_view.setFilterValues(cacheUrls) { } } diff --git a/app/src/main/java/io/legado/app/utils/ACache.kt b/app/src/main/java/io/legado/app/utils/ACache.kt index f40fac7f2..049b623da 100644 --- a/app/src/main/java/io/legado/app/utils/ACache.kt +++ b/app/src/main/java/io/legado/app/utils/ACache.kt @@ -769,31 +769,27 @@ class ACache private constructor(cacheDir: File, max_size: Long, max_count: Int) private val mInstanceMap = HashMap() @JvmOverloads - operator fun get(ctx: Context, cacheName: String = "ACache"): ACache? { - val f = File(ctx.cacheDir, cacheName) - return get(f, MAX_SIZE.toLong(), MAX_COUNT) - } - - operator fun get(ctx: Context, max_zise: Long, max_count: Int): ACache? { - try { - val f = File(ctx.cacheDir, "ACache") - return get(f, max_zise, max_count) - } catch (ignored: Exception) { - } - - return null + fun get( + ctx: Context, + cacheName: String = "ACache", + maxSize: Long = MAX_SIZE.toLong(), + maxCount: Int = MAX_COUNT, + cacheDir: Boolean = true + ): ACache? { + val f = if (cacheDir) File(ctx.cacheDir, cacheName) else File(ctx.filesDir, cacheName) + return get(f, maxSize, maxCount) } @JvmOverloads - operator fun get( + fun get( cacheDir: File, - max_zise: Long = MAX_SIZE.toLong(), - max_count: Int = MAX_COUNT + maxSize: Long = MAX_SIZE.toLong(), + maxCount: Int = MAX_COUNT ): ACache? { try { var manager = mInstanceMap[cacheDir.absoluteFile.toString() + myPid()] if (manager == null) { - manager = ACache(cacheDir, max_zise, max_count) + manager = ACache(cacheDir, maxSize, maxCount) mInstanceMap[cacheDir.absolutePath + myPid()] = manager } return manager From 3efd9363574750d960fb78b902e1514b064e0d6a Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 25 Sep 2019 20:08:32 +0800 Subject: [PATCH 1644/1997] up --- .../io/legado/app/data/entities/BookSource.kt | 4 +-- .../app/ui/main/explore/ExploreAdapter.kt | 2 +- .../main/java/io/legado/app/utils/ACache.kt | 29 ++++++++++--------- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/BookSource.kt b/app/src/main/java/io/legado/app/data/entities/BookSource.kt index a8a88e4cb..d2a61e330 100644 --- a/app/src/main/java/io/legado/app/data/entities/BookSource.kt +++ b/app/src/main/java/io/legado/app/data/entities/BookSource.kt @@ -126,7 +126,7 @@ data class BookSource( try { if (it.startsWith("", false)) { val aCache = ACache.get(App.INSTANCE, "explore") - a = aCache.getAsString(bookSourceUrl) ?: "" + a = aCache?.getAsString(bookSourceUrl) ?: "" if (a.isBlank()) { val bindings = SimpleBindings() bindings["baseUrl"] = bookSourceUrl @@ -135,7 +135,7 @@ data class BookSource( it.substring(4, it.lastIndexOf("<")), bindings ).toString() - aCache.put(bookSourceUrl, a) + aCache?.put(bookSourceUrl, a) } } val b = a.split("(&&|\n)+".toRegex()) diff --git a/app/src/main/java/io/legado/app/ui/main/explore/ExploreAdapter.kt b/app/src/main/java/io/legado/app/ui/main/explore/ExploreAdapter.kt index 0bc6c0891..136d7d4bf 100644 --- a/app/src/main/java/io/legado/app/ui/main/explore/ExploreAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/explore/ExploreAdapter.kt @@ -48,7 +48,7 @@ class ExploreAdapter(context: Context, private val scope: CoroutineScope, val ca R.id.menu_edit -> callBack.editSource(item.bookSourceUrl) R.id.menu_top -> callBack.toTop(item) R.id.menu_refresh -> { - ACache.get(context, "explore").remove(item.bookSourceUrl) + ACache.get(context, "explore")?.remove(item.bookSourceUrl) notifyItemChanged(holder.layoutPosition) } } diff --git a/app/src/main/java/io/legado/app/utils/ACache.kt b/app/src/main/java/io/legado/app/utils/ACache.kt index 049b623da..c9b2fda3d 100644 --- a/app/src/main/java/io/legado/app/utils/ACache.kt +++ b/app/src/main/java/io/legado/app/utils/ACache.kt @@ -336,7 +336,7 @@ class ACache private constructor(cacheDir: File, max_size: Long, max_count: Int) * @param value 保存的bitmap数据 */ fun put(key: String, value: Bitmap) { - put(key, Utils.Bitmap2Bytes(value)) + put(key, Utils.bitmap2Bytes(value)) } /** @@ -347,7 +347,7 @@ class ACache private constructor(cacheDir: File, max_size: Long, max_count: Int) * @param saveTime 保存的时间,单位:秒 */ fun put(key: String, value: Bitmap, saveTime: Int) { - put(key, Utils.Bitmap2Bytes(value), saveTime) + put(key, Utils.bitmap2Bytes(value), saveTime) } /** @@ -358,7 +358,7 @@ class ACache private constructor(cacheDir: File, max_size: Long, max_count: Int) fun getAsBitmap(key: String): Bitmap? { return if (getAsBinary(key) == null) { null - } else Utils.Bytes2Bimap(getAsBinary(key)!!) + } else Utils.bytes2Bitmap(getAsBinary(key)!!) } // ======================================= @@ -395,7 +395,7 @@ class ACache private constructor(cacheDir: File, max_size: Long, max_count: Int) return if (getAsBinary(key) == null) { null } else Utils.bitmap2Drawable( - Utils.Bytes2Bimap( + Utils.bytes2Bitmap( getAsBinary(key)!! ) ) @@ -486,16 +486,17 @@ class ACache private constructor(cacheDir: File, max_size: Long, max_count: Int) fun newByteArrayWithDateInfo(second: Int, data2: ByteArray): ByteArray { val data1 = createDateInfo(second).toByteArray() - val retdata = ByteArray(data1.size + data2.size) - System.arraycopy(data1, 0, retdata, 0, data1.size) - System.arraycopy(data2, 0, retdata, data1.size, data2.size) - return retdata + val retData = ByteArray(data1.size + data2.size) + System.arraycopy(data1, 0, retData, 0, data1.size) + System.arraycopy(data2, 0, retData, data1.size, data2.size) + return retData } fun clearDateInfo(strInfo: String?): String? { - var strInfo = strInfo - if (strInfo != null && hasDateInfo(strInfo.toByteArray())) { - strInfo = strInfo.substring(strInfo.indexOf(mSeparator) + 1) + strInfo?.let { + if (hasDateInfo(strInfo.toByteArray())) { + return strInfo.substring(strInfo.indexOf(mSeparator) + 1) + } } return strInfo } @@ -559,7 +560,7 @@ class ACache private constructor(cacheDir: File, max_size: Long, max_count: Int) /* * Bitmap → byte[] */ - fun Bitmap2Bytes(bm: Bitmap): ByteArray { + fun bitmap2Bytes(bm: Bitmap): ByteArray { val baos = ByteArrayOutputStream() bm.compress(Bitmap.CompressFormat.PNG, 100, baos) return baos.toByteArray() @@ -568,8 +569,8 @@ class ACache private constructor(cacheDir: File, max_size: Long, max_count: Int) /* * byte[] → Bitmap */ - fun Bytes2Bimap(b: ByteArray): Bitmap? { - return if (b.size == 0) { + fun bytes2Bitmap(b: ByteArray): Bitmap? { + return if (b.isEmpty()) { null } else BitmapFactory.decodeByteArray(b, 0, b.size) } From d8e33b1d9c4406b03ba60728706738a6232f9a6b Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 25 Sep 2019 21:45:02 +0800 Subject: [PATCH 1645/1997] up --- .../main/java/io/legado/app/data/entities/BookSource.kt | 4 ++-- .../app/ui/book/source/manage/BookSourceActivity.kt | 2 +- .../java/io/legado/app/ui/main/explore/ExploreAdapter.kt | 2 +- app/src/main/java/io/legado/app/utils/ACache.kt | 8 +++----- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/BookSource.kt b/app/src/main/java/io/legado/app/data/entities/BookSource.kt index d2a61e330..a8a88e4cb 100644 --- a/app/src/main/java/io/legado/app/data/entities/BookSource.kt +++ b/app/src/main/java/io/legado/app/data/entities/BookSource.kt @@ -126,7 +126,7 @@ data class BookSource( try { if (it.startsWith("", false)) { val aCache = ACache.get(App.INSTANCE, "explore") - a = aCache?.getAsString(bookSourceUrl) ?: "" + a = aCache.getAsString(bookSourceUrl) ?: "" if (a.isBlank()) { val bindings = SimpleBindings() bindings["baseUrl"] = bookSourceUrl @@ -135,7 +135,7 @@ data class BookSource( it.substring(4, it.lastIndexOf("<")), bindings ).toString() - aCache?.put(bookSourceUrl, a) + aCache.put(bookSourceUrl, a) } } val b = a.split("(&&|\n)+".toRegex()) diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt index c00d4167f..df1202bc8 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt @@ -167,7 +167,7 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity private fun showImportDialog() { val cacheUrls: List? = ACache .get(this, "cacheUrls", cacheDir = false) - ?.getAsString("sourceUrl") + .getAsString("sourceUrl") ?.splitNotBlank(";") ?.toMutableList() alert(titleResource = R.string.import_book_source_on_line) { diff --git a/app/src/main/java/io/legado/app/ui/main/explore/ExploreAdapter.kt b/app/src/main/java/io/legado/app/ui/main/explore/ExploreAdapter.kt index 136d7d4bf..0bc6c0891 100644 --- a/app/src/main/java/io/legado/app/ui/main/explore/ExploreAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/explore/ExploreAdapter.kt @@ -48,7 +48,7 @@ class ExploreAdapter(context: Context, private val scope: CoroutineScope, val ca R.id.menu_edit -> callBack.editSource(item.bookSourceUrl) R.id.menu_top -> callBack.toTop(item) R.id.menu_refresh -> { - ACache.get(context, "explore")?.remove(item.bookSourceUrl) + ACache.get(context, "explore").remove(item.bookSourceUrl) notifyItemChanged(holder.layoutPosition) } } diff --git a/app/src/main/java/io/legado/app/utils/ACache.kt b/app/src/main/java/io/legado/app/utils/ACache.kt index c9b2fda3d..570560e76 100644 --- a/app/src/main/java/io/legado/app/utils/ACache.kt +++ b/app/src/main/java/io/legado/app/utils/ACache.kt @@ -776,7 +776,7 @@ class ACache private constructor(cacheDir: File, max_size: Long, max_count: Int) maxSize: Long = MAX_SIZE.toLong(), maxCount: Int = MAX_COUNT, cacheDir: Boolean = true - ): ACache? { + ): ACache { val f = if (cacheDir) File(ctx.cacheDir, cacheName) else File(ctx.filesDir, cacheName) return get(f, maxSize, maxCount) } @@ -786,17 +786,15 @@ class ACache private constructor(cacheDir: File, max_size: Long, max_count: Int) cacheDir: File, maxSize: Long = MAX_SIZE.toLong(), maxCount: Int = MAX_COUNT - ): ACache? { - try { + ): ACache { + synchronized(this) { var manager = mInstanceMap[cacheDir.absoluteFile.toString() + myPid()] if (manager == null) { manager = ACache(cacheDir, maxSize, maxCount) mInstanceMap[cacheDir.absolutePath + myPid()] = manager } return manager - } catch (ignored: Exception) { } - return null } private fun myPid(): String { From 8c360c7d88336584a268c10b763ea2e3b012d332 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 25 Sep 2019 22:00:48 +0800 Subject: [PATCH 1646/1997] up --- .../main/java/io/legado/app/utils/ACache.kt | 77 +++++-------------- 1 file changed, 20 insertions(+), 57 deletions(-) diff --git a/app/src/main/java/io/legado/app/utils/ACache.kt b/app/src/main/java/io/legado/app/utils/ACache.kt index 570560e76..69603f9bd 100644 --- a/app/src/main/java/io/legado/app/utils/ACache.kt +++ b/app/src/main/java/io/legado/app/utils/ACache.kt @@ -15,6 +15,7 @@ import java.io.* import java.util.* import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicLong +import kotlin.math.min /** @@ -47,25 +48,11 @@ class ACache private constructor(cacheDir: File, max_size: Long, max_count: Int) fun put(key: String, value: String) { try { val file = mCache.newFile(key) - var out: BufferedWriter? = null - try { - out = BufferedWriter(FileWriter(file), 1024) - out.write(value) - } catch (ignored: IOException) { - } finally { - if (out != null) { - try { - out.flush() - out.close() - } catch (ignored: IOException) { - } - - } - mCache.put(file) - } - } catch (ignored: Exception) { + file.writeText(value) + mCache.put(file) + } catch (e: Exception) { + e.printStackTrace() } - } /** @@ -197,22 +184,8 @@ class ACache private constructor(cacheDir: File, max_size: Long, max_count: Int) */ fun put(key: String, value: ByteArray) { val file = mCache.newFile(key) - var out: FileOutputStream? = null - try { - out = FileOutputStream(file) - out.write(value) - } catch (ignored: Exception) { - } finally { - if (out != null) { - try { - out.flush() - out.close() - } catch (ignored: IOException) { - } - - } - mCache.put(file) - } + file.writeBytes(value) + mCache.put(file) } /** @@ -232,15 +205,13 @@ class ACache private constructor(cacheDir: File, max_size: Long, max_count: Int) * @return byte 数据 */ fun getAsBinary(key: String): ByteArray? { - var raf: RandomAccessFile? = null var removeFile = false try { val file = mCache[key] if (!file.exists()) return null - raf = RandomAccessFile(file, "r") - val byteArray = ByteArray(raf.length().toInt()) - raf.read(byteArray) + + val byteArray = file.readBytes() return if (!Utils.isDue(byteArray)) { Utils.clearDateInfo(byteArray) } else { @@ -251,14 +222,6 @@ class ACache private constructor(cacheDir: File, max_size: Long, max_count: Int) e.printStackTrace() return null } finally { - if (raf != null) { - try { - raf.close() - } catch (e: IOException) { - e.printStackTrace() - } - - } if (removeFile) remove(key) } @@ -274,10 +237,10 @@ class ACache private constructor(cacheDir: File, max_size: Long, max_count: Int) @JvmOverloads fun put(key: String, value: Serializable, saveTime: Int = -1) { try { - val baos = ByteArrayOutputStream() - ObjectOutputStream(baos).use { oos -> + val byteArrayOutputStream = ByteArrayOutputStream() + ObjectOutputStream(byteArrayOutputStream).use { oos -> oos.writeObject(value) - val data = baos.toByteArray() + val data = byteArrayOutputStream.toByteArray() if (saveTime != -1) { put(key, data, saveTime) } else { @@ -460,15 +423,15 @@ class ACache private constructor(cacheDir: File, max_size: Long, max_count: Int) */ fun isDue(data: ByteArray): Boolean { try { - val strs = getDateInfoFromDate(data) - if (strs != null && strs.size == 2) { - var saveTimeStr = strs[0] + val text = getDateInfoFromDate(data) + if (text != null && text.size == 2) { + var saveTimeStr = text[0] while (saveTimeStr.startsWith("0")) { saveTimeStr = saveTimeStr .substring(1) } val saveTime = java.lang.Long.valueOf(saveTimeStr) - val deleteAfter = java.lang.Long.valueOf(strs[1]) + val deleteAfter = java.lang.Long.valueOf(text[1]) if (System.currentTimeMillis() > saveTime + deleteAfter * 1000) { return true } @@ -544,7 +507,7 @@ class ACache private constructor(cacheDir: File, max_size: Long, max_count: Int) val copy = ByteArray(newLength) System.arraycopy( original, from, copy, 0, - Math.min(original.size - from, newLength) + min(original.size - from, newLength) ) return copy } @@ -561,9 +524,9 @@ class ACache private constructor(cacheDir: File, max_size: Long, max_count: Int) * Bitmap → byte[] */ fun bitmap2Bytes(bm: Bitmap): ByteArray { - val baos = ByteArrayOutputStream() - bm.compress(Bitmap.CompressFormat.PNG, 100, baos) - return baos.toByteArray() + val byteArrayOutputStream = ByteArrayOutputStream() + bm.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream) + return byteArrayOutputStream.toByteArray() } /* From eeabf34dcd79f5f0b38b1608a66158628c0e7b76 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 25 Sep 2019 22:05:21 +0800 Subject: [PATCH 1647/1997] up --- app/src/main/java/io/legado/app/utils/ACache.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/utils/ACache.kt b/app/src/main/java/io/legado/app/utils/ACache.kt index 69603f9bd..c8ef92b26 100644 --- a/app/src/main/java/io/legado/app/utils/ACache.kt +++ b/app/src/main/java/io/legado/app/utils/ACache.kt @@ -9,6 +9,7 @@ import android.graphics.PixelFormat import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable import android.util.Log +import io.legado.app.App import org.json.JSONArray import org.json.JSONObject import java.io.* @@ -405,7 +406,7 @@ class ACache private constructor(cacheDir: File, max_size: Long, max_count: Int) */ private object Utils { - private val mSeparator = ' ' + private const val mSeparator = ' ' /** * 判断缓存的String数据是否到期 @@ -566,7 +567,7 @@ class ACache private constructor(cacheDir: File, max_size: Long, max_count: Int) fun bitmap2Drawable(bm: Bitmap?): Drawable? { return if (bm == null) { null - } else BitmapDrawable(bm) + } else BitmapDrawable(App.INSTANCE.resources, bm) } } From e3a00202cce94ee19e900986824f703d5be24b7f Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 25 Sep 2019 22:07:07 +0800 Subject: [PATCH 1648/1997] up --- app/src/main/java/io/legado/app/utils/ACache.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/utils/ACache.kt b/app/src/main/java/io/legado/app/utils/ACache.kt index c8ef92b26..5ac75f875 100644 --- a/app/src/main/java/io/legado/app/utils/ACache.kt +++ b/app/src/main/java/io/legado/app/utils/ACache.kt @@ -31,7 +31,8 @@ class ACache private constructor(cacheDir: File, max_size: Long, max_count: Int) Log.i("ACache", "can't make dirs in %s" + cacheDir.absolutePath) } mCache = ACacheManager(cacheDir, max_size, max_count) - } catch (ignored: Exception) { + } catch (e: Exception) { + e.printStackTrace() } } @@ -130,7 +131,6 @@ class ACache private constructor(cacheDir: File, max_size: Long, max_count: Int) } catch (e: Exception) { null } - } // ======================================= From 6d6558160718c86fb0b4fadf201f3fbbcd9b924f Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 25 Sep 2019 22:18:35 +0800 Subject: [PATCH 1649/1997] up --- .../app/ui/book/source/manage/BookSourceActivity.kt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt index df1202bc8..ca7add879 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt @@ -165,7 +165,7 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity @SuppressLint("InflateParams") private fun showImportDialog() { - val cacheUrls: List? = ACache + val cacheUrls: MutableList? = ACache .get(this, "cacheUrls", cacheDir = false) .getAsString("sourceUrl") ?.splitNotBlank(";") @@ -176,12 +176,17 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity layoutInflater.inflate(R.layout.dialog_edit_text, null).apply { editText = edit_view edit_view.setFilterValues(cacheUrls) { - + cacheUrls?.remove(it) } } } okButton { - editText?.text + val text = editText?.text?.toString() + text?.let { + if (cacheUrls?.contains(it) == true) { + cacheUrls.add(0, it) + } + } } cancelButton() }.show().applyTint() From a5044a3f68c78d7a60a75eb7ac44ade3399fe2dd Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 25 Sep 2019 22:27:09 +0800 Subject: [PATCH 1650/1997] up --- .../legado/app/ui/book/source/manage/BookSourceActivity.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt index ca7add879..a71483930 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt @@ -165,10 +165,10 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity @SuppressLint("InflateParams") private fun showImportDialog() { - val cacheUrls: MutableList? = ACache - .get(this, "cacheUrls", cacheDir = false) + val aCache = ACache.get(this, cacheDir = false) + val cacheUrls: MutableList? = aCache .getAsString("sourceUrl") - ?.splitNotBlank(";") + ?.splitNotBlank(",") ?.toMutableList() alert(titleResource = R.string.import_book_source_on_line) { var editText: ATEAutoCompleteTextView? = null @@ -185,6 +185,7 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity text?.let { if (cacheUrls?.contains(it) == true) { cacheUrls.add(0, it) + aCache.put("sourceUrl", cacheUrls.joinToString(",")) } } } From 4e5e8c698bd78be0aada734494cf5d44752931ce Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 25 Sep 2019 22:37:36 +0800 Subject: [PATCH 1651/1997] up --- .../app/ui/book/source/manage/BookSourceActivity.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt index a71483930..4ece6fc99 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt @@ -166,24 +166,24 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity @SuppressLint("InflateParams") private fun showImportDialog() { val aCache = ACache.get(this, cacheDir = false) - val cacheUrls: MutableList? = aCache + val cacheUrls: MutableList = aCache .getAsString("sourceUrl") ?.splitNotBlank(",") - ?.toMutableList() + ?.toMutableList() ?: mutableListOf() alert(titleResource = R.string.import_book_source_on_line) { var editText: ATEAutoCompleteTextView? = null customView { layoutInflater.inflate(R.layout.dialog_edit_text, null).apply { editText = edit_view edit_view.setFilterValues(cacheUrls) { - cacheUrls?.remove(it) + cacheUrls.remove(it) } } } okButton { val text = editText?.text?.toString() text?.let { - if (cacheUrls?.contains(it) == true) { + if (!cacheUrls.contains(it)) { cacheUrls.add(0, it) aCache.put("sourceUrl", cacheUrls.joinToString(",")) } From d9c9802ef2b2b23bc7a56af92376763363dc989c Mon Sep 17 00:00:00 2001 From: mabdc <747455334@qq.com> Date: Thu, 26 Sep 2019 00:12:41 +0800 Subject: [PATCH 1652/1997] =?UTF-8?q?=E5=88=AA=E9=99=A4=E6=9C=80=E8=BF=91?= =?UTF-8?q?=E9=96=B2=E8=AE=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../legado/app/ui/main/bookshelf/BookshelfFragment.kt | 1 - app/src/main/res/layout/fragment_bookshelf.xml | 10 ---------- 2 files changed, 11 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index 60bccd39f..df11b8a71 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -72,7 +72,6 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b refresh_layout.isRefreshing = false viewModel.upChapterList() } - tv_recent_reading.textColor = accentColor rv_book_group.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) bookGroupAdapter = BookGroupAdapter() diff --git a/app/src/main/res/layout/fragment_bookshelf.xml b/app/src/main/res/layout/fragment_bookshelf.xml index 5e34af041..e160da925 100644 --- a/app/src/main/res/layout/fragment_bookshelf.xml +++ b/app/src/main/res/layout/fragment_bookshelf.xml @@ -18,16 +18,6 @@ android:layout_height="wrap_content" android:overScrollMode="never"/> - - Date: Thu, 26 Sep 2019 08:10:20 +0800 Subject: [PATCH 1653/1997] up --- .../io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt index 8fb7063e0..6c0d8ec7a 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt @@ -35,7 +35,9 @@ class ATEAutoCompleteTextView : AppCompatAutoCompleteTextView { override fun onFocusChanged(focused: Boolean, direction: Int, previouslyFocusedRect: Rect?) { super.onFocusChanged(focused, direction, previouslyFocusedRect) - showDropDown() + if (focused) { + showDropDown() + } } fun setFilterValues(values: List?, delCallBack: ((value: String) -> Unit)? = null) { From 70d0c4c89fc0c3168bd5cede73781d3968f77ed6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 26 Sep 2019 08:48:33 +0800 Subject: [PATCH 1654/1997] up --- .../io/legado/app/ui/book/source/manage/BookSourceActivity.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt index 4ece6fc99..8c1b5b954 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt @@ -177,6 +177,7 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity editText = edit_view edit_view.setFilterValues(cacheUrls) { cacheUrls.remove(it) + aCache.put("sourceUrl", cacheUrls.joinToString(",")) } } } From 2fbb4f1df79d9145a441e7b7ab8b08807c9d7b36 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 26 Sep 2019 10:24:53 +0800 Subject: [PATCH 1655/1997] up --- .../app/lib/theme/view/ATEAutoCompleteTextView.kt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt b/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt index 6c0d8ec7a..ae7dec6e0 100644 --- a/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt +++ b/app/src/main/java/io/legado/app/lib/theme/view/ATEAutoCompleteTextView.kt @@ -1,9 +1,10 @@ package io.legado.app.lib.theme.view +import android.annotation.SuppressLint import android.content.Context -import android.graphics.Rect import android.util.AttributeSet import android.view.LayoutInflater +import android.view.MotionEvent import android.view.View import android.view.ViewGroup import android.widget.ArrayAdapter @@ -32,12 +33,13 @@ class ATEAutoCompleteTextView : AppCompatAutoCompleteTextView { return true } - override fun onFocusChanged(focused: Boolean, direction: Int, previouslyFocusedRect: Rect?) { - super.onFocusChanged(focused, direction, previouslyFocusedRect) - if (focused) { + @SuppressLint("ClickableViewAccessibility") + override fun onTouchEvent(event: MotionEvent?): Boolean { + if (event?.action == MotionEvent.ACTION_DOWN) { showDropDown() } + return super.onTouchEvent(event) } fun setFilterValues(values: List?, delCallBack: ((value: String) -> Unit)? = null) { From c0ae964d5c3f54e49dd4d4b517da69470b7b4115 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 26 Sep 2019 11:41:29 +0800 Subject: [PATCH 1656/1997] up --- .../io/legado/app/help/storage/OldRule.kt | 9 +--- .../io/legado/app/help/storage/Restore.kt | 13 +++-- .../book/source/manage/BookSourceActivity.kt | 1 + .../book/source/manage/BookSourceViewModel.kt | 53 ++++++++++++++++++- .../io/legado/app/utils/StringExtensions.kt | 16 ++++++ 5 files changed, 78 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/storage/OldRule.kt b/app/src/main/java/io/legado/app/help/storage/OldRule.kt index 3c49817a8..9295aaa0d 100644 --- a/app/src/main/java/io/legado/app/help/storage/OldRule.kt +++ b/app/src/main/java/io/legado/app/help/storage/OldRule.kt @@ -1,10 +1,8 @@ package io.legado.app.help.storage -import com.jayway.jsonpath.Configuration -import com.jayway.jsonpath.JsonPath -import com.jayway.jsonpath.Option import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.rule.* +import io.legado.app.help.storage.Restore.jsonPath import io.legado.app.utils.GSON import io.legado.app.utils.fromJsonObject import io.legado.app.utils.readInt @@ -14,11 +12,6 @@ import java.util.regex.Pattern object OldRule { private val headerPattern = Pattern.compile("@Header:\\{.+?\\}", Pattern.CASE_INSENSITIVE) private val jsPattern = Pattern.compile("\\{\\{.+?\\}\\}", Pattern.CASE_INSENSITIVE) - private val jsonPath = JsonPath.using( - Configuration.builder() - .options(Option.SUPPRESS_EXCEPTIONS) - .build() - ) fun jsonToBookSource(json: String): BookSource? { var source: BookSource? = null diff --git a/app/src/main/java/io/legado/app/help/storage/Restore.kt b/app/src/main/java/io/legado/app/help/storage/Restore.kt index ad0db5710..593bbec5e 100644 --- a/app/src/main/java/io/legado/app/help/storage/Restore.kt +++ b/app/src/main/java/io/legado/app/help/storage/Restore.kt @@ -5,6 +5,7 @@ import android.util.Log import com.jayway.jsonpath.Configuration import com.jayway.jsonpath.JsonPath import com.jayway.jsonpath.Option +import com.jayway.jsonpath.ParseContext import io.legado.app.App import io.legado.app.constant.AppConst import io.legado.app.data.entities.Book @@ -21,11 +22,13 @@ import org.jetbrains.anko.uiThread import java.io.File object Restore { - private val jsonPath = JsonPath.using( - Configuration.builder() - .options(Option.SUPPRESS_EXCEPTIONS) - .build() - ) + val jsonPath: ParseContext by lazy { + JsonPath.using( + Configuration.builder() + .options(Option.SUPPRESS_EXCEPTIONS) + .build() + ) + } fun restore(path: String = defaultPath) { doAsync { diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt index 8c1b5b954..6dfc8f3a2 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt @@ -188,6 +188,7 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity cacheUrls.add(0, it) aCache.put("sourceUrl", cacheUrls.joinToString(",")) } + viewModel.importSource(it) } } cancelButton() diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt index 289b3a84a..3ae268728 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt @@ -2,10 +2,15 @@ package io.legado.app.ui.book.source.manage import android.app.Application import android.text.TextUtils +import com.jayway.jsonpath.JsonPath import io.legado.app.App import io.legado.app.base.BaseViewModel +import io.legado.app.data.api.IHttpGetApi import io.legado.app.data.entities.BookSource -import io.legado.app.utils.splitNotBlank +import io.legado.app.help.http.HttpHelper +import io.legado.app.help.storage.OldRule +import io.legado.app.help.storage.Restore.jsonPath +import io.legado.app.utils.* class BookSourceViewModel(application: Application) : BaseViewModel(application) { @@ -92,4 +97,50 @@ class BookSourceViewModel(application: Application) : BaseViewModel(application) } } } + + fun importSource(text: String) { + execute { + val text1 = text.trim() + if (text1.isJsonObject()) { + val json = JsonPath.parse(text1) + val urls = json.read>("$.sourceUrls") + if (!urls.isNullOrEmpty()) { + urls.forEach { importSourceUrl(it) } + } else { + OldRule.jsonToBookSource(text1)?.let { + App.db.bookSourceDao().insert(it) + } + } + } else if (text1.isJsonArray()) { + val bookSources = mutableListOf() + val items: List> = jsonPath.parse(text1).read("$") + for (item in items) { + val jsonItem = jsonPath.parse(item) + OldRule.jsonToBookSource(jsonItem.jsonString())?.let { + bookSources.add(it) + } + } + App.db.bookSourceDao().insert(*bookSources.toTypedArray()) + } else if (text1.isAbsUrl()) { + importSourceUrl(text1) + } else { + toast("格式不对") + } + }.onError { + toast(it.localizedMessage) + } + } + + private fun importSourceUrl(url: String) { + execute { + NetworkUtils.getBaseUrl(url)?.let { + val response = HttpHelper.getApiService(it).get(url, mapOf()).execute() + response.body()?.let { body -> + importSource(body) + } + } + }.onError { + toast(it.localizedMessage) + } + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/utils/StringExtensions.kt b/app/src/main/java/io/legado/app/utils/StringExtensions.kt index a31dff411..a58e17c56 100644 --- a/app/src/main/java/io/legado/app/utils/StringExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/StringExtensions.kt @@ -18,6 +18,22 @@ fun String?.isJson(): Boolean = this?.run { } } ?: false +fun String?.isJsonObject(): Boolean = this?.run { + val str = this.trim() + when { + str.startsWith("{") && str.endsWith("}") -> true + else -> false + } +} ?: false + +fun String?.isJsonArray(): Boolean = this?.run { + val str = this.trim() + when { + str.startsWith("[") && str.endsWith("]") -> true + else -> false + } +} ?: false + fun String?.htmlFormat(): String = if (this.isNullOrBlank()) "" else this.replace("(?i)<(br[\\s/]*|/*p\\b.*?|/*div\\b.*?)>".toRegex(), "\n")// 替换特定标签为换行符 .replace("<[script>]*.*?>| ".toRegex(), "")// 删除script标签对和空格转义符 From 46020796524d1a398dff7da7a4b6557c9ffab317 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 26 Sep 2019 11:44:22 +0800 Subject: [PATCH 1657/1997] up --- .../io/legado/app/ui/book/source/manage/BookSourceViewModel.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt index 3ae268728..31accc240 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt @@ -110,6 +110,7 @@ class BookSourceViewModel(application: Application) : BaseViewModel(application) OldRule.jsonToBookSource(text1)?.let { App.db.bookSourceDao().insert(it) } + toast("成功导入1条") } } else if (text1.isJsonArray()) { val bookSources = mutableListOf() @@ -121,6 +122,7 @@ class BookSourceViewModel(application: Application) : BaseViewModel(application) } } App.db.bookSourceDao().insert(*bookSources.toTypedArray()) + toast("成功导入${bookSources.size}条") } else if (text1.isAbsUrl()) { importSourceUrl(text1) } else { From 4aec23aa1cfab987926ab16f90cc7f0cb83860cc Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 26 Sep 2019 13:52:26 +0800 Subject: [PATCH 1658/1997] up --- app/src/main/res/layout/item_1line_text_and_del.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/layout/item_1line_text_and_del.xml b/app/src/main/res/layout/item_1line_text_and_del.xml index b30b387d2..1b43e8d27 100644 --- a/app/src/main/res/layout/item_1line_text_and_del.xml +++ b/app/src/main/res/layout/item_1line_text_and_del.xml @@ -3,6 +3,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" + android:gravity="center_vertical" android:orientation="horizontal" android:padding="6dp" tools:ignore="UseCompoundDrawables"> From 866289bae2134ebcb3b4f3af23db3e0d0d320807 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 26 Sep 2019 17:40:52 +0800 Subject: [PATCH 1659/1997] up --- app/build.gradle | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 648e65cae..22922cbbe 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -88,10 +88,11 @@ dependencies { //androidX implementation 'androidx.core:core-ktx:1.2.0-alpha04' implementation 'androidx.appcompat:appcompat:1.1.0' + implementation 'androidx.media:media:1.1.0' implementation 'androidx.preference:preference:1.1.0' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0' - implementation 'androidx.media:media:1.1.0' + implementation 'androidx.viewpager2:viewpager2:1.0.0-beta04' implementation 'com.google.android.material:material:1.1.0-alpha10' implementation 'com.google.android:flexbox:1.1.0' From 33bcc77103d22a310f194f62722ea7f2edf3f848 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 26 Sep 2019 21:53:04 +0800 Subject: [PATCH 1660/1997] up --- app/src/main/AndroidManifest.xml | 1 - .../app/ui/bookshelf/BookshelfActivity.kt | 76 ------------- .../app/ui/bookshelf/BookshelfViewModel.kt | 11 -- .../io/legado/app/ui/main/MainViewModel.kt | 40 +++++++ .../bookshelf/BooksAdapter.kt} | 57 +++++++--- .../app/ui/main/bookshelf/BooksFragment.kt | 102 ++++++++++++++++++ .../app/ui/main/bookshelf/BooksViewModel.kt | 9 ++ .../app/ui/main/bookshelf/BookshelfAdapter.kt | 98 ++--------------- .../ui/main/bookshelf/BookshelfFragment.kt | 53 ++------- .../ui/main/bookshelf/BookshelfViewModel.kt | 41 ------- ...ivity_bookshelf.xml => fragment_books.xml} | 11 +- .../main/res/layout/fragment_bookshelf.xml | 15 +-- 12 files changed, 212 insertions(+), 302 deletions(-) delete mode 100644 app/src/main/java/io/legado/app/ui/bookshelf/BookshelfActivity.kt delete mode 100644 app/src/main/java/io/legado/app/ui/bookshelf/BookshelfViewModel.kt rename app/src/main/java/io/legado/app/ui/{bookshelf/BookshelfAdapter.kt => main/bookshelf/BooksAdapter.kt} (52%) create mode 100644 app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt create mode 100644 app/src/main/java/io/legado/app/ui/main/bookshelf/BooksViewModel.kt rename app/src/main/res/layout/{activity_bookshelf.xml => fragment_books.xml} (50%) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 10b20cba9..96e2b7ea2 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -59,7 +59,6 @@ - diff --git a/app/src/main/java/io/legado/app/ui/bookshelf/BookshelfActivity.kt b/app/src/main/java/io/legado/app/ui/bookshelf/BookshelfActivity.kt deleted file mode 100644 index 590699652..000000000 --- a/app/src/main/java/io/legado/app/ui/bookshelf/BookshelfActivity.kt +++ /dev/null @@ -1,76 +0,0 @@ -package io.legado.app.ui.bookshelf - -import android.os.Bundle -import android.widget.LinearLayout -import androidx.lifecycle.LiveData -import androidx.lifecycle.Observer -import androidx.paging.LivePagedListBuilder -import androidx.paging.PagedList -import androidx.recyclerview.widget.DividerItemDecoration -import androidx.recyclerview.widget.LinearLayoutManager -import io.legado.app.App -import io.legado.app.R -import io.legado.app.base.VMBaseActivity -import io.legado.app.data.entities.Book -import io.legado.app.lib.theme.ATH -import io.legado.app.utils.getViewModel -import kotlinx.android.synthetic.main.activity_bookshelf.* - -class BookshelfActivity : VMBaseActivity(R.layout.activity_bookshelf) { - override val viewModel: BookshelfViewModel - get() = getViewModel(BookshelfViewModel::class.java) - - private lateinit var bookshelfAdapter: BookshelfAdapter - private var bookshelfLiveData: LiveData>? = null - - override fun onActivityCreated(savedInstanceState: Bundle?) { - if (viewModel.bookGroup == null) { - viewModel.bookGroup = intent.getParcelableExtra("data") - } - viewModel.bookGroup?.let { - title_bar.title = it.groupName - } - initRecyclerView() - upRecyclerData() - } - - private fun initRecyclerView() { - ATH.applyEdgeEffectColor(rv_bookshelf) - rv_bookshelf.layoutManager = LinearLayoutManager(this) - rv_bookshelf.addItemDecoration(DividerItemDecoration(this, LinearLayout.VERTICAL)) - bookshelfAdapter = BookshelfAdapter() - rv_bookshelf.adapter = bookshelfAdapter - } - - private fun upRecyclerData() { - viewModel.bookGroup?.let { - bookshelfLiveData?.removeObservers(this) - when (it.groupId) { - -1 -> { - - bookshelfLiveData = - LivePagedListBuilder(App.db.bookDao().observeAll(), 10).build() - } - -2 -> { - bookshelfLiveData = - LivePagedListBuilder(App.db.bookDao().observeLocal(), 10).build() - } - -3 -> { - bookshelfLiveData = - LivePagedListBuilder(App.db.bookDao().observeAudio(), 10).build() - } - else -> { - bookshelfLiveData = - LivePagedListBuilder( - App.db.bookDao().observeByGroup(it.groupId), - 10 - ).build() - } - } - bookshelfLiveData?.observe( - this, - Observer { pageList -> bookshelfAdapter.submitList(pageList) }) - } - } - -} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/bookshelf/BookshelfViewModel.kt b/app/src/main/java/io/legado/app/ui/bookshelf/BookshelfViewModel.kt deleted file mode 100644 index 3948465ac..000000000 --- a/app/src/main/java/io/legado/app/ui/bookshelf/BookshelfViewModel.kt +++ /dev/null @@ -1,11 +0,0 @@ -package io.legado.app.ui.bookshelf - -import android.app.Application -import io.legado.app.base.BaseViewModel -import io.legado.app.data.entities.BookGroup - -class BookshelfViewModel(application: Application) : BaseViewModel(application) { - - var bookGroup: BookGroup? = null - -} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt b/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt index 95890e830..9f191510a 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt @@ -1,16 +1,56 @@ package io.legado.app.ui.main import android.app.Application +import io.legado.app.App import io.legado.app.base.BaseViewModel +import io.legado.app.constant.BookType +import io.legado.app.constant.Bus import io.legado.app.help.storage.Restore +import io.legado.app.model.WebBook +import io.legado.app.utils.postEvent import kotlinx.coroutines.Dispatchers.IO +import kotlinx.coroutines.delay import kotlinx.coroutines.launch class MainViewModel(application: Application) : BaseViewModel(application) { + val updateList = arrayListOf() fun restore() { launch(IO) { Restore.importYueDuData(getApplication()) } } + + fun upChapterList() { + execute { + App.db.bookDao().getRecentRead().forEach { book -> + if (book.origin != BookType.local) { + App.db.bookSourceDao().getBookSource(book.origin)?.let { bookSource -> + synchronized(this) { + updateList.add(book.bookUrl) + postEvent(Bus.UP_BOOK, book.bookUrl) + } + WebBook(bookSource).getChapterList(book) + .onSuccess(IO) { + it?.let { + App.db.bookDao().update(book) + App.db.bookChapterDao().delByBook(book.bookUrl) + App.db.bookChapterDao().insert(*it.toTypedArray()) + } + } + .onError { + it.printStackTrace() + } + .onFinally { + synchronized(this) { + updateList.remove(book.bookUrl) + postEvent(Bus.UP_BOOK, book.bookUrl) + } + } + } + } + delay(50) + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/bookshelf/BookshelfAdapter.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt similarity index 52% rename from app/src/main/java/io/legado/app/ui/bookshelf/BookshelfAdapter.kt rename to app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt index 1a8ed67f6..603684163 100644 --- a/app/src/main/java/io/legado/app/ui/bookshelf/BookshelfAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt @@ -1,4 +1,4 @@ -package io.legado.app.ui.bookshelf +package io.legado.app.ui.main.bookshelf import android.view.LayoutInflater import android.view.View @@ -7,12 +7,18 @@ import androidx.paging.PagedListAdapter import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import io.legado.app.R +import io.legado.app.constant.BookType import io.legado.app.data.entities.Book import io.legado.app.help.ImageLoader -import io.legado.app.lib.theme.ATH +import io.legado.app.lib.theme.ThemeStore +import io.legado.app.utils.getCompatColor +import io.legado.app.utils.invisible import kotlinx.android.synthetic.main.item_bookshelf_list.view.* +import org.jetbrains.anko.sdk27.listeners.onClick +import org.jetbrains.anko.sdk27.listeners.onLongClick -class BookshelfAdapter : PagedListAdapter(DIFF_CALLBACK) { +class BooksAdapter(private val callBack: CallBack) : + PagedListAdapter(DIFF_CALLBACK) { companion object { @JvmField @@ -21,23 +27,28 @@ class BookshelfAdapter : PagedListAdapter(D oldItem.bookUrl == newItem.bookUrl override fun areContentsTheSame(oldItem: Book, newItem: Book): Boolean = - oldItem.bookUrl == newItem.bookUrl - && oldItem.durChapterTitle == newItem.durChapterTitle + oldItem.durChapterTitle == newItem.durChapterTitle && oldItem.latestChapterTitle == newItem.latestChapterTitle && oldItem.durChapterTime == newItem.durChapterTime && oldItem.lastCheckTime == newItem.lastCheckTime } } - var callBack: CallBack? = null + fun notification(bookUrl: String) { + for (i in 0..itemCount) { + getItem(i)?.let { + if (it.bookUrl == bookUrl) { + notifyItemChanged(i) + return + } + } + } + } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { return MyViewHolder( - LayoutInflater.from(parent.context).inflate( - R.layout.item_bookshelf_list, - parent, - false - ) + LayoutInflater.from(parent.context) + .inflate(R.layout.item_bookshelf_list, parent, false) ) } @@ -50,27 +61,41 @@ class BookshelfAdapter : PagedListAdapter(D class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { init { - ATH.applyBackgroundTint(itemView) + itemView.setBackgroundColor(ThemeStore.backgroundColor(itemView.context)) } - fun bind(book: Book, callBack: CallBack?) = with(itemView) { + fun bind(book: Book, callBack: CallBack) = with(itemView) { + this.setBackgroundColor(context.getCompatColor(R.color.background)) tv_name.text = book.name tv_author.text = book.author tv_read.text = book.durChapterTitle tv_last.text = book.latestChapterTitle book.getDisplayCover()?.let { - ImageLoader.load(context, it)//Glide自动识别http://和file:/// + ImageLoader.load(context, it)//Glide自动识别http://和file:// .placeholder(R.drawable.img_cover_default) .error(R.drawable.img_cover_default) .centerCrop() .setAsDrawable(iv_cover) } - itemView.setOnClickListener { callBack?.open(book) } + itemView.onClick { callBack.open(book) } + itemView.onLongClick { + callBack.openBookInfo(book) + true + } + if (book.origin != BookType.local && callBack.isUpdate(book.bookUrl)) { + bv_unread.invisible() + rl_loading.show() + } else { + rl_loading.hide() + bv_unread.setBadgeCount(book.getUnreadChapterNum()) + bv_unread.setHighlight(book.lastCheckCount > 0) + } } } interface CallBack { fun open(book: Book) - fun search() + fun openBookInfo(book: Book) + fun isUpdate(bookUrl: String): Boolean } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt new file mode 100644 index 000000000..ee8236255 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt @@ -0,0 +1,102 @@ +package io.legado.app.ui.main.bookshelf + +import android.os.Bundle +import android.view.View +import androidx.lifecycle.LiveData +import androidx.lifecycle.Observer +import androidx.paging.LivePagedListBuilder +import androidx.paging.PagedList +import androidx.recyclerview.widget.DividerItemDecoration +import androidx.recyclerview.widget.LinearLayoutManager +import io.legado.app.App +import io.legado.app.R +import io.legado.app.base.VMBaseFragment +import io.legado.app.data.entities.Book +import io.legado.app.lib.theme.ATH +import io.legado.app.lib.theme.accentColor +import io.legado.app.ui.book.info.BookInfoActivity +import io.legado.app.ui.book.read.ReadBookActivity +import io.legado.app.ui.main.MainViewModel +import io.legado.app.utils.getViewModel +import io.legado.app.utils.getViewModelOfActivity +import kotlinx.android.synthetic.main.fragment_books.* +import org.jetbrains.anko.startActivity + + +class BooksFragment : VMBaseFragment(R.layout.fragment_books), + BooksAdapter.CallBack { + override val viewModel: BooksViewModel + get() = getViewModel(BooksViewModel::class.java) + + private lateinit var activityViewModel: MainViewModel + private lateinit var booksAdapter: BooksAdapter + private var bookshelfLiveData: LiveData>? = null + private val groupId = -1 + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + activityViewModel = getViewModelOfActivity(MainViewModel::class.java) + initRecyclerView() + upRecyclerData() + } + + private fun initRecyclerView() { + ATH.applyEdgeEffectColor(rv_bookshelf) + refresh_layout.setColorSchemeColors(accentColor) + refresh_layout.setOnRefreshListener { + refresh_layout.isRefreshing = false + activityViewModel.upChapterList() + } + rv_bookshelf.layoutManager = LinearLayoutManager(context) + rv_bookshelf.addItemDecoration( + DividerItemDecoration( + rv_bookshelf.context, + LinearLayoutManager.VERTICAL + ) + ) + booksAdapter = BooksAdapter(this) + rv_bookshelf.adapter = booksAdapter + + } + + private fun upRecyclerData() { + bookshelfLiveData?.removeObservers(this) + when (groupId) { + -1 -> { + + bookshelfLiveData = + LivePagedListBuilder(App.db.bookDao().observeAll(), 10).build() + } + -2 -> { + bookshelfLiveData = + LivePagedListBuilder(App.db.bookDao().observeLocal(), 10).build() + } + -3 -> { + bookshelfLiveData = + LivePagedListBuilder(App.db.bookDao().observeAudio(), 10).build() + } + else -> { + bookshelfLiveData = + LivePagedListBuilder( + App.db.bookDao().observeByGroup(groupId), + 10 + ).build() + } + } + bookshelfLiveData?.observe( + this, + Observer { pageList -> booksAdapter.submitList(pageList) }) + } + + override fun open(book: Book) { + context?.startActivity(Pair("bookUrl", book.bookUrl)) + } + + override fun openBookInfo(book: Book) { + context?.startActivity(Pair("bookUrl", book.bookUrl)) + } + + override fun isUpdate(bookUrl: String): Boolean { + return bookUrl in activityViewModel.updateList + } + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksViewModel.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksViewModel.kt new file mode 100644 index 000000000..19fa12c04 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksViewModel.kt @@ -0,0 +1,9 @@ +package io.legado.app.ui.main.bookshelf + +import android.app.Application +import io.legado.app.base.BaseViewModel + + +class BooksViewModel(application: Application) : BaseViewModel(application) { + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt index 34172056d..86238a663 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt @@ -1,101 +1,17 @@ package io.legado.app.ui.main.bookshelf -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.paging.PagedListAdapter -import androidx.recyclerview.widget.DiffUtil -import androidx.recyclerview.widget.RecyclerView -import io.legado.app.R -import io.legado.app.constant.BookType -import io.legado.app.data.entities.Book -import io.legado.app.help.ImageLoader -import io.legado.app.lib.theme.ThemeStore -import io.legado.app.utils.getCompatColor -import io.legado.app.utils.invisible -import kotlinx.android.synthetic.main.item_bookshelf_list.view.* -import org.jetbrains.anko.sdk27.listeners.onClick -import org.jetbrains.anko.sdk27.listeners.onLongClick +import androidx.fragment.app.Fragment +import androidx.viewpager2.adapter.FragmentStateAdapter -class BookshelfAdapter(private val callBack: CallBack) : - PagedListAdapter(DIFF_CALLBACK) { - companion object { - @JvmField - val DIFF_CALLBACK = object : DiffUtil.ItemCallback() { - override fun areItemsTheSame(oldItem: Book, newItem: Book): Boolean = - oldItem.bookUrl == newItem.bookUrl +class BookshelfAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) { - override fun areContentsTheSame(oldItem: Book, newItem: Book): Boolean = - oldItem.durChapterTitle == newItem.durChapterTitle - && oldItem.latestChapterTitle == newItem.latestChapterTitle - && oldItem.durChapterTime == newItem.durChapterTime - && oldItem.lastCheckTime == newItem.lastCheckTime - } + override fun getItemCount(): Int { + return 3 } - fun notification(bookUrl: String) { - for (i in 0..itemCount) { - getItem(i)?.let { - if (it.bookUrl == bookUrl) { - notifyItemChanged(i) - return - } - } - } + override fun createFragment(position: Int): Fragment { + return BooksFragment() } - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { - return MyViewHolder( - LayoutInflater.from(parent.context) - .inflate(R.layout.item_bookshelf_list, parent, false) - ) - } - - override fun onBindViewHolder(holder: MyViewHolder, position: Int) { - currentList?.get(position)?.let { - holder.bind(it, callBack) - } - } - - class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { - - init { - itemView.setBackgroundColor(ThemeStore.backgroundColor(itemView.context)) - } - - fun bind(book: Book, callBack: CallBack) = with(itemView) { - this.setBackgroundColor(context.getCompatColor(R.color.background)) - tv_name.text = book.name - tv_author.text = book.author - tv_read.text = book.durChapterTitle - tv_last.text = book.latestChapterTitle - book.getDisplayCover()?.let { - ImageLoader.load(context, it)//Glide自动识别http://和file:// - .placeholder(R.drawable.img_cover_default) - .error(R.drawable.img_cover_default) - .centerCrop() - .setAsDrawable(iv_cover) - } - itemView.onClick { callBack.open(book) } - itemView.onLongClick { - callBack.openBookInfo(book) - true - } - if (book.origin != BookType.local && callBack.isUpdate(book.bookUrl)) { - bv_unread.invisible() - rl_loading.show() - } else { - rl_loading.hide() - bv_unread.setBadgeCount(book.getUnreadChapterNum()) - bv_unread.setHighlight(book.lastCheckCount > 0) - } - } - } - - interface CallBack { - fun open(book: Book) - fun openBookInfo(book: Book) - fun isUpdate(bookUrl: String): Boolean - } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index df11b8a71..9b6d5f90b 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -11,46 +11,36 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.Observer import androidx.paging.LivePagedListBuilder import androidx.paging.PagedList -import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.App import io.legado.app.R import io.legado.app.base.VMBaseFragment import io.legado.app.constant.Bus -import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookGroup import io.legado.app.lib.dialogs.* import io.legado.app.lib.theme.ATH -import io.legado.app.lib.theme.accentColor -import io.legado.app.ui.book.info.BookInfoActivity -import io.legado.app.ui.book.read.ReadBookActivity import io.legado.app.ui.book.search.SearchActivity -import io.legado.app.ui.bookshelf.BookshelfActivity import io.legado.app.utils.* import kotlinx.android.synthetic.main.dialog_edit_text.view.* import kotlinx.android.synthetic.main.fragment_bookshelf.* import kotlinx.android.synthetic.main.view_title_bar.* import org.jetbrains.anko.startActivity -import org.jetbrains.anko.textColor class BookshelfFragment : VMBaseFragment(R.layout.fragment_bookshelf), SearchView.OnQueryTextListener, - BookGroupAdapter.CallBack, - BookshelfAdapter.CallBack { + BookGroupAdapter.CallBack { override val viewModel: BookshelfViewModel get() = getViewModel(BookshelfViewModel::class.java) - private lateinit var bookshelfAdapter: BookshelfAdapter + private lateinit var booksAdapter: BooksAdapter private lateinit var bookGroupAdapter: BookGroupAdapter private var bookGroupLiveData: LiveData>? = null - private var bookshelfLiveData: LiveData>? = null override fun onViewCreated(view: View, savedInstanceState: Bundle?) { setSupportToolbar(toolbar) initRecyclerView() initBookGroupData() - initBookshelfData() } override fun onCompatCreateOptionsMenu(menu: Menu) { @@ -66,27 +56,14 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b } private fun initRecyclerView() { - ATH.applyEdgeEffectColor(rv_bookshelf) - refresh_layout.setColorSchemeColors(accentColor) - refresh_layout.setOnRefreshListener { - refresh_layout.isRefreshing = false - viewModel.upChapterList() - } + ATH.applyEdgeEffectColor(view_pager_bookshelf) rv_book_group.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) bookGroupAdapter = BookGroupAdapter() rv_book_group.adapter = bookGroupAdapter bookGroupAdapter.callBack = this - rv_bookshelf.layoutManager = LinearLayoutManager(context) - rv_bookshelf.addItemDecoration( - DividerItemDecoration( - rv_bookshelf.context, - LinearLayoutManager.VERTICAL - ) - ) - bookshelfAdapter = BookshelfAdapter(this) - rv_bookshelf.adapter = bookshelfAdapter - observeEvent(Bus.UP_BOOK) { bookshelfAdapter.notification(it) } + view_pager_bookshelf.adapter = BookshelfAdapter(this) + observeEvent(Bus.UP_BOOK) { booksAdapter.notification(it) } } private fun initBookGroupData() { @@ -95,31 +72,13 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b bookGroupLiveData?.observe(viewLifecycleOwner, Observer { bookGroupAdapter.submitList(it) }) } - private fun initBookshelfData() { - bookshelfLiveData?.removeObservers(viewLifecycleOwner) - bookshelfLiveData = LivePagedListBuilder(App.db.bookDao().recentRead(), 20).build() - bookshelfLiveData?.observe(viewLifecycleOwner, Observer { bookshelfAdapter.submitList(it) }) - } - override fun open(bookGroup: BookGroup) { when (bookGroup.groupId) { -10 -> showGroupInputDialog() - else -> context?.startActivity(Pair("data", bookGroup)) + else -> context } } - override fun open(book: Book) { - context?.startActivity(Pair("bookUrl", book.bookUrl)) - } - - override fun openBookInfo(book: Book) { - context?.startActivity(Pair("bookUrl", book.bookUrl)) - } - - override fun isUpdate(bookUrl: String): Boolean { - return bookUrl in viewModel.updateList - } - override fun onQueryTextSubmit(query: String?): Boolean { context?.startActivity(Pair("key", query)) return false diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt index c9baf1494..1bb9a3b64 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt @@ -3,18 +3,10 @@ package io.legado.app.ui.main.bookshelf import android.app.Application import io.legado.app.App import io.legado.app.base.BaseViewModel -import io.legado.app.constant.BookType -import io.legado.app.constant.Bus import io.legado.app.data.entities.BookGroup -import io.legado.app.model.WebBook -import io.legado.app.utils.postEvent -import kotlinx.coroutines.Dispatchers.IO -import kotlinx.coroutines.delay class BookshelfViewModel(application: Application) : BaseViewModel(application) { - val updateList = arrayListOf() - fun saveBookGroup(group: String?) { if (!group.isNullOrBlank()) { execute { @@ -28,37 +20,4 @@ class BookshelfViewModel(application: Application) : BaseViewModel(application) } } - - fun upChapterList() { - execute { - App.db.bookDao().getRecentRead().forEach { book -> - if (book.origin != BookType.local) { - App.db.bookSourceDao().getBookSource(book.origin)?.let { bookSource -> - synchronized(this) { - updateList.add(book.bookUrl) - postEvent(Bus.UP_BOOK, book.bookUrl) - } - WebBook(bookSource).getChapterList(book) - .onSuccess(IO) { - it?.let { - App.db.bookDao().update(book) - App.db.bookChapterDao().delByBook(book.bookUrl) - App.db.bookChapterDao().insert(*it.toTypedArray()) - } - } - .onError { - it.printStackTrace() - } - .onFinally { - synchronized(this) { - updateList.remove(book.bookUrl) - postEvent(Bus.UP_BOOK, book.bookUrl) - } - } - } - } - delay(50) - } - } - } } diff --git a/app/src/main/res/layout/activity_bookshelf.xml b/app/src/main/res/layout/fragment_books.xml similarity index 50% rename from app/src/main/res/layout/activity_bookshelf.xml rename to app/src/main/res/layout/fragment_books.xml index a18920e81..30f8ce74c 100644 --- a/app/src/main/res/layout/activity_bookshelf.xml +++ b/app/src/main/res/layout/fragment_books.xml @@ -1,17 +1,12 @@ - - - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_bookshelf.xml b/app/src/main/res/layout/fragment_bookshelf.xml index e160da925..8bba3afae 100644 --- a/app/src/main/res/layout/fragment_bookshelf.xml +++ b/app/src/main/res/layout/fragment_bookshelf.xml @@ -18,16 +18,9 @@ android:layout_height="wrap_content" android:overScrollMode="never"/> - - - + - \ No newline at end of file From 3ebb83a6af38a081e7c6e4318412354fbd4dd990 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 26 Sep 2019 22:30:31 +0800 Subject: [PATCH 1661/1997] up --- .../legado/app/ui/changesource/ChangeSourceDialog.kt | 12 ++++++------ .../io/legado/app/ui/main/bookshelf/BooksFragment.kt | 11 +++++++++++ .../legado/app/ui/main/bookshelf/BookshelfAdapter.kt | 2 +- .../app/ui/main/bookshelf/BookshelfFragment.kt | 9 +++++++++ 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt index df03b920e..8f02698b9 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt @@ -26,12 +26,12 @@ class ChangeSourceDialog : DialogFragment(), const val tag = "changeSourceDialog" fun newInstance(name: String, author: String): ChangeSourceDialog { - val changeSourceDialog = ChangeSourceDialog() - val bundle = Bundle() - bundle.putString("name", name) - bundle.putString("author", author) - changeSourceDialog.arguments = bundle - return changeSourceDialog + return ChangeSourceDialog().apply { + val bundle = Bundle() + bundle.putString("name", name) + bundle.putString("author", author) + arguments = bundle + } } } diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt index ee8236255..4b26fed38 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt @@ -25,6 +25,17 @@ import org.jetbrains.anko.startActivity class BooksFragment : VMBaseFragment(R.layout.fragment_books), BooksAdapter.CallBack { + + companion object { + fun newInstance(position: Int): BooksFragment { + return BooksFragment().apply { + val bundle = Bundle() + bundle.putInt("position", position) + arguments = bundle + } + } + } + override val viewModel: BooksViewModel get() = getViewModel(BooksViewModel::class.java) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt index 86238a663..c18c8ae13 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt @@ -11,7 +11,7 @@ class BookshelfAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) { } override fun createFragment(position: Int): Fragment { - return BooksFragment() + return BooksFragment.newInstance(position) } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index 9b6d5f90b..d931f3a48 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -12,6 +12,7 @@ import androidx.lifecycle.Observer import androidx.paging.LivePagedListBuilder import androidx.paging.PagedList import androidx.recyclerview.widget.LinearLayoutManager +import androidx.viewpager2.widget.ViewPager2 import io.legado.app.App import io.legado.app.R import io.legado.app.base.VMBaseFragment @@ -36,6 +37,7 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b private lateinit var booksAdapter: BooksAdapter private lateinit var bookGroupAdapter: BookGroupAdapter private var bookGroupLiveData: LiveData>? = null + private var position = -1 override fun onViewCreated(view: View, savedInstanceState: Bundle?) { setSupportToolbar(toolbar) @@ -63,6 +65,13 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b rv_book_group.adapter = bookGroupAdapter bookGroupAdapter.callBack = this view_pager_bookshelf.adapter = BookshelfAdapter(this) + view_pager_bookshelf.registerOnPageChangeCallback(object : + ViewPager2.OnPageChangeCallback() { + override fun onPageSelected(position: Int) { + super.onPageSelected(position) + this@BookshelfFragment.position = position + } + }) observeEvent(Bus.UP_BOOK) { booksAdapter.notification(it) } } From a46886a833a8646625ad6a6b1cb7034926b8cfe6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 27 Sep 2019 08:18:00 +0800 Subject: [PATCH 1662/1997] up --- .../io/legado/app/data/dao/BookGroupDao.kt | 4 +- .../app/ui/main/bookshelf/BookGroupAdapter.kt | 64 +++---------------- .../app/ui/main/bookshelf/BooksFragment.kt | 6 +- .../ui/main/bookshelf/BookshelfFragment.kt | 21 ++++-- 4 files changed, 30 insertions(+), 65 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/BookGroupDao.kt b/app/src/main/java/io/legado/app/data/dao/BookGroupDao.kt index 2a32912ee..51068b149 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookGroupDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookGroupDao.kt @@ -1,6 +1,6 @@ package io.legado.app.data.dao -import androidx.paging.DataSource +import androidx.lifecycle.LiveData import androidx.room.Dao import androidx.room.Insert import androidx.room.OnConflictStrategy @@ -11,7 +11,7 @@ import io.legado.app.data.entities.BookGroup interface BookGroupDao { @Query("SELECT * FROM book_groups ORDER BY `order`") - fun observeAll(): DataSource.Factory + fun liveDataAll(): LiveData> @get:Query("SELECT MAX(groupId) FROM book_groups") val maxId: Int diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookGroupAdapter.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookGroupAdapter.kt index bb3adbf8f..4e0a9e4d8 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookGroupAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookGroupAdapter.kt @@ -1,65 +1,19 @@ package io.legado.app.ui.main.bookshelf -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.paging.PagedListAdapter -import androidx.recyclerview.widget.DiffUtil -import androidx.recyclerview.widget.RecyclerView +import android.content.Context import io.legado.app.R +import io.legado.app.base.adapter.ItemViewHolder +import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.data.entities.BookGroup -import io.legado.app.help.AdapterDataObserverProxy import kotlinx.android.synthetic.main.item_book_group.view.* -class BookGroupAdapter : PagedListAdapter(DIFF_CALLBACK) { +class BookGroupAdapter(context: Context, val callBack: CallBack) : + SimpleRecyclerAdapter(context, R.layout.item_book_group) { - companion object { - @JvmField - val DIFF_CALLBACK = object : DiffUtil.ItemCallback() { - override fun areItemsTheSame(oldItem: BookGroup, newItem: BookGroup): Boolean = - oldItem.groupId == newItem.groupId - - override fun areContentsTheSame(oldItem: BookGroup, newItem: BookGroup): Boolean = - oldItem.groupId == newItem.groupId - && oldItem.groupName == newItem.groupName - && oldItem.order == newItem.order - } - } - - var callBack: CallBack? = null - private val defaultGroups = arrayOf(BookGroup(-1, "全部"), - BookGroup(-2, "本地"), - BookGroup(-3, "音频")) - - private val addBookGroup = BookGroup(-10, "+") - - override fun getItemCount(): Int { - return super.getItemCount() + defaultGroups.size + 1 - } - - override fun registerAdapterDataObserver(observer: RecyclerView.AdapterDataObserver) { - super.registerAdapterDataObserver(AdapterDataObserverProxy(observer, defaultGroups.size)) - } - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { - return MyViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_book_group, parent, false)) - } - - override fun onBindViewHolder(holder: MyViewHolder, position: Int) { - when { - position < defaultGroups.size -> holder.bind(defaultGroups[position], callBack) - position == itemCount - 1 -> holder.bind(addBookGroup, callBack) - else -> currentList?.get(position - defaultGroups.size)?.let { - holder.bind(it, callBack) - } - } - } - - class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { - - fun bind(bookGroup: BookGroup, callBack: CallBack?) = with(itemView) { - tv_group.text = bookGroup.groupName - tv_group.setOnClickListener { callBack?.open(bookGroup) } + override fun convert(holder: ItemViewHolder, item: BookGroup, payloads: MutableList) { + with(holder.itemView) { + tv_group.text = item.groupName + tv_group.setOnClickListener { callBack.open(item) } } } diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt index 4b26fed38..ac1142f7a 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt @@ -42,10 +42,14 @@ class BooksFragment : VMBaseFragment(R.layout.fragment_books), private lateinit var activityViewModel: MainViewModel private lateinit var booksAdapter: BooksAdapter private var bookshelfLiveData: LiveData>? = null - private val groupId = -1 + private var groupId = -1 override fun onViewCreated(view: View, savedInstanceState: Bundle?) { activityViewModel = getViewModelOfActivity(MainViewModel::class.java) + arguments?.let { + val position = it.getInt("position", 0) + + } initRecyclerView() upRecyclerData() } diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index d931f3a48..e4d212e4e 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -9,8 +9,6 @@ import android.widget.EditText import androidx.appcompat.widget.SearchView import androidx.lifecycle.LiveData import androidx.lifecycle.Observer -import androidx.paging.LivePagedListBuilder -import androidx.paging.PagedList import androidx.recyclerview.widget.LinearLayoutManager import androidx.viewpager2.widget.ViewPager2 import io.legado.app.App @@ -36,7 +34,7 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b private lateinit var booksAdapter: BooksAdapter private lateinit var bookGroupAdapter: BookGroupAdapter - private var bookGroupLiveData: LiveData>? = null + private var bookGroupLiveData: LiveData>? = null private var position = -1 override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -61,9 +59,8 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b ATH.applyEdgeEffectColor(view_pager_bookshelf) rv_book_group.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) - bookGroupAdapter = BookGroupAdapter() + bookGroupAdapter = BookGroupAdapter(requireContext(), this) rv_book_group.adapter = bookGroupAdapter - bookGroupAdapter.callBack = this view_pager_bookshelf.adapter = BookshelfAdapter(this) view_pager_bookshelf.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { @@ -77,8 +74,18 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b private fun initBookGroupData() { bookGroupLiveData?.removeObservers(viewLifecycleOwner) - bookGroupLiveData = LivePagedListBuilder(App.db.bookGroupDao().observeAll(), 10).build() - bookGroupLiveData?.observe(viewLifecycleOwner, Observer { bookGroupAdapter.submitList(it) }) + bookGroupLiveData = App.db.bookGroupDao().liveDataAll() + bookGroupLiveData?.observe(viewLifecycleOwner, Observer { + mutableListOf( + BookGroup(-1, "全部"), + BookGroup(-2, "本地"), + BookGroup(-3, "音频") + ).apply { + addAll(it) + }.let { + bookGroupAdapter.setItems(it) + } + }) } override fun open(bookGroup: BookGroup) { From a58bbfbfcea58a46aac542e2d41bb9ddb9c18485 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 27 Sep 2019 08:35:18 +0800 Subject: [PATCH 1663/1997] up --- .../java/io/legado/app/constant/AppConst.kt | 9 +++++++++ .../app/ui/main/bookshelf/BooksFragment.kt | 5 ++--- .../app/ui/main/bookshelf/BookshelfAdapter.kt | 13 +++++++++--- .../ui/main/bookshelf/BookshelfFragment.kt | 20 ++++++++++++------- 4 files changed, 34 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/io/legado/app/constant/AppConst.kt b/app/src/main/java/io/legado/app/constant/AppConst.kt index 58c51fb25..10a2007c1 100644 --- a/app/src/main/java/io/legado/app/constant/AppConst.kt +++ b/app/src/main/java/io/legado/app/constant/AppConst.kt @@ -3,6 +3,7 @@ package io.legado.app.constant import android.annotation.SuppressLint import io.legado.app.App import io.legado.app.R +import io.legado.app.data.entities.BookGroup import java.text.SimpleDateFormat import javax.script.ScriptEngine import javax.script.ScriptEngineManager @@ -37,4 +38,12 @@ object AppConst { "json", "css", "id", "class", "tag" ) } + + val defaultBookGroups by lazy { + mutableListOf( + BookGroup(-1, "全部"), + BookGroup(-2, "本地"), + BookGroup(-3, "音频") + ) + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt index ac1142f7a..bf556ffd5 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt @@ -30,7 +30,7 @@ class BooksFragment : VMBaseFragment(R.layout.fragment_books), fun newInstance(position: Int): BooksFragment { return BooksFragment().apply { val bundle = Bundle() - bundle.putInt("position", position) + bundle.putInt("groupId", position) arguments = bundle } } @@ -47,8 +47,7 @@ class BooksFragment : VMBaseFragment(R.layout.fragment_books), override fun onViewCreated(view: View, savedInstanceState: Bundle?) { activityViewModel = getViewModelOfActivity(MainViewModel::class.java) arguments?.let { - val position = it.getInt("position", 0) - + groupId = it.getInt("groupId", -1) } initRecyclerView() upRecyclerData() diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt index c18c8ae13..40778ce6d 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt @@ -2,16 +2,23 @@ package io.legado.app.ui.main.bookshelf import androidx.fragment.app.Fragment import androidx.viewpager2.adapter.FragmentStateAdapter +import io.legado.app.data.entities.BookGroup -class BookshelfAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) { +class BookshelfAdapter(fragment: Fragment, val callBack: CallBack) : + FragmentStateAdapter(fragment) { override fun getItemCount(): Int { - return 3 + return callBack.groupSize } override fun createFragment(position: Int): Fragment { - return BooksFragment.newInstance(position) + val groupId = callBack.getGroup(position)?.groupId ?: -1 + return BooksFragment.newInstance(groupId) } + interface CallBack { + val groupSize: Int + fun getGroup(position: Int): BookGroup? + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index e4d212e4e..e82bf72c2 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -14,6 +14,7 @@ import androidx.viewpager2.widget.ViewPager2 import io.legado.app.App import io.legado.app.R import io.legado.app.base.VMBaseFragment +import io.legado.app.constant.AppConst import io.legado.app.constant.Bus import io.legado.app.data.entities.BookGroup import io.legado.app.lib.dialogs.* @@ -27,7 +28,8 @@ import org.jetbrains.anko.startActivity class BookshelfFragment : VMBaseFragment(R.layout.fragment_bookshelf), SearchView.OnQueryTextListener, - BookGroupAdapter.CallBack { + BookGroupAdapter.CallBack, + BookshelfAdapter.CallBack { override val viewModel: BookshelfViewModel get() = getViewModel(BookshelfViewModel::class.java) @@ -55,13 +57,21 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b } } + override val groupSize: Int + get() = bookGroupAdapter.itemCount + + override fun getGroup(position: Int): BookGroup? { + return bookGroupAdapter.getItem(position) + } + private fun initRecyclerView() { ATH.applyEdgeEffectColor(view_pager_bookshelf) rv_book_group.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) bookGroupAdapter = BookGroupAdapter(requireContext(), this) rv_book_group.adapter = bookGroupAdapter - view_pager_bookshelf.adapter = BookshelfAdapter(this) + bookGroupAdapter.setItems(AppConst.defaultBookGroups) + view_pager_bookshelf.adapter = BookshelfAdapter(this, this) view_pager_bookshelf.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { override fun onPageSelected(position: Int) { @@ -76,11 +86,7 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b bookGroupLiveData?.removeObservers(viewLifecycleOwner) bookGroupLiveData = App.db.bookGroupDao().liveDataAll() bookGroupLiveData?.observe(viewLifecycleOwner, Observer { - mutableListOf( - BookGroup(-1, "全部"), - BookGroup(-2, "本地"), - BookGroup(-3, "音频") - ).apply { + AppConst.defaultBookGroups.apply { addAll(it) }.let { bookGroupAdapter.setItems(it) From 9414f5e82a82c7e7cf07fcb468944be60800a74c Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 27 Sep 2019 08:40:30 +0800 Subject: [PATCH 1664/1997] up --- app/src/main/java/io/legado/app/constant/AppConst.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/constant/AppConst.kt b/app/src/main/java/io/legado/app/constant/AppConst.kt index 10a2007c1..b484993d5 100644 --- a/app/src/main/java/io/legado/app/constant/AppConst.kt +++ b/app/src/main/java/io/legado/app/constant/AppConst.kt @@ -33,9 +33,8 @@ object AppConst { val keyboardToolChars: List by lazy { arrayListOf( - "@", "&", "|", "%", "/", ":", "[", "]", "{", "}", "<", ">", - "\\", "$", "#", "!", ".", "href", "src", "textNodes", "xpath", - "json", "css", "id", "class", "tag" + "@", "&", "|", "%", "/", ":", "[", "]", "{", "}", "<", ">", "\\", "$", "#", "!", ".", + "href", "src", "textNodes", "xpath", "json", "css", "id", "class", "tag" ) } From cf88899eb02298f9e274e730d9c45500f2818481 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 27 Sep 2019 08:53:19 +0800 Subject: [PATCH 1665/1997] up --- .../io/legado/app/ui/main/bookshelf/BookGroupAdapter.kt | 5 +++-- .../io/legado/app/ui/main/bookshelf/BookshelfFragment.kt | 7 ++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookGroupAdapter.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookGroupAdapter.kt index 4e0a9e4d8..9e5dd0722 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookGroupAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookGroupAdapter.kt @@ -6,6 +6,7 @@ import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.data.entities.BookGroup import kotlinx.android.synthetic.main.item_book_group.view.* +import org.jetbrains.anko.sdk27.listeners.onClick class BookGroupAdapter(context: Context, val callBack: CallBack) : SimpleRecyclerAdapter(context, R.layout.item_book_group) { @@ -13,11 +14,11 @@ class BookGroupAdapter(context: Context, val callBack: CallBack) : override fun convert(holder: ItemViewHolder, item: BookGroup, payloads: MutableList) { with(holder.itemView) { tv_group.text = item.groupName - tv_group.setOnClickListener { callBack.open(item) } + tv_group.onClick { callBack.onClickGroup(holder.layoutPosition) } } } interface CallBack { - fun open(bookGroup: BookGroup) + fun onClickGroup(position: Int) } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index e82bf72c2..0a546e57d 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -94,11 +94,8 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b }) } - override fun open(bookGroup: BookGroup) { - when (bookGroup.groupId) { - -10 -> showGroupInputDialog() - else -> context - } + override fun onClickGroup(position: Int) { + view_pager_bookshelf.setCurrentItem(position, false) } override fun onQueryTextSubmit(query: String?): Boolean { From 65211b19d544f908ebe51e88dabc899e72a9c7f3 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 27 Sep 2019 10:42:18 +0800 Subject: [PATCH 1666/1997] up --- .../java/io/legado/app/constant/AppConst.kt | 2 +- .../app/ui/main/bookshelf/BookshelfAdapter.kt | 4 +- .../ui/main/bookshelf/BookshelfFragment.kt | 39 +++++++------------ .../main/res/layout/fragment_bookshelf.xml | 34 ++++++++-------- 4 files changed, 32 insertions(+), 47 deletions(-) diff --git a/app/src/main/java/io/legado/app/constant/AppConst.kt b/app/src/main/java/io/legado/app/constant/AppConst.kt index b484993d5..f9fe5b942 100644 --- a/app/src/main/java/io/legado/app/constant/AppConst.kt +++ b/app/src/main/java/io/legado/app/constant/AppConst.kt @@ -39,7 +39,7 @@ object AppConst { } val defaultBookGroups by lazy { - mutableListOf( + listOf( BookGroup(-1, "全部"), BookGroup(-2, "本地"), BookGroup(-3, "音频") diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt index 40778ce6d..c4176f78d 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfAdapter.kt @@ -13,12 +13,12 @@ class BookshelfAdapter(fragment: Fragment, val callBack: CallBack) : } override fun createFragment(position: Int): Fragment { - val groupId = callBack.getGroup(position)?.groupId ?: -1 + val groupId = callBack.getGroup(position).groupId return BooksFragment.newInstance(groupId) } interface CallBack { val groupSize: Int - fun getGroup(position: Int): BookGroup? + fun getGroup(position: Int): BookGroup } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index 0a546e57d..1102ea3de 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -9,13 +9,11 @@ import android.widget.EditText import androidx.appcompat.widget.SearchView import androidx.lifecycle.LiveData import androidx.lifecycle.Observer -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.viewpager2.widget.ViewPager2 +import com.google.android.material.tabs.TabLayoutMediator import io.legado.app.App import io.legado.app.R import io.legado.app.base.VMBaseFragment import io.legado.app.constant.AppConst -import io.legado.app.constant.Bus import io.legado.app.data.entities.BookGroup import io.legado.app.lib.dialogs.* import io.legado.app.lib.theme.ATH @@ -23,6 +21,7 @@ import io.legado.app.ui.book.search.SearchActivity import io.legado.app.utils.* import kotlinx.android.synthetic.main.dialog_edit_text.view.* import kotlinx.android.synthetic.main.fragment_bookshelf.* +import kotlinx.android.synthetic.main.view_tab_layout.* import kotlinx.android.synthetic.main.view_title_bar.* import org.jetbrains.anko.startActivity @@ -34,10 +33,8 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b override val viewModel: BookshelfViewModel get() = getViewModel(BookshelfViewModel::class.java) - private lateinit var booksAdapter: BooksAdapter - private lateinit var bookGroupAdapter: BookGroupAdapter private var bookGroupLiveData: LiveData>? = null - private var position = -1 + private val bookGroups = mutableListOf().apply { addAll(AppConst.defaultBookGroups) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { setSupportToolbar(toolbar) @@ -58,39 +55,29 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b } override val groupSize: Int - get() = bookGroupAdapter.itemCount + get() = bookGroups.size - override fun getGroup(position: Int): BookGroup? { - return bookGroupAdapter.getItem(position) + override fun getGroup(position: Int): BookGroup { + return bookGroups[position] } private fun initRecyclerView() { ATH.applyEdgeEffectColor(view_pager_bookshelf) - rv_book_group.layoutManager = - LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) - bookGroupAdapter = BookGroupAdapter(requireContext(), this) - rv_book_group.adapter = bookGroupAdapter - bookGroupAdapter.setItems(AppConst.defaultBookGroups) view_pager_bookshelf.adapter = BookshelfAdapter(this, this) - view_pager_bookshelf.registerOnPageChangeCallback(object : - ViewPager2.OnPageChangeCallback() { - override fun onPageSelected(position: Int) { - super.onPageSelected(position) - this@BookshelfFragment.position = position - } - }) - observeEvent(Bus.UP_BOOK) { booksAdapter.notification(it) } + TabLayoutMediator(tab_layout, view_pager_bookshelf) { tab, position -> + tab.text = bookGroups[position].groupName + }.attach() } private fun initBookGroupData() { bookGroupLiveData?.removeObservers(viewLifecycleOwner) bookGroupLiveData = App.db.bookGroupDao().liveDataAll() bookGroupLiveData?.observe(viewLifecycleOwner, Observer { - AppConst.defaultBookGroups.apply { - addAll(it) - }.let { - bookGroupAdapter.setItems(it) + for (index in AppConst.defaultBookGroups.size until bookGroups.size) { + bookGroups.removeAt(AppConst.defaultBookGroups.size) } + bookGroups.addAll(it) + view_pager_bookshelf.adapter?.notifyDataSetChanged() }) } diff --git a/app/src/main/res/layout/fragment_bookshelf.xml b/app/src/main/res/layout/fragment_bookshelf.xml index 8bba3afae..aa76e7563 100644 --- a/app/src/main/res/layout/fragment_bookshelf.xml +++ b/app/src/main/res/layout/fragment_bookshelf.xml @@ -1,26 +1,24 @@ - + - - + android:id="@+id/title_bar" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:attachToActivity="false" + app:title="@string/bookshelf" + app:contentLayout="@layout/view_tab_layout" + app:layout_constraintTop_toTopOf="parent" /> + android:layout_height="0dp" + app:layout_constraintTop_toBottomOf="@+id/title_bar" + app:layout_constraintBottom_toBottomOf="parent" /> - \ No newline at end of file + \ No newline at end of file From 4b846714d09f08de18dc9304ee5da1309de83e3a Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 27 Sep 2019 11:54:50 +0800 Subject: [PATCH 1667/1997] up --- .../io/legado/app/ui/main/bookshelf/BooksFragment.kt | 11 ++++++----- .../legado/app/ui/main/bookshelf/BookshelfFragment.kt | 3 +++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt index bf556ffd5..98fc44aee 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt @@ -2,6 +2,7 @@ package io.legado.app.ui.main.bookshelf import android.os.Bundle import android.view.View +import androidx.core.content.ContextCompat import androidx.lifecycle.LiveData import androidx.lifecycle.Observer import androidx.paging.LivePagedListBuilder @@ -62,11 +63,11 @@ class BooksFragment : VMBaseFragment(R.layout.fragment_books), } rv_bookshelf.layoutManager = LinearLayoutManager(context) rv_bookshelf.addItemDecoration( - DividerItemDecoration( - rv_bookshelf.context, - LinearLayoutManager.VERTICAL - ) - ) + DividerItemDecoration(requireContext(), DividerItemDecoration.VERTICAL).apply { + ContextCompat.getDrawable(requireContext(), R.drawable.ic_divider)?.let { + this.setDrawable(it) + } + }) booksAdapter = BooksAdapter(this) rv_bookshelf.adapter = booksAdapter diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index 1102ea3de..26924d5d3 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -9,6 +9,7 @@ import android.widget.EditText import androidx.appcompat.widget.SearchView import androidx.lifecycle.LiveData import androidx.lifecycle.Observer +import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayoutMediator import io.legado.app.App import io.legado.app.R @@ -62,6 +63,8 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b } private fun initRecyclerView() { + tab_layout.isTabIndicatorFullWidth = false + tab_layout.tabMode = TabLayout.MODE_SCROLLABLE ATH.applyEdgeEffectColor(view_pager_bookshelf) view_pager_bookshelf.adapter = BookshelfAdapter(this, this) TabLayoutMediator(tab_layout, view_pager_bookshelf) { tab, position -> From 85902e702eed98088eef90e076df18bfb21043b3 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 27 Sep 2019 13:14:49 +0800 Subject: [PATCH 1668/1997] up --- .../app/ui/main/bookshelf/BookGroupAdapter.kt | 24 ------------------- .../ui/main/bookshelf/BookshelfFragment.kt | 5 ---- 2 files changed, 29 deletions(-) delete mode 100644 app/src/main/java/io/legado/app/ui/main/bookshelf/BookGroupAdapter.kt diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookGroupAdapter.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookGroupAdapter.kt deleted file mode 100644 index 9e5dd0722..000000000 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookGroupAdapter.kt +++ /dev/null @@ -1,24 +0,0 @@ -package io.legado.app.ui.main.bookshelf - -import android.content.Context -import io.legado.app.R -import io.legado.app.base.adapter.ItemViewHolder -import io.legado.app.base.adapter.SimpleRecyclerAdapter -import io.legado.app.data.entities.BookGroup -import kotlinx.android.synthetic.main.item_book_group.view.* -import org.jetbrains.anko.sdk27.listeners.onClick - -class BookGroupAdapter(context: Context, val callBack: CallBack) : - SimpleRecyclerAdapter(context, R.layout.item_book_group) { - - override fun convert(holder: ItemViewHolder, item: BookGroup, payloads: MutableList) { - with(holder.itemView) { - tv_group.text = item.groupName - tv_group.onClick { callBack.onClickGroup(holder.layoutPosition) } - } - } - - interface CallBack { - fun onClickGroup(position: Int) - } -} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index 26924d5d3..b7f91a0af 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -28,7 +28,6 @@ import org.jetbrains.anko.startActivity class BookshelfFragment : VMBaseFragment(R.layout.fragment_bookshelf), SearchView.OnQueryTextListener, - BookGroupAdapter.CallBack, BookshelfAdapter.CallBack { override val viewModel: BookshelfViewModel @@ -84,10 +83,6 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b }) } - override fun onClickGroup(position: Int) { - view_pager_bookshelf.setCurrentItem(position, false) - } - override fun onQueryTextSubmit(query: String?): Boolean { context?.startActivity(Pair("key", query)) return false From d3d0265bd7f0520c5fe1ee3ad5c59a172587f4f0 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 27 Sep 2019 13:22:53 +0800 Subject: [PATCH 1669/1997] up --- .../main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt index 98fc44aee..4819d288f 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt @@ -77,7 +77,6 @@ class BooksFragment : VMBaseFragment(R.layout.fragment_books), bookshelfLiveData?.removeObservers(this) when (groupId) { -1 -> { - bookshelfLiveData = LivePagedListBuilder(App.db.bookDao().observeAll(), 10).build() } From 7ba212b449249391616acf92aa5d6860f82590b5 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 27 Sep 2019 14:28:57 +0800 Subject: [PATCH 1670/1997] up --- app/src/main/java/io/legado/app/data/dao/BookDao.kt | 13 ++++--------- .../java/io/legado/app/ui/main/MainViewModel.kt | 2 +- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/BookDao.kt b/app/src/main/java/io/legado/app/data/dao/BookDao.kt index 04e76d3bd..bae53c8f2 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookDao.kt @@ -9,13 +9,13 @@ import io.legado.app.data.entities.Book @Dao interface BookDao { - @Query("SELECT * FROM books") + @Query("SELECT * FROM books order by durChapterTime desc") fun observeAll(): DataSource.Factory - @Query("SELECT * FROM books WHERE type = ${BookType.audio}") + @Query("SELECT * FROM books WHERE type = ${BookType.audio} order by durChapterTime desc") fun observeAudio(): DataSource.Factory - @Query("SELECT * FROM books WHERE origin = '${BookType.local}'") + @Query("SELECT * FROM books WHERE origin = '${BookType.local}' order by durChapterTime desc") fun observeLocal(): DataSource.Factory @Query("SELECT * FROM books WHERE `group` = :group") @@ -42,12 +42,6 @@ interface BookDao { @get:Query("SELECT COUNT(*) FROM books") val allBookCount: Int - @Query("SELECT * FROM books ORDER BY durChapterTime DESC limit 0,20") - fun recentRead(): DataSource.Factory - - @Query("SELECT * FROM books ORDER BY durChapterTime DESC limit 0,20") - fun getRecentRead(): List - @Insert(onConflict = OnConflictStrategy.REPLACE) fun insert(vararg book: Book) @@ -56,4 +50,5 @@ interface BookDao { @Query("delete from books where bookUrl = :bookUrl") fun delete(bookUrl: String) + } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt b/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt index 9f191510a..3a9c1db32 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt @@ -23,7 +23,7 @@ class MainViewModel(application: Application) : BaseViewModel(application) { fun upChapterList() { execute { - App.db.bookDao().getRecentRead().forEach { book -> + App.db.bookDao().allBooks.forEach { book -> if (book.origin != BookType.local) { App.db.bookSourceDao().getBookSource(book.origin)?.let { bookSource -> synchronized(this) { From 3962ebc5dbbb27737c338052e2da0f30d6076b81 Mon Sep 17 00:00:00 2001 From: yans Date: Fri, 27 Sep 2019 14:37:13 +0800 Subject: [PATCH 1671/1997] add import booksources urischeme --- app/src/main/AndroidManifest.xml | 10 +++++++++- .../ui/book/source/manage/BookSourceActivity.kt | 16 ++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 96e2b7ea2..c1e691938 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -64,7 +64,15 @@ - + + + + + + + + + diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt index 6dfc8f3a2..bf357319f 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt @@ -41,6 +41,7 @@ import kotlinx.android.synthetic.main.view_title_bar.* import org.jetbrains.anko.startActivity import org.jetbrains.anko.startActivityForResult import org.jetbrains.anko.startService +import org.jetbrains.anko.toast class BookSourceActivity : VMBaseActivity(R.layout.activity_book_source), BookSourceAdapter.CallBack, @@ -56,6 +57,7 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity override fun onActivityCreated(savedInstanceState: Bundle?) { setSupportActionBar(toolbar) + initUriScheme() initRecyclerView() initSearchView() initLiveDataBookSource() @@ -101,6 +103,20 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity return super.onCompatOptionsItemSelected(item) } + private fun initUriScheme() { + intent.data?.let{ + when(it.path) + { + "/importonline" -> { + it.getQueryParameter("src")?.let{ + viewModel.importSource(it) + } + } + else -> {toast("格式不对")} + } + } + } + private fun initRecyclerView() { ATH.applyEdgeEffectColor(recycler_view) recycler_view.layoutManager = LinearLayoutManager(this) From b2ac302c45e987379b46b0ddecd82fd8efcb6b1f Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 27 Sep 2019 14:38:49 +0800 Subject: [PATCH 1672/1997] up --- .../java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt | 2 +- .../java/io/legado/app/ui/main/bookshelf/BooksFragment.kt | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt index 603684163..d6df919e0 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt @@ -35,7 +35,7 @@ class BooksAdapter(private val callBack: CallBack) : } fun notification(bookUrl: String) { - for (i in 0..itemCount) { + for (i in 0 until itemCount) { getItem(i)?.let { if (it.bookUrl == bookUrl) { notifyItemChanged(i) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt index 4819d288f..47d168562 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt @@ -12,6 +12,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.App import io.legado.app.R import io.legado.app.base.VMBaseFragment +import io.legado.app.constant.Bus import io.legado.app.data.entities.Book import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.accentColor @@ -20,6 +21,7 @@ import io.legado.app.ui.book.read.ReadBookActivity import io.legado.app.ui.main.MainViewModel import io.legado.app.utils.getViewModel import io.legado.app.utils.getViewModelOfActivity +import io.legado.app.utils.observeEvent import kotlinx.android.synthetic.main.fragment_books.* import org.jetbrains.anko.startActivity @@ -52,6 +54,9 @@ class BooksFragment : VMBaseFragment(R.layout.fragment_books), } initRecyclerView() upRecyclerData() + observeEvent(Bus.UP_BOOK) { + booksAdapter.notification(it) + } } private fun initRecyclerView() { @@ -70,7 +75,6 @@ class BooksFragment : VMBaseFragment(R.layout.fragment_books), }) booksAdapter = BooksAdapter(this) rv_bookshelf.adapter = booksAdapter - } private fun upRecyclerData() { From bced8f38377f7e5374951d621ed162024dab4449 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 27 Sep 2019 17:51:58 +0800 Subject: [PATCH 1673/1997] up --- .../java/io/legado/app/help/ReadBookConfig.kt | 37 ++- .../ui/book/read/config/ReadStyleDialog.kt | 2 +- .../legado/app/ui/widget/page/ContentView.kt | 6 +- .../java/io/legado/app/utils/BitmapUtil.kt | 252 ++++++++++++++++++ 4 files changed, 280 insertions(+), 17 deletions(-) create mode 100644 app/src/main/java/io/legado/app/utils/BitmapUtil.kt diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index 915ea9f5a..9238c1341 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -1,6 +1,7 @@ package io.legado.app.help import android.graphics.Color +import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.ColorDrawable import android.graphics.drawable.Drawable import io.legado.app.App @@ -52,7 +53,11 @@ object ReadBookConfig { } fun upBg() { - bg = getConfig().bgDrawable() + val resources = App.INSTANCE.resources + val dm = resources.displayMetrics + val width = dm.widthPixels + val height = dm.heightPixels + bg = getConfig().bgDrawable(width, height) } fun save() { @@ -162,20 +167,30 @@ object ReadBookConfig { else bgType } - fun bgDrawable(): Drawable { + fun bgDrawable(width: Int, height: Int): Drawable { var bgDrawable: Drawable? = null - kotlin.runCatching { - when (bgType()) { - 0 -> bgDrawable = ColorDrawable(Color.parseColor(bgStr())) - 1 -> bgDrawable = - Drawable.createFromStream( - App.INSTANCE.assets.open("bg" + File.separator + bgStr()), - "bg" + val resources = App.INSTANCE.resources + try { + bgDrawable = when (bgType()) { + 0 -> ColorDrawable(Color.parseColor(bgStr())) + 1 -> { + BitmapDrawable( + resources, + BitmapUtil.decodeBitmap( + App.INSTANCE, + "bg" + File.separator + bgStr(), + width, + height + ) ) - else -> runCatching { - bgDrawable = Drawable.createFromPath(bgStr()) } + else -> BitmapDrawable( + resources, + BitmapUtil.decodeBitmap(bgStr(), width, height) + ) } + } catch (e: Exception) { + e.printStackTrace() } return bgDrawable ?: ColorDrawable(App.INSTANCE.getCompatColor(R.color.background)) } diff --git a/app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt index ea80392c8..114552bf6 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt @@ -249,7 +249,7 @@ class ReadStyleDialog : DialogFragment() { ReadBookConfig.getConfig(i).apply { when (bgType()) { 2 -> ImageLoader.load(requireContext(), bgStr()).centerCrop().setAsDrawable(iv) - else -> iv.setImageDrawable(bgDrawable()) + else -> iv.setImageDrawable(bgDrawable(100, 150)) } } } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt index 719129a03..228e6f2e9 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentView.kt @@ -10,7 +10,6 @@ import android.widget.ImageView import androidx.appcompat.widget.AppCompatImageView import io.legado.app.R import io.legado.app.constant.AppConst.TIME_FORMAT -import io.legado.app.help.ImageLoader import io.legado.app.help.ReadBookConfig import io.legado.app.utils.* import kotlinx.android.synthetic.main.view_book_page.view.* @@ -90,10 +89,7 @@ class ContentView : FrameLayout { } fun setBg(bg: Drawable?) { - //all supported - ImageLoader.load(context, bg) - .centerCrop() - .setAsDrawable(bgImage) + bgImage.background = bg } fun upTime() { diff --git a/app/src/main/java/io/legado/app/utils/BitmapUtil.kt b/app/src/main/java/io/legado/app/utils/BitmapUtil.kt new file mode 100644 index 000000000..a5c7b776f --- /dev/null +++ b/app/src/main/java/io/legado/app/utils/BitmapUtil.kt @@ -0,0 +1,252 @@ +package io.legado.app.utils + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.Bitmap.Config +import android.graphics.BitmapFactory +import android.graphics.Canvas +import android.renderscript.Allocation +import android.renderscript.Element +import android.renderscript.RenderScript +import android.renderscript.ScriptIntrinsicBlur +import android.view.View +import io.legado.app.App +import java.io.IOException +import kotlin.math.ceil + + +@SuppressWarnings("unused", "WeakerAccess") +object BitmapUtil { + /** + * 从path中获取图片信息,在通过BitmapFactory.decodeFile(String path)方法将突破转成Bitmap时, + * 遇到大一些的图片,我们经常会遇到OOM(Out Of Memory)的问题。所以用到了我们上面提到的BitmapFactory.Options这个类。 + * + * @param path 文件路径 + * @param width 想要显示的图片的宽度 + * @param height 想要显示的图片的高度 + * @return + */ + fun decodeBitmap(path: String, width: Int, height: Int): Bitmap { + val op = BitmapFactory.Options() + // inJustDecodeBounds如果设置为true,仅仅返回图片实际的宽和高,宽和高是赋值给opts.outWidth,opts.outHeight; + op.inJustDecodeBounds = true + BitmapFactory.decodeFile(path, op) //获取尺寸信息 + //获取比例大小 + val wRatio = ceil((op.outWidth / width).toDouble()).toInt() + val hRatio = ceil((op.outHeight / height).toDouble()).toInt() + //如果超出指定大小,则缩小相应的比例 + if (wRatio > 1 && hRatio > 1) { + if (wRatio > hRatio) { + op.inSampleSize = wRatio + } else { + op.inSampleSize = hRatio + } + } + op.inJustDecodeBounds = false + return BitmapFactory.decodeFile(path, op) + } + + /** 从path中获取Bitmap图片 + * @param path 图片路径 + * @return + */ + + fun decodeBitmap(path: String): Bitmap { + val opts = BitmapFactory.Options() + + opts.inJustDecodeBounds = true + BitmapFactory.decodeFile(path, opts) + + opts.inSampleSize = computeSampleSize(opts, -1, 128 * 128) + + opts.inJustDecodeBounds = false + + return BitmapFactory.decodeFile(path, opts) + } + + /** + * 以最省内存的方式读取本地资源的图片 + * @param context 设备上下文 + * @param resId 资源ID + * @return + */ + fun decodeBitmap(context: Context, resId: Int): Bitmap? { + val opt = BitmapFactory.Options() + opt.inPreferredConfig = Config.RGB_565 + //获取资源图片 + val `is` = context.resources.openRawResource(resId) + return BitmapFactory.decodeStream(`is`, null, opt) + } + + /** + * @param context 设备上下文 + * @param resId 资源ID + * @param width + * @param height + * @return + */ + fun decodeBitmap(context: Context, resId: Int, width: Int, height: Int): Bitmap? { + + var inputStream = context.resources.openRawResource(resId) + + val op = BitmapFactory.Options() + // inJustDecodeBounds如果设置为true,仅仅返回图片实际的宽和高,宽和高是赋值给opts.outWidth,opts.outHeight; + op.inJustDecodeBounds = true + BitmapFactory.decodeStream(inputStream, null, op) //获取尺寸信息 + //获取比例大小 + val wRatio = ceil((op.outWidth / width).toDouble()).toInt() + val hRatio = ceil((op.outHeight / height).toDouble()).toInt() + //如果超出指定大小,则缩小相应的比例 + if (wRatio > 1 && hRatio > 1) { + if (wRatio > hRatio) { + op.inSampleSize = wRatio + } else { + op.inSampleSize = hRatio + } + } + inputStream = context.resources.openRawResource(resId) + op.inJustDecodeBounds = false + return BitmapFactory.decodeStream(inputStream, null, op) + } + + /** + * @param context 设备上下文 + * @param fileNameInAssets Assets里面文件的名称 + * @param width 图片的宽度 + * @param height 图片的高度 + * @return Bitmap + * @throws IOException + */ + @Throws(IOException::class) + fun decodeBitmap(context: Context, fileNameInAssets: String, width: Int, height: Int): Bitmap? { + + var inputStream = context.assets.open(fileNameInAssets) + val op = BitmapFactory.Options() + // inJustDecodeBounds如果设置为true,仅仅返回图片实际的宽和高,宽和高是赋值给opts.outWidth,opts.outHeight; + op.inJustDecodeBounds = true + BitmapFactory.decodeStream(inputStream, null, op) //获取尺寸信息 + //获取比例大小 + val wRatio = ceil((op.outWidth / width).toDouble()).toInt() + val hRatio = ceil((op.outHeight / height).toDouble()).toInt() + //如果超出指定大小,则缩小相应的比例 + if (wRatio > 1 && hRatio > 1) { + if (wRatio > hRatio) { + op.inSampleSize = wRatio + } else { + op.inSampleSize = hRatio + } + } + inputStream = context.assets.open(fileNameInAssets) + op.inJustDecodeBounds = false + return BitmapFactory.decodeStream(inputStream, null, op) + } + + + //图片不被压缩 + fun convertViewToBitmap(view: View, bitmapWidth: Int, bitmapHeight: Int): Bitmap { + val bitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888) + view.draw(Canvas(bitmap)) + return bitmap + } + + + /** + * @param options + * @param minSideLength + * @param maxNumOfPixels + * @return + * 设置恰当的inSampleSize是解决该问题的关键之一。BitmapFactory.Options提供了另一个成员inJustDecodeBounds。 + * 设置inJustDecodeBounds为true后,decodeFile并不分配空间,但可计算出原始图片的长度和宽度,即opts.width和opts.height。 + * 有了这两个参数,再通过一定的算法,即可得到一个恰当的inSampleSize。 + * 查看Android源码,Android提供了下面这种动态计算的方法。 + */ + fun computeSampleSize( + options: BitmapFactory.Options, + minSideLength: Int, + maxNumOfPixels: Int + ): Int { + + val initialSize = computeInitialSampleSize(options, minSideLength, maxNumOfPixels) + + var roundedSize: Int + + if (initialSize <= 8) { + roundedSize = 1 + while (roundedSize < initialSize) { + roundedSize = roundedSize shl 1 + } + } else { + roundedSize = (initialSize + 7) / 8 * 8 + } + + return roundedSize + } + + + private fun computeInitialSampleSize( + options: BitmapFactory.Options, + minSideLength: Int, + maxNumOfPixels: Int + ): Int { + + val w = options.outWidth.toDouble() + val h = options.outHeight.toDouble() + + val lowerBound = if (maxNumOfPixels == -1) + 1 + else + Math.ceil(Math.sqrt(w * h / maxNumOfPixels)).toInt() + + val upperBound = if (minSideLength == -1) 128 else Math.min( + Math.floor(w / minSideLength), + Math.floor(h / minSideLength) + ).toInt() + + if (upperBound < lowerBound) { + // return the larger one when there is no overlapping zone. + return lowerBound + } + + return if (maxNumOfPixels == -1 && minSideLength == -1) { + 1 + } else if (minSideLength == -1) { + lowerBound + } else { + upperBound + } + } + + /** + * 高斯模糊 + */ + fun stackBlur(srcBitmap: Bitmap?): Bitmap? { + if (srcBitmap == null) return null + val rs = RenderScript.create(App.INSTANCE) + val blurredBitmap = srcBitmap.copy(Config.ARGB_8888, true) + + //分配用于渲染脚本的内存 + val input = Allocation.createFromBitmap( + rs, + blurredBitmap, + Allocation.MipmapControl.MIPMAP_FULL, + Allocation.USAGE_SHARED + ) + val output = Allocation.createTyped(rs, input.type) + + //加载我们想要使用的特定脚本的实例。 + val script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)) + script.setInput(input) + + //设置模糊半径 + script.setRadius(8f) + + //启动 ScriptIntrinsicBlur + script.forEach(output) + + //将输出复制到模糊的位图 + output.copyTo(blurredBitmap) + + return blurredBitmap + } + +} From 0a26d404b05bca83df5b5436599552650df93fbc Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 27 Sep 2019 18:01:11 +0800 Subject: [PATCH 1674/1997] up --- app/src/main/java/io/legado/app/utils/BitmapUtil.kt | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/utils/BitmapUtil.kt b/app/src/main/java/io/legado/app/utils/BitmapUtil.kt index a5c7b776f..2b72e17db 100644 --- a/app/src/main/java/io/legado/app/utils/BitmapUtil.kt +++ b/app/src/main/java/io/legado/app/utils/BitmapUtil.kt @@ -13,9 +13,12 @@ import android.view.View import io.legado.app.App import java.io.IOException import kotlin.math.ceil +import kotlin.math.floor +import kotlin.math.min +import kotlin.math.sqrt -@SuppressWarnings("unused", "WeakerAccess") +@Suppress("unused", "WeakerAccess") object BitmapUtil { /** * 从path中获取图片信息,在通过BitmapFactory.decodeFile(String path)方法将突破转成Bitmap时, @@ -195,11 +198,11 @@ object BitmapUtil { val lowerBound = if (maxNumOfPixels == -1) 1 else - Math.ceil(Math.sqrt(w * h / maxNumOfPixels)).toInt() + ceil(sqrt(w * h / maxNumOfPixels)).toInt() - val upperBound = if (minSideLength == -1) 128 else Math.min( - Math.floor(w / minSideLength), - Math.floor(h / minSideLength) + val upperBound = if (minSideLength == -1) 128 else min( + floor(w / minSideLength), + floor(h / minSideLength) ).toInt() if (upperBound < lowerBound) { From 8b22086d54596788a1061d4070815c2ee00a0d21 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 27 Sep 2019 22:03:20 +0800 Subject: [PATCH 1675/1997] up --- app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt index dbcc05184..a44cab248 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt @@ -312,6 +312,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } private fun curPageChanged() { + seek_read_page.progress = viewModel.durPageIndex when (readAloudStatus) { Status.PLAY -> readAloud() Status.PAUSE -> { From 85cbe43e240f1561f12d05e998d1796d6c2d3ea8 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 27 Sep 2019 22:10:32 +0800 Subject: [PATCH 1676/1997] up --- .../main/java/io/legado/app/ui/book/read/ReadBookActivity.kt | 2 +- app/src/main/java/io/legado/app/ui/book/read/ReadMenu.kt | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt index a44cab248..b8bb11427 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt @@ -304,7 +304,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea tv_chapter_url.text = it.url tv_chapter_url.visible() } - read_menu.upReadProgress(it.pageSize().minus(1), viewModel.durPageIndex) + seek_read_page.max = it.pageSize().minus(1) tv_pre.isEnabled = viewModel.durChapterIndex != 0 tv_next.isEnabled = viewModel.durChapterIndex != viewModel.chapterSize - 1 curPageChanged() diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadMenu.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadMenu.kt index bb321fd65..0aa08497c 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadMenu.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadMenu.kt @@ -95,11 +95,6 @@ class ReadMenu : FrameLayout { } } - fun upReadProgress(max: Int, dur: Int) { - seek_read_page.max = max - seek_read_page.progress = dur - } - private fun brightnessAuto(): Boolean { return context.getPrefBoolean("brightnessAuto", true) } From 565de5db0744c173801d8f08062852ba459ddb8e Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 28 Sep 2019 11:55:10 +0800 Subject: [PATCH 1677/1997] up --- .../book/source/manage/GroupManageDialog.kt | 1 - .../ui/main/bookshelf/BookshelfViewModel.kt | 11 ++ .../ui/main/bookshelf/GroupManageDialog.kt | 136 ++++++++++++++++++ .../app/ui/replacerule/GroupManageDialog.kt | 1 - app/src/main/res/layout/item_book_group.xml | 8 -- 5 files changed, 147 insertions(+), 10 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageDialog.kt delete mode 100644 app/src/main/res/layout/item_book_group.xml diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/GroupManageDialog.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/GroupManageDialog.kt index 1cdcccd45..59f5e73af 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/manage/GroupManageDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/GroupManageDialog.kt @@ -29,7 +29,6 @@ import io.legado.app.utils.requestInputMethod import io.legado.app.utils.splitNotBlank import kotlinx.android.synthetic.main.dialog_edit_text.view.* import kotlinx.android.synthetic.main.dialog_recycler_view.* -import kotlinx.android.synthetic.main.item_book_group.view.tv_group import kotlinx.android.synthetic.main.item_group_manage.view.* import org.jetbrains.anko.sdk27.listeners.onClick diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt index 1bb9a3b64..a56a08871 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt @@ -20,4 +20,15 @@ class BookshelfViewModel(application: Application) : BaseViewModel(application) } } + fun addGroup(groupName: String) { + + } + + fun upGroup(bookGroup: BookGroup) { + + } + + fun delGroup(bookGroup: BookGroup) { + + } } diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageDialog.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageDialog.kt new file mode 100644 index 000000000..d33a62476 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageDialog.kt @@ -0,0 +1,136 @@ +package io.legado.app.ui.main.bookshelf + +import android.annotation.SuppressLint +import android.content.Context +import android.os.Bundle +import android.util.DisplayMetrics +import android.view.LayoutInflater +import android.view.MenuItem +import android.view.View +import android.view.ViewGroup +import android.widget.EditText +import androidx.appcompat.widget.Toolbar +import androidx.fragment.app.DialogFragment +import androidx.lifecycle.Observer +import androidx.recyclerview.widget.DividerItemDecoration +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import io.legado.app.App +import io.legado.app.R +import io.legado.app.base.adapter.ItemViewHolder +import io.legado.app.base.adapter.SimpleRecyclerAdapter +import io.legado.app.data.entities.BookGroup +import io.legado.app.lib.dialogs.alert +import io.legado.app.lib.dialogs.customView +import io.legado.app.lib.dialogs.noButton +import io.legado.app.lib.dialogs.yesButton +import io.legado.app.utils.applyTint +import io.legado.app.utils.getViewModel +import io.legado.app.utils.requestInputMethod +import kotlinx.android.synthetic.main.dialog_edit_text.view.* +import kotlinx.android.synthetic.main.dialog_recycler_view.* +import kotlinx.android.synthetic.main.item_group_manage.view.* +import org.jetbrains.anko.sdk27.listeners.onClick + +class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { + private lateinit var viewModel: BookshelfViewModel + private lateinit var adapter: GroupAdapter + + override fun onStart() { + super.onStart() + val dm = DisplayMetrics() + activity?.windowManager?.defaultDisplay?.getMetrics(dm) + dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.9).toInt()) + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + viewModel = getViewModel(BookshelfViewModel::class.java) + return inflater.inflate(R.layout.dialog_recycler_view, container) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + initData() + } + + private fun initData() { + tool_bar.title = getString(R.string.group_manage) + tool_bar.inflateMenu(R.menu.group_manage) + tool_bar.menu.applyTint(requireContext(), false) + tool_bar.setOnMenuItemClickListener(this) + adapter = GroupAdapter(requireContext()) + recycler_view.layoutManager = LinearLayoutManager(requireContext()) + recycler_view.addItemDecoration( + DividerItemDecoration(requireContext(), RecyclerView.VERTICAL) + ) + recycler_view.adapter = adapter + App.db.bookGroupDao().liveDataAll().observe(viewLifecycleOwner, Observer { + adapter.setItems(it) + }) + } + + override fun onMenuItemClick(item: MenuItem?): Boolean { + when (item?.itemId) { + R.id.menu_add -> addGroup() + } + return true + } + + @SuppressLint("InflateParams") + private fun addGroup() { + alert(title = getString(R.string.add_group)) { + var editText: EditText? = null + customView { + layoutInflater.inflate(R.layout.dialog_edit_text, null).apply { + editText = edit_view.apply { + hint = "分组名称" + } + } + } + yesButton { + editText?.text?.toString()?.let { + if (it.isNotBlank()) { + viewModel.addGroup(it) + } + } + } + noButton() + }.show().applyTint().requestInputMethod() + } + + @SuppressLint("InflateParams") + private fun editGroup(bookGroup: BookGroup) { + alert(title = getString(R.string.group_edit)) { + var editText: EditText? = null + customView { + layoutInflater.inflate(R.layout.dialog_edit_text, null).apply { + editText = edit_view.apply { + hint = "分组名称" + setText(bookGroup.groupName) + } + } + } + yesButton { + viewModel.upGroup(bookGroup.copy(groupName = editText?.text?.toString() ?: "")) + } + noButton() + }.show().applyTint().requestInputMethod() + } + + private inner class GroupAdapter(context: Context) : + SimpleRecyclerAdapter(context, R.layout.item_group_manage) { + + override fun convert(holder: ItemViewHolder, item: BookGroup, payloads: MutableList) { + with(holder.itemView) { + tv_group.text = item.groupName + tv_edit.onClick { editGroup(item) } + tv_del.onClick { viewModel.delGroup(item) } + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/replacerule/GroupManageDialog.kt b/app/src/main/java/io/legado/app/ui/replacerule/GroupManageDialog.kt index 49fb8c3e6..2b2a84835 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/GroupManageDialog.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/GroupManageDialog.kt @@ -29,7 +29,6 @@ import io.legado.app.utils.requestInputMethod import io.legado.app.utils.splitNotBlank import kotlinx.android.synthetic.main.dialog_edit_text.view.* import kotlinx.android.synthetic.main.dialog_recycler_view.* -import kotlinx.android.synthetic.main.item_book_group.view.tv_group import kotlinx.android.synthetic.main.item_group_manage.view.* import org.jetbrains.anko.sdk27.listeners.onClick diff --git a/app/src/main/res/layout/item_book_group.xml b/app/src/main/res/layout/item_book_group.xml deleted file mode 100644 index 04536bac4..000000000 --- a/app/src/main/res/layout/item_book_group.xml +++ /dev/null @@ -1,8 +0,0 @@ - - \ No newline at end of file From 6fb960f6de5d45c2dbc0639da3bceaca87f0c2b1 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 28 Sep 2019 16:13:11 +0800 Subject: [PATCH 1678/1997] up --- .../ui/main/bookshelf/BookshelfFragment.kt | 36 +++++++------------ app/src/main/res/menu/main_bookshelf.xml | 6 ++++ 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index b7f91a0af..008ff6131 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -1,11 +1,9 @@ package io.legado.app.ui.main.bookshelf -import android.annotation.SuppressLint import android.os.Bundle import android.view.Menu import android.view.MenuItem import android.view.View -import android.widget.EditText import androidx.appcompat.widget.SearchView import androidx.lifecycle.LiveData import androidx.lifecycle.Observer @@ -16,11 +14,12 @@ import io.legado.app.R import io.legado.app.base.VMBaseFragment import io.legado.app.constant.AppConst import io.legado.app.data.entities.BookGroup -import io.legado.app.lib.dialogs.* +import io.legado.app.lib.dialogs.selector import io.legado.app.lib.theme.ATH import io.legado.app.ui.book.search.SearchActivity -import io.legado.app.utils.* -import kotlinx.android.synthetic.main.dialog_edit_text.view.* +import io.legado.app.utils.getViewModel +import io.legado.app.utils.putPrefInt +import io.legado.app.utils.startActivity import kotlinx.android.synthetic.main.fragment_bookshelf.* import kotlinx.android.synthetic.main.view_tab_layout.* import kotlinx.android.synthetic.main.view_title_bar.* @@ -51,6 +50,15 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b when (item.itemId) { R.id.menu_search -> startActivity() R.id.menu_bookshelf_layout -> selectBookshelfLayout() + R.id.menu_group_manage -> fragmentManager?.let { + GroupManageDialog().show(it, "groupManageDialog") + } + R.id.menu_add_local -> { + } + R.id.menu_add_url -> { + } + R.id.menu_arrange_bookshelf -> { + } } } @@ -92,24 +100,6 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b return false } - @SuppressLint("InflateParams") - private fun showGroupInputDialog() { - alert(title = "新建分组") { - var editText: EditText? = null - customView { - layoutInflater.inflate(R.layout.dialog_edit_text, null).apply { - editText = edit_view.apply { - hint = "分组名称" - } - } - } - yesButton { - viewModel.saveBookGroup(editText?.text?.toString()) - } - noButton() - }.show().applyTint().requestInputMethod() - } - private fun selectBookshelfLayout() { selector( title = "选择书架布局", diff --git a/app/src/main/res/menu/main_bookshelf.xml b/app/src/main/res/menu/main_bookshelf.xml index 19bbbdb7f..45b586ca8 100644 --- a/app/src/main/res/menu/main_bookshelf.xml +++ b/app/src/main/res/menu/main_bookshelf.xml @@ -26,6 +26,12 @@ android:title="@string/download_all" app:showAsAction="never" /> + + Date: Sat, 28 Sep 2019 17:00:53 +0800 Subject: [PATCH 1679/1997] up --- .../io/legado/app/data/dao/BookGroupDao.kt | 13 ++++---- .../ui/main/bookshelf/BookshelfViewModel.kt | 30 +++++++++---------- .../ui/main/bookshelf/GroupManageDialog.kt | 2 +- app/src/main/res/menu/book_group_manage.xml | 27 +++++++++++++++++ 4 files changed, 51 insertions(+), 21 deletions(-) create mode 100644 app/src/main/res/menu/book_group_manage.xml diff --git a/app/src/main/java/io/legado/app/data/dao/BookGroupDao.kt b/app/src/main/java/io/legado/app/data/dao/BookGroupDao.kt index 51068b149..6162ffc5a 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookGroupDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookGroupDao.kt @@ -1,10 +1,7 @@ package io.legado.app.data.dao import androidx.lifecycle.LiveData -import androidx.room.Dao -import androidx.room.Insert -import androidx.room.OnConflictStrategy -import androidx.room.Query +import androidx.room.* import io.legado.app.data.entities.BookGroup @Dao @@ -17,5 +14,11 @@ interface BookGroupDao { val maxId: Int @Insert(onConflict = OnConflictStrategy.REPLACE) - fun insert(bookGroup: BookGroup) + fun insert(vararg bookGroup: BookGroup) + + @Update + fun update(vararg bookGroup: BookGroup) + + @Delete + fun delete(vararg bookGroup: BookGroup) } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt index a56a08871..f4664fa22 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt @@ -7,28 +7,28 @@ import io.legado.app.data.entities.BookGroup class BookshelfViewModel(application: Application) : BaseViewModel(application) { - fun saveBookGroup(group: String?) { - if (!group.isNullOrBlank()) { - execute { - App.db.bookGroupDao().insert( - BookGroup( - App.db.bookGroupDao().maxId + 1, - group - ) - ) - } - } - } fun addGroup(groupName: String) { - + execute { + val maxId = App.db.bookGroupDao().maxId + val bookGroup = BookGroup( + groupId = maxId.plus(1), + groupName = groupName, + order = maxId.plus(1) + ) + App.db.bookGroupDao().insert(bookGroup) + } } fun upGroup(bookGroup: BookGroup) { - + execute { + App.db.bookGroupDao().update(bookGroup) + } } fun delGroup(bookGroup: BookGroup) { - + execute { + App.db.bookGroupDao().delete(bookGroup) + } } } diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageDialog.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageDialog.kt index d33a62476..7db85906e 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageDialog.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageDialog.kt @@ -59,7 +59,7 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { private fun initData() { tool_bar.title = getString(R.string.group_manage) - tool_bar.inflateMenu(R.menu.group_manage) + tool_bar.inflateMenu(R.menu.book_group_manage) tool_bar.menu.applyTint(requireContext(), false) tool_bar.setOnMenuItemClickListener(this) adapter = GroupAdapter(requireContext()) diff --git a/app/src/main/res/menu/book_group_manage.xml b/app/src/main/res/menu/book_group_manage.xml new file mode 100644 index 000000000..4c887905d --- /dev/null +++ b/app/src/main/res/menu/book_group_manage.xml @@ -0,0 +1,27 @@ + + + + + + + + + + \ No newline at end of file From 6bed8c39c2a67b2c0a0b27a02b9d2b225047678d Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 28 Sep 2019 22:00:35 +0800 Subject: [PATCH 1680/1997] up --- .../java/io/legado/app/constant/AppConst.kt | 10 ++--- .../ui/main/bookshelf/BookshelfFragment.kt | 38 +++++++++++++++---- .../ui/main/bookshelf/GroupManageDialog.kt | 23 +++++++++-- app/src/main/res/values/strings.xml | 1 + 4 files changed, 54 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/io/legado/app/constant/AppConst.kt b/app/src/main/java/io/legado/app/constant/AppConst.kt index f9fe5b942..99dcb17cb 100644 --- a/app/src/main/java/io/legado/app/constant/AppConst.kt +++ b/app/src/main/java/io/legado/app/constant/AppConst.kt @@ -38,11 +38,7 @@ object AppConst { ) } - val defaultBookGroups by lazy { - listOf( - BookGroup(-1, "全部"), - BookGroup(-2, "本地"), - BookGroup(-3, "音频") - ) - } + val bookGroupAll = BookGroup(-1, App.INSTANCE.getString(R.string.all)) + val bookGroupLocal = BookGroup(-2, App.INSTANCE.getString(R.string.local)) + val bookGroupAudio = BookGroup(-3, App.INSTANCE.getString(R.string.audio)) } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index 008ff6131..797ef096d 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -17,6 +17,7 @@ import io.legado.app.data.entities.BookGroup import io.legado.app.lib.dialogs.selector import io.legado.app.lib.theme.ATH import io.legado.app.ui.book.search.SearchActivity +import io.legado.app.utils.getPrefBoolean import io.legado.app.utils.getViewModel import io.legado.app.utils.putPrefInt import io.legado.app.utils.startActivity @@ -27,13 +28,14 @@ import org.jetbrains.anko.startActivity class BookshelfFragment : VMBaseFragment(R.layout.fragment_bookshelf), SearchView.OnQueryTextListener, + GroupManageDialog.CallBack, BookshelfAdapter.CallBack { override val viewModel: BookshelfViewModel get() = getViewModel(BookshelfViewModel::class.java) private var bookGroupLiveData: LiveData>? = null - private val bookGroups = mutableListOf().apply { addAll(AppConst.defaultBookGroups) } + private val bookGroups = mutableListOf() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { setSupportToolbar(toolbar) @@ -50,9 +52,8 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b when (item.itemId) { R.id.menu_search -> startActivity() R.id.menu_bookshelf_layout -> selectBookshelfLayout() - R.id.menu_group_manage -> fragmentManager?.let { - GroupManageDialog().show(it, "groupManageDialog") - } + R.id.menu_group_manage -> GroupManageDialog() + .show(childFragmentManager, "groupManageDialog") R.id.menu_add_local -> { } R.id.menu_add_url -> { @@ -83,11 +84,18 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b bookGroupLiveData?.removeObservers(viewLifecycleOwner) bookGroupLiveData = App.db.bookGroupDao().liveDataAll() bookGroupLiveData?.observe(viewLifecycleOwner, Observer { - for (index in AppConst.defaultBookGroups.size until bookGroups.size) { - bookGroups.removeAt(AppConst.defaultBookGroups.size) + synchronized(this) { + bookGroups.clear() + bookGroups.add(AppConst.bookGroupAll) + if (getPrefBoolean("bookGroupLocal", true)) { + bookGroups.add(AppConst.bookGroupLocal) + } + if (getPrefBoolean("bookGroupAudio", true)) { + bookGroups.add(AppConst.bookGroupAudio) + } + bookGroups.addAll(it) + view_pager_bookshelf.adapter?.notifyDataSetChanged() } - bookGroups.addAll(it) - view_pager_bookshelf.adapter?.notifyDataSetChanged() }) } @@ -100,6 +108,20 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b return false } + override fun upGroup() { + synchronized(this) { + bookGroups.remove(AppConst.bookGroupLocal) + bookGroups.remove(AppConst.bookGroupAudio) + if (getPrefBoolean("bookGroupAudio", true)) { + bookGroups.add(1, AppConst.bookGroupAudio) + } + if (getPrefBoolean("bookGroupLocal", true)) { + bookGroups.add(1, AppConst.bookGroupLocal) + } + view_pager_bookshelf.adapter?.notifyDataSetChanged() + } + } + private fun selectBookshelfLayout() { selector( title = "选择书架布局", diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageDialog.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageDialog.kt index 7db85906e..87d43bc1b 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageDialog.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageDialog.kt @@ -24,9 +24,7 @@ import io.legado.app.lib.dialogs.alert import io.legado.app.lib.dialogs.customView import io.legado.app.lib.dialogs.noButton import io.legado.app.lib.dialogs.yesButton -import io.legado.app.utils.applyTint -import io.legado.app.utils.getViewModel -import io.legado.app.utils.requestInputMethod +import io.legado.app.utils.* import kotlinx.android.synthetic.main.dialog_edit_text.view.* import kotlinx.android.synthetic.main.dialog_recycler_view.* import kotlinx.android.synthetic.main.item_group_manage.view.* @@ -35,6 +33,7 @@ import org.jetbrains.anko.sdk27.listeners.onClick class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { private lateinit var viewModel: BookshelfViewModel private lateinit var adapter: GroupAdapter + private var callBack: CallBack? = null override fun onStart() { super.onStart() @@ -54,6 +53,7 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + callBack = parentFragment as? CallBack initData() } @@ -62,6 +62,10 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { tool_bar.inflateMenu(R.menu.book_group_manage) tool_bar.menu.applyTint(requireContext(), false) tool_bar.setOnMenuItemClickListener(this) + tool_bar.menu.findItem(R.id.menu_group_local) + .isChecked = getPrefBoolean("bookGroupLocal", true) + tool_bar.menu.findItem(R.id.menu_group_audio) + .isChecked = getPrefBoolean("bookGroupAudio", true) adapter = GroupAdapter(requireContext()) recycler_view.layoutManager = LinearLayoutManager(requireContext()) recycler_view.addItemDecoration( @@ -76,6 +80,16 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { override fun onMenuItemClick(item: MenuItem?): Boolean { when (item?.itemId) { R.id.menu_add -> addGroup() + R.id.menu_group_local -> { + item.isChecked = !item.isChecked + putPrefBoolean("bookGroupLocal", item.isChecked) + callBack?.upGroup() + } + R.id.menu_group_audio -> { + item.isChecked = !item.isChecked + putPrefBoolean("bookGroupAudio", item.isChecked) + callBack?.upGroup() + } } return true } @@ -133,4 +147,7 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { } } + interface CallBack { + fun upGroup() + } } \ 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 72667cbab..af7b4e933 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -35,6 +35,7 @@ 替换净化-搜索 书架 订阅 + 全部 最近阅读 最后阅读 让阅读成为一种习惯。 From cca3920c76a0f01987d0815f56439e09f977c6a2 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 28 Sep 2019 22:19:58 +0800 Subject: [PATCH 1681/1997] up --- .../ui/main/bookshelf/BookshelfViewModel.kt | 8 +++--- .../ui/main/bookshelf/GroupManageDialog.kt | 25 ++++++++++++++++++- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt index f4664fa22..0499e5e5e 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt @@ -20,15 +20,15 @@ class BookshelfViewModel(application: Application) : BaseViewModel(application) } } - fun upGroup(bookGroup: BookGroup) { + fun upGroup(vararg bookGroup: BookGroup) { execute { - App.db.bookGroupDao().update(bookGroup) + App.db.bookGroupDao().update(*bookGroup) } } - fun delGroup(bookGroup: BookGroup) { + fun delGroup(vararg bookGroup: BookGroup) { execute { - App.db.bookGroupDao().delete(bookGroup) + App.db.bookGroupDao().delete(*bookGroup) } } } diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageDialog.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageDialog.kt index 87d43bc1b..f6151edaf 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageDialog.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageDialog.kt @@ -13,6 +13,7 @@ import androidx.appcompat.widget.Toolbar import androidx.fragment.app.DialogFragment import androidx.lifecycle.Observer import androidx.recyclerview.widget.DividerItemDecoration +import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import io.legado.app.App @@ -20,6 +21,7 @@ import io.legado.app.R import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.data.entities.BookGroup +import io.legado.app.help.ItemTouchCallback import io.legado.app.lib.dialogs.alert import io.legado.app.lib.dialogs.customView import io.legado.app.lib.dialogs.noButton @@ -75,6 +77,10 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { App.db.bookGroupDao().liveDataAll().observe(viewLifecycleOwner, Observer { adapter.setItems(it) }) + val itemTouchCallback = ItemTouchCallback() + itemTouchCallback.onItemTouchCallbackListener = adapter + itemTouchCallback.isCanDrag = true + ItemTouchHelper(itemTouchCallback).attachToRecyclerView(recycler_view) } override fun onMenuItemClick(item: MenuItem?): Boolean { @@ -136,7 +142,8 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { } private inner class GroupAdapter(context: Context) : - SimpleRecyclerAdapter(context, R.layout.item_group_manage) { + SimpleRecyclerAdapter(context, R.layout.item_group_manage), + ItemTouchCallback.OnItemTouchCallbackListener { override fun convert(holder: ItemViewHolder, item: BookGroup, payloads: MutableList) { with(holder.itemView) { @@ -145,6 +152,22 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { tv_del.onClick { viewModel.delGroup(item) } } } + + override fun onMove(srcPosition: Int, targetPosition: Int): Boolean { + val srcItem = getItem(srcPosition) + val targetItem = getItem(targetPosition) + if (srcItem != null && targetItem != null) { + val order = srcItem.order + srcItem.order = targetItem.order + targetItem.order = order + viewModel.upGroup(srcItem, targetItem) + } + return true + } + + override fun onSwiped(adapterPosition: Int) { + + } } interface CallBack { From 69960cefbd82a045f8d77fb86c1eaceed47de9f0 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 28 Sep 2019 22:23:02 +0800 Subject: [PATCH 1682/1997] up --- app/src/main/res/layout/item_group_manage.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/layout/item_group_manage.xml b/app/src/main/res/layout/item_group_manage.xml index 493bf7998..d7d85630a 100644 --- a/app/src/main/res/layout/item_group_manage.xml +++ b/app/src/main/res/layout/item_group_manage.xml @@ -2,6 +2,7 @@ From fa933273d9e63f85a450e3e792d95c822d8bbf91 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 28 Sep 2019 22:26:26 +0800 Subject: [PATCH 1683/1997] up --- app/src/main/res/values-zh/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 app/src/main/res/values-zh/strings.xml diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml new file mode 100644 index 000000000..78554f9eb --- /dev/null +++ b/app/src/main/res/values-zh/strings.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file From 0104a541e021e208f638aaccc58dd58930967745 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 29 Sep 2019 09:47:44 +0800 Subject: [PATCH 1684/1997] up --- .../io/legado/app/ui/book/info/BookInfoActivity.kt | 6 ++++-- .../main/res/layout-land/activity_book_info.xml | 14 ++++++++++++-- app/src/main/res/layout/activity_book_info.xml | 14 ++++++++++++-- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt index 62bc33ca9..8905a248c 100644 --- a/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt @@ -204,8 +204,10 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo } } iv_chapter_top.onClick { - adapter.reorder = !adapter.reorder - adapter.notifyDataSetChanged() + rv_chapter_list.scrollToPosition(0) + } + iv_chapter_bottom.onClick { + rv_chapter_list.scrollToPosition(adapter.itemCount - 1) } } diff --git a/app/src/main/res/layout-land/activity_book_info.xml b/app/src/main/res/layout-land/activity_book_info.xml index a5419f1e6..efc24a7a4 100644 --- a/app/src/main/res/layout-land/activity_book_info.xml +++ b/app/src/main/res/layout-land/activity_book_info.xml @@ -245,11 +245,21 @@ android:layout_height="match_parent" android:background="?android:attr/selectableItemBackgroundBorderless" android:contentDescription="@string/go_to_top" - android:padding="10dp" - android:src="@drawable/ic_exchange_order" + android:src="@drawable/ic_arrow_drop_up" android:tooltipText="@string/go_to_top" app:tint="@color/tv_text_default" tools:ignore="UnusedAttribute" /> + + diff --git a/app/src/main/res/layout/activity_book_info.xml b/app/src/main/res/layout/activity_book_info.xml index 2ccef7e17..b5981556c 100644 --- a/app/src/main/res/layout/activity_book_info.xml +++ b/app/src/main/res/layout/activity_book_info.xml @@ -237,11 +237,21 @@ android:layout_height="match_parent" android:background="?android:attr/selectableItemBackgroundBorderless" android:contentDescription="@string/go_to_top" - android:padding="10dp" - android:src="@drawable/ic_exchange_order" + android:src="@drawable/ic_arrow_drop_up" android:tooltipText="@string/go_to_top" app:tint="@color/tv_text_default" tools:ignore="UnusedAttribute" /> + + From adc7867306e42de2eda4fe3e9bbb6d094c0d5be4 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 29 Sep 2019 16:04:55 +0800 Subject: [PATCH 1685/1997] up --- .../io/legado/app/ui/config/ConfigFragment.kt | 2 + .../io/legado/app/ui/main/my/MyFragment.kt | 8 ++- .../main/java/io/legado/app/utils/LogUtils.kt | 70 ++++++------------- 3 files changed, 27 insertions(+), 53 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt index c3b0ae799..fd957e433 100644 --- a/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt @@ -10,6 +10,7 @@ import io.legado.app.App import io.legado.app.R import io.legado.app.help.BookHelp import io.legado.app.lib.theme.ATH +import io.legado.app.utils.LogUtils import io.legado.app.utils.getPrefString @@ -39,6 +40,7 @@ class ConfigFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChange override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { when (key) { "downloadPath" -> BookHelp.upDownloadPath() + "recordLog" -> LogUtils.upLevel() } } diff --git a/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt b/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt index 36f2db63b..af839204e 100644 --- a/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt @@ -10,6 +10,7 @@ import androidx.preference.PreferenceFragmentCompat import io.legado.app.App import io.legado.app.R import io.legado.app.base.BaseFragment +import io.legado.app.help.BookHelp import io.legado.app.help.permission.Permissions import io.legado.app.help.permission.PermissionsCompat import io.legado.app.help.storage.Backup @@ -21,6 +22,7 @@ import io.legado.app.ui.book.source.manage.BookSourceActivity import io.legado.app.ui.config.ConfigActivity import io.legado.app.ui.config.ConfigViewModel import io.legado.app.ui.replacerule.ReplaceRuleActivity +import io.legado.app.utils.LogUtils import io.legado.app.utils.startActivity import kotlinx.android.synthetic.main.view_title_bar.* import org.jetbrains.anko.startActivity @@ -82,9 +84,9 @@ class MyFragment : BaseFragment(R.layout.fragment_my_config) { key: String? ) { when (key) { - "isNightTheme" -> { - App.INSTANCE.applyDayNight() - } + "isNightTheme" -> App.INSTANCE.applyDayNight() + "recordLog" -> LogUtils.upLevel() + "downloadPath" -> BookHelp.upDownloadPath() } } diff --git a/app/src/main/java/io/legado/app/utils/LogUtils.kt b/app/src/main/java/io/legado/app/utils/LogUtils.kt index 571c4e4cf..b271cbda0 100644 --- a/app/src/main/java/io/legado/app/utils/LogUtils.kt +++ b/app/src/main/java/io/legado/app/utils/LogUtils.kt @@ -11,66 +11,36 @@ import java.util.logging.Formatter object LogUtils { + const val TIME_PATTERN = "yyyy-MM-dd HH:mm:ss" - private val logger: Logger by lazy { + val logger: Logger by lazy { Logger.getGlobal().apply { - addFileHandler( - this, - Level.INFO, - FileHelp.getCachePath() - ) + addHandler(fileHandler) } } - fun log(msg: String) { - if (App.INSTANCE.getPrefBoolean("recordLog")) { - logger.log(Level.INFO, msg) - } - } - - private const val DATE_PATTERN = "yyyy-MM-dd" - const val TIME_PATTERN = "HH:mm:ss" - - /** - * 为log添加控制台handler - * - * @param log 要添加handler的log - * @param level 控制台的输出等级 - */ - fun addConsoleHandler(log: Logger, level: Level) { - // 控制台输出的handler - val consoleHandler = ConsoleHandler() - // 设置控制台输出的等级(如果ConsoleHandler的等级高于或者等于log的level,则按照FileHandler的level输出到控制台,如果低于,则按照Log等级输出) - consoleHandler.level = level - // 添加控制台的handler - log.addHandler(consoleHandler) - } - - /** - * 为log添加文件输出Handler - * - * @param log 要添加文件输出handler的log - * @param level log输出等级 - * @param filePath 指定文件全路径 - */ - fun addFileHandler(log: Logger, level: Level, filePath: String) { - var fileHandler: FileHandler? = null - try { - fileHandler = - FileHandler(filePath + File.separator + getCurrentDateStr(DATE_PATTERN) + ".log") - // 设置输出文件的等级(如果FileHandler的等级高于或者等于log的level,则按照FileHandler的level输出到文件,如果低于,则按照Log等级输出) - fileHandler.level = level - fileHandler.formatter = object : Formatter() { + private val fileHandler by lazy { + FileHandler(FileHelp.getCachePath() + File.separator + "app.log", 1024, 2).apply { + formatter = object : Formatter() { override fun format(record: LogRecord): String { // 设置文件输出格式 - return (getCurrentDateStr(TIME_PATTERN) + ":" + record.message + "\n") + return (getCurrentDateStr(TIME_PATTERN) + ": " + record.message + "\n") } } - } catch (e: Exception) { - e.printStackTrace() + level = if (App.INSTANCE.getPrefBoolean("recordLog")) { + Level.INFO + } else { + Level.OFF + } + } + } + + fun upLevel() { + fileHandler.level = if (App.INSTANCE.getPrefBoolean("recordLog")) { + Level.INFO + } else { + Level.OFF } - // 添加输出文件handler - log.addHandler(fileHandler) } /** From b4894d43d32d6a11b416565c114bff85621188c1 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 29 Sep 2019 16:15:23 +0800 Subject: [PATCH 1686/1997] up --- .../main/java/io/legado/app/receiver/MediaButtonReceiver.kt | 4 +++- app/src/main/java/io/legado/app/utils/LogUtils.kt | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt index 17eba6b18..1dfa59fcc 100644 --- a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt +++ b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt @@ -7,7 +7,9 @@ import android.view.KeyEvent import io.legado.app.constant.Bus import io.legado.app.help.ActivityHelp import io.legado.app.ui.book.read.ReadBookActivity +import io.legado.app.utils.LogUtils.MyLogger import io.legado.app.utils.postEvent +import java.util.logging.Level /** @@ -22,7 +24,7 @@ class MediaButtonReceiver : BroadcastReceiver() { fun handleIntent(context: Context, intent: Intent): Boolean { val intentAction = intent.action val keyEventAction = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT)?.action -// LogUtils.log("耳机按键: $intentAction $keyEventAction") + MyLogger.log(Level.INFO, "耳机按键: $intentAction $keyEventAction") if (Intent.ACTION_MEDIA_BUTTON == intentAction) { if (keyEventAction == KeyEvent.ACTION_DOWN) { readAloud(context) diff --git a/app/src/main/java/io/legado/app/utils/LogUtils.kt b/app/src/main/java/io/legado/app/utils/LogUtils.kt index b271cbda0..82b2c8cc4 100644 --- a/app/src/main/java/io/legado/app/utils/LogUtils.kt +++ b/app/src/main/java/io/legado/app/utils/LogUtils.kt @@ -13,7 +13,7 @@ import java.util.logging.Formatter object LogUtils { const val TIME_PATTERN = "yyyy-MM-dd HH:mm:ss" - val logger: Logger by lazy { + val MyLogger: Logger by lazy { Logger.getGlobal().apply { addHandler(fileHandler) } From 016e98f4855ca322c38090c5d6002cc311f66622 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 29 Sep 2019 18:02:33 +0800 Subject: [PATCH 1687/1997] up --- app/build.gradle | 3 + app/src/main/java/io/legado/app/App.kt | 10 ++++ .../app/receiver/MediaButtonReceiver.kt | 5 +- .../io/legado/app/ui/config/ConfigFragment.kt | 5 +- .../io/legado/app/ui/main/my/MyFragment.kt | 5 +- .../main/java/io/legado/app/utils/LogUtils.kt | 55 ------------------- 6 files changed, 21 insertions(+), 62 deletions(-) delete mode 100644 app/src/main/java/io/legado/app/utils/LogUtils.kt diff --git a/app/build.gradle b/app/build.gradle index 22922cbbe..97a5a9dc0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -148,4 +148,7 @@ dependencies { //颜色选择 implementation 'com.jaredrummler:colorpicker:1.1.0' + //日志记录 + implementation 'com.apkfuns.logutils:library:1.7.5' + implementation 'com.apkfuns.log2file:log2file:1.3.1' } diff --git a/app/src/main/java/io/legado/app/App.kt b/app/src/main/java/io/legado/app/App.kt index 54238a6ad..ea8a30f66 100644 --- a/app/src/main/java/io/legado/app/App.kt +++ b/app/src/main/java/io/legado/app/App.kt @@ -9,6 +9,8 @@ import android.os.Build import android.os.Bundle import androidx.annotation.RequiresApi import androidx.appcompat.app.AppCompatDelegate +import com.apkfuns.log2file.LogFileEngineFactory +import com.apkfuns.logutils.LogUtils import com.jeremyliao.liveeventbus.LiveEventBus import io.legado.app.constant.AppConst.channelIdDownload import io.legado.app.constant.AppConst.channelIdReadAloud @@ -16,12 +18,15 @@ import io.legado.app.constant.AppConst.channelIdWeb import io.legado.app.data.AppDatabase import io.legado.app.help.ActivityHelp import io.legado.app.help.CrashHandler +import io.legado.app.help.FileHelp import io.legado.app.help.ReadBookConfig import io.legado.app.lib.theme.ThemeStore import io.legado.app.ui.widget.page.ChapterProvider import io.legado.app.utils.getCompatColor +import io.legado.app.utils.getPrefBoolean import io.legado.app.utils.getPrefInt import io.legado.app.utils.isNightTheme +import java.io.File @Suppress("DEPRECATION") class App : Application() { @@ -43,6 +48,11 @@ class App : Application() { super.onCreate() INSTANCE = this CrashHandler().init(this) + LogUtils.getLog2FileConfig() + .configLog2FileEnable(getPrefBoolean("recordLog")) + .configLog2FilePath(FileHelp.getCachePath() + File.separator + "logs" + File.separator) + .configLog2FileNameFormat("%d{yyyyMMdd}.log") + .configLogFileEngine(LogFileEngineFactory(this)) db = AppDatabase.createDatabase(INSTANCE) packageManager.getPackageInfo(packageName, 0)?.let { versionCode = it.versionCode diff --git a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt index 1dfa59fcc..45565c31c 100644 --- a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt +++ b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt @@ -4,12 +4,11 @@ import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.view.KeyEvent +import com.apkfuns.logutils.LogUtils import io.legado.app.constant.Bus import io.legado.app.help.ActivityHelp import io.legado.app.ui.book.read.ReadBookActivity -import io.legado.app.utils.LogUtils.MyLogger import io.legado.app.utils.postEvent -import java.util.logging.Level /** @@ -24,7 +23,7 @@ class MediaButtonReceiver : BroadcastReceiver() { fun handleIntent(context: Context, intent: Intent): Boolean { val intentAction = intent.action val keyEventAction = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT)?.action - MyLogger.log(Level.INFO, "耳机按键: $intentAction $keyEventAction") + LogUtils.d("耳机按键", "$intentAction $keyEventAction") if (Intent.ACTION_MEDIA_BUTTON == intentAction) { if (keyEventAction == KeyEvent.ACTION_DOWN) { readAloud(context) diff --git a/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt index fd957e433..c111b9401 100644 --- a/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt @@ -6,11 +6,12 @@ import android.view.View import androidx.preference.ListPreference import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat +import com.apkfuns.logutils.LogUtils import io.legado.app.App import io.legado.app.R import io.legado.app.help.BookHelp import io.legado.app.lib.theme.ATH -import io.legado.app.utils.LogUtils +import io.legado.app.utils.getPrefBoolean import io.legado.app.utils.getPrefString @@ -40,7 +41,7 @@ class ConfigFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChange override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { when (key) { "downloadPath" -> BookHelp.upDownloadPath() - "recordLog" -> LogUtils.upLevel() + "recordLog" -> LogUtils.getLog2FileConfig().configLog2FileEnable(getPrefBoolean("recordLog")) } } diff --git a/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt b/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt index af839204e..350737281 100644 --- a/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt @@ -7,6 +7,7 @@ import android.view.MenuItem import android.view.View import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat +import com.apkfuns.logutils.LogUtils import io.legado.app.App import io.legado.app.R import io.legado.app.base.BaseFragment @@ -22,7 +23,7 @@ import io.legado.app.ui.book.source.manage.BookSourceActivity import io.legado.app.ui.config.ConfigActivity import io.legado.app.ui.config.ConfigViewModel import io.legado.app.ui.replacerule.ReplaceRuleActivity -import io.legado.app.utils.LogUtils +import io.legado.app.utils.getPrefBoolean import io.legado.app.utils.startActivity import kotlinx.android.synthetic.main.view_title_bar.* import org.jetbrains.anko.startActivity @@ -85,7 +86,7 @@ class MyFragment : BaseFragment(R.layout.fragment_my_config) { ) { when (key) { "isNightTheme" -> App.INSTANCE.applyDayNight() - "recordLog" -> LogUtils.upLevel() + "recordLog" -> LogUtils.getLog2FileConfig().configLog2FileEnable(getPrefBoolean("recordLog")) "downloadPath" -> BookHelp.upDownloadPath() } } diff --git a/app/src/main/java/io/legado/app/utils/LogUtils.kt b/app/src/main/java/io/legado/app/utils/LogUtils.kt deleted file mode 100644 index 82b2c8cc4..000000000 --- a/app/src/main/java/io/legado/app/utils/LogUtils.kt +++ /dev/null @@ -1,55 +0,0 @@ -package io.legado.app.utils - -import android.annotation.SuppressLint -import io.legado.app.App -import io.legado.app.help.FileHelp -import java.io.File -import java.text.SimpleDateFormat -import java.util.* -import java.util.logging.* -import java.util.logging.Formatter - - -object LogUtils { - const val TIME_PATTERN = "yyyy-MM-dd HH:mm:ss" - - val MyLogger: Logger by lazy { - Logger.getGlobal().apply { - addHandler(fileHandler) - } - } - - private val fileHandler by lazy { - FileHandler(FileHelp.getCachePath() + File.separator + "app.log", 1024, 2).apply { - formatter = object : Formatter() { - override fun format(record: LogRecord): String { - // 设置文件输出格式 - return (getCurrentDateStr(TIME_PATTERN) + ": " + record.message + "\n") - } - } - level = if (App.INSTANCE.getPrefBoolean("recordLog")) { - Level.INFO - } else { - Level.OFF - } - } - } - - fun upLevel() { - fileHandler.level = if (App.INSTANCE.getPrefBoolean("recordLog")) { - Level.INFO - } else { - Level.OFF - } - } - - /** - * 获取当前时间 - */ - @SuppressLint("SimpleDateFormat") - fun getCurrentDateStr(pattern: String): String { - val date = Date() - val sdf = SimpleDateFormat(pattern) - return sdf.format(date) - } -} \ No newline at end of file From 1ce32423a90367c3a9f50f2f4dda1f2545264762 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 29 Sep 2019 18:45:43 +0800 Subject: [PATCH 1688/1997] up --- app/build.gradle | 3 - app/src/main/java/io/legado/app/App.kt | 10 --- .../app/receiver/MediaButtonReceiver.kt | 2 +- .../io/legado/app/ui/config/ConfigFragment.kt | 5 +- .../io/legado/app/ui/main/my/MyFragment.kt | 5 +- .../main/java/io/legado/app/utils/LogUtils.kt | 63 +++++++++++++++++++ 6 files changed, 68 insertions(+), 20 deletions(-) create mode 100644 app/src/main/java/io/legado/app/utils/LogUtils.kt diff --git a/app/build.gradle b/app/build.gradle index 97a5a9dc0..22922cbbe 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -148,7 +148,4 @@ dependencies { //颜色选择 implementation 'com.jaredrummler:colorpicker:1.1.0' - //日志记录 - implementation 'com.apkfuns.logutils:library:1.7.5' - implementation 'com.apkfuns.log2file:log2file:1.3.1' } diff --git a/app/src/main/java/io/legado/app/App.kt b/app/src/main/java/io/legado/app/App.kt index ea8a30f66..54238a6ad 100644 --- a/app/src/main/java/io/legado/app/App.kt +++ b/app/src/main/java/io/legado/app/App.kt @@ -9,8 +9,6 @@ import android.os.Build import android.os.Bundle import androidx.annotation.RequiresApi import androidx.appcompat.app.AppCompatDelegate -import com.apkfuns.log2file.LogFileEngineFactory -import com.apkfuns.logutils.LogUtils import com.jeremyliao.liveeventbus.LiveEventBus import io.legado.app.constant.AppConst.channelIdDownload import io.legado.app.constant.AppConst.channelIdReadAloud @@ -18,15 +16,12 @@ import io.legado.app.constant.AppConst.channelIdWeb import io.legado.app.data.AppDatabase import io.legado.app.help.ActivityHelp import io.legado.app.help.CrashHandler -import io.legado.app.help.FileHelp import io.legado.app.help.ReadBookConfig import io.legado.app.lib.theme.ThemeStore import io.legado.app.ui.widget.page.ChapterProvider import io.legado.app.utils.getCompatColor -import io.legado.app.utils.getPrefBoolean import io.legado.app.utils.getPrefInt import io.legado.app.utils.isNightTheme -import java.io.File @Suppress("DEPRECATION") class App : Application() { @@ -48,11 +43,6 @@ class App : Application() { super.onCreate() INSTANCE = this CrashHandler().init(this) - LogUtils.getLog2FileConfig() - .configLog2FileEnable(getPrefBoolean("recordLog")) - .configLog2FilePath(FileHelp.getCachePath() + File.separator + "logs" + File.separator) - .configLog2FileNameFormat("%d{yyyyMMdd}.log") - .configLogFileEngine(LogFileEngineFactory(this)) db = AppDatabase.createDatabase(INSTANCE) packageManager.getPackageInfo(packageName, 0)?.let { versionCode = it.versionCode diff --git a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt index 45565c31c..ce3908021 100644 --- a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt +++ b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt @@ -4,10 +4,10 @@ import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.view.KeyEvent -import com.apkfuns.logutils.LogUtils import io.legado.app.constant.Bus import io.legado.app.help.ActivityHelp import io.legado.app.ui.book.read.ReadBookActivity +import io.legado.app.utils.LogUtils import io.legado.app.utils.postEvent diff --git a/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt index c111b9401..fd957e433 100644 --- a/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt @@ -6,12 +6,11 @@ import android.view.View import androidx.preference.ListPreference import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat -import com.apkfuns.logutils.LogUtils import io.legado.app.App import io.legado.app.R import io.legado.app.help.BookHelp import io.legado.app.lib.theme.ATH -import io.legado.app.utils.getPrefBoolean +import io.legado.app.utils.LogUtils import io.legado.app.utils.getPrefString @@ -41,7 +40,7 @@ class ConfigFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChange override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { when (key) { "downloadPath" -> BookHelp.upDownloadPath() - "recordLog" -> LogUtils.getLog2FileConfig().configLog2FileEnable(getPrefBoolean("recordLog")) + "recordLog" -> LogUtils.upLevel() } } diff --git a/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt b/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt index 350737281..af839204e 100644 --- a/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt @@ -7,7 +7,6 @@ import android.view.MenuItem import android.view.View import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat -import com.apkfuns.logutils.LogUtils import io.legado.app.App import io.legado.app.R import io.legado.app.base.BaseFragment @@ -23,7 +22,7 @@ import io.legado.app.ui.book.source.manage.BookSourceActivity import io.legado.app.ui.config.ConfigActivity import io.legado.app.ui.config.ConfigViewModel import io.legado.app.ui.replacerule.ReplaceRuleActivity -import io.legado.app.utils.getPrefBoolean +import io.legado.app.utils.LogUtils import io.legado.app.utils.startActivity import kotlinx.android.synthetic.main.view_title_bar.* import org.jetbrains.anko.startActivity @@ -86,7 +85,7 @@ class MyFragment : BaseFragment(R.layout.fragment_my_config) { ) { when (key) { "isNightTheme" -> App.INSTANCE.applyDayNight() - "recordLog" -> LogUtils.getLog2FileConfig().configLog2FileEnable(getPrefBoolean("recordLog")) + "recordLog" -> LogUtils.upLevel() "downloadPath" -> BookHelp.upDownloadPath() } } diff --git a/app/src/main/java/io/legado/app/utils/LogUtils.kt b/app/src/main/java/io/legado/app/utils/LogUtils.kt new file mode 100644 index 000000000..27c3015fe --- /dev/null +++ b/app/src/main/java/io/legado/app/utils/LogUtils.kt @@ -0,0 +1,63 @@ +package io.legado.app.utils + +import android.annotation.SuppressLint +import io.legado.app.App +import io.legado.app.help.FileHelp +import java.io.File +import java.text.SimpleDateFormat +import java.util.* +import java.util.logging.* +import java.util.logging.Formatter + + +object LogUtils { + const val TIME_PATTERN = "yyyy-MM-dd HH:mm:ss" + + fun d(tag: String, msg: String) { + logger.log(Level.INFO, "$tag $msg") + } + + fun e(tag: String, msg: String) { + logger.log(Level.WARNING, "$tag $msg") + } + + private val logger: Logger by lazy { + Logger.getGlobal().apply { + addHandler(fileHandler) + } + } + + private val fileHandler by lazy { + FileHandler(FileHelp.getCachePath() + File.separator + "app.log", 1024, 2).apply { + formatter = object : Formatter() { + override fun format(record: LogRecord): String { + // 设置文件输出格式 + return (getCurrentDateStr(TIME_PATTERN) + ": " + record.message + "\n") + } + } + level = if (App.INSTANCE.getPrefBoolean("recordLog")) { + Level.INFO + } else { + Level.OFF + } + } + } + + fun upLevel() { + fileHandler.level = if (App.INSTANCE.getPrefBoolean("recordLog")) { + Level.INFO + } else { + Level.OFF + } + } + + /** + * 获取当前时间 + */ + @SuppressLint("SimpleDateFormat") + fun getCurrentDateStr(pattern: String): String { + val date = Date() + val sdf = SimpleDateFormat(pattern) + return sdf.format(date) + } +} \ No newline at end of file From f6685e5dd29b396c1d269337fe6543fa358918da Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 29 Sep 2019 18:49:58 +0800 Subject: [PATCH 1689/1997] up --- app/src/main/java/io/legado/app/utils/LogUtils.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/utils/LogUtils.kt b/app/src/main/java/io/legado/app/utils/LogUtils.kt index 27c3015fe..1ae855b6b 100644 --- a/app/src/main/java/io/legado/app/utils/LogUtils.kt +++ b/app/src/main/java/io/legado/app/utils/LogUtils.kt @@ -28,7 +28,11 @@ object LogUtils { } private val fileHandler by lazy { - FileHandler(FileHelp.getCachePath() + File.separator + "app.log", 1024, 2).apply { + FileHandler( + FileHelp.getCachePath() + File.separator + "logs" + File.separator + "app.log", + 2048, + 10 + ).apply { formatter = object : Formatter() { override fun format(record: LogRecord): String { // 设置文件输出格式 From fe8c4e02e55a35422b4bd5e63eefba26adc4b9a6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 29 Sep 2019 19:33:19 +0800 Subject: [PATCH 1690/1997] up --- app/src/main/java/io/legado/app/utils/LogUtils.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/io/legado/app/utils/LogUtils.kt b/app/src/main/java/io/legado/app/utils/LogUtils.kt index 1ae855b6b..f8b8b6bb6 100644 --- a/app/src/main/java/io/legado/app/utils/LogUtils.kt +++ b/app/src/main/java/io/legado/app/utils/LogUtils.kt @@ -13,10 +13,12 @@ import java.util.logging.Formatter object LogUtils { const val TIME_PATTERN = "yyyy-MM-dd HH:mm:ss" + @JvmStatic fun d(tag: String, msg: String) { logger.log(Level.INFO, "$tag $msg") } + @JvmStatic fun e(tag: String, msg: String) { logger.log(Level.WARNING, "$tag $msg") } From 4227b8ccc78e2ff77cf650ef33eeffe58bc66ba6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 29 Sep 2019 19:46:00 +0800 Subject: [PATCH 1691/1997] up --- .../main/java/io/legado/app/utils/ACache.kt | 196 +++++++++--------- 1 file changed, 103 insertions(+), 93 deletions(-) diff --git a/app/src/main/java/io/legado/app/utils/ACache.kt b/app/src/main/java/io/legado/app/utils/ACache.kt index 5ac75f875..7549813e8 100644 --- a/app/src/main/java/io/legado/app/utils/ACache.kt +++ b/app/src/main/java/io/legado/app/utils/ACache.kt @@ -23,7 +23,49 @@ import kotlin.math.min * 本地缓存 */ class ACache private constructor(cacheDir: File, max_size: Long, max_count: Int) { - private lateinit var mCache: ACacheManager + + + companion object { + const val TIME_HOUR = 60 * 60 + const val TIME_DAY = TIME_HOUR * 24 + private const val MAX_SIZE = 1000 * 1000 * 50 // 50 mb + private const val MAX_COUNT = Integer.MAX_VALUE // 不限制存放数据的数量 + private val mInstanceMap = HashMap() + + @JvmOverloads + fun get( + ctx: Context, + cacheName: String = "ACache", + maxSize: Long = MAX_SIZE.toLong(), + maxCount: Int = MAX_COUNT, + cacheDir: Boolean = true + ): ACache { + val f = if (cacheDir) File(ctx.cacheDir, cacheName) else File(ctx.filesDir, cacheName) + return get(f, maxSize, maxCount) + } + + @JvmOverloads + fun get( + cacheDir: File, + maxSize: Long = MAX_SIZE.toLong(), + maxCount: Int = MAX_COUNT + ): ACache { + synchronized(this) { + var manager = mInstanceMap[cacheDir.absoluteFile.toString() + myPid()] + if (manager == null) { + manager = ACache(cacheDir, maxSize, maxCount) + mInstanceMap[cacheDir.absolutePath + myPid()] = manager + } + return manager + } + } + + private fun myPid(): String { + return "_" + android.os.Process.myPid() + } + } + + private var mCache: ACacheManager? = null init { try { @@ -48,12 +90,14 @@ class ACache private constructor(cacheDir: File, max_size: Long, max_count: Int) * @param value 保存的String数据 */ fun put(key: String, value: String) { - try { - val file = mCache.newFile(key) - file.writeText(value) - mCache.put(file) - } catch (e: Exception) { - e.printStackTrace() + mCache?.let { mCache -> + try { + val file = mCache.newFile(key) + file.writeText(value) + mCache.put(file) + } catch (e: Exception) { + e.printStackTrace() + } } } @@ -74,24 +118,26 @@ class ACache private constructor(cacheDir: File, max_size: Long, max_count: Int) * @return String 数据 */ fun getAsString(key: String): String? { - val file = mCache[key] - if (!file.exists()) - return null - var removeFile = false - return try { - val text = file.readText() - if (!Utils.isDue(text)) { - Utils.clearDateInfo(text) - } else { - removeFile = true - null + mCache?.let { mCache -> + val file = mCache[key] + if (!file.exists()) + return null + var removeFile = false + try { + val text = file.readText() + if (!Utils.isDue(text)) { + return Utils.clearDateInfo(text) + } else { + removeFile = true + } + } catch (e: IOException) { + e.printStackTrace() + } finally { + if (removeFile) + remove(key) } - } catch (e: IOException) { - null - } finally { - if (removeFile) - remove(key) } + return null } // ======================================= @@ -184,9 +230,11 @@ class ACache private constructor(cacheDir: File, max_size: Long, max_count: Int) * @param value 保存的数据 */ fun put(key: String, value: ByteArray) { - val file = mCache.newFile(key) - file.writeBytes(value) - mCache.put(file) + mCache?.let { mCache -> + val file = mCache.newFile(key) + file.writeBytes(value) + mCache.put(file) + } } /** @@ -206,26 +254,28 @@ class ACache private constructor(cacheDir: File, max_size: Long, max_count: Int) * @return byte 数据 */ fun getAsBinary(key: String): ByteArray? { - var removeFile = false - try { - val file = mCache[key] - if (!file.exists()) - return null + mCache?.let { mCache -> + var removeFile = false + try { + val file = mCache[key] + if (!file.exists()) + return null - val byteArray = file.readBytes() - return if (!Utils.isDue(byteArray)) { - Utils.clearDateInfo(byteArray) - } else { - removeFile = true - null + val byteArray = file.readBytes() + return if (!Utils.isDue(byteArray)) { + Utils.clearDateInfo(byteArray) + } else { + removeFile = true + null + } + } catch (e: Exception) { + e.printStackTrace() + } finally { + if (removeFile) + remove(key) } - } catch (e: Exception) { - e.printStackTrace() - return null - } finally { - if (removeFile) - remove(key) } + return null } /** @@ -269,7 +319,6 @@ class ACache private constructor(cacheDir: File, max_size: Long, max_count: Int) return ois.readObject() } catch (e: Exception) { e.printStackTrace() - return null } finally { try { bais?.close() @@ -371,15 +420,16 @@ class ACache private constructor(cacheDir: File, max_size: Long, max_count: Int) * @return value 缓存的文件 */ fun file(key: String): File? { - try { - val f = mCache.newFile(key) - if (f.exists()) { - return f + mCache?.let { mCache -> + try { + val f = mCache.newFile(key) + if (f.exists()) { + return f + } + } catch (e: Exception) { + e.printStackTrace() } - } catch (e: Exception) { - e.printStackTrace() } - return null } @@ -389,14 +439,14 @@ class ACache private constructor(cacheDir: File, max_size: Long, max_count: Int) * @return 是否移除成功 */ fun remove(key: String): Boolean { - return mCache.remove(key) + return mCache?.remove(key) == true } /** * 清除所有数据 */ fun clear() { - mCache.clear() + mCache?.clear() } /** @@ -726,44 +776,4 @@ class ACache private constructor(cacheDir: File, max_size: Long, max_count: Int) } } - companion object { - const val TIME_HOUR = 60 * 60 - const val TIME_DAY = TIME_HOUR * 24 - private const val MAX_SIZE = 1000 * 1000 * 50 // 50 mb - private const val MAX_COUNT = Integer.MAX_VALUE // 不限制存放数据的数量 - private val mInstanceMap = HashMap() - - @JvmOverloads - fun get( - ctx: Context, - cacheName: String = "ACache", - maxSize: Long = MAX_SIZE.toLong(), - maxCount: Int = MAX_COUNT, - cacheDir: Boolean = true - ): ACache { - val f = if (cacheDir) File(ctx.cacheDir, cacheName) else File(ctx.filesDir, cacheName) - return get(f, maxSize, maxCount) - } - - @JvmOverloads - fun get( - cacheDir: File, - maxSize: Long = MAX_SIZE.toLong(), - maxCount: Int = MAX_COUNT - ): ACache { - synchronized(this) { - var manager = mInstanceMap[cacheDir.absoluteFile.toString() + myPid()] - if (manager == null) { - manager = ACache(cacheDir, maxSize, maxCount) - mInstanceMap[cacheDir.absolutePath + myPid()] = manager - } - return manager - } - } - - private fun myPid(): String { - return "_" + android.os.Process.myPid() - } - } - } \ No newline at end of file From 0f1c604ba33bd6a743a77bffa51d95f0e900cf2f Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 29 Sep 2019 20:02:02 +0800 Subject: [PATCH 1692/1997] up --- .../app/ui/book/search/SearchActivity.kt | 5 ++-- ...ty_search.xml => activity_book_search.xml} | 29 +++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) rename app/src/main/res/layout/{activity_search.xml => activity_book_search.xml} (68%) diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt index 64d5d76f8..5e01ac820 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt @@ -17,12 +17,13 @@ import io.legado.app.ui.book.info.BookInfoActivity import io.legado.app.utils.getViewModel import io.legado.app.utils.invisible import io.legado.app.utils.visible -import kotlinx.android.synthetic.main.activity_search.* +import kotlinx.android.synthetic.main.activity_book_search.* import kotlinx.android.synthetic.main.view_search.* import org.jetbrains.anko.sdk27.listeners.onClick import org.jetbrains.anko.startActivity -class SearchActivity : VMBaseActivity(R.layout.activity_search), SearchAdapter.CallBack { +class SearchActivity : VMBaseActivity(R.layout.activity_book_search), + SearchAdapter.CallBack { override val viewModel: SearchViewModel get() = getViewModel(SearchViewModel::class.java) diff --git a/app/src/main/res/layout/activity_search.xml b/app/src/main/res/layout/activity_book_search.xml similarity index 68% rename from app/src/main/res/layout/activity_search.xml rename to app/src/main/res/layout/activity_book_search.xml index 3fd29e772..e4588e73c 100644 --- a/app/src/main/res/layout/activity_search.xml +++ b/app/src/main/res/layout/activity_book_search.xml @@ -36,6 +36,35 @@ + + + + + + + + + + + + Date: Sun, 29 Sep 2019 20:09:07 +0800 Subject: [PATCH 1693/1997] up --- app/src/main/res/layout/activity_book_search.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/layout/activity_book_search.xml b/app/src/main/res/layout/activity_book_search.xml index e4588e73c..15e895b18 100644 --- a/app/src/main/res/layout/activity_book_search.xml +++ b/app/src/main/res/layout/activity_book_search.xml @@ -41,6 +41,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" + android:visibility="gone" app:layout_constraintTop_toBottomOf="@id/title_bar"> From abc9c2f196314e62641e2fd5eefd0be217406922 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 29 Sep 2019 20:28:30 +0800 Subject: [PATCH 1694/1997] up --- .../legado/app/ui/book/search/BookAdapter.kt | 15 +++++++++++++ .../app/ui/book/search/HistoryKeyAdapter.kt | 16 ++++++++++++++ .../app/ui/book/search/SearchActivity.kt | 21 ++++++++++++++++++- .../main/res/layout/activity_book_search.xml | 4 ++-- 4 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/book/search/BookAdapter.kt create mode 100644 app/src/main/java/io/legado/app/ui/book/search/HistoryKeyAdapter.kt diff --git a/app/src/main/java/io/legado/app/ui/book/search/BookAdapter.kt b/app/src/main/java/io/legado/app/ui/book/search/BookAdapter.kt new file mode 100644 index 000000000..7b018db40 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/book/search/BookAdapter.kt @@ -0,0 +1,15 @@ +package io.legado.app.ui.book.search + +import android.content.Context +import io.legado.app.R +import io.legado.app.base.adapter.ItemViewHolder +import io.legado.app.base.adapter.SimpleRecyclerAdapter + +class BookAdapter(context: Context) : + SimpleRecyclerAdapter(context, R.layout.item_text) { + + override fun convert(holder: ItemViewHolder, item: String, payloads: MutableList) { + + } + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/book/search/HistoryKeyAdapter.kt b/app/src/main/java/io/legado/app/ui/book/search/HistoryKeyAdapter.kt new file mode 100644 index 000000000..7ceb93993 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/book/search/HistoryKeyAdapter.kt @@ -0,0 +1,16 @@ +package io.legado.app.ui.book.search + +import android.content.Context +import io.legado.app.R +import io.legado.app.base.adapter.ItemViewHolder +import io.legado.app.base.adapter.SimpleRecyclerAdapter + + +class HistoryKeyAdapter(context: Context) : + SimpleRecyclerAdapter(context, R.layout.item_text) { + + override fun convert(holder: ItemViewHolder, item: String, payloads: MutableList) { + + } + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt index 5e01ac820..5d3299611 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt @@ -7,6 +7,7 @@ import androidx.lifecycle.Observer import androidx.paging.LivePagedListBuilder import androidx.paging.PagedList import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView import io.legado.app.App import io.legado.app.R import io.legado.app.base.VMBaseActivity @@ -29,6 +30,8 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se get() = getViewModel(SearchViewModel::class.java) private lateinit var adapter: SearchAdapter + private lateinit var bookAdapter: BookAdapter + private lateinit var historyKeyAdapter: HistoryKeyAdapter private var searchBookData: LiveData>? = null override fun onActivityCreated(savedInstanceState: Bundle?) { @@ -67,14 +70,30 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se return false } }) - fb_stop.onClick { viewModel.stop() } + search_view.setOnQueryTextFocusChangeListener { v, hasFocus -> + if (hasFocus) { + ll_history.visible() + } else { + ll_history.invisible() + } + } } private fun initRecyclerView() { ATH.applyEdgeEffectColor(recycler_view) + ATH.applyEdgeEffectColor(rv_bookshelf_search) + ATH.applyEdgeEffectColor(rv_history_key) + bookAdapter = BookAdapter(this) + rv_bookshelf_search.layoutManager = + LinearLayoutManager(this, RecyclerView.HORIZONTAL, false) + rv_bookshelf_search.adapter = bookAdapter + historyKeyAdapter = HistoryKeyAdapter(this) + rv_history_key.layoutManager = LinearLayoutManager(this, RecyclerView.HORIZONTAL, false) + rv_history_key.adapter = historyKeyAdapter adapter = SearchAdapter(this) recycler_view.layoutManager = LinearLayoutManager(this) recycler_view.adapter = adapter + fb_stop.onClick { viewModel.stop() } } private fun initData() { diff --git a/app/src/main/res/layout/activity_book_search.xml b/app/src/main/res/layout/activity_book_search.xml index 15e895b18..f231b65cb 100644 --- a/app/src/main/res/layout/activity_book_search.xml +++ b/app/src/main/res/layout/activity_book_search.xml @@ -50,7 +50,7 @@ android:text="@string/bookshelf" /> @@ -61,7 +61,7 @@ android:text="@string/searchHistory" /> From 5c41348cb58c725f6d72d7df142e9567418ff6de Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 29 Sep 2019 22:03:08 +0800 Subject: [PATCH 1695/1997] up --- .../java/io/legado/app/data/dao/BookDao.kt | 3 ++ .../legado/app/data/dao/SearchKeywordDao.kt | 12 ++++---- .../legado/app/ui/book/search/BookAdapter.kt | 10 +++++-- .../app/ui/book/search/HistoryKeyAdapter.kt | 10 +++++-- .../app/ui/book/search/SearchActivity.kt | 29 ++++++++++++++++++- .../main/res/layout/activity_book_search.xml | 3 ++ 6 files changed, 54 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/BookDao.kt b/app/src/main/java/io/legado/app/data/dao/BookDao.kt index bae53c8f2..a174e0829 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookDao.kt @@ -24,6 +24,9 @@ interface BookDao { @Query("SELECT bookUrl FROM books WHERE `group` = :group") fun observeUrlsByGroup(group: Int): LiveData> + @Query("SELECT bookUrl FROM books WHERE name like '%' | :key | '%' or author like '%' | :key | '%'") + fun liveDataSearch(key: String): LiveData> + @Query("SELECT * FROM books WHERE `name` in (:names)") fun findByName(vararg names: String): List diff --git a/app/src/main/java/io/legado/app/data/dao/SearchKeywordDao.kt b/app/src/main/java/io/legado/app/data/dao/SearchKeywordDao.kt index b2370ceb6..fcd7130ef 100644 --- a/app/src/main/java/io/legado/app/data/dao/SearchKeywordDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/SearchKeywordDao.kt @@ -1,6 +1,6 @@ package io.legado.app.data.dao -import androidx.paging.DataSource +import androidx.lifecycle.LiveData import androidx.room.* import io.legado.app.data.entities.SearchKeyword @@ -9,16 +9,16 @@ import io.legado.app.data.entities.SearchKeyword interface SearchKeywordDao { @Query("SELECT * FROM search_keywords ORDER BY usage DESC") - fun observeByUsage(): DataSource.Factory + fun liveDataByUsage(): LiveData> @Query("SELECT * FROM search_keywords ORDER BY lastUseTime DESC") - fun observeByTime(): DataSource.Factory + fun liveDataByTime(): LiveData> - @Insert(onConflict = OnConflictStrategy.REPLACE) - fun insert(vararg keywords: SearchKeyword) + @Query("SELECT * FROM search_keywords where word like '%' | :key | '%' ORDER BY usage DESC") + fun liveDataSearch(key: String): LiveData> @Insert(onConflict = OnConflictStrategy.REPLACE) - fun insert(keyword: SearchKeyword): Long + fun insert(vararg keywords: SearchKeyword) @Update fun update(vararg keywords: SearchKeyword) diff --git a/app/src/main/java/io/legado/app/ui/book/search/BookAdapter.kt b/app/src/main/java/io/legado/app/ui/book/search/BookAdapter.kt index 7b018db40..9c8f2735c 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/BookAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/BookAdapter.kt @@ -4,12 +4,16 @@ import android.content.Context import io.legado.app.R import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter +import io.legado.app.data.entities.Book +import kotlinx.android.synthetic.main.item_text.view.* class BookAdapter(context: Context) : - SimpleRecyclerAdapter(context, R.layout.item_text) { - - override fun convert(holder: ItemViewHolder, item: String, payloads: MutableList) { + SimpleRecyclerAdapter(context, R.layout.item_text) { + override fun convert(holder: ItemViewHolder, item: Book, payloads: MutableList) { + with(holder.itemView) { + text_view.text = item.name + } } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/book/search/HistoryKeyAdapter.kt b/app/src/main/java/io/legado/app/ui/book/search/HistoryKeyAdapter.kt index 7ceb93993..752c1f705 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/HistoryKeyAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/HistoryKeyAdapter.kt @@ -4,13 +4,17 @@ import android.content.Context import io.legado.app.R import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter +import io.legado.app.data.entities.SearchKeyword +import kotlinx.android.synthetic.main.item_text.view.* class HistoryKeyAdapter(context: Context) : - SimpleRecyclerAdapter(context, R.layout.item_text) { - - override fun convert(holder: ItemViewHolder, item: String, payloads: MutableList) { + SimpleRecyclerAdapter(context, R.layout.item_text) { + override fun convert(holder: ItemViewHolder, item: SearchKeyword, payloads: MutableList) { + with(holder.itemView) { + text_view.text = item.word + } } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt index 5d3299611..eae5a9ec2 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt @@ -11,11 +11,14 @@ import androidx.recyclerview.widget.RecyclerView import io.legado.app.App import io.legado.app.R import io.legado.app.base.VMBaseActivity +import io.legado.app.data.entities.Book +import io.legado.app.data.entities.SearchKeyword import io.legado.app.data.entities.SearchShow import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.primaryTextColor import io.legado.app.ui.book.info.BookInfoActivity import io.legado.app.utils.getViewModel +import io.legado.app.utils.gone import io.legado.app.utils.invisible import io.legado.app.utils.visible import kotlinx.android.synthetic.main.activity_book_search.* @@ -33,6 +36,8 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se private lateinit var bookAdapter: BookAdapter private lateinit var historyKeyAdapter: HistoryKeyAdapter private var searchBookData: LiveData>? = null + private var historyData: LiveData>? = null + private var bookData: LiveData>? = null override fun onActivityCreated(savedInstanceState: Bundle?) { initRecyclerView() @@ -67,10 +72,11 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se override fun onQueryTextChange(newText: String?): Boolean { if (newText.isNullOrBlank()) viewModel.stop() + upHistory(newText) return false } }) - search_view.setOnQueryTextFocusChangeListener { v, hasFocus -> + search_view.setOnQueryTextFocusChangeListener { _, hasFocus -> if (hasFocus) { ll_history.visible() } else { @@ -107,6 +113,27 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se searchBookData?.observe(this, Observer { adapter.submitList(it) }) } + private fun upHistory(key: String?) { + bookData?.removeObservers(this) + if (key.isNullOrBlank()) { + tv_book_show.gone() + rv_bookshelf_search.gone() + } else { + tv_book_show.visible() + rv_bookshelf_search.visible() + bookData = App.db.bookDao().liveDataSearch(key) + bookData?.observe(this, Observer { bookAdapter.setItems(it) }) + } + historyData?.removeObservers(this) + historyData = + if (key.isNullOrBlank()) { + App.db.searchKeywordDao().liveDataByUsage() + } else { + App.db.searchKeywordDao().liveDataSearch(key) + } + historyData?.observe(this, Observer { historyKeyAdapter.setItems(it) }) + } + override fun showBookInfo(name: String, author: String) { viewModel.getSearchBook(name, author) { searchBook -> searchBook?.let { diff --git a/app/src/main/res/layout/activity_book_search.xml b/app/src/main/res/layout/activity_book_search.xml index f231b65cb..246341e4c 100644 --- a/app/src/main/res/layout/activity_book_search.xml +++ b/app/src/main/res/layout/activity_book_search.xml @@ -45,8 +45,10 @@ app:layout_constraintTop_toBottomOf="@id/title_bar"> Date: Sun, 29 Sep 2019 22:06:48 +0800 Subject: [PATCH 1696/1997] up --- app/src/main/java/io/legado/app/data/dao/BookDao.kt | 2 +- app/src/main/java/io/legado/app/data/dao/SearchKeywordDao.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/BookDao.kt b/app/src/main/java/io/legado/app/data/dao/BookDao.kt index a174e0829..ccbf8e3c9 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookDao.kt @@ -24,7 +24,7 @@ interface BookDao { @Query("SELECT bookUrl FROM books WHERE `group` = :group") fun observeUrlsByGroup(group: Int): LiveData> - @Query("SELECT bookUrl FROM books WHERE name like '%' | :key | '%' or author like '%' | :key | '%'") + @Query("SELECT bookUrl FROM books WHERE name like '%' || :key || '%' or author like '%' || :key || '%'") fun liveDataSearch(key: String): LiveData> @Query("SELECT * FROM books WHERE `name` in (:names)") diff --git a/app/src/main/java/io/legado/app/data/dao/SearchKeywordDao.kt b/app/src/main/java/io/legado/app/data/dao/SearchKeywordDao.kt index fcd7130ef..81badc15e 100644 --- a/app/src/main/java/io/legado/app/data/dao/SearchKeywordDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/SearchKeywordDao.kt @@ -14,7 +14,7 @@ interface SearchKeywordDao { @Query("SELECT * FROM search_keywords ORDER BY lastUseTime DESC") fun liveDataByTime(): LiveData> - @Query("SELECT * FROM search_keywords where word like '%' | :key | '%' ORDER BY usage DESC") + @Query("SELECT * FROM search_keywords where word like '%' || :key || '%' ORDER BY usage DESC") fun liveDataSearch(key: String): LiveData> @Insert(onConflict = OnConflictStrategy.REPLACE) From 39c8a1d06bc8eb31a2285b67b7af4f4750cf5aa4 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 29 Sep 2019 22:12:22 +0800 Subject: [PATCH 1697/1997] up --- app/src/main/java/io/legado/app/data/dao/BookDao.kt | 2 +- .../main/java/io/legado/app/data/dao/SearchKeywordDao.kt | 2 +- app/src/main/res/layout/activity_book_search.xml | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/BookDao.kt b/app/src/main/java/io/legado/app/data/dao/BookDao.kt index ccbf8e3c9..c74172c37 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookDao.kt @@ -24,7 +24,7 @@ interface BookDao { @Query("SELECT bookUrl FROM books WHERE `group` = :group") fun observeUrlsByGroup(group: Int): LiveData> - @Query("SELECT bookUrl FROM books WHERE name like '%' || :key || '%' or author like '%' || :key || '%'") + @Query("SELECT * FROM books WHERE name like '%'||:key||'%' or author like '%'||:key||'%'") fun liveDataSearch(key: String): LiveData> @Query("SELECT * FROM books WHERE `name` in (:names)") diff --git a/app/src/main/java/io/legado/app/data/dao/SearchKeywordDao.kt b/app/src/main/java/io/legado/app/data/dao/SearchKeywordDao.kt index 81badc15e..704f37287 100644 --- a/app/src/main/java/io/legado/app/data/dao/SearchKeywordDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/SearchKeywordDao.kt @@ -14,7 +14,7 @@ interface SearchKeywordDao { @Query("SELECT * FROM search_keywords ORDER BY lastUseTime DESC") fun liveDataByTime(): LiveData> - @Query("SELECT * FROM search_keywords where word like '%' || :key || '%' ORDER BY usage DESC") + @Query("SELECT * FROM search_keywords where word like '%'||:key||'%' ORDER BY usage DESC") fun liveDataSearch(key: String): LiveData> @Insert(onConflict = OnConflictStrategy.REPLACE) diff --git a/app/src/main/res/layout/activity_book_search.xml b/app/src/main/res/layout/activity_book_search.xml index 246341e4c..8064c107d 100644 --- a/app/src/main/res/layout/activity_book_search.xml +++ b/app/src/main/res/layout/activity_book_search.xml @@ -49,12 +49,14 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="6dp" - android:text="@string/bookshelf" /> + android:text="@string/bookshelf" + android:visibility="gone" /> + android:layout_height="wrap_content" + android:visibility="gone" /> Date: Sun, 29 Sep 2019 22:20:21 +0800 Subject: [PATCH 1698/1997] up --- .../java/io/legado/app/data/dao/SearchKeywordDao.kt | 3 +++ .../java/io/legado/app/data/entities/SearchKeyword.kt | 2 +- .../io/legado/app/ui/book/search/SearchActivity.kt | 1 + .../io/legado/app/ui/book/search/SearchViewModel.kt | 10 ++++++++++ 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/data/dao/SearchKeywordDao.kt b/app/src/main/java/io/legado/app/data/dao/SearchKeywordDao.kt index 704f37287..be7ad75c5 100644 --- a/app/src/main/java/io/legado/app/data/dao/SearchKeywordDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/SearchKeywordDao.kt @@ -17,6 +17,9 @@ interface SearchKeywordDao { @Query("SELECT * FROM search_keywords where word like '%'||:key||'%' ORDER BY usage DESC") fun liveDataSearch(key: String): LiveData> + @Query("select * from search_keywords where word = :key") + fun get(key: String): SearchKeyword? + @Insert(onConflict = OnConflictStrategy.REPLACE) fun insert(vararg keywords: SearchKeyword) diff --git a/app/src/main/java/io/legado/app/data/entities/SearchKeyword.kt b/app/src/main/java/io/legado/app/data/entities/SearchKeyword.kt index 1c1c5015b..89d1c3baf 100644 --- a/app/src/main/java/io/legado/app/data/entities/SearchKeyword.kt +++ b/app/src/main/java/io/legado/app/data/entities/SearchKeyword.kt @@ -13,5 +13,5 @@ data class SearchKeyword( @PrimaryKey var word: String = "", // 搜索关键词 var usage: Int = 1, // 使用次数 - var lastUseTime: Long = 0 // 最后一次使用时间 + var lastUseTime: Long = System.currentTimeMillis() // 最后一次使用时间 ) : Parcelable diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt index eae5a9ec2..ed51e45df 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt @@ -58,6 +58,7 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se override fun onQueryTextSubmit(query: String?): Boolean { search_view.clearFocus() query?.let { + viewModel.saveSearchKey(query) viewModel.search(it, { refresh_progress_bar.isAutoLoading = true initData() diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt index f8550229f..85b3694db 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt @@ -4,6 +4,7 @@ import android.app.Application import io.legado.app.App import io.legado.app.base.BaseViewModel import io.legado.app.data.entities.SearchBook +import io.legado.app.data.entities.SearchKeyword import io.legado.app.help.coroutine.Coroutine import io.legado.app.model.WebBook import kotlinx.coroutines.Dispatchers @@ -61,4 +62,13 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { success?.invoke(searchBook) } } + + fun saveSearchKey(key: String) { + execute { + App.db.searchKeywordDao().get(key)?.let { + it.usage = it.usage + 1 + App.db.searchKeywordDao().update(it) + } ?: App.db.searchKeywordDao().insert(SearchKeyword(key, 1)) + } + } } From 1743dfc1f92d63d989c42bbeac46e0567f3ff946 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 30 Sep 2019 08:16:10 +0800 Subject: [PATCH 1699/1997] up --- app/src/main/java/io/legado/app/ui/about/DonateActivity.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/about/DonateActivity.kt b/app/src/main/java/io/legado/app/ui/about/DonateActivity.kt index 313a6bec6..6d0671029 100644 --- a/app/src/main/java/io/legado/app/ui/about/DonateActivity.kt +++ b/app/src/main/java/io/legado/app/ui/about/DonateActivity.kt @@ -8,11 +8,10 @@ import android.content.Intent import android.net.Uri import android.os.Bundle import android.widget.Toast -import androidx.lifecycle.AndroidViewModel import io.legado.app.R import io.legado.app.base.BaseActivity import io.legado.app.lib.theme.ATH -import io.legado.app.utils.getViewModel +import io.legado.app.utils.ACache import kotlinx.android.synthetic.main.activity_donate.* import kotlinx.android.synthetic.main.view_title_bar.* import org.jetbrains.anko.toast @@ -60,7 +59,7 @@ class DonateActivity : BaseActivity(R.layout.activity_donate) { } catch (e: Exception) { e.printStackTrace() } finally { - + ACache.get(this, cacheDir = false).put("proTime", System.currentTimeMillis()) } } From 02b27a5c5a64eaf6c6276aa228d369b5bc1cefbf Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 30 Sep 2019 09:11:11 +0800 Subject: [PATCH 1700/1997] up --- .../main/java/io/legado/app/ui/book/read/ReadBookActivity.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt index b8bb11427..eb72a47f4 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt @@ -36,6 +36,7 @@ import io.legado.app.ui.book.source.edit.SourceEditActivity import io.legado.app.ui.changesource.ChangeSourceDialog import io.legado.app.ui.chapterlist.ChapterListActivity import io.legado.app.ui.replacerule.ReplaceRuleActivity +import io.legado.app.ui.replacerule.edit.ReplaceEditDialog import io.legado.app.ui.widget.page.ChapterProvider import io.legado.app.ui.widget.page.PageView import io.legado.app.ui.widget.page.TextChapter @@ -609,7 +610,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea } } observeEvent(Bus.REPLACE) { - toast(it) + ReplaceEditDialog().show(supportFragmentManager, "replaceEditDialog") } } From 9a4ef149a6bedd1c94daa956911346dbfbfb9fd9 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 30 Sep 2019 15:52:46 +0800 Subject: [PATCH 1701/1997] up --- .../main/res/layout/activity_book_search.xml | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/app/src/main/res/layout/activity_book_search.xml b/app/src/main/res/layout/activity_book_search.xml index 8064c107d..4e5789b55 100644 --- a/app/src/main/res/layout/activity_book_search.xml +++ b/app/src/main/res/layout/activity_book_search.xml @@ -39,10 +39,12 @@ + app:layout_constraintTop_toBottomOf="@id/title_bar" + app:layout_constraintBottom_toBottomOf="parent"> - + android:orientation="horizontal"> + + + + + + Date: Mon, 30 Sep 2019 15:55:18 +0800 Subject: [PATCH 1702/1997] up --- .../io/legado/app/ui/book/search/SearchActivity.kt | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt index ed51e45df..6d5ca5563 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt @@ -120,10 +120,17 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se tv_book_show.gone() rv_bookshelf_search.gone() } else { - tv_book_show.visible() - rv_bookshelf_search.visible() bookData = App.db.bookDao().liveDataSearch(key) - bookData?.observe(this, Observer { bookAdapter.setItems(it) }) + bookData?.observe(this, Observer { + if (it.isEmpty()) { + tv_book_show.gone() + rv_bookshelf_search.gone() + } else { + tv_book_show.visible() + rv_bookshelf_search.visible() + } + bookAdapter.setItems(it) + }) } historyData?.removeObservers(this) historyData = From 1c0335b2f1ea2c4779b52488014f5bb855ba9a14 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 30 Sep 2019 17:12:23 +0800 Subject: [PATCH 1703/1997] up --- .../legado/app/ui/book/search/BookAdapter.kt | 7 ++++++- .../app/ui/book/search/HistoryKeyAdapter.kt | 18 +++++++++++++++++- .../app/ui/book/search/SearchActivity.kt | 17 ++++++++++++++--- .../main/res/layout/activity_book_search.xml | 4 +++- 4 files changed, 40 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/search/BookAdapter.kt b/app/src/main/java/io/legado/app/ui/book/search/BookAdapter.kt index 9c8f2735c..3a08418e1 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/BookAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/BookAdapter.kt @@ -6,14 +6,19 @@ import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.data.entities.Book import kotlinx.android.synthetic.main.item_text.view.* +import org.jetbrains.anko.sdk27.listeners.onClick -class BookAdapter(context: Context) : +class BookAdapter(context: Context, val callBack: CallBack) : SimpleRecyclerAdapter(context, R.layout.item_text) { override fun convert(holder: ItemViewHolder, item: Book, payloads: MutableList) { with(holder.itemView) { text_view.text = item.name + onClick { callBack.showBookInfo(item.bookUrl) } } } + interface CallBack { + fun showBookInfo(url: String) + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/book/search/HistoryKeyAdapter.kt b/app/src/main/java/io/legado/app/ui/book/search/HistoryKeyAdapter.kt index 752c1f705..48b60e9b0 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/HistoryKeyAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/HistoryKeyAdapter.kt @@ -5,16 +5,32 @@ import io.legado.app.R import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.data.entities.SearchKeyword +import io.legado.app.ui.widget.anima.explosion_field.ExplosionField import kotlinx.android.synthetic.main.item_text.view.* +import org.jetbrains.anko.sdk27.listeners.onClick +import org.jetbrains.anko.sdk27.listeners.onLongClick -class HistoryKeyAdapter(context: Context) : +class HistoryKeyAdapter(context: Context, val callBack: CallBack) : SimpleRecyclerAdapter(context, R.layout.item_text) { override fun convert(holder: ItemViewHolder, item: SearchKeyword, payloads: MutableList) { with(holder.itemView) { text_view.text = item.word + onClick { + callBack.searchHistory(item.word) + } + onLongClick { + it?.let { + ExplosionField(context).explode(it, true) + } + + true + } } } + interface CallBack { + fun searchHistory(key: String) + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt index 6d5ca5563..bdf2525f0 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt @@ -27,6 +27,8 @@ import org.jetbrains.anko.sdk27.listeners.onClick import org.jetbrains.anko.startActivity class SearchActivity : VMBaseActivity(R.layout.activity_book_search), + BookAdapter.CallBack, + HistoryKeyAdapter.CallBack, SearchAdapter.CallBack { override val viewModel: SearchViewModel @@ -90,11 +92,11 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se ATH.applyEdgeEffectColor(recycler_view) ATH.applyEdgeEffectColor(rv_bookshelf_search) ATH.applyEdgeEffectColor(rv_history_key) - bookAdapter = BookAdapter(this) + bookAdapter = BookAdapter(this, this) rv_bookshelf_search.layoutManager = LinearLayoutManager(this, RecyclerView.HORIZONTAL, false) rv_bookshelf_search.adapter = bookAdapter - historyKeyAdapter = HistoryKeyAdapter(this) + historyKeyAdapter = HistoryKeyAdapter(this, this) rv_history_key.layoutManager = LinearLayoutManager(this, RecyclerView.HORIZONTAL, false) rv_history_key.adapter = historyKeyAdapter adapter = SearchAdapter(this) @@ -112,9 +114,10 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se ), 30 ).build() searchBookData?.observe(this, Observer { adapter.submitList(it) }) + upHistory() } - private fun upHistory(key: String?) { + private fun upHistory(key: String? = null) { bookData?.removeObservers(this) if (key.isNullOrBlank()) { tv_book_show.gone() @@ -149,4 +152,12 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se } } } + + override fun showBookInfo(url: String) { + startActivity(Pair("bookUrl", url)) + } + + override fun searchHistory(key: String) { + search_view.setQuery(key, false) + } } diff --git a/app/src/main/res/layout/activity_book_search.xml b/app/src/main/res/layout/activity_book_search.xml index 4e5789b55..ebb7a3186 100644 --- a/app/src/main/res/layout/activity_book_search.xml +++ b/app/src/main/res/layout/activity_book_search.xml @@ -43,6 +43,8 @@ android:background="@color/background" android:orientation="vertical" android:visibility="gone" + android:clickable="true" + android:focusable="true" app:layout_constraintTop_toBottomOf="@id/title_bar" app:layout_constraintBottom_toBottomOf="parent"> @@ -84,7 +86,7 @@ From 4877bad39720e5c4d5259c807a63f95a032c754f Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 30 Sep 2019 18:13:11 +0800 Subject: [PATCH 1704/1997] up --- .../java/io/legado/app/ui/book/info/BookInfoActivity.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt index 8905a248c..3d170cc6e 100644 --- a/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt @@ -183,7 +183,11 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo } } } - tv_loading.onClick { } + tv_loading.onClick { + viewModel.bookData.value?.let { + viewModel.loadBookInfo(it) + } + } tv_origin.onClick { viewModel.bookData.value?.let { startActivity(Pair("data", it.origin)) From 27d076847099e1503c89a595e1b25d475e75f25b Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 30 Sep 2019 18:19:56 +0800 Subject: [PATCH 1705/1997] up --- .../res/layout-land/activity_book_info.xml | 25 +++++++---------- .../main/res/layout/activity_book_info.xml | 27 +++++++------------ app/src/main/res/values/strings.xml | 1 + 3 files changed, 19 insertions(+), 34 deletions(-) diff --git a/app/src/main/res/layout-land/activity_book_info.xml b/app/src/main/res/layout-land/activity_book_info.xml index efc24a7a4..d043d23f7 100644 --- a/app/src/main/res/layout-land/activity_book_info.xml +++ b/app/src/main/res/layout-land/activity_book_info.xml @@ -165,7 +165,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="8dp" - android:text="简介" + android:text="@string/book_intro" android:textColor="@color/tv_text_default" android:textSize="16sp" /> @@ -192,22 +192,15 @@ app:layout_constraintRight_toRightOf="parent" app:layout_constraintLeft_toRightOf="@+id/fg"> - - - - - + android:paddingLeft="8dp" + android:paddingRight="8dp" + android:paddingTop="8dp" + android:text="@string/chapter_list" + android:textColor="@color/tv_text_default" + android:textSize="16sp" /> + android:text="@string/dur_pos" /> @@ -184,22 +184,15 @@ android:layout_height="5dp" android:background="@color/bg_divider_line" /> - - - - - + android:paddingLeft="8dp" + android:paddingRight="8dp" + android:paddingTop="8dp" + android:text="@string/chapter_list" + android:textColor="@color/tv_text_default" + android:textSize="16sp" /> + android:text="@string/dur_pos" /> 编辑订阅源 筛选 筛选发现 + 当前位置: From c77c257556c41ac90dadce7b7f75aae9bd11802a Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 30 Sep 2019 19:42:10 +0800 Subject: [PATCH 1706/1997] up --- .../io/legado/app/ui/book/search/HistoryKeyAdapter.kt | 8 +++++++- .../java/io/legado/app/ui/book/search/SearchActivity.kt | 7 +++++++ .../java/io/legado/app/ui/book/search/SearchViewModel.kt | 6 ++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/book/search/HistoryKeyAdapter.kt b/app/src/main/java/io/legado/app/ui/book/search/HistoryKeyAdapter.kt index 48b60e9b0..213157e90 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/HistoryKeyAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/HistoryKeyAdapter.kt @@ -1,12 +1,16 @@ package io.legado.app.ui.book.search import android.content.Context +import io.legado.app.App import io.legado.app.R import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.data.entities.SearchKeyword import io.legado.app.ui.widget.anima.explosion_field.ExplosionField import kotlinx.android.synthetic.main.item_text.view.* +import kotlinx.coroutines.Dispatchers.IO +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch import org.jetbrains.anko.sdk27.listeners.onClick import org.jetbrains.anko.sdk27.listeners.onLongClick @@ -24,7 +28,9 @@ class HistoryKeyAdapter(context: Context, val callBack: CallBack) : it?.let { ExplosionField(context).explode(it, true) } - + GlobalScope.launch(IO) { + App.db.searchKeywordDao().delete(item) + } true } } diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt index bdf2525f0..098fe7983 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt @@ -44,6 +44,7 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se override fun onActivityCreated(savedInstanceState: Bundle?) { initRecyclerView() initSearchView() + initOtherView() initData() intent.getStringExtra("key")?.let { search_view.setQuery(it, true) @@ -105,6 +106,12 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se fb_stop.onClick { viewModel.stop() } } + private fun initOtherView() { + tv_clear_history.onClick { + viewModel.clearHistory() + } + } + private fun initData() { searchBookData?.removeObservers(this) searchBookData = LivePagedListBuilder( diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt index 85b3694db..011a13d8a 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt @@ -71,4 +71,10 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { } ?: App.db.searchKeywordDao().insert(SearchKeyword(key, 1)) } } + + fun clearHistory() { + execute { + App.db.searchKeywordDao().deleteAll() + } + } } From e9279fd1035598916aa2e37e6d07b20d28fc01ae Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 30 Sep 2019 19:43:07 +0800 Subject: [PATCH 1707/1997] up --- .../java/io/legado/app/ui/book/search/SearchActivity.kt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt index 098fe7983..1ed4fae13 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt @@ -103,13 +103,11 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se adapter = SearchAdapter(this) recycler_view.layoutManager = LinearLayoutManager(this) recycler_view.adapter = adapter - fb_stop.onClick { viewModel.stop() } } private fun initOtherView() { - tv_clear_history.onClick { - viewModel.clearHistory() - } + tv_clear_history.onClick { viewModel.clearHistory() } + fb_stop.onClick { viewModel.stop() } } private fun initData() { From 5c594ffbd55de6d53700c9d602ad660a55f9dcb1 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 30 Sep 2019 20:25:29 +0800 Subject: [PATCH 1708/1997] up --- .../java/io/legado/app/base/BaseViewModel.kt | 15 ++++++++-- .../io/legado/app/help/coroutine/Coroutine.kt | 29 +++++++++++++------ .../app/ui/book/search/SearchActivity.kt | 5 +++- .../app/ui/book/search/SearchViewModel.kt | 12 +++++++- 4 files changed, 47 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/io/legado/app/base/BaseViewModel.kt b/app/src/main/java/io/legado/app/base/BaseViewModel.kt index 1aa8452c9..d59bb15f7 100644 --- a/app/src/main/java/io/legado/app/base/BaseViewModel.kt +++ b/app/src/main/java/io/legado/app/base/BaseViewModel.kt @@ -8,17 +8,26 @@ import io.legado.app.help.coroutine.Coroutine import kotlinx.coroutines.* import org.jetbrains.anko.AnkoLogger import org.jetbrains.anko.toast +import kotlin.coroutines.CoroutineContext -open class BaseViewModel(application: Application) : AndroidViewModel(application), CoroutineScope by MainScope(), +open class BaseViewModel(application: Application) : AndroidViewModel(application), + CoroutineScope by MainScope(), AnkoLogger { val context: Context by lazy { this.getApplication() } - fun execute(scope: CoroutineScope = this, block: suspend CoroutineScope.() -> T): Coroutine { + fun execute( + scope: CoroutineScope = this, + context: CoroutineContext = scope.coroutineContext.plus(Dispatchers.IO), + block: suspend CoroutineScope.() -> T + ): Coroutine { return Coroutine.async(scope) { block() } } - fun submit(scope: CoroutineScope = this, block: suspend CoroutineScope.() -> Deferred): Coroutine { + fun submit( + scope: CoroutineScope = this, + block: suspend CoroutineScope.() -> Deferred + ): Coroutine { return Coroutine.async(scope) { block().await() } } diff --git a/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt b/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt index 5b8c3d2c0..e72a3df22 100644 --- a/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt +++ b/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt @@ -1,18 +1,25 @@ package io.legado.app.help.coroutine -import android.util.Log import kotlinx.coroutines.* import kotlin.coroutines.CoroutineContext -class Coroutine(scope: CoroutineScope, block: suspend CoroutineScope.() -> T) { +class Coroutine( + scope: CoroutineScope, + context: CoroutineContext = scope.coroutineContext.plus(Dispatchers.IO), + block: suspend CoroutineScope.() -> T +) { companion object { val DEFAULT = MainScope() - fun async(scope: CoroutineScope = DEFAULT, block: suspend CoroutineScope.() -> T): Coroutine { - return Coroutine(scope, block) + fun async( + scope: CoroutineScope = DEFAULT, + context: CoroutineContext = scope.coroutineContext.plus(Dispatchers.IO), + block: suspend CoroutineScope.() -> T + ): Coroutine { + return Coroutine(scope, context, block) } } @@ -37,7 +44,7 @@ class Coroutine(scope: CoroutineScope, block: suspend CoroutineScope.() -> T) get() = job.isCompleted init { - this.job = executeInternal(scope, block) + this.job = executeInternal(scope, context, block) } fun timeout(timeMillis: () -> Long): Coroutine { @@ -101,11 +108,15 @@ class Coroutine(scope: CoroutineScope, block: suspend CoroutineScope.() -> T) return job.invokeOnCompletion(handler) } - private fun executeInternal(scope: CoroutineScope, block: suspend CoroutineScope.() -> T): Job { + private fun executeInternal( + scope: CoroutineScope, + context: CoroutineContext, + block: suspend CoroutineScope.() -> T + ): Job { return scope.plus(Dispatchers.Main).launch { try { start?.let { dispatchVoidCallback(this, it) } - val value = executeBlock(scope, timeMillis ?: 0L, block) + val value = executeBlock(context, timeMillis ?: 0L, block) success?.let { dispatchCallback(this, value, it) } } catch (e: Throwable) { val consume: Boolean = errorReturn?.value?.let { value -> @@ -147,11 +158,11 @@ class Coroutine(scope: CoroutineScope, block: suspend CoroutineScope.() -> T) } private suspend inline fun executeBlock( - scope: CoroutineScope, + context: CoroutineContext, timeMillis: Long, noinline block: suspend CoroutineScope.() -> T ): T? { - return withContext(scope.coroutineContext.plus(Dispatchers.IO)) { + return withContext(context) { if (timeMillis > 0L) withTimeout(timeMillis) { block() } else block() diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt index 1ed4fae13..bc25fa64f 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt @@ -107,7 +107,10 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se private fun initOtherView() { tv_clear_history.onClick { viewModel.clearHistory() } - fb_stop.onClick { viewModel.stop() } + fb_stop.onClick { + viewModel.stop() + refresh_progress_bar.isAutoLoading = false + } } private fun initData() { diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt index 011a13d8a..0890ef013 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt @@ -8,9 +8,13 @@ import io.legado.app.data.entities.SearchKeyword import io.legado.app.help.coroutine.Coroutine import io.legado.app.model.WebBook import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.asCoroutineDispatcher +import kotlinx.coroutines.cancel import kotlinx.coroutines.delay +import java.util.concurrent.Executors class SearchViewModel(application: Application) : BaseViewModel(application) { + private var searchPool = Executors.newFixedThreadPool(99).asCoroutineDispatcher() private var task: Coroutine<*>? = null var searchKey: String = "" var startTime: Long = 0 @@ -26,7 +30,7 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { searchKey = key startTime = System.currentTimeMillis() start?.invoke() - task = execute { + task = execute(context = searchPool) { //onCleared时自动取消 val bookSourceList = App.db.bookSourceDao().allEnabled for (item in bookSourceList) { @@ -53,6 +57,7 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { } fun stop() { + searchPool.cancel() task?.cancel() } @@ -77,4 +82,9 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { App.db.searchKeywordDao().deleteAll() } } + + override fun onCleared() { + searchPool.close() + super.onCleared() + } } From a73dd8a20d96b70e5e2ee29d0ddfb90ca3f3cd45 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 30 Sep 2019 20:48:54 +0800 Subject: [PATCH 1709/1997] up --- .../app/ui/book/info/BookInfoActivity.kt | 10 ++--- .../app/ui/book/read/ReadBookActivity.kt | 10 ++--- .../app/ui/changesource/ChangeSourceDialog.kt | 37 ++++++++----------- 3 files changed, 24 insertions(+), 33 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt index 3d170cc6e..74d3b4495 100644 --- a/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt @@ -232,13 +232,11 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo } } - override fun curOrigin(): String? { - return viewModel.bookData.value?.origin - } + override val curOrigin: String? + get() = viewModel.bookData.value?.origin - override fun oldBook(): Book? { - return viewModel.bookData.value - } + override val oldBook: Book? + get() = viewModel.bookData.value override fun changeTo(book: Book) { upLoading(true) diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt index eb72a47f4..2a3bf10a6 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt @@ -330,13 +330,11 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_rea return viewModel.chapterSize } - override fun curOrigin(): String? { - return viewModel.bookData.value?.origin - } + override val curOrigin: String? + get() = viewModel.bookData.value?.origin - override fun oldBook(): Book? { - return viewModel.bookData.value - } + override val oldBook: Book? + get() = viewModel.bookData.value override fun changeTo(book: Book) { viewModel.changeTo(book) diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt index 8f02698b9..674db46c1 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceDialog.kt @@ -35,6 +35,7 @@ class ChangeSourceDialog : DialogFragment(), } } + private var callBack: CallBack? = null private lateinit var viewModel: ChangeSourceViewModel private lateinit var changeSourceAdapter: ChangeSourceAdapter @@ -49,6 +50,7 @@ class ChangeSourceDialog : DialogFragment(), override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + callBack = activity as? CallBack viewModel.searchStateData.observe(viewLifecycleOwner, Observer { refresh_progress_bar.isAutoLoading = it }) @@ -114,31 +116,24 @@ class ChangeSourceDialog : DialogFragment(), } override fun changeTo(searchBook: SearchBook) { - val activity = activity - if (activity is CallBack) { - val book = searchBook.toBook() - activity.oldBook()?.let { oldBook -> - book.durChapterIndex = oldBook.durChapterIndex - book.durChapterPos = oldBook.durChapterPos - book.durChapterTitle = oldBook.durChapterTitle - book.customCoverUrl = oldBook.customCoverUrl - book.customIntro = oldBook.customIntro - book.order = oldBook.order - if (book.coverUrl.isNullOrEmpty()) { - book.coverUrl = oldBook.getDisplayCover() - } - activity.changeTo(book) + val book = searchBook.toBook() + callBack?.oldBook?.let { oldBook -> + book.durChapterIndex = oldBook.durChapterIndex + book.durChapterPos = oldBook.durChapterPos + book.durChapterTitle = oldBook.durChapterTitle + book.customCoverUrl = oldBook.customCoverUrl + book.customIntro = oldBook.customIntro + book.order = oldBook.order + if (book.coverUrl.isNullOrEmpty()) { + book.coverUrl = oldBook.getDisplayCover() } + callBack?.changeTo(book) } dismiss() } override fun curOrigin(): String { - val activity = activity - if (activity is CallBack) { - return activity.curOrigin() ?: "" - } - return "" + return callBack?.curOrigin ?: "" } override fun adapter(): ChangeSourceAdapter { @@ -146,8 +141,8 @@ class ChangeSourceDialog : DialogFragment(), } interface CallBack { - fun curOrigin(): String? - fun oldBook(): Book? + val curOrigin: String? + val oldBook: Book? fun changeTo(book: Book) } From ddb55cfc52cc545ff1b19a15f22efd7060e60339 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 30 Sep 2019 20:55:55 +0800 Subject: [PATCH 1710/1997] up --- app/src/main/java/io/legado/app/base/BaseViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/base/BaseViewModel.kt b/app/src/main/java/io/legado/app/base/BaseViewModel.kt index d59bb15f7..e9bae2236 100644 --- a/app/src/main/java/io/legado/app/base/BaseViewModel.kt +++ b/app/src/main/java/io/legado/app/base/BaseViewModel.kt @@ -21,7 +21,7 @@ open class BaseViewModel(application: Application) : AndroidViewModel(applicatio context: CoroutineContext = scope.coroutineContext.plus(Dispatchers.IO), block: suspend CoroutineScope.() -> T ): Coroutine { - return Coroutine.async(scope) { block() } + return Coroutine.async(scope, context) { block() } } fun submit( From a083bf31b468d93e528eecd44947aefe91f73682 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 30 Sep 2019 21:00:12 +0800 Subject: [PATCH 1711/1997] up --- .../main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt b/app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt index cb54f4df1..8c00a19d4 100644 --- a/app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt @@ -134,6 +134,8 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { App.db.bookChapterDao().insert(*chapters.toTypedArray()) bookData.postValue(book) chapterListData.postValue(chapters) + }.onError { + it.printStackTrace() } } From d6832a91ecdac1ad45eb28d2a500295a861a7ebf Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 30 Sep 2019 21:49:40 +0800 Subject: [PATCH 1712/1997] up --- app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt | 4 ++++ .../main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt | 2 -- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt b/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt index e72a3df22..c61efdd23 100644 --- a/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt +++ b/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt @@ -1,5 +1,6 @@ package io.legado.app.help.coroutine +import io.legado.app.BuildConfig import kotlinx.coroutines.* import kotlin.coroutines.CoroutineContext @@ -119,6 +120,9 @@ class Coroutine( val value = executeBlock(context, timeMillis ?: 0L, block) success?.let { dispatchCallback(this, value, it) } } catch (e: Throwable) { + if (BuildConfig.DEBUG) { + e.printStackTrace() + } val consume: Boolean = errorReturn?.value?.let { value -> success?.let { dispatchCallback(this, value, it) } true diff --git a/app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt b/app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt index 8c00a19d4..cb54f4df1 100644 --- a/app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt @@ -134,8 +134,6 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { App.db.bookChapterDao().insert(*chapters.toTypedArray()) bookData.postValue(book) chapterListData.postValue(chapters) - }.onError { - it.printStackTrace() } } From 0b2007870f99eefc9b3bd788113ec83bb6b8a1cd Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 30 Sep 2019 21:53:23 +0800 Subject: [PATCH 1713/1997] up --- .../main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt | 1 - .../main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt | 3 +-- .../main/java/io/legado/app/ui/book/search/SearchViewModel.kt | 2 -- .../main/java/io/legado/app/ui/explore/ExploreShowViewModel.kt | 2 -- app/src/main/java/io/legado/app/ui/main/MainViewModel.kt | 3 --- 5 files changed, 1 insertion(+), 10 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt b/app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt index cb54f4df1..7b9ee2118 100644 --- a/app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt @@ -99,7 +99,6 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { } }.onError { toast(R.string.error_get_chapter_list) - it.printStackTrace() } } ?: toast(R.string.error_no_source) } diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt index a0b02a402..d6d6ae004 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt @@ -68,7 +68,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } } saveRead(book) - }.onError { it.printStackTrace() } + } } private fun loadBookInfo( @@ -103,7 +103,6 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) { } }?.onError { toast(R.string.error_load_toc) - it.printStackTrace() } ?: autoChangeSource() } } diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt index 0890ef013..c70078a45 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt @@ -47,8 +47,6 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { } delay(100)//每隔100毫秒搜索一个书源 } - }.onError { - it.printStackTrace() } task?.invokeOnCompletion { diff --git a/app/src/main/java/io/legado/app/ui/explore/ExploreShowViewModel.kt b/app/src/main/java/io/legado/app/ui/explore/ExploreShowViewModel.kt index f36a5fc69..a9514c8e4 100644 --- a/app/src/main/java/io/legado/app/ui/explore/ExploreShowViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/explore/ExploreShowViewModel.kt @@ -39,8 +39,6 @@ class ExploreShowViewModel(application: Application) : BaseViewModel(application App.db.searchBookDao().insert(*searchBooks.toTypedArray()) page++ } - }.onError { - it.printStackTrace() } } } diff --git a/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt b/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt index 3a9c1db32..992ed6a16 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt @@ -38,9 +38,6 @@ class MainViewModel(application: Application) : BaseViewModel(application) { App.db.bookChapterDao().insert(*it.toTypedArray()) } } - .onError { - it.printStackTrace() - } .onFinally { synchronized(this) { updateList.remove(book.bookUrl) From e362ab2ad955bef4ea114c257271089e4eb3282f Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 30 Sep 2019 22:21:36 +0800 Subject: [PATCH 1714/1997] up --- .../main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt | 2 +- .../io/legado/app/ui/widget/anima/explosion_field/Utils.kt | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt index bc38b8571..c04981cdd 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt @@ -445,7 +445,7 @@ class AnalyzeRule(private var book: BaseBook? = null) { } //分离正则表达式 val ruleStrS = - rule.trim { it <= ' ' }.splitNotBlank("##") + rule.trim { it <= ' ' }.split("##") rule = ruleStrS[0] if (ruleStrS.size > 1) { replaceRegex = ruleStrS[1] diff --git a/app/src/main/java/io/legado/app/ui/widget/anima/explosion_field/Utils.kt b/app/src/main/java/io/legado/app/ui/widget/anima/explosion_field/Utils.kt index 2f99191d2..6e33941fb 100644 --- a/app/src/main/java/io/legado/app/ui/widget/anima/explosion_field/Utils.kt +++ b/app/src/main/java/io/legado/app/ui/widget/anima/explosion_field/Utils.kt @@ -22,6 +22,7 @@ import android.graphics.Canvas import android.graphics.drawable.BitmapDrawable import android.view.View import android.widget.ImageView +import kotlin.math.roundToInt object Utils { @@ -29,7 +30,7 @@ object Utils { private val sCanvas = Canvas() fun dp2Px(dp: Int): Int { - return Math.round(dp * DENSITY) + return (dp * DENSITY).roundToInt() } fun createBitmapFromView(view: View): Bitmap? { @@ -55,7 +56,7 @@ object Utils { return bitmap } - fun createBitmapSafely( + private fun createBitmapSafely( width: Int, height: Int, config: Bitmap.Config, From 11d7133f93042f6c64c32c8806ea4c9e40ceb527 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 30 Sep 2019 22:38:46 +0800 Subject: [PATCH 1715/1997] up --- .../main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt b/app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt index 7b9ee2118..dc96b4c0c 100644 --- a/app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt @@ -129,7 +129,7 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { chapters ) book.durChapterTitle = chapters[book.durChapterIndex].title - App.db.bookDao().update(book) + App.db.bookDao().insert(book) App.db.bookChapterDao().insert(*chapters.toTypedArray()) bookData.postValue(book) chapterListData.postValue(chapters) From cde3bcf0cb2829cf2cc77fa09134763f9bf7b4c6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 30 Sep 2019 22:57:32 +0800 Subject: [PATCH 1716/1997] up --- app/src/main/java/io/legado/app/base/BaseViewModel.kt | 2 ++ .../app/ui/changesource/ChangeSourceViewModel.kt | 10 +++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/base/BaseViewModel.kt b/app/src/main/java/io/legado/app/base/BaseViewModel.kt index e9bae2236..98e09354b 100644 --- a/app/src/main/java/io/legado/app/base/BaseViewModel.kt +++ b/app/src/main/java/io/legado/app/base/BaseViewModel.kt @@ -2,6 +2,7 @@ package io.legado.app.base import android.app.Application import android.content.Context +import androidx.annotation.CallSuper import androidx.lifecycle.AndroidViewModel import io.legado.app.App import io.legado.app.help.coroutine.Coroutine @@ -31,6 +32,7 @@ open class BaseViewModel(application: Application) : AndroidViewModel(applicatio return Coroutine.async(scope) { block().await() } } + @CallSuper override fun onCleared() { super.onCleared() cancel() diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt index db4a5e889..cd67d50ec 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt @@ -12,11 +12,14 @@ import io.legado.app.help.coroutine.Coroutine import io.legado.app.model.WebBook import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.Main +import kotlinx.coroutines.asCoroutineDispatcher import kotlinx.coroutines.delay import kotlinx.coroutines.withContext import org.jetbrains.anko.debug +import java.util.concurrent.Executors class ChangeSourceViewModel(application: Application) : BaseViewModel(application) { + private var searchPool = Executors.newFixedThreadPool(99).asCoroutineDispatcher() var callBack: CallBack? = null val searchStateData = MutableLiveData() var name: String = "" @@ -51,7 +54,7 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio } fun search() { - task = execute { + task = execute(context = searchPool) { searchStateData.postValue(true) val bookSourceList = App.db.bookSourceDao().allEnabled for (item in bookSourceList) { @@ -130,4 +133,9 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio interface CallBack { fun adapter(): ChangeSourceAdapter } + + override fun onCleared() { + searchPool.close() + super.onCleared() + } } \ No newline at end of file From 86a99da671fa7a75475d9eeddcfc6c3b2cefec6f Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 1 Oct 2019 11:51:15 +0800 Subject: [PATCH 1717/1997] up --- app/src/main/java/io/legado/app/base/BaseViewModel.kt | 5 +++-- .../main/java/io/legado/app/help/coroutine/Coroutine.kt | 9 +++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/base/BaseViewModel.kt b/app/src/main/java/io/legado/app/base/BaseViewModel.kt index 98e09354b..3610a00a5 100644 --- a/app/src/main/java/io/legado/app/base/BaseViewModel.kt +++ b/app/src/main/java/io/legado/app/base/BaseViewModel.kt @@ -19,7 +19,7 @@ open class BaseViewModel(application: Application) : AndroidViewModel(applicatio fun execute( scope: CoroutineScope = this, - context: CoroutineContext = scope.coroutineContext.plus(Dispatchers.IO), + context: CoroutineContext = Dispatchers.IO, block: suspend CoroutineScope.() -> T ): Coroutine { return Coroutine.async(scope, context) { block() } @@ -27,9 +27,10 @@ open class BaseViewModel(application: Application) : AndroidViewModel(applicatio fun submit( scope: CoroutineScope = this, + context: CoroutineContext = Dispatchers.IO, block: suspend CoroutineScope.() -> Deferred ): Coroutine { - return Coroutine.async(scope) { block().await() } + return Coroutine.async(scope, context) { block().await() } } @CallSuper diff --git a/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt b/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt index c61efdd23..e9fd0df86 100644 --- a/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt +++ b/app/src/main/java/io/legado/app/help/coroutine/Coroutine.kt @@ -7,7 +7,7 @@ import kotlin.coroutines.CoroutineContext class Coroutine( scope: CoroutineScope, - context: CoroutineContext = scope.coroutineContext.plus(Dispatchers.IO), + context: CoroutineContext = Dispatchers.IO, block: suspend CoroutineScope.() -> T ) { @@ -17,7 +17,7 @@ class Coroutine( fun async( scope: CoroutineScope = DEFAULT, - context: CoroutineContext = scope.coroutineContext.plus(Dispatchers.IO), + context: CoroutineContext = Dispatchers.IO, block: suspend CoroutineScope.() -> T ): Coroutine { return Coroutine(scope, context, block) @@ -117,7 +117,7 @@ class Coroutine( return scope.plus(Dispatchers.Main).launch { try { start?.let { dispatchVoidCallback(this, it) } - val value = executeBlock(context, timeMillis ?: 0L, block) + val value = executeBlock(scope, context, timeMillis ?: 0L, block) success?.let { dispatchCallback(this, value, it) } } catch (e: Throwable) { if (BuildConfig.DEBUG) { @@ -162,11 +162,12 @@ class Coroutine( } private suspend inline fun executeBlock( + scope: CoroutineScope, context: CoroutineContext, timeMillis: Long, noinline block: suspend CoroutineScope.() -> T ): T? { - return withContext(context) { + return withContext(scope.coroutineContext.plus(context)) { if (timeMillis > 0L) withTimeout(timeMillis) { block() } else block() From 8d7bdb3ad10525674483febf8816b2af6455c2bf Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 1 Oct 2019 11:58:54 +0800 Subject: [PATCH 1718/1997] up --- .../main/java/io/legado/app/ui/book/search/SearchViewModel.kt | 4 +--- .../io/legado/app/ui/changesource/ChangeSourceViewModel.kt | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt index c70078a45..de1131371 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt @@ -9,7 +9,6 @@ import io.legado.app.help.coroutine.Coroutine import io.legado.app.model.WebBook import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.asCoroutineDispatcher -import kotlinx.coroutines.cancel import kotlinx.coroutines.delay import java.util.concurrent.Executors @@ -55,7 +54,6 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { } fun stop() { - searchPool.cancel() task?.cancel() } @@ -82,7 +80,7 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { } override fun onCleared() { - searchPool.close() super.onCleared() + searchPool.close() } } diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt index cd67d50ec..f3a468da1 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt @@ -135,7 +135,7 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio } override fun onCleared() { - searchPool.close() super.onCleared() + searchPool.close() } } \ No newline at end of file From 423cff9d9576e89deefdc72101ae5731c5f23458 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 1 Oct 2019 12:51:27 +0800 Subject: [PATCH 1719/1997] up --- .../main/java/io/legado/app/ui/book/search/SearchViewModel.kt | 2 +- .../java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt index de1131371..b754f91f1 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt @@ -13,7 +13,7 @@ import kotlinx.coroutines.delay import java.util.concurrent.Executors class SearchViewModel(application: Application) : BaseViewModel(application) { - private var searchPool = Executors.newFixedThreadPool(99).asCoroutineDispatcher() + private var searchPool = Executors.newFixedThreadPool(16).asCoroutineDispatcher() private var task: Coroutine<*>? = null var searchKey: String = "" var startTime: Long = 0 diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt index f3a468da1..265dcc227 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt @@ -19,7 +19,7 @@ import org.jetbrains.anko.debug import java.util.concurrent.Executors class ChangeSourceViewModel(application: Application) : BaseViewModel(application) { - private var searchPool = Executors.newFixedThreadPool(99).asCoroutineDispatcher() + private var searchPool = Executors.newFixedThreadPool(16).asCoroutineDispatcher() var callBack: CallBack? = null val searchStateData = MutableLiveData() var name: String = "" From 3e808b12dc7aeb3c8ce6f0f35a41c6d4feaf2507 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 1 Oct 2019 12:57:17 +0800 Subject: [PATCH 1720/1997] up --- .../main/java/io/legado/app/model/WebBook.kt | 40 +++++++++++++------ .../app/ui/book/search/SearchViewModel.kt | 9 ++++- .../ui/changesource/ChangeSourceViewModel.kt | 4 +- 3 files changed, 37 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/WebBook.kt b/app/src/main/java/io/legado/app/model/WebBook.kt index a09e9f326..9201fd542 100644 --- a/app/src/main/java/io/legado/app/model/WebBook.kt +++ b/app/src/main/java/io/legado/app/model/WebBook.kt @@ -11,6 +11,8 @@ import io.legado.app.model.webbook.BookContent import io.legado.app.model.webbook.BookInfo import io.legado.app.model.webbook.BookList import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlin.coroutines.CoroutineContext class WebBook(val bookSource: BookSource) { @@ -20,9 +22,13 @@ class WebBook(val bookSource: BookSource) { /** * 搜索 */ - fun searchBook(key: String, page: Int? = 1, scope: CoroutineScope = Coroutine.DEFAULT) - : Coroutine> { - return Coroutine.async(scope) { + fun searchBook( + key: String, + page: Int? = 1, + scope: CoroutineScope = Coroutine.DEFAULT, + context: CoroutineContext = Dispatchers.IO + ): Coroutine> { + return Coroutine.async(scope, context) { bookSource.searchUrl?.let { searchUrl -> val analyzeUrl = AnalyzeUrl( ruleUrl = searchUrl, @@ -40,9 +46,13 @@ class WebBook(val bookSource: BookSource) { /** * 发现 */ - fun exploreBook(url: String, page: Int? = 1, scope: CoroutineScope = Coroutine.DEFAULT) - : Coroutine> { - return Coroutine.async(scope) { + fun exploreBook( + url: String, + page: Int? = 1, + scope: CoroutineScope = Coroutine.DEFAULT, + context: CoroutineContext = Dispatchers.IO + ): Coroutine> { + return Coroutine.async(scope, context) { val analyzeUrl = AnalyzeUrl( ruleUrl = url, page = page, @@ -57,8 +67,12 @@ class WebBook(val bookSource: BookSource) { /** * 书籍信息 */ - fun getBookInfo(book: Book, scope: CoroutineScope = Coroutine.DEFAULT): Coroutine { - return Coroutine.async(scope) { + fun getBookInfo( + book: Book, + scope: CoroutineScope = Coroutine.DEFAULT, + context: CoroutineContext = Dispatchers.IO + ): Coroutine { + return Coroutine.async(scope, context) { val analyzeUrl = AnalyzeUrl( book = book, ruleUrl = book.bookUrl, @@ -76,9 +90,10 @@ class WebBook(val bookSource: BookSource) { */ fun getChapterList( book: Book, - scope: CoroutineScope = Coroutine.DEFAULT + scope: CoroutineScope = Coroutine.DEFAULT, + context: CoroutineContext = Dispatchers.IO ): Coroutine> { - return Coroutine.async(scope) { + return Coroutine.async(scope, context) { val analyzeUrl = AnalyzeUrl( book = book, ruleUrl = book.tocUrl, @@ -97,9 +112,10 @@ class WebBook(val bookSource: BookSource) { book: Book, bookChapter: BookChapter, nextChapterUrl: String? = null, - scope: CoroutineScope = Coroutine.DEFAULT + scope: CoroutineScope = Coroutine.DEFAULT, + context: CoroutineContext = Dispatchers.IO ): Coroutine { - return Coroutine.async(scope) { + return Coroutine.async(scope, context) { val analyzeUrl = AnalyzeUrl( book = book, diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt index b754f91f1..a9e84bf0d 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt @@ -29,12 +29,17 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { searchKey = key startTime = System.currentTimeMillis() start?.invoke() - task = execute(context = searchPool) { + task = execute { //onCleared时自动取消 val bookSourceList = App.db.bookSourceDao().allEnabled for (item in bookSourceList) { //task取消时自动取消 by (scope = this@execute) - WebBook(item).searchBook(key, searchPage, scope = this@execute) + WebBook(item).searchBook( + key, + searchPage, + scope = this@execute, + context = searchPool + ) .timeout(30000L) .onSuccess(Dispatchers.IO) { it?.let { list -> diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt index 265dcc227..9843ec994 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt @@ -54,12 +54,12 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio } fun search() { - task = execute(context = searchPool) { + task = execute { searchStateData.postValue(true) val bookSourceList = App.db.bookSourceDao().allEnabled for (item in bookSourceList) { //task取消时自动取消 by (scope = this@execute) - WebBook(item).searchBook(name, scope = this@execute) + WebBook(item).searchBook(name, scope = this@execute, context = searchPool) .timeout(30000L) .onSuccess(IO) { it?.forEach { searchBook -> From 97c8fa5953d700bede7a315cc47dfa9a33018a62 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 1 Oct 2019 17:29:54 +0800 Subject: [PATCH 1721/1997] up --- .../main/java/io/legado/app/ui/book/search/SearchViewModel.kt | 2 -- .../java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt | 2 -- 2 files changed, 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt index a9e84bf0d..0c21d1820 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt @@ -9,7 +9,6 @@ import io.legado.app.help.coroutine.Coroutine import io.legado.app.model.WebBook import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.asCoroutineDispatcher -import kotlinx.coroutines.delay import java.util.concurrent.Executors class SearchViewModel(application: Application) : BaseViewModel(application) { @@ -49,7 +48,6 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { } } } - delay(100)//每隔100毫秒搜索一个书源 } } diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt index 9843ec994..44483aa07 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt @@ -13,7 +13,6 @@ import io.legado.app.model.WebBook import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.asCoroutineDispatcher -import kotlinx.coroutines.delay import kotlinx.coroutines.withContext import org.jetbrains.anko.debug import java.util.concurrent.Executors @@ -73,7 +72,6 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio } } } - delay(100) } } From 91e3ae3c5d0e60b20f14f2bfb30c12f0637cee1d Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 1 Oct 2019 17:54:35 +0800 Subject: [PATCH 1722/1997] up --- app/src/main/java/io/legado/app/utils/LogUtils.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/utils/LogUtils.kt b/app/src/main/java/io/legado/app/utils/LogUtils.kt index f8b8b6bb6..3dd8f3dfe 100644 --- a/app/src/main/java/io/legado/app/utils/LogUtils.kt +++ b/app/src/main/java/io/legado/app/utils/LogUtils.kt @@ -30,8 +30,10 @@ object LogUtils { } private val fileHandler by lazy { + val logFolder = FileHelp.getCachePath() + File.separator + "logs" + FileHelp.getFolder(logFolder) FileHandler( - FileHelp.getCachePath() + File.separator + "logs" + File.separator + "app.log", + logFolder + File.separator + "app.log", 2048, 10 ).apply { From 5c3d50657ab8eb879d8366c4868b24e3473565a4 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 1 Oct 2019 18:54:45 +0800 Subject: [PATCH 1723/1997] up --- .../io/legado/app/data/entities/EditEntity.kt | 3 + .../ui/book/source/edit/SourceEditActivity.kt | 2 +- .../ui/book/source/edit/SourceEditAdapter.kt | 5 +- .../rss/source/edit/RssSourceEditActivity.kt | 1 + .../rss/source/edit/RssSourceEditAdapter.kt | 85 +++++++++++++++++++ .../res/layout/activity_rss_source_edit.xml | 4 + 6 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/io/legado/app/data/entities/EditEntity.kt create mode 100644 app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditAdapter.kt diff --git a/app/src/main/java/io/legado/app/data/entities/EditEntity.kt b/app/src/main/java/io/legado/app/data/entities/EditEntity.kt new file mode 100644 index 000000000..d4c1ecc1a --- /dev/null +++ b/app/src/main/java/io/legado/app/data/entities/EditEntity.kt @@ -0,0 +1,3 @@ +package io.legado.app.data.entities + +data class EditEntity(var key: String, var value: String?, var hint: Int) \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditActivity.kt index 8a2db83d6..3abcbcacf 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditActivity.kt @@ -19,6 +19,7 @@ import io.legado.app.R import io.legado.app.base.VMBaseActivity import io.legado.app.constant.AppConst import io.legado.app.data.entities.BookSource +import io.legado.app.data.entities.EditEntity import io.legado.app.data.entities.rule.* import io.legado.app.lib.theme.ATH import io.legado.app.ui.book.source.debug.SourceDebugActivity @@ -618,5 +619,4 @@ class SourceEditActivity : } } - class EditEntity(var key: String, var value: String?, var hint: Int) } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditAdapter.kt b/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditAdapter.kt index 3ac5fc3d1..434f2071a 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditAdapter.kt @@ -7,11 +7,12 @@ import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import io.legado.app.R +import io.legado.app.data.entities.EditEntity import kotlinx.android.synthetic.main.item_source_edit.view.* class SourceEditAdapter : RecyclerView.Adapter() { - var editEntities: ArrayList = ArrayList() + var editEntities: ArrayList = ArrayList() set(value) { field = value notifyDataSetChanged() @@ -34,7 +35,7 @@ class SourceEditAdapter : RecyclerView.Adapter() } class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { - fun bind(editEntity: SourceEditActivity.EditEntity) = with(itemView) { + fun bind(editEntity: EditEntity) = with(itemView) { if (editText.getTag(R.id.tag1) == null) { val listener = object : View.OnAttachStateChangeListener { override fun onViewAttachedToWindow(v: View) { diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt index e58ba568c..40ce0ba97 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt @@ -16,4 +16,5 @@ class RssSourceEditActivity : } + } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditAdapter.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditAdapter.kt new file mode 100644 index 000000000..78e0740ef --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditAdapter.kt @@ -0,0 +1,85 @@ +package io.legado.app.ui.rss.source.edit + +import android.text.Editable +import android.text.TextWatcher +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import io.legado.app.R +import io.legado.app.data.entities.EditEntity +import kotlinx.android.synthetic.main.item_source_edit.view.* + +class RssSourceEditAdapter : RecyclerView.Adapter() { + + var editEntities: ArrayList = ArrayList() + set(value) { + field = value + notifyDataSetChanged() + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { + return MyViewHolder( + LayoutInflater.from( + parent.context + ).inflate(R.layout.item_source_edit, parent, false) + ) + } + + override fun onBindViewHolder(holder: MyViewHolder, position: Int) { + holder.bind(editEntities[position]) + } + + override fun getItemCount(): Int { + return editEntities.size + } + + class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { + fun bind(editEntity: EditEntity) = with(itemView) { + if (editText.getTag(R.id.tag1) == null) { + val listener = object : View.OnAttachStateChangeListener { + override fun onViewAttachedToWindow(v: View) { + editText.isCursorVisible = false + editText.isCursorVisible = true + editText.isFocusable = true + editText.isFocusableInTouchMode = true + } + + override fun onViewDetachedFromWindow(v: View) { + + } + } + editText.addOnAttachStateChangeListener(listener) + editText.setTag(R.id.tag1, listener) + } + editText.getTag(R.id.tag2)?.let { + if (it is TextWatcher) { + editText.removeTextChangedListener(it) + } + } + editText.setText(editEntity.value) + textInputLayout.hint = context.getString(editEntity.hint) + val textWatcher = object : TextWatcher { + override fun beforeTextChanged( + s: CharSequence, + start: Int, + count: Int, + after: Int + ) { + + } + + override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { + + } + + override fun afterTextChanged(s: Editable?) { + editEntity.value = (s?.toString()) + } + } + editText.addTextChangedListener(textWatcher) + editText.setTag(R.id.tag2, textWatcher) + } + } + +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_rss_source_edit.xml b/app/src/main/res/layout/activity_rss_source_edit.xml index 437330f50..5579d3de5 100644 --- a/app/src/main/res/layout/activity_rss_source_edit.xml +++ b/app/src/main/res/layout/activity_rss_source_edit.xml @@ -13,5 +13,9 @@ app:displayHomeAsUp="true" app:title="@string/rss_source_edit" /> + \ No newline at end of file From 358f955071eae78be7a6d7ee7d91c79b136307ea Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 1 Oct 2019 19:44:52 +0800 Subject: [PATCH 1724/1997] up --- .../ui/book/source/edit/SourceEditActivity.kt | 6 +- .../rss/source/edit/RssSourceEditActivity.kt | 90 ++++++++++++++++++- .../legado/app/ui/widget/KeyboardToolPop.kt | 8 +- 3 files changed, 96 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditActivity.kt index 3abcbcacf..4a9cc535f 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditActivity.kt @@ -34,7 +34,7 @@ import kotlin.math.abs class SourceEditActivity : VMBaseActivity(R.layout.activity_book_source_edit, false), - KeyboardToolPop.OnClickListener { + KeyboardToolPop.CallBack { override val viewModel: SourceEditViewModel get() = getViewModel(SourceEditViewModel::class.java) @@ -92,7 +92,7 @@ class SourceEditActivity : toast("书源名称和URL不能为空") } else { viewModel.save(bookSource) { - startActivity("key" to bookSource.bookSourceUrl) + startActivity(Pair("key", bookSource.bookSourceUrl)) } } } @@ -567,7 +567,7 @@ class SourceEditActivity : return source } - override fun click(text: String) { + override fun sendText(text: String) { if (text.isBlank()) return val view = window.decorView.findFocus() if (view is EditText) { diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt index 40ce0ba97..effc75a44 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt @@ -1,20 +1,108 @@ package io.legado.app.ui.rss.source.edit +import android.graphics.Rect import android.os.Bundle +import android.view.Gravity +import android.view.Menu +import android.view.ViewTreeObserver +import android.widget.EditText +import android.widget.PopupWindow +import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.R import io.legado.app.base.VMBaseActivity +import io.legado.app.constant.AppConst +import io.legado.app.lib.theme.ATH +import io.legado.app.ui.widget.KeyboardToolPop import io.legado.app.utils.getViewModel +import kotlinx.android.synthetic.main.activity_book_source_edit.* +import org.jetbrains.anko.displayMetrics +import kotlin.math.abs class RssSourceEditActivity : - VMBaseActivity(R.layout.activity_rss_source_edit, false) { + VMBaseActivity(R.layout.activity_rss_source_edit, false), + KeyboardToolPop.CallBack { + + private var mSoftKeyboardTool: PopupWindow? = null + private var mIsSoftKeyBoardShowing = false + + private lateinit var adapter: RssSourceEditAdapter override val viewModel: RssSourceEditViewModel get() = getViewModel(RssSourceEditViewModel::class.java) override fun onActivityCreated(savedInstanceState: Bundle?) { + initView() + } + + override fun onDestroy() { + super.onDestroy() + mSoftKeyboardTool?.dismiss() + } + + override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { + menuInflater.inflate(R.menu.source_edit, menu) + return super.onCompatCreateOptionsMenu(menu) + } + private fun initView() { + ATH.applyEdgeEffectColor(recycler_view) + mSoftKeyboardTool = KeyboardToolPop(this, AppConst.keyboardToolChars, this) + window.decorView.viewTreeObserver.addOnGlobalLayoutListener(KeyboardOnGlobalChangeListener()) + recycler_view.layoutManager = LinearLayoutManager(this) + recycler_view.adapter = adapter } + override fun sendText(text: String) { + if (text.isBlank()) return + val view = 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)//光标所在位置插入文字 + } + } + } + + private fun showKeyboardTopPopupWindow() { + mSoftKeyboardTool?.isShowing?.let { if (it) return } + if (!isFinishing) { + mSoftKeyboardTool?.showAtLocation(ll_content, Gravity.BOTTOM, 0, 0) + } + } + + private fun closePopupWindow() { + mSoftKeyboardTool?.let { + if (it.isShowing) { + it.dismiss() + } + } + } + + private inner class KeyboardOnGlobalChangeListener : ViewTreeObserver.OnGlobalLayoutListener { + override fun onGlobalLayout() { + val rect = Rect() + // 获取当前页面窗口的显示范围 + window.decorView.getWindowVisibleDisplayFrame(rect) + val screenHeight = this@RssSourceEditActivity.displayMetrics.heightPixels + val keyboardHeight = screenHeight - rect.bottom // 输入法的高度 + val preShowing = mIsSoftKeyBoardShowing + if (abs(keyboardHeight) > screenHeight / 5) { + mIsSoftKeyBoardShowing = true // 超过屏幕五分之一则表示弹出了输入法 + recycler_view.setPadding(0, 0, 0, 100) + showKeyboardTopPopupWindow() + } else { + mIsSoftKeyBoardShowing = false + recycler_view.setPadding(0, 0, 0, 0) + if (preShowing) { + closePopupWindow() + } + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/KeyboardToolPop.kt b/app/src/main/java/io/legado/app/ui/widget/KeyboardToolPop.kt index 57f40c039..40e321b87 100644 --- a/app/src/main/java/io/legado/app/ui/widget/KeyboardToolPop.kt +++ b/app/src/main/java/io/legado/app/ui/widget/KeyboardToolPop.kt @@ -18,7 +18,7 @@ import org.jetbrains.anko.sdk27.listeners.onClick class KeyboardToolPop( context: Context, private val chars: List, - val onClickListener: OnClickListener? + val callBack: CallBack? ) : PopupWindow(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) { init { @@ -45,13 +45,13 @@ class KeyboardToolPop( override fun convert(holder: ItemViewHolder, item: String, payloads: MutableList) { with(holder.itemView) { text_view.text = item - onClick { onClickListener?.click(item) } + onClick { callBack?.sendText(item) } } } } - interface OnClickListener { - fun click(text: String) + interface CallBack { + fun sendText(text: String) } } From 498cbf99a5299663b50cf5b1a7d765ffbf3989b7 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 1 Oct 2019 19:55:31 +0800 Subject: [PATCH 1725/1997] up --- .../io/legado/app/data/dao/RssSourceDao.kt | 3 +++ .../io/legado/app/data/entities/RssSource.kt | 6 +++--- .../rss/source/edit/RssSourceEditActivity.kt | 18 ++++++++++++++++++ .../rss/source/edit/RssSourceEditViewModel.kt | 13 +++++++++++++ 4 files changed, 37 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt b/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt index 999898598..d6b2d7767 100644 --- a/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt @@ -7,6 +7,9 @@ import io.legado.app.data.entities.RssSource @Dao interface RssSourceDao { + @Query("select * from rssSources where sourceUrl = :key") + fun getByKey(key: String): RssSource? + @get:Query("SELECT * FROM rssSources") val all: List diff --git a/app/src/main/java/io/legado/app/data/entities/RssSource.kt b/app/src/main/java/io/legado/app/data/entities/RssSource.kt index 17a7064e9..7a1d8d045 100644 --- a/app/src/main/java/io/legado/app/data/entities/RssSource.kt +++ b/app/src/main/java/io/legado/app/data/entities/RssSource.kt @@ -8,10 +8,10 @@ import kotlinx.android.parcel.Parcelize @Parcelize @Entity(tableName = "rssSources") data class RssSource( - var sourceName: String, + var sourceName: String = "", @PrimaryKey - var sourceUrl: String, - var iconUrl: String, + var sourceUrl: String = "", + var iconUrl: String = "", var enabled: Boolean = true, var ruleGuid: String? = null, var ruleTitle: String? = null, diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt index effc75a44..afffb7b97 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt @@ -7,10 +7,12 @@ import android.view.Menu import android.view.ViewTreeObserver import android.widget.EditText import android.widget.PopupWindow +import androidx.lifecycle.Observer import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.R import io.legado.app.base.VMBaseActivity import io.legado.app.constant.AppConst +import io.legado.app.data.entities.RssSource import io.legado.app.lib.theme.ATH import io.legado.app.ui.widget.KeyboardToolPop import io.legado.app.utils.getViewModel @@ -33,6 +35,19 @@ class RssSourceEditActivity : override fun onActivityCreated(savedInstanceState: Bundle?) { initView() + viewModel.sourceLiveData.observe(this, Observer { + upRecyclerView(it) + }) + if (viewModel.sourceLiveData.value == null) { + val sourceID = intent.getStringExtra("data") + if (sourceID == null) { + upRecyclerView(null) + } else { + sourceID.let { viewModel.setSource(sourceID) } + } + } else { + upRecyclerView(viewModel.sourceLiveData.value) + } } override fun onDestroy() { @@ -53,6 +68,9 @@ class RssSourceEditActivity : recycler_view.adapter = adapter } + private fun upRecyclerView(rssSource: RssSource?) { + + } override fun sendText(text: String) { if (text.isBlank()) return diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt index fdb353c69..53f7d01de 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt @@ -1,9 +1,22 @@ package io.legado.app.ui.rss.source.edit import android.app.Application +import androidx.lifecycle.MutableLiveData +import io.legado.app.App import io.legado.app.base.BaseViewModel +import io.legado.app.data.entities.RssSource class RssSourceEditViewModel(application: Application) : BaseViewModel(application) { + val sourceLiveData: MutableLiveData = MutableLiveData() + + fun setSource(key: String) { + execute { + App.db.rssSourceDao().getByKey(key)?.let { + sourceLiveData.postValue(it) + } ?: sourceLiveData.postValue(RssSource()) + } + } + } \ No newline at end of file From 4ff6ea6653dd6cc4e0ebb4ee6c7d1006bd386ee0 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 1 Oct 2019 22:09:52 +0800 Subject: [PATCH 1726/1997] up --- .../io/legado/app/data/entities/RssSource.kt | 8 +- .../ui/book/source/edit/SourceEditActivity.kt | 358 ++++-------------- .../rss/source/edit/RssSourceEditActivity.kt | 29 ++ app/src/main/res/values/strings.xml | 15 + 4 files changed, 113 insertions(+), 297 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/RssSource.kt b/app/src/main/java/io/legado/app/data/entities/RssSource.kt index 7a1d8d045..d17ab598d 100644 --- a/app/src/main/java/io/legado/app/data/entities/RssSource.kt +++ b/app/src/main/java/io/legado/app/data/entities/RssSource.kt @@ -16,11 +16,13 @@ data class RssSource( var ruleGuid: String? = null, var ruleTitle: String? = null, var ruleAuthor: String? = null, - var ruleLink: String? = null, var rulePubDate: String? = null, + //类别 + var ruleCategories: String? = null, + //描述 var ruleDescription: String? = null, - var ruleContent: String? = null, var ruleImage: String? = null, - var ruleCategories: String? = null, + var ruleContent: String? = null, + var ruleLink: String? = null, var customOrder: Int = 0 ) : Parcelable \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditActivity.kt index 4a9cc535f..c7e6dbbf5 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditActivity.kt @@ -146,322 +146,92 @@ class SourceEditActivity : cb_is_enable_find.isChecked = it.enabledExplore } //基本信息 - with(bookSource) { - sourceEntities.clear() - sourceEntities - .add( - EditEntity( - "bookSourceUrl", - this?.bookSourceUrl, - R.string.book_source_url - ) - ) - sourceEntities - .add( - EditEntity( - "bookSourceName", - this?.bookSourceName, - R.string.book_source_name - ) - ) - sourceEntities.add( + sourceEntities.clear() + searchEntities.apply { + add(EditEntity("bookSourceUrl", bookSource?.bookSourceUrl, R.string.book_source_url)) + add(EditEntity("bookSourceName", bookSource?.bookSourceName, R.string.book_source_name)) + add( EditEntity( "bookSourceGroup", - this?.bookSourceGroup, + bookSource?.bookSourceGroup, R.string.book_source_group ) ) - sourceEntities - .add( - EditEntity( - "loginUrl", - this?.loginUrl, - R.string.book_source_login_url - ) - ) - sourceEntities - .add( - EditEntity( - "bookUrlPattern", - this?.bookUrlPattern, - R.string.book_url_pattern - ) - ) - sourceEntities.add( - EditEntity( - "header", - this?.header, - R.string.source_http_header - ) - ) + add(EditEntity("loginUrl", bookSource?.loginUrl, R.string.book_source_login_url)) + add(EditEntity("bookUrlPattern", bookSource?.bookUrlPattern, R.string.book_url_pattern)) + add(EditEntity("header", bookSource?.header, R.string.source_http_header)) } //搜索 - with(bookSource?.getSearchRule()) { + (bookSource?.getSearchRule()).let { searchRule -> searchEntities.clear() - searchEntities - .add( - EditEntity( - "searchUrl", - bookSource?.searchUrl, - R.string.rule_search_url - ) - ) - searchEntities.add( - EditEntity( - "bookList", - this?.bookList, - R.string.rule_book_list - ) - ) - searchEntities.add( - EditEntity( - "name", - this?.name, - R.string.rule_book_name - ) - ) - searchEntities.add( - EditEntity( - "author", - this?.author, - R.string.rule_book_author - ) - ) - searchEntities.add( - EditEntity( - "kind", - this?.kind, - R.string.rule_book_kind - ) - ) - searchEntities.add( - EditEntity( - "wordCount", - this?.wordCount, - R.string.rule_word_count - ) - ) - searchEntities - .add( - EditEntity( - "lastChapter", - this?.lastChapter, - R.string.rule_last_chapter - ) - ) - searchEntities.add( - EditEntity( - "intro", - this?.intro, - R.string.rule_book_intro - ) - ) - searchEntities.add( - EditEntity( - "coverUrl", - this?.coverUrl, - R.string.rule_cover_url - ) - ) - searchEntities.add( - EditEntity( - "bookUrl", - this?.bookUrl, - R.string.rule_book_url - ) - ) + searchEntities.apply { + add(EditEntity("searchUrl", bookSource?.searchUrl, R.string.rule_search_url)) + add(EditEntity("bookList", searchRule?.bookList, R.string.rule_book_list)) + add(EditEntity("name", searchRule?.name, R.string.rule_book_name)) + add(EditEntity("author", searchRule?.author, R.string.rule_book_author)) + add(EditEntity("kind", searchRule?.kind, R.string.rule_book_kind)) + add(EditEntity("wordCount", searchRule?.wordCount, R.string.rule_word_count)) + add(EditEntity("lastChapter", searchRule?.lastChapter, R.string.rule_last_chapter)) + add(EditEntity("intro", searchRule?.intro, R.string.rule_book_intro)) + add(EditEntity("coverUrl", searchRule?.coverUrl, R.string.rule_cover_url)) + add(EditEntity("bookUrl", searchRule?.bookUrl, R.string.rule_book_url)) + } } //详情页 - with(bookSource?.getBookInfoRule()) { + (bookSource?.getBookInfoRule()).let { infoRule -> infoEntities.clear() - infoEntities.add( - EditEntity( - "init", - this?.init, - R.string.rule_book_info_init - ) - ) - infoEntities.add( - EditEntity( - "name", - this?.name, - R.string.rule_book_name - ) - ) - infoEntities.add( - EditEntity( - "author", - this?.author, - R.string.rule_book_author - ) - ) - infoEntities.add( - EditEntity( - "coverUrl", - this?.coverUrl, - R.string.rule_cover_url - ) - ) - infoEntities.add( - EditEntity( - "intro", - this?.intro, - R.string.rule_book_intro - ) - ) - infoEntities.add( - EditEntity( - "kind", - this?.kind, - R.string.rule_book_kind - ) - ) - infoEntities.add( - EditEntity( - "wordCount", - this?.wordCount, - R.string.rule_word_count - ) - ) - infoEntities.add( - EditEntity( - "lastChapter", - this?.lastChapter, - R.string.rule_last_chapter - ) - ) - infoEntities.add( - EditEntity( - "tocUrl", - this?.tocUrl, - R.string.rule_toc_url - ) - ) + infoEntities.apply { + add(EditEntity("init", infoRule?.init, R.string.rule_book_info_init)) + add(EditEntity("name", infoRule?.name, R.string.rule_book_name)) + add(EditEntity("author", infoRule?.author, R.string.rule_book_author)) + add(EditEntity("coverUrl", infoRule?.coverUrl, R.string.rule_cover_url)) + add(EditEntity("intro", infoRule?.intro, R.string.rule_book_intro)) + add(EditEntity("kind", infoRule?.kind, R.string.rule_book_kind)) + add(EditEntity("wordCount", infoRule?.wordCount, R.string.rule_word_count)) + add(EditEntity("lastChapter", infoRule?.lastChapter, R.string.rule_last_chapter)) + add(EditEntity("tocUrl", infoRule?.tocUrl, R.string.rule_toc_url)) + } } //目录页 - with(bookSource?.getTocRule()) { + (bookSource?.getTocRule()).let { tocRule -> tocEntities.clear() - tocEntities.add( - EditEntity( - "chapterList", - this?.chapterList, - R.string.rule_chapter_list - ) - ) - tocEntities.add( - EditEntity( - "chapterName", - this?.chapterName, - R.string.rule_chapter_name - ) - ) - tocEntities.add( - EditEntity( - "chapterUrl", - this?.chapterUrl, - R.string.rule_chapter_url - ) - ) - tocEntities.add( - EditEntity( - "nextTocUrl", - this?.nextTocUrl, - R.string.rule_next_toc_url - ) - ) + tocEntities.apply { + add(EditEntity("chapterList", tocRule?.chapterList, R.string.rule_chapter_list)) + add(EditEntity("chapterName", tocRule?.chapterName, R.string.rule_chapter_name)) + add(EditEntity("chapterUrl", tocRule?.chapterUrl, R.string.rule_chapter_url)) + add(EditEntity("nextTocUrl", tocRule?.nextTocUrl, R.string.rule_next_toc_url)) + } } //正文页 - with(bookSource?.getContentRule()) { + (bookSource?.getContentRule()).let { contentRule -> contentEntities.clear() - contentEntities.add( - EditEntity( - "content", - this?.content, - R.string.rule_book_content - ) - ) - contentEntities.add( - EditEntity( - "nextContentUrl", - this?.nextContentUrl, - R.string.rule_content_url_next + contentEntities.apply { + add(EditEntity("content", contentRule?.content, R.string.rule_book_content)) + add( + EditEntity( + "nextContentUrl", + contentRule?.nextContentUrl, + R.string.rule_content_url_next + ) ) - ) + } } //发现 - with(bookSource?.getExploreRule()) { + (bookSource?.getExploreRule()).let { exploreRule -> findEntities.clear() - findEntities.add( - EditEntity( - "exploreUrl", - bookSource?.exploreUrl, - R.string.rule_find_url - ) - ) - findEntities.add( - EditEntity( - "bookList", - this?.bookList, - R.string.rule_book_list - ) - ) - findEntities.add( - EditEntity( - "name", - this?.name, - R.string.rule_book_name - ) - ) - findEntities.add( - EditEntity( - "author", - this?.author, - R.string.rule_book_author - ) - ) - findEntities.add( - EditEntity( - "kind", - this?.kind, - R.string.rule_book_kind - ) - ) - findEntities.add( - EditEntity( - "wordCount", - this?.wordCount, - R.string.rule_word_count - ) - ) - findEntities.add( - EditEntity( - "intro", - this?.intro, - R.string.rule_book_intro - ) - ) - findEntities.add( - EditEntity( - "lastChapter", - this?.lastChapter, - R.string.rule_last_chapter - ) - ) - findEntities.add( - EditEntity( - "coverUrl", - this?.coverUrl, - R.string.rule_cover_url - ) - ) - findEntities.add( - EditEntity( - "bookUrl", - this?.bookUrl, - R.string.rule_book_url - ) - ) + findEntities.apply { + add(EditEntity("exploreUrl", bookSource?.exploreUrl, R.string.rule_find_url)) + add(EditEntity("bookList", exploreRule?.bookList, R.string.rule_book_list)) + add(EditEntity("name", exploreRule?.name, R.string.rule_book_name)) + add(EditEntity("author", exploreRule?.author, R.string.rule_book_author)) + add(EditEntity("kind", exploreRule?.kind, R.string.rule_book_kind)) + add(EditEntity("wordCount", exploreRule?.wordCount, R.string.rule_word_count)) + add(EditEntity("intro", exploreRule?.intro, R.string.rule_book_intro)) + add(EditEntity("lastChapter", exploreRule?.lastChapter, R.string.rule_last_chapter)) + add(EditEntity("coverUrl", exploreRule?.coverUrl, R.string.rule_cover_url)) + add(EditEntity("bookUrl", exploreRule?.bookUrl, R.string.rule_book_url)) + } } setEditEntities(0) } diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt index afffb7b97..e623420f4 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt @@ -12,6 +12,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.R import io.legado.app.base.VMBaseActivity import io.legado.app.constant.AppConst +import io.legado.app.data.entities.EditEntity import io.legado.app.data.entities.RssSource import io.legado.app.lib.theme.ATH import io.legado.app.ui.widget.KeyboardToolPop @@ -28,6 +29,7 @@ class RssSourceEditActivity : private var mIsSoftKeyBoardShowing = false private lateinit var adapter: RssSourceEditAdapter + private val sourceEntities: ArrayList = ArrayList() override val viewModel: RssSourceEditViewModel get() = getViewModel(RssSourceEditViewModel::class.java) @@ -69,6 +71,33 @@ class RssSourceEditActivity : } private fun upRecyclerView(rssSource: RssSource?) { + sourceEntities.clear() + sourceEntities.apply { + add(EditEntity("sourceName", rssSource?.sourceName, R.string.rss_source_name)) + add(EditEntity("sourceUrl", rssSource?.sourceUrl, R.string.rss_source_url)) + add(EditEntity("iconUrl", rssSource?.iconUrl, R.string.rss_source_icon)) + add(EditEntity("ruleTitle", rssSource?.ruleTitle, R.string.rss_rule_title)) + add(EditEntity("ruleAuthor", rssSource?.ruleAuthor, R.string.rss_rule_author)) + add(EditEntity("ruleGuid", rssSource?.ruleGuid, R.string.rss_rule_guid)) + add(EditEntity("rulePubDate", rssSource?.rulePubDate, R.string.rss_rule_date)) + add( + EditEntity( + "ruleCategories", + rssSource?.ruleCategories, + R.string.rss_rule_categories + ) + ) + add( + EditEntity( + "ruleDescription", + rssSource?.ruleDescription, + R.string.rss_rule_description + ) + ) + add(EditEntity("ruleImage", rssSource?.ruleImage, R.string.rss_rule_image)) + add(EditEntity("ruleContent", rssSource?.ruleContent, R.string.rss_rule_content)) + add(EditEntity("ruleLink", rssSource?.ruleLink, R.string.rss_rule_link)) + } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2b3bceac2..990597367 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -375,6 +375,21 @@ 正文下一页URL规则(nextContentUrl) + + 名称 + url + 图标 + 标题 + 作者 + guid + 时间 + 类别 + 描述 + 图片url + 内容 + 链接 + + 没有书源 书籍信息获取失败 From 2dc2d6728b89d35faff01a2af9956d8ffdac9be0 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 1 Oct 2019 22:39:30 +0800 Subject: [PATCH 1727/1997] up --- .../ui/book/source/edit/SourceEditActivity.kt | 144 ++++++++---------- .../rss/source/edit/RssSourceEditActivity.kt | 39 +++++ .../rss/source/edit/RssSourceEditViewModel.kt | 8 +- 3 files changed, 111 insertions(+), 80 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditActivity.kt index c7e6dbbf5..8e3f1c940 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditActivity.kt @@ -79,20 +79,14 @@ class SourceEditActivity : override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { R.id.menu_save -> { - val bookSource = getSource() - if (bookSource == null) { - toast("书源名称和URL不能为空") - } else { - viewModel.save(bookSource) { setResult(Activity.RESULT_OK); finish() } + getSource()?.let { + viewModel.save(it) { setResult(Activity.RESULT_OK); finish() } } } R.id.menu_debug_source -> { - val bookSource = getSource() - if (bookSource == null) { - toast("书源名称和URL不能为空") - } else { - viewModel.save(bookSource) { - startActivity(Pair("key", bookSource.bookSourceUrl)) + getSource()?.let { + viewModel.save(it) { + startActivity(Pair("key", it.bookSourceUrl)) } } } @@ -249,84 +243,76 @@ class SourceEditActivity : val bookInfoRule = BookInfoRule() val tocRule = TocRule() val contentRule = ContentRule() - for (entity in sourceEntities) { - with(entity) { - when (key) { - "bookSourceUrl" -> value?.let { source.bookSourceUrl = it } ?: return null - "bookSourceName" -> value?.let { source.bookSourceName = it } ?: return null - "bookSourceGroup" -> source.bookSourceGroup = value - "loginUrl" -> source.loginUrl = value - "bookUrlPattern" -> source.bookUrlPattern = value - "header" -> source.header = value - } + sourceEntities.forEach { + when (it.key) { + "bookSourceUrl" -> source.bookSourceUrl = it.value ?: "" + "bookSourceName" -> source.bookSourceName = it.value ?: "" + "bookSourceGroup" -> source.bookSourceGroup = it.value + "loginUrl" -> source.loginUrl = it.value + "bookUrlPattern" -> source.bookUrlPattern = it.value + "header" -> source.header = it.value } } - for (entity in searchEntities) { - with(entity) { - when (key) { - "searchUrl" -> source.searchUrl = value - "bookList" -> searchRule.bookList = value - "name" -> searchRule.name = value - "author" -> searchRule.author = value - "kind" -> searchRule.kind = value - "intro" -> searchRule.intro = value - "updateTime" -> searchRule.updateTime = value - "wordCount" -> searchRule.wordCount = value - "lastChapter" -> searchRule.lastChapter = value - "coverUrl" -> searchRule.coverUrl = value - "bookUrl" -> searchRule.bookUrl = value - } + if (source.bookSourceUrl.isBlank() || source.bookSourceName.isBlank()) { + toast("书源名称和URL不能为空") + return null + } + searchEntities.forEach { + when (it.key) { + "searchUrl" -> source.searchUrl = it.value + "bookList" -> searchRule.bookList = it.value + "name" -> searchRule.name = it.value + "author" -> searchRule.author = it.value + "kind" -> searchRule.kind = it.value + "intro" -> searchRule.intro = it.value + "updateTime" -> searchRule.updateTime = it.value + "wordCount" -> searchRule.wordCount = it.value + "lastChapter" -> searchRule.lastChapter = it.value + "coverUrl" -> searchRule.coverUrl = it.value + "bookUrl" -> searchRule.bookUrl = it.value } } - for (entity in findEntities) { - with(entity) { - when (key) { - "exploreUrl" -> source.exploreUrl = value - "bookList" -> exploreRule.bookList = value - "name" -> exploreRule.name = value - "author" -> exploreRule.author = value - "kind" -> exploreRule.kind = value - "intro" -> exploreRule.intro = value - "updateTime" -> exploreRule.updateTime = value - "wordCount" -> exploreRule.wordCount = value - "lastChapter" -> exploreRule.lastChapter = value - "coverUrl" -> exploreRule.coverUrl = value - "bookUrl" -> exploreRule.bookUrl = value - } + findEntities.forEach { + when (it.key) { + "exploreUrl" -> source.exploreUrl = it.value + "bookList" -> exploreRule.bookList = it.value + "name" -> exploreRule.name = it.value + "author" -> exploreRule.author = it.value + "kind" -> exploreRule.kind = it.value + "intro" -> exploreRule.intro = it.value + "updateTime" -> exploreRule.updateTime = it.value + "wordCount" -> exploreRule.wordCount = it.value + "lastChapter" -> exploreRule.lastChapter = it.value + "coverUrl" -> exploreRule.coverUrl = it.value + "bookUrl" -> exploreRule.bookUrl = it.value } } - for (entity in infoEntities) { - with(entity) { - when (key) { - "init" -> bookInfoRule.init = value - "name" -> bookInfoRule.name = value - "author" -> bookInfoRule.author = value - "kind" -> bookInfoRule.kind = value - "intro" -> bookInfoRule.intro = value - "updateTime" -> bookInfoRule.updateTime = value - "wordCount" -> bookInfoRule.wordCount = value - "lastChapter" -> bookInfoRule.lastChapter = value - "coverUrl" -> bookInfoRule.coverUrl = value - "tocUrl" -> bookInfoRule.tocUrl = value - } + infoEntities.forEach { + when (it.key) { + "init" -> bookInfoRule.init = it.value + "name" -> bookInfoRule.name = it.value + "author" -> bookInfoRule.author = it.value + "kind" -> bookInfoRule.kind = it.value + "intro" -> bookInfoRule.intro = it.value + "updateTime" -> bookInfoRule.updateTime = it.value + "wordCount" -> bookInfoRule.wordCount = it.value + "lastChapter" -> bookInfoRule.lastChapter = it.value + "coverUrl" -> bookInfoRule.coverUrl = it.value + "tocUrl" -> bookInfoRule.tocUrl = it.value } } - for (entity in tocEntities) { - with(entity) { - when (key) { - "chapterList" -> tocRule.chapterList = value - "chapterName" -> tocRule.chapterName = value - "chapterUrl" -> tocRule.chapterUrl = value - "nextTocUrl" -> tocRule.nextTocUrl = value - } + tocEntities.forEach { + when (it.key) { + "chapterList" -> tocRule.chapterList = it.value + "chapterName" -> tocRule.chapterName = it.value + "chapterUrl" -> tocRule.chapterUrl = it.value + "nextTocUrl" -> tocRule.nextTocUrl = it.value } } - for (entity in contentEntities) { - with(entity) { - when (key) { - "content" -> contentRule.content = value - "nextContentUrl" -> contentRule.nextContentUrl = value - } + contentEntities.forEach { + when (it.key) { + "content" -> contentRule.content = it.value + "nextContentUrl" -> contentRule.nextContentUrl = it.value } } source.ruleSearch = GSON.toJson(searchRule) diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt index e623420f4..cfee144db 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt @@ -1,9 +1,11 @@ package io.legado.app.ui.rss.source.edit +import android.app.Activity import android.graphics.Rect import android.os.Bundle import android.view.Gravity import android.view.Menu +import android.view.MenuItem import android.view.ViewTreeObserver import android.widget.EditText import android.widget.PopupWindow @@ -62,6 +64,20 @@ class RssSourceEditActivity : return super.onCompatCreateOptionsMenu(menu) } + override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.menu_save -> { + getRssSource()?.let { + viewModel.save(it) { + setResult(Activity.RESULT_OK) + finish() + } + } + } + } + return super.onCompatOptionsItemSelected(item) + } + private fun initView() { ATH.applyEdgeEffectColor(recycler_view) mSoftKeyboardTool = KeyboardToolPop(this, AppConst.keyboardToolChars, this) @@ -98,7 +114,30 @@ class RssSourceEditActivity : add(EditEntity("ruleContent", rssSource?.ruleContent, R.string.rss_rule_content)) add(EditEntity("ruleLink", rssSource?.ruleLink, R.string.rss_rule_link)) } + } + private fun getRssSource(): RssSource? { + val source = viewModel.sourceLiveData.value ?: RssSource() + sourceEntities.forEach { + when (it.key) { + "sourceName" -> source.sourceName = it.value ?: "" + "sourceUrl" -> source.sourceName = it.value ?: "" + "iconUrl" -> source.sourceName = it.value ?: "" + "ruleTitle" -> source.sourceName = it.value ?: "" + "ruleAuthor" -> source.sourceName = it.value ?: "" + "ruleGuid" -> source.sourceName = it.value ?: "" + "rulePubDate" -> source.sourceName = it.value ?: "" + "ruleCategories" -> source.sourceName = it.value ?: "" + "ruleDescription" -> source.sourceName = it.value ?: "" + "ruleImage" -> source.sourceName = it.value ?: "" + "ruleContent" -> source.sourceName = it.value ?: "" + "ruleLink" -> source.sourceName = it.value ?: "" + } + } + if (source.sourceName.isBlank() || source.sourceName.isBlank()) { + return null + } + return source } override fun sendText(text: String) { diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt index 53f7d01de..6d089a865 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt @@ -18,5 +18,11 @@ class RssSourceEditViewModel(application: Application) : BaseViewModel(applicati } } - + fun save(rssSource: RssSource, success: (() -> Unit)) { + execute { + App.db.rssSourceDao().insert(rssSource) + }.onSuccess { + success() + } + } } \ No newline at end of file From 54320528ddc6ce9935a68d44ce5d053f07606deb Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 1 Oct 2019 22:44:42 +0800 Subject: [PATCH 1728/1997] up --- .../rss/source/edit/RssSourceEditActivity.kt | 20 +++++++++++++++++++ .../rss/source/edit/RssSourceEditViewModel.kt | 18 +++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt index cfee144db..023aee11c 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt @@ -1,6 +1,9 @@ package io.legado.app.ui.rss.source.edit import android.app.Activity +import android.content.ClipData +import android.content.ClipboardManager +import android.content.Context import android.graphics.Rect import android.os.Bundle import android.view.Gravity @@ -17,10 +20,13 @@ import io.legado.app.constant.AppConst import io.legado.app.data.entities.EditEntity import io.legado.app.data.entities.RssSource import io.legado.app.lib.theme.ATH +import io.legado.app.ui.book.source.debug.SourceDebugActivity import io.legado.app.ui.widget.KeyboardToolPop +import io.legado.app.utils.GSON import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_book_source_edit.* import org.jetbrains.anko.displayMetrics +import org.jetbrains.anko.startActivity import kotlin.math.abs class RssSourceEditActivity : @@ -74,6 +80,20 @@ class RssSourceEditActivity : } } } + R.id.menu_debug_source -> { + getRssSource()?.let { + viewModel.save(it) { + startActivity(Pair("key", it.sourceUrl)) + } + } + } + R.id.menu_copy_source -> { + GSON.toJson(getRssSource())?.let { sourceStr -> + val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager? + clipboard?.primaryClip = ClipData.newPlainText(null, sourceStr) + } + } + R.id.menu_paste_source -> viewModel.pasteSource() } return super.onCompatOptionsItemSelected(item) } diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt index 6d089a865..b4c0133a8 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt @@ -1,10 +1,14 @@ package io.legado.app.ui.rss.source.edit import android.app.Application +import android.content.ClipboardManager +import android.content.Context import androidx.lifecycle.MutableLiveData import io.legado.app.App import io.legado.app.base.BaseViewModel import io.legado.app.data.entities.RssSource +import io.legado.app.utils.GSON +import io.legado.app.utils.fromJsonObject class RssSourceEditViewModel(application: Application) : BaseViewModel(application) { @@ -25,4 +29,18 @@ class RssSourceEditViewModel(application: Application) : BaseViewModel(applicati success() } } + + fun pasteSource() { + execute { + val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager? + clipboard?.primaryClip?.let { + if (it.itemCount > 0) { + val json = it.getItemAt(0).text.toString() + GSON.fromJsonObject(json)?.let { source -> + sourceLiveData.postValue(source) + } ?: toast("格式不对") + } + } + } + } } \ No newline at end of file From ecd264bac724157dbf178ae15fb9488292db25c0 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 1 Oct 2019 22:47:53 +0800 Subject: [PATCH 1729/1997] up --- app/src/main/AndroidManifest.xml | 1 + .../ui/rss/source/debug/RssSourceDebugActivity.kt | 14 ++++++++++++++ .../ui/rss/source/edit/RssSourceEditActivity.kt | 4 ++-- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 96e2b7ea2..928c4d99d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -70,6 +70,7 @@ + diff --git a/app/src/main/java/io/legado/app/ui/rss/source/debug/RssSourceDebugActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/debug/RssSourceDebugActivity.kt index de8bf27dc..0c55e2270 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/debug/RssSourceDebugActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/debug/RssSourceDebugActivity.kt @@ -1,2 +1,16 @@ package io.legado.app.ui.rss.source.debug +import android.os.Bundle +import io.legado.app.R +import io.legado.app.base.BaseActivity + + +class RssSourceDebugActivity : BaseActivity(R.layout.activity_book_source_debug, false) { + + + override fun onActivityCreated(savedInstanceState: Bundle?) { + + } + + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt index 023aee11c..9fd580e9c 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt @@ -20,7 +20,7 @@ import io.legado.app.constant.AppConst import io.legado.app.data.entities.EditEntity import io.legado.app.data.entities.RssSource import io.legado.app.lib.theme.ATH -import io.legado.app.ui.book.source.debug.SourceDebugActivity +import io.legado.app.ui.rss.source.debug.RssSourceDebugActivity import io.legado.app.ui.widget.KeyboardToolPop import io.legado.app.utils.GSON import io.legado.app.utils.getViewModel @@ -83,7 +83,7 @@ class RssSourceEditActivity : R.id.menu_debug_source -> { getRssSource()?.let { viewModel.save(it) { - startActivity(Pair("key", it.sourceUrl)) + startActivity(Pair("key", it.sourceUrl)) } } } From 3fe9d763c9b864aca507fa6c393604b3f4e9dd12 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 1 Oct 2019 22:49:29 +0800 Subject: [PATCH 1730/1997] up --- .../io/legado/app/ui/book/source/debug/SourceDebugActivity.kt | 4 ++-- .../legado/app/ui/rss/source/debug/RssSourceDebugActivity.kt | 2 +- ...tivity_book_source_debug.xml => activity_source_debug.xml} | 0 3 files changed, 3 insertions(+), 3 deletions(-) rename app/src/main/res/layout/{activity_book_source_debug.xml => activity_source_debug.xml} (100%) diff --git a/app/src/main/java/io/legado/app/ui/book/source/debug/SourceDebugActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/debug/SourceDebugActivity.kt index b180f6b17..de2ef20e7 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/debug/SourceDebugActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/debug/SourceDebugActivity.kt @@ -12,13 +12,13 @@ import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.accentColor import io.legado.app.ui.qrcode.QrCodeActivity import io.legado.app.utils.getViewModel -import kotlinx.android.synthetic.main.activity_book_source_debug.* +import kotlinx.android.synthetic.main.activity_source_debug.* import kotlinx.android.synthetic.main.view_search.* import kotlinx.coroutines.launch import org.jetbrains.anko.startActivityForResult import org.jetbrains.anko.toast -class SourceDebugActivity : VMBaseActivity(R.layout.activity_book_source_debug) { +class SourceDebugActivity : VMBaseActivity(R.layout.activity_source_debug) { override val viewModel: SourceDebugModel get() = getViewModel(SourceDebugModel::class.java) diff --git a/app/src/main/java/io/legado/app/ui/rss/source/debug/RssSourceDebugActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/debug/RssSourceDebugActivity.kt index 0c55e2270..3018a1f1e 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/debug/RssSourceDebugActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/debug/RssSourceDebugActivity.kt @@ -5,7 +5,7 @@ import io.legado.app.R import io.legado.app.base.BaseActivity -class RssSourceDebugActivity : BaseActivity(R.layout.activity_book_source_debug, false) { +class RssSourceDebugActivity : BaseActivity(R.layout.activity_source_debug, false) { override fun onActivityCreated(savedInstanceState: Bundle?) { diff --git a/app/src/main/res/layout/activity_book_source_debug.xml b/app/src/main/res/layout/activity_source_debug.xml similarity index 100% rename from app/src/main/res/layout/activity_book_source_debug.xml rename to app/src/main/res/layout/activity_source_debug.xml From 9634cfac60fbb6aa463afd941f86d13ce2f15e4d Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 1 Oct 2019 22:58:50 +0800 Subject: [PATCH 1731/1997] up --- .../io/legado/app/ui/book/source/edit/SourceEditActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditActivity.kt index 8e3f1c940..4eb28dcea 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditActivity.kt @@ -141,7 +141,7 @@ class SourceEditActivity : } //基本信息 sourceEntities.clear() - searchEntities.apply { + sourceEntities.apply { add(EditEntity("bookSourceUrl", bookSource?.bookSourceUrl, R.string.book_source_url)) add(EditEntity("bookSourceName", bookSource?.bookSourceName, R.string.book_source_name)) add( From 0b76f7b967d7cc87e1b5901d8a07e7c689d0a212 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 1 Oct 2019 23:00:55 +0800 Subject: [PATCH 1732/1997] up --- .../io/legado/app/ui/rss/source/manage/RssSourceActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt index 047a342d4..f0052917e 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt @@ -43,7 +43,7 @@ class RssSourceActivity : VMBaseActivity(R.layout.activity_r override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { - R.id.menu_add_book_source -> startActivity() + R.id.menu_add -> startActivity() } return super.onCompatOptionsItemSelected(item) } From b3da0df8a55e61e679a6897efeb3189d54199d1b Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 1 Oct 2019 23:05:22 +0800 Subject: [PATCH 1733/1997] up --- .../io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt index 9fd580e9c..4113261fb 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt @@ -36,7 +36,7 @@ class RssSourceEditActivity : private var mSoftKeyboardTool: PopupWindow? = null private var mIsSoftKeyBoardShowing = false - private lateinit var adapter: RssSourceEditAdapter + private val adapter = RssSourceEditAdapter() private val sourceEntities: ArrayList = ArrayList() override val viewModel: RssSourceEditViewModel From 699b715f3d785cf9d2f5b86514a7e5cb68bb56fb Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 1 Oct 2019 23:06:25 +0800 Subject: [PATCH 1734/1997] up --- .../io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt index 4113261fb..79eb9552d 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt @@ -134,6 +134,7 @@ class RssSourceEditActivity : add(EditEntity("ruleContent", rssSource?.ruleContent, R.string.rss_rule_content)) add(EditEntity("ruleLink", rssSource?.ruleLink, R.string.rss_rule_link)) } + adapter.editEntities = sourceEntities } private fun getRssSource(): RssSource? { From 54bad44495afc75ff8405c408256ad48dc2b41c3 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 1 Oct 2019 23:11:23 +0800 Subject: [PATCH 1735/1997] up --- app/src/main/res/layout/activity_rss_source_edit.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/layout/activity_rss_source_edit.xml b/app/src/main/res/layout/activity_rss_source_edit.xml index 5579d3de5..d47a244de 100644 --- a/app/src/main/res/layout/activity_rss_source_edit.xml +++ b/app/src/main/res/layout/activity_rss_source_edit.xml @@ -1,6 +1,7 @@ From 0b3199e204b8178ba9260dcd49e3dc2d3d734c08 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 1 Oct 2019 23:13:48 +0800 Subject: [PATCH 1736/1997] up --- app/src/main/res/layout/activity_rss_source_edit.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/layout/activity_rss_source_edit.xml b/app/src/main/res/layout/activity_rss_source_edit.xml index d47a244de..dd2545faf 100644 --- a/app/src/main/res/layout/activity_rss_source_edit.xml +++ b/app/src/main/res/layout/activity_rss_source_edit.xml @@ -12,6 +12,7 @@ android:layout_height="wrap_content" app:contentInsetStartWithNavigation="0dp" app:displayHomeAsUp="true" + app:fitStatusBar="false" app:title="@string/rss_source_edit" /> Date: Wed, 2 Oct 2019 03:24:38 +0800 Subject: [PATCH 1737/1997] =?UTF-8?q?=E6=B5=8B=E8=AF=95RSS=E8=A7=A3?= =?UTF-8?q?=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 2 +- .../io/legado/app/constant/RSSKeywords.kt | 2 +- .../io/legado/app/ui/main/rss/RssFragment.kt | 4 + .../app/ui/rss/article/RssArticlesActivity.kt | 93 ++++++++++++++++++- .../legado/app/ui/rss/read/ReadRssActivity.kt | 18 ++-- app/src/main/res/layout/activity_read_rss.xml | 5 +- app/src/main/res/layout/fragment_rss.xml | 1 - app/src/main/res/layout/item_rss.xml | 41 +++++++- app/src/main/res/menu/main_rss.xml | 5 + 9 files changed, 153 insertions(+), 18 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 96e2b7ea2..98701bba5 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -70,7 +70,7 @@ - + diff --git a/app/src/main/java/io/legado/app/constant/RSSKeywords.kt b/app/src/main/java/io/legado/app/constant/RSSKeywords.kt index 5a4119e05..bb8d4207a 100644 --- a/app/src/main/java/io/legado/app/constant/RSSKeywords.kt +++ b/app/src/main/java/io/legado/app/constant/RSSKeywords.kt @@ -5,7 +5,7 @@ object RSSKeywords { const val RSS_ITEM = "item" const val RSS_ITEM_TITLE = "title" const val RSS_ITEM_LINK = "link" - const val RSS_ITEM_AUTHOR = "dc:creator" + const val RSS_ITEM_AUTHOR = "author" const val RSS_ITEM_CATEGORY = "category" const val RSS_ITEM_THUMBNAIL = "media:thumbnail" const val RSS_ITEM_ENCLOSURE = "enclosure" diff --git a/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt b/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt index 79c82bf1d..347b95a23 100644 --- a/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt @@ -10,6 +10,7 @@ import io.legado.app.App import io.legado.app.R import io.legado.app.base.BaseFragment import io.legado.app.lib.theme.ATH +import io.legado.app.ui.rss.article.RssArticlesActivity import io.legado.app.ui.rss.source.manage.RssSourceActivity import io.legado.app.utils.startActivity import kotlinx.android.synthetic.main.fragment_rss.* @@ -34,6 +35,9 @@ class RssFragment : BaseFragment(R.layout.fragment_rss), super.onCompatOptionsItemSelected(item) when (item.itemId) { R.id.menu_rss_config -> startActivity() + R.id.menu_rss_add -> { + startActivity() + } } } diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt index a69c70fb5..6a52df7b3 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt @@ -1,3 +1,94 @@ package io.legado.app.ui.rss.article -class RssArticlesActivity \ No newline at end of file +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.BaseAdapter +import androidx.appcompat.app.AppCompatActivity +import io.legado.app.R +import io.legado.app.data.entities.RssArticle +import io.legado.app.model.rss.RssParser +import io.legado.app.ui.rss.read.ReadRssActivity +import kotlinx.android.synthetic.main.item_rss.view.* +import org.jetbrains.anko.* +import org.jetbrains.anko.sdk27.listeners.onClick +import org.jetbrains.anko.sdk27.listeners.onItemClick +import java.net.URL + +class RssArticlesActivity : AppCompatActivity() { + val zhihu_dayli = "https://rsshub.app/zhihu/daily" + val nytimes = "https://rsshub.app/nytimes/dual" + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + var articles = mutableListOf() + val adapter = ArticleAdapter(articles, this) + verticalLayout { + val url = editText { + hint = "请输入RSS地址" + } + fun loadRss(urlString:String){ + Thread { + val xml = URL(urlString).readText() + articles = RssParser.parseXML(xml) + runOnUiThread { + adapter.articles = articles + adapter.notifyDataSetChanged() + } + }.start() + } + button("解析") { + onClick { + val urlString = url.text.toString().trim() + if(urlString != ""){ + loadRss(urlString) + } + } + } + button("知乎日报") { + onClick { + loadRss(zhihu_dayli) + } + } + button("纽约时报") { + onClick { + loadRss(nytimes) + } + } + listView { + this.adapter = adapter + onItemClick { p0, p1, p2, p3 -> + startActivity("description" to articles[p2].description) + } + } + } + } +} + +class ArticleAdapter(var articles: List, var context: Context) : BaseAdapter() { + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { + val item_rss= LayoutInflater.from(context).inflate(R.layout.item_rss, null) + val article = articles[position] + item_rss.title.text = article.title + item_rss.pub_date.text = article.pubDate + if(article.author != null && article.author != ""){ + item_rss.author.text = article.author + } else{ + item_rss.author.text = article.link + } + return item_rss + } + + override fun getItem(position: Int): Any { + return articles[position] + } + + override fun getItemId(position: Int): Long { + return 1 + } + + override fun getCount(): Int { + return articles.size + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt index 5e7972c6d..984cc0ea4 100644 --- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt @@ -1,15 +1,15 @@ package io.legado.app.ui.rss.read import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity import io.legado.app.R -import io.legado.app.base.BaseActivity - - -class ReadRssActivity : BaseActivity(R.layout.activity_read_rss) { - - override fun onActivityCreated(savedInstanceState: Bundle?) { - +import kotlinx.android.synthetic.main.activity_read_rss.* + +class ReadRssActivity : AppCompatActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_read_rss) + val s = intent.getStringExtra("description") + webView.loadData(""+s,"text/html","utf-8") } - - } \ No newline at end of file diff --git a/app/src/main/res/layout/activity_read_rss.xml b/app/src/main/res/layout/activity_read_rss.xml index d829e291c..0650007cf 100644 --- a/app/src/main/res/layout/activity_read_rss.xml +++ b/app/src/main/res/layout/activity_read_rss.xml @@ -3,5 +3,8 @@ android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> - + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_rss.xml b/app/src/main/res/layout/fragment_rss.xml index 3d9e9a4b5..f5a3b374c 100644 --- a/app/src/main/res/layout/fragment_rss.xml +++ b/app/src/main/res/layout/fragment_rss.xml @@ -11,7 +11,6 @@ android:layout_height="wrap_content" app:attachToActivity="false" app:title="@string/rss" /> - - + android:layout_height="wrap_content" + app:cardCornerRadius="2dp" + app:cardElevation="8dp"> - \ No newline at end of file + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/main_rss.xml b/app/src/main/res/menu/main_rss.xml index 9c051a1d2..f1e39cae2 100644 --- a/app/src/main/res/menu/main_rss.xml +++ b/app/src/main/res/menu/main_rss.xml @@ -2,6 +2,11 @@
    + Date: Wed, 2 Oct 2019 10:20:33 +0800 Subject: [PATCH 1738/1997] up --- .../app/ui/rss/source/edit/RssSourceEditViewModel.kt | 2 ++ app/src/main/res/values/strings.xml | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt index b4c0133a8..0f002d627 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt @@ -27,6 +27,8 @@ class RssSourceEditViewModel(application: Application) : BaseViewModel(applicati App.db.rssSourceDao().insert(rssSource) }.onSuccess { success() + }.onError { + toast(it.localizedMessage) } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 990597367..a0bb5a060 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -150,9 +150,9 @@ 新建订阅源 添加书籍 扫描 - 拷贝书源 - 粘贴书源 - 书源规则说明 + 拷贝源 + 粘贴源 + 源规则说明 检查更新 扫描二维码 扫描本地图片 @@ -406,7 +406,7 @@ header - 调试书源 + 调试源 二维码导入 扫描二维码 选中时点击可弹出菜单 From 98317208317ed4dcedd1eb0c1716de570da13643 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 2 Oct 2019 10:49:36 +0800 Subject: [PATCH 1739/1997] up --- .../io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt index 79eb9552d..2f0d601ff 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt @@ -27,6 +27,7 @@ import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_book_source_edit.* import org.jetbrains.anko.displayMetrics import org.jetbrains.anko.startActivity +import org.jetbrains.anko.toast import kotlin.math.abs class RssSourceEditActivity : @@ -156,6 +157,7 @@ class RssSourceEditActivity : } } if (source.sourceName.isBlank() || source.sourceName.isBlank()) { + toast("名称或url不能为空") return null } return source From 6953feef0d920a3d095088e2541e739e749e2d0a Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 2 Oct 2019 10:51:24 +0800 Subject: [PATCH 1740/1997] up --- .../rss/source/edit/RssSourceEditActivity.kt | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt index 2f0d601ff..bb3e493ec 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt @@ -143,17 +143,17 @@ class RssSourceEditActivity : sourceEntities.forEach { when (it.key) { "sourceName" -> source.sourceName = it.value ?: "" - "sourceUrl" -> source.sourceName = it.value ?: "" - "iconUrl" -> source.sourceName = it.value ?: "" - "ruleTitle" -> source.sourceName = it.value ?: "" - "ruleAuthor" -> source.sourceName = it.value ?: "" - "ruleGuid" -> source.sourceName = it.value ?: "" - "rulePubDate" -> source.sourceName = it.value ?: "" - "ruleCategories" -> source.sourceName = it.value ?: "" - "ruleDescription" -> source.sourceName = it.value ?: "" - "ruleImage" -> source.sourceName = it.value ?: "" - "ruleContent" -> source.sourceName = it.value ?: "" - "ruleLink" -> source.sourceName = it.value ?: "" + "sourceUrl" -> source.sourceUrl = it.value ?: "" + "iconUrl" -> source.iconUrl = it.value ?: "" + "ruleTitle" -> source.ruleTitle = it.value ?: "" + "ruleAuthor" -> source.ruleAuthor = it.value ?: "" + "ruleGuid" -> source.ruleGuid = it.value ?: "" + "rulePubDate" -> source.rulePubDate = it.value ?: "" + "ruleCategories" -> source.ruleCategories = it.value ?: "" + "ruleDescription" -> source.ruleDescription = it.value ?: "" + "ruleImage" -> source.ruleImage = it.value ?: "" + "ruleContent" -> source.ruleContent = it.value ?: "" + "ruleLink" -> source.ruleLink = it.value ?: "" } } if (source.sourceName.isBlank() || source.sourceName.isBlank()) { From f1e9345c47e18ce89c8abea861b9e5ba089de04d Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 2 Oct 2019 11:08:01 +0800 Subject: [PATCH 1741/1997] up --- .../book/source/manage/BookSourceActivity.kt | 5 +-- .../app/ui/rss/source/manage/DiffCallBack.kt | 41 +++++++++++++++++++ .../ui/rss/source/manage/RssSourceActivity.kt | 18 ++++++++ 3 files changed, 60 insertions(+), 4 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/rss/source/manage/DiffCallBack.kt diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt index 6dfc8f3a2..81364c11e 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt @@ -136,10 +136,7 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity bookSourceLiveDate?.observe(this, Observer { search_view.queryHint = getString(R.string.search_book_source_num, it.size) val diffResult = DiffUtil.calculateDiff( - DiffCallBack( - adapter.getItems(), - it - ) + DiffCallBack(adapter.getItems(), it) ) adapter.setItemsNoNotify(it) diffResult.dispatchUpdatesTo(adapter) diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/DiffCallBack.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/DiffCallBack.kt new file mode 100644 index 000000000..4260febe4 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/DiffCallBack.kt @@ -0,0 +1,41 @@ +package io.legado.app.ui.rss.source.manage + +import androidx.recyclerview.widget.DiffUtil +import io.legado.app.data.entities.RssSource + +class DiffCallBack( + private val oldItems: List, + private val newItems: List +) : DiffUtil.Callback() { + + override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { + val oldItem = oldItems[oldItemPosition] + val newItem = newItems[newItemPosition] + return oldItem.sourceUrl == newItem.sourceUrl + } + + override fun getOldListSize(): Int { + return oldItems.size + } + + override fun getNewListSize(): Int { + return newItems.size + } + + override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { + val oldItem = oldItems[oldItemPosition] + val newItem = newItems[newItemPosition] + return oldItem.sourceName == newItem.sourceName + && oldItem.enabled == newItem.enabled + } + + override fun getChangePayload(oldItemPosition: Int, newItemPosition: Int): Any? { + val oldItem = oldItems[oldItemPosition] + val newItem = newItems[newItemPosition] + return when { + oldItem.sourceName == newItem.sourceName + && oldItem.enabled != newItem.enabled -> 2 + else -> null + } + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt index f0052917e..09eb27e39 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt @@ -5,9 +5,13 @@ import android.view.Menu import android.view.MenuItem import androidx.appcompat.widget.SearchView import androidx.core.content.ContextCompat +import androidx.lifecycle.LiveData +import androidx.lifecycle.Observer +import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager +import io.legado.app.App import io.legado.app.R import io.legado.app.base.VMBaseActivity import io.legado.app.data.entities.RssSource @@ -29,11 +33,13 @@ class RssSourceActivity : VMBaseActivity(R.layout.activity_r get() = getViewModel(RssSourceViewModel::class.java) private lateinit var adapter: RssSourceAdapter + private var sourceLiveData: LiveData>? = null override fun onActivityCreated(savedInstanceState: Bundle?) { setSupportActionBar(toolbar) initRecyclerView() initSearchView() + initData() } override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { @@ -81,6 +87,18 @@ class RssSourceActivity : VMBaseActivity(R.layout.activity_r }) } + private fun initData() { + sourceLiveData?.removeObservers(this) + sourceLiveData = App.db.rssSourceDao().liveAll() + sourceLiveData?.observe(this, Observer { + val diffResult = DiffUtil.calculateDiff( + DiffCallBack(adapter.getItems(), it) + ) + adapter.setItemsNoNotify(it) + diffResult.dispatchUpdatesTo(adapter) + }) + } + override fun del(source: RssSource) { } From 89512c0db8a77debf26e7608e87078ac0742875d Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 2 Oct 2019 11:08:58 +0800 Subject: [PATCH 1742/1997] up --- .../legado/app/ui/book/source/manage/BookSourceActivity.kt | 5 ++--- .../io/legado/app/ui/rss/source/manage/RssSourceActivity.kt | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt index 81364c11e..258e8b52d 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt @@ -135,9 +135,8 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity } bookSourceLiveDate?.observe(this, Observer { search_view.queryHint = getString(R.string.search_book_source_num, it.size) - val diffResult = DiffUtil.calculateDiff( - DiffCallBack(adapter.getItems(), it) - ) + val diffResult = DiffUtil + .calculateDiff(DiffCallBack(adapter.getItems(), it)) adapter.setItemsNoNotify(it) diffResult.dispatchUpdatesTo(adapter) }) diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt index 09eb27e39..0a2c2f0bd 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt @@ -91,9 +91,8 @@ class RssSourceActivity : VMBaseActivity(R.layout.activity_r sourceLiveData?.removeObservers(this) sourceLiveData = App.db.rssSourceDao().liveAll() sourceLiveData?.observe(this, Observer { - val diffResult = DiffUtil.calculateDiff( - DiffCallBack(adapter.getItems(), it) - ) + val diffResult = DiffUtil + .calculateDiff(DiffCallBack(adapter.getItems(), it)) adapter.setItemsNoNotify(it) diffResult.dispatchUpdatesTo(adapter) }) From 0d127074c954da1d5a4048c01270efd6972d52a7 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 2 Oct 2019 11:12:03 +0800 Subject: [PATCH 1743/1997] up --- .../io/legado/app/ui/rss/source/manage/RssSourceAdapter.kt | 4 ++++ app/src/main/res/layout/item_rss_source.xml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceAdapter.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceAdapter.kt index 85aebdb18..35492aa48 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceAdapter.kt @@ -6,13 +6,17 @@ import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.data.entities.RssSource import io.legado.app.help.ItemTouchCallback +import kotlinx.android.synthetic.main.item_rss_source.view.* class RssSourceAdapter(context: Context, val callBack: CallBack) : SimpleRecyclerAdapter(context, R.layout.item_rss_source), ItemTouchCallback.OnItemTouchCallbackListener { override fun convert(holder: ItemViewHolder, item: RssSource, payloads: MutableList) { + with(holder.itemView) { + cb_source.text = item.sourceName + } } diff --git a/app/src/main/res/layout/item_rss_source.xml b/app/src/main/res/layout/item_rss_source.xml index 7d9513d98..d0ecd8788 100644 --- a/app/src/main/res/layout/item_rss_source.xml +++ b/app/src/main/res/layout/item_rss_source.xml @@ -9,7 +9,7 @@ android:padding="16dp"> Date: Wed, 2 Oct 2019 11:48:20 +0800 Subject: [PATCH 1744/1997] up --- .../io/legado/app/data/dao/RssSourceDao.kt | 9 +++ .../io/legado/app/data/entities/RssSource.kt | 5 +- .../rss/source/edit/RssSourceEditActivity.kt | 24 +++--- .../ui/rss/source/manage/RssSourceActivity.kt | 7 +- .../ui/rss/source/manage/RssSourceAdapter.kt | 77 ++++++++++++++++++- .../rss/source/manage/RssSourceViewModel.kt | 18 +++++ app/src/main/res/values/strings.xml | 1 + 7 files changed, 125 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt b/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt index d6b2d7767..e931f25d7 100644 --- a/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt @@ -22,6 +22,15 @@ interface RssSourceDao { @Insert(onConflict = OnConflictStrategy.REPLACE) fun insert(vararg rssSource: RssSource) + @Query("update rssSources set enabled = 1 where sourceUrl in (:sourceUrls)") + fun enableSection(vararg sourceUrls: String) + + @Query("update rssSources set enabled = 0 where sourceUrl in (:sourceUrls)") + fun disableSection(vararg sourceUrls: String) + + @Query("delete from rssSources where sourceUrl in (:sourceUrls)") + fun delSection(vararg sourceUrls: String) + @Update fun update(vararg rssSource: RssSource) diff --git a/app/src/main/java/io/legado/app/data/entities/RssSource.kt b/app/src/main/java/io/legado/app/data/entities/RssSource.kt index d17ab598d..f15a14696 100644 --- a/app/src/main/java/io/legado/app/data/entities/RssSource.kt +++ b/app/src/main/java/io/legado/app/data/entities/RssSource.kt @@ -8,10 +8,11 @@ import kotlinx.android.parcel.Parcelize @Parcelize @Entity(tableName = "rssSources") data class RssSource( - var sourceName: String = "", @PrimaryKey var sourceUrl: String = "", - var iconUrl: String = "", + var sourceName: String = "", + var sourceIcon: String = "", + var sourceGroup: String? = null, var enabled: Boolean = true, var ruleGuid: String? = null, var ruleTitle: String? = null, diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt index bb3e493ec..0636afda6 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt @@ -112,7 +112,8 @@ class RssSourceEditActivity : sourceEntities.apply { add(EditEntity("sourceName", rssSource?.sourceName, R.string.rss_source_name)) add(EditEntity("sourceUrl", rssSource?.sourceUrl, R.string.rss_source_url)) - add(EditEntity("iconUrl", rssSource?.iconUrl, R.string.rss_source_icon)) + add(EditEntity("sourceIcon", rssSource?.sourceIcon, R.string.rss_source_icon)) + add(EditEntity("sourceGroup", rssSource?.sourceGroup, R.string.rss_source_group)) add(EditEntity("ruleTitle", rssSource?.ruleTitle, R.string.rss_rule_title)) add(EditEntity("ruleAuthor", rssSource?.ruleAuthor, R.string.rss_rule_author)) add(EditEntity("ruleGuid", rssSource?.ruleGuid, R.string.rss_rule_guid)) @@ -144,16 +145,17 @@ class RssSourceEditActivity : when (it.key) { "sourceName" -> source.sourceName = it.value ?: "" "sourceUrl" -> source.sourceUrl = it.value ?: "" - "iconUrl" -> source.iconUrl = it.value ?: "" - "ruleTitle" -> source.ruleTitle = it.value ?: "" - "ruleAuthor" -> source.ruleAuthor = it.value ?: "" - "ruleGuid" -> source.ruleGuid = it.value ?: "" - "rulePubDate" -> source.rulePubDate = it.value ?: "" - "ruleCategories" -> source.ruleCategories = it.value ?: "" - "ruleDescription" -> source.ruleDescription = it.value ?: "" - "ruleImage" -> source.ruleImage = it.value ?: "" - "ruleContent" -> source.ruleContent = it.value ?: "" - "ruleLink" -> source.ruleLink = it.value ?: "" + "sourceIcon" -> source.sourceIcon = it.value ?: "" + "sourceGroup" -> source.sourceGroup = it.value + "ruleTitle" -> source.ruleTitle = it.value + "ruleAuthor" -> source.ruleAuthor = it.value + "ruleGuid" -> source.ruleGuid = it.value + "rulePubDate" -> source.rulePubDate = it.value + "ruleCategories" -> source.ruleCategories = it.value + "ruleDescription" -> source.ruleDescription = it.value + "ruleImage" -> source.ruleImage = it.value + "ruleContent" -> source.ruleContent = it.value + "ruleLink" -> source.ruleLink = it.value } } if (source.sourceName.isBlank() || source.sourceName.isBlank()) { diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt index 0a2c2f0bd..b2d996fb2 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt @@ -50,6 +50,11 @@ class RssSourceActivity : VMBaseActivity(R.layout.activity_r override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { R.id.menu_add -> startActivity() + R.id.menu_select_all -> adapter.selectAll() + R.id.menu_revert_selection -> adapter.revertSelection() + R.id.menu_enable_selection -> viewModel.enableSelection(adapter.getSelectionIds()) + R.id.menu_disable_selection -> viewModel.disableSelection(adapter.getSelectionIds()) + R.id.menu_del_selection -> viewModel.delSelection(adapter.getSelectionIds()) } return super.onCompatOptionsItemSelected(item) } @@ -103,7 +108,7 @@ class RssSourceActivity : VMBaseActivity(R.layout.activity_r } override fun edit(source: RssSource) { - + startActivity(Pair("data", source.sourceUrl)) } override fun update(vararg source: RssSource) { diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceAdapter.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceAdapter.kt index 35492aa48..8dee3c485 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceAdapter.kt @@ -1,21 +1,94 @@ package io.legado.app.ui.rss.source.manage import android.content.Context +import android.view.Menu +import android.widget.PopupMenu import io.legado.app.R import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.data.entities.RssSource import io.legado.app.help.ItemTouchCallback +import io.legado.app.lib.theme.backgroundColor import kotlinx.android.synthetic.main.item_rss_source.view.* +import org.jetbrains.anko.sdk27.listeners.onClick class RssSourceAdapter(context: Context, val callBack: CallBack) : SimpleRecyclerAdapter(context, R.layout.item_rss_source), ItemTouchCallback.OnItemTouchCallbackListener { + private val selectedIds = linkedSetOf() + + fun selectAll() { + getItems().forEach { + selectedIds.add(it.sourceUrl) + } + notifyItemRangeChanged(0, itemCount, 1) + } + + fun revertSelection() { + getItems().forEach { + if (selectedIds.contains(it.sourceUrl)) { + selectedIds.remove(it.sourceUrl) + } else { + selectedIds.add(it.sourceUrl) + } + } + notifyItemRangeChanged(0, itemCount, 1) + } + + fun getSelectionIds(): LinkedHashSet { + val selection = linkedSetOf() + getItems().map { + if (selectedIds.contains(it.sourceUrl)) { + selection.add(it.sourceUrl) + } + } + return selection + } + override fun convert(holder: ItemViewHolder, item: RssSource, payloads: MutableList) { with(holder.itemView) { - cb_source.text = item.sourceName - + if (payloads.isEmpty()) { + this.setBackgroundColor(context.backgroundColor) + if (item.sourceGroup.isNullOrEmpty()) { + cb_source.text = item.sourceName + } else { + cb_source.text = + String.format("%s (%s)", item.sourceName, item.sourceGroup) + } + swt_enabled.isChecked = item.enabled + swt_enabled.onClick { + item.enabled = swt_enabled.isChecked + callBack.update(item) + } + cb_source.isChecked = selectedIds.contains(item.sourceUrl) + cb_source.setOnClickListener { + if (cb_source.isChecked) { + selectedIds.add(item.sourceUrl) + } else { + selectedIds.remove(item.sourceUrl) + } + } + iv_edit.onClick { callBack.edit(item) } + iv_menu_more.onClick { + val popupMenu = PopupMenu(context, it) + popupMenu.menu.add(Menu.NONE, R.id.menu_top, Menu.NONE, R.string.to_top) + popupMenu.menu.add(Menu.NONE, R.id.menu_del, Menu.NONE, R.string.delete) + popupMenu.setOnMenuItemClickListener { menuItem -> + when (menuItem.itemId) { + R.id.menu_top -> callBack.toTop(item) + R.id.menu_del -> callBack.del(item) + } + true + } + popupMenu.show() + } + } else { + when (payloads[0]) { + 1 -> cb_source.isChecked = selectedIds.contains(item.sourceUrl) + 2 -> swt_enabled.isChecked = item.enabled + } + } } } diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt index c91f73ef7..199532d72 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt @@ -1,8 +1,26 @@ package io.legado.app.ui.rss.source.manage import android.app.Application +import io.legado.app.App import io.legado.app.base.BaseViewModel class RssSourceViewModel(application: Application) : BaseViewModel(application) { + fun enableSelection(ids: LinkedHashSet) { + execute { + App.db.rssSourceDao().enableSection(*ids.toTypedArray()) + } + } + + fun disableSelection(ids: LinkedHashSet) { + execute { + App.db.rssSourceDao().disableSection(*ids.toTypedArray()) + } + } + + fun delSelection(ids: LinkedHashSet) { + execute { + App.db.rssSourceDao().delSection(*ids.toTypedArray()) + } + } } \ 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 a0bb5a060..bfe21f7a4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -379,6 +379,7 @@ 名称 url 图标 + 分组 标题 作者 guid From 34536c91c0d5d463522d309f67c1ba73343edf88 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 2 Oct 2019 12:00:56 +0800 Subject: [PATCH 1745/1997] up --- app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt b/app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt index 128fb6078..3d82b5320 100644 --- a/app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt +++ b/app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt @@ -39,8 +39,8 @@ object WebDavHelp { val url = getWebDavUrl() val names = arrayListOf() if (!url.isNullOrBlank() && initWebDav()) { - val files = WebDav(url + "legado/").listFiles() - files.reversed() + var files = WebDav(url + "legado/").listFiles() + files = files.reversed() for (index: Int in 0 until min(10, files.size)) { files[index].displayName?.let { names.add(it) From 1188b7089d487c5aeba47bb423c67ff7fa6807ef Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 2 Oct 2019 12:15:06 +0800 Subject: [PATCH 1746/1997] up --- .../io/legado/app/data/dao/BookSourceDao.kt | 4 +- .../io/legado/app/data/dao/RssSourceDao.kt | 10 ++++- .../ui/rss/source/manage/RssSourceActivity.kt | 39 +++++++++++++++++-- 3 files changed, 46 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt index 39dc91264..334bb7a82 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt @@ -11,7 +11,7 @@ interface BookSourceDao { @Query("select * from book_sources order by customOrder asc") fun liveDataAll(): LiveData> - @Query("select * from book_sources where bookSourceName like :searchKey or `bookSourceGroup` like :searchKey or bookSourceUrl like :searchKey order by customOrder asc") + @Query("select * from book_sources where bookSourceName like :searchKey or bookSourceGroup like :searchKey or bookSourceUrl like :searchKey order by customOrder asc") fun liveDataSearch(searchKey: String = ""): LiveData> @Query("select * from book_sources where enabledExplore = 1 and exploreUrl is not null and exploreUrl <> '' order by customOrder asc") @@ -23,7 +23,7 @@ interface BookSourceDao { @Query("select bookSourceGroup from book_sources where bookSourceGroup is not null and bookSourceGroup <> ''") fun liveGroup(): LiveData> - @Query("select distinct enabled from book_sources where bookSourceName like :searchKey or `bookSourceGroup` like :searchKey or bookSourceUrl like :searchKey") + @Query("select distinct enabled from book_sources where bookSourceName like :searchKey or bookSourceGroup like :searchKey or bookSourceUrl like :searchKey") fun searchIsEnable(searchKey: String = ""): List @Query("update book_sources set enabled = 1 where bookSourceUrl in (:sourceUrls)") diff --git a/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt b/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt index e931f25d7..9390b04ac 100644 --- a/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt @@ -16,11 +16,14 @@ interface RssSourceDao { @Query("SELECT * FROM rssSources") fun liveAll(): LiveData> + @Query("SELECT * FROM rssSources where sourceName like :key or sourceUrl like :key or sourceGroup like :key") + fun liveSearch(key: String): LiveData> + @Query("SELECT * FROM rssSources where enabled = 1") fun liveEnabled(): LiveData> - @Insert(onConflict = OnConflictStrategy.REPLACE) - fun insert(vararg rssSource: RssSource) + @Query("select sourceGroup from rssSources where sourceGroup is not null and sourceGroup <> ''") + fun liveGroup(): LiveData> @Query("update rssSources set enabled = 1 where sourceUrl in (:sourceUrls)") fun enableSection(vararg sourceUrls: String) @@ -31,6 +34,9 @@ interface RssSourceDao { @Query("delete from rssSources where sourceUrl in (:sourceUrls)") fun delSection(vararg sourceUrls: String) + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun insert(vararg rssSource: RssSource) + @Update fun update(vararg rssSource: RssSource) diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt index b2d996fb2..4ef9c9a0f 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt @@ -3,6 +3,7 @@ package io.legado.app.ui.rss.source.manage import android.os.Bundle import android.view.Menu import android.view.MenuItem +import android.view.SubMenu import androidx.appcompat.widget.SearchView import androidx.core.content.ContextCompat import androidx.lifecycle.LiveData @@ -20,6 +21,7 @@ import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.primaryTextColor import io.legado.app.ui.rss.source.edit.RssSourceEditActivity import io.legado.app.utils.getViewModel +import io.legado.app.utils.splitNotBlank import kotlinx.android.synthetic.main.activity_rss_source.* import kotlinx.android.synthetic.main.view_search.* import kotlinx.android.synthetic.main.view_title_bar.* @@ -34,12 +36,15 @@ class RssSourceActivity : VMBaseActivity(R.layout.activity_r private lateinit var adapter: RssSourceAdapter private var sourceLiveData: LiveData>? = null + private var groups = hashSetOf() + private var groupMenu: SubMenu? = null override fun onActivityCreated(savedInstanceState: Bundle?) { setSupportActionBar(toolbar) initRecyclerView() initSearchView() - initData() + initLiveDataGroup() + initLiveDataSource() } override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { @@ -47,6 +52,12 @@ class RssSourceActivity : VMBaseActivity(R.layout.activity_r return super.onCompatCreateOptionsMenu(menu) } + override fun onPrepareOptionsMenu(menu: Menu?): Boolean { + groupMenu = menu?.findItem(R.id.menu_group)?.subMenu + upGroupMenu() + return super.onPrepareOptionsMenu(menu) + } + override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { R.id.menu_add -> startActivity() @@ -92,9 +103,31 @@ class RssSourceActivity : VMBaseActivity(R.layout.activity_r }) } - private fun initData() { + private fun initLiveDataGroup() { + App.db.rssSourceDao().liveGroup().observe(this, Observer { + groups.clear() + it.map { group -> + groups.addAll(group.splitNotBlank(",", ";")) + } + upGroupMenu() + }) + } + + private fun upGroupMenu() { + groupMenu?.removeGroup(R.id.source_group) + groups.map { + groupMenu?.add(R.id.source_group, Menu.NONE, Menu.NONE, it) + } + } + + private fun initLiveDataSource(key: String? = null) { sourceLiveData?.removeObservers(this) - sourceLiveData = App.db.rssSourceDao().liveAll() + sourceLiveData = + if (key.isNullOrBlank()) { + App.db.rssSourceDao().liveAll() + } else { + App.db.rssSourceDao().liveSearch("%$key%") + } sourceLiveData?.observe(this, Observer { val diffResult = DiffUtil .calculateDiff(DiffCallBack(adapter.getItems(), it)) From 95b763104829d299addce01fb9e72315000224c3 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 2 Oct 2019 12:23:11 +0800 Subject: [PATCH 1747/1997] up --- .../java/io/legado/app/help/storage/Backup.kt | 40 +++++++++++++------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/storage/Backup.kt b/app/src/main/java/io/legado/app/help/storage/Backup.kt index 92333d1d3..97497a854 100644 --- a/app/src/main/java/io/legado/app/help/storage/Backup.kt +++ b/app/src/main/java/io/legado/app/help/storage/Backup.kt @@ -45,27 +45,43 @@ object Backup { } private fun backupBookshelf(path: String) { - val json = GSON.toJson(App.db.bookDao().allBooks) - val file = FileHelp.getFile(path + File.separator + "bookshelf.json") - file.writeText(json) + App.db.bookDao().allBooks.let { + if (it.isNotEmpty()) { + val json = GSON.toJson(it) + val file = FileHelp.getFile(path + File.separator + "bookshelf.json") + file.writeText(json) + } + } } private fun backupBookSource(path: String) { - val json = GSON.toJson(App.db.bookSourceDao().all) - val file = FileHelp.getFile(path + File.separator + "bookSource.json") - file.writeText(json) + App.db.bookSourceDao().all.let { + if (it.isNotEmpty()) { + val json = GSON.toJson(it) + val file = FileHelp.getFile(path + File.separator + "bookSource.json") + file.writeText(json) + } + } } private fun backupRssSource(path: String) { - val json = GSON.toJson(App.db.rssSourceDao().all) - val file = FileHelp.getFile(path + File.separator + "rssSource.json") - file.writeText(json) + App.db.rssSourceDao().all.let { + if (it.isNotEmpty()) { + val json = GSON.toJson(it) + val file = FileHelp.getFile(path + File.separator + "rssSource.json") + file.writeText(json) + } + } } private fun backupReplaceRule(path: String) { - val json = GSON.toJson(App.db.replaceRuleDao().all) - val file = FileHelp.getFile(path + File.separator + "replaceRule.json") - file.writeText(json) + App.db.replaceRuleDao().all.let { + if (it.isNotEmpty()) { + val json = GSON.toJson(it) + val file = FileHelp.getFile(path + File.separator + "replaceRule.json") + file.writeText(json) + } + } } private fun backupPreference(path: String) { From e034bb55a5d25d38b64f6a32e89477ce633bc60c Mon Sep 17 00:00:00 2001 From: mabdc <747455334@qq.com> Date: Wed, 2 Oct 2019 12:34:00 +0800 Subject: [PATCH 1748/1997] up --- app/src/main/AndroidManifest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 98701bba5..8c0318cae 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -70,6 +70,7 @@ + From c5c5aa0213adb0e6c72353c130749370e33dddb3 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 2 Oct 2019 12:58:16 +0800 Subject: [PATCH 1749/1997] up --- .../app/ui/rss/article/RssArticlesActivity.kt | 5 ++- app/src/main/res/layout/item_rss_article.xml | 45 +++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 app/src/main/res/layout/item_rss_article.xml diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt index 3686dacdf..8e1e9ac6b 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt @@ -13,8 +13,9 @@ import io.legado.app.data.entities.RssArticle import io.legado.app.model.rss.RssParser import io.legado.app.ui.rss.read.ReadRssActivity import kotlinx.android.synthetic.main.item_rss.view.* -import org.jetbrains.anko.* +import org.jetbrains.anko.listView import org.jetbrains.anko.sdk27.listeners.onItemClick +import org.jetbrains.anko.startActivity import java.net.URL class RssArticlesActivity : AppCompatActivity() { @@ -48,7 +49,7 @@ class RssArticlesActivity : AppCompatActivity() { class ArticleAdapter(var articles: MutableList, var context: Context) : BaseAdapter() { override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { - val item_rss = LayoutInflater.from(context).inflate(R.layout.item_rss, null) + val item_rss = LayoutInflater.from(context).inflate(R.layout.item_rss_article, null) val article = articles[position] item_rss.title.text = article.title item_rss.pub_date.text = article.pubDate diff --git a/app/src/main/res/layout/item_rss_article.xml b/app/src/main/res/layout/item_rss_article.xml new file mode 100644 index 000000000..d406fc228 --- /dev/null +++ b/app/src/main/res/layout/item_rss_article.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + \ No newline at end of file From dee7495f8fbaed3fbb355b335e497cd169d7d4af Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 2 Oct 2019 15:48:44 +0800 Subject: [PATCH 1750/1997] up --- app/src/main/res/layout/item_rss.xml | 54 +++++++++------------------- 1 file changed, 17 insertions(+), 37 deletions(-) diff --git a/app/src/main/res/layout/item_rss.xml b/app/src/main/res/layout/item_rss.xml index da5b52d42..532f166b7 100644 --- a/app/src/main/res/layout/item_rss.xml +++ b/app/src/main/res/layout/item_rss.xml @@ -1,44 +1,24 @@ - + android:layout_height="wrap_content"> - - + - + - - - - \ No newline at end of file + \ No newline at end of file From b37141cbf9be50efce0017381603d65db9a3c2d8 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 2 Oct 2019 16:10:03 +0800 Subject: [PATCH 1751/1997] up --- .../java/io/legado/app/ui/main/rss/RssAdapter.kt | 13 +++++++++++-- app/src/main/res/layout/item_rss.xml | 3 +++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/main/rss/RssAdapter.kt b/app/src/main/java/io/legado/app/ui/main/rss/RssAdapter.kt index 6bef664c6..a5efbf379 100644 --- a/app/src/main/java/io/legado/app/ui/main/rss/RssAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/rss/RssAdapter.kt @@ -5,15 +5,24 @@ import io.legado.app.R import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.data.entities.RssSource +import io.legado.app.help.ImageLoader +import kotlinx.android.synthetic.main.item_rss.view.* +import org.jetbrains.anko.sdk27.listeners.onClick class RssAdapter(context: Context, val callBack: CallBack) : SimpleRecyclerAdapter(context, R.layout.item_rss) { override fun convert(holder: ItemViewHolder, item: RssSource, payloads: MutableList) { - + with(holder.itemView) { + tv_name.text = item.sourceName + ImageLoader.load(context, item.sourceIcon) + .centerCrop() + .setAsBitmap(iv_icon) + onClick { callBack.openRss(item) } + } } interface CallBack { - fun openRss() + fun openRss(rssSource: RssSource) } } \ No newline at end of file diff --git a/app/src/main/res/layout/item_rss.xml b/app/src/main/res/layout/item_rss.xml index 532f166b7..1b55a8ed1 100644 --- a/app/src/main/res/layout/item_rss.xml +++ b/app/src/main/res/layout/item_rss.xml @@ -9,6 +9,8 @@ android:id="@+id/iv_icon" android:layout_width="60dp" android:layout_height="60dp" + android:src="@drawable/ic_image" + android:scaleType="centerCrop" app:layout_constraintTop_toTopOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" /> @@ -17,6 +19,7 @@ android:id="@+id/tv_name" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:layout_marginTop="16dp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@+id/iv_icon" /> From f41c2a7073d75d85e9dce26055c39b7d95b6251a Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 2 Oct 2019 16:12:43 +0800 Subject: [PATCH 1752/1997] up --- .../java/io/legado/app/ui/rss/article/RssArticlesActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt index 8e1e9ac6b..3ab686c7f 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt @@ -12,7 +12,7 @@ import io.legado.app.R import io.legado.app.data.entities.RssArticle import io.legado.app.model.rss.RssParser import io.legado.app.ui.rss.read.ReadRssActivity -import kotlinx.android.synthetic.main.item_rss.view.* +import kotlinx.android.synthetic.main.item_rss_article.view.* import org.jetbrains.anko.listView import org.jetbrains.anko.sdk27.listeners.onItemClick import org.jetbrains.anko.startActivity From 186e6c865501f39c9c221dc9d8f559fbf4f5464d Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 2 Oct 2019 16:14:05 +0800 Subject: [PATCH 1753/1997] up --- app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt b/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt index 0e0819ce5..aa3419b72 100644 --- a/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt @@ -13,6 +13,7 @@ import androidx.recyclerview.widget.GridLayoutManager import io.legado.app.App import io.legado.app.R import io.legado.app.base.BaseFragment +import io.legado.app.data.entities.RssSource import io.legado.app.lib.dialogs.alert import io.legado.app.lib.dialogs.cancelButton import io.legado.app.lib.dialogs.yesButton @@ -22,7 +23,6 @@ import io.legado.app.ui.rss.source.manage.RssSourceActivity import io.legado.app.utils.startActivity import kotlinx.android.synthetic.main.fragment_rss.* import kotlinx.android.synthetic.main.view_title_bar.* -import org.jetbrains.anko.padding class RssFragment : BaseFragment(R.layout.fragment_rss), RssAdapter.CallBack { @@ -78,7 +78,7 @@ class RssFragment : BaseFragment(R.layout.fragment_rss), }) } - override fun openRss() { + override fun openRss(rssSource: RssSource) { } } \ No newline at end of file From d6fc96ca19260b5dc0bf99d3f3adf18d94076dc6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 2 Oct 2019 16:21:41 +0800 Subject: [PATCH 1754/1997] up --- app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt | 4 ++-- .../java/io/legado/app/ui/rss/article/RssArticlesActivity.kt | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt b/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt index aa3419b72..0dddd4426 100644 --- a/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt @@ -58,7 +58,7 @@ class RssFragment : BaseFragment(R.layout.fragment_rss), } yesButton{ Log.i("RSS","Quick Add URL: ${urlEdit.text}") - startActivity("QuickAddURL" to urlEdit.text.toString().trim()) + startActivity("url" to urlEdit.text.toString().trim()) } }.show() } @@ -79,6 +79,6 @@ class RssFragment : BaseFragment(R.layout.fragment_rss), } override fun openRss(rssSource: RssSource) { - + startActivity(Pair("url", rssSource.sourceUrl)) } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt index 3ab686c7f..3590627a1 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt @@ -21,9 +21,9 @@ import java.net.URL class RssArticlesActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - if (intent.hasExtra("QuickAddURL")) { + if (intent.hasExtra("url")) { // 处理从 快速添加并预览 跳转到这个页面 - val urlString = intent.getStringExtra("QuickAddURL") + val urlString = intent.getStringExtra("url") val adapter = ArticleAdapter(mutableListOf(), this) listView { this.adapter = adapter From 8a284c2b04a34bc106f2485dffcdc2831e7cfbd1 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 2 Oct 2019 16:50:09 +0800 Subject: [PATCH 1755/1997] up --- .../java/io/legado/app/data/AppDatabase.kt | 3 +- .../io/legado/app/data/dao/RssArticleDao.kt | 14 +++ .../app/ui/rss/article/RssArticlesActivity.kt | 91 ++++++------------- .../app/ui/rss/article/RssArticlesAdapter.kt | 27 ++++++ .../ui/rss/article/RssArticlesViewModel.kt | 10 ++ .../main/res/layout/activity_rss_artivles.xml | 26 ++++++ 6 files changed, 109 insertions(+), 62 deletions(-) create mode 100644 app/src/main/java/io/legado/app/data/dao/RssArticleDao.kt create mode 100644 app/src/main/java/io/legado/app/ui/rss/article/RssArticlesAdapter.kt create mode 100644 app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt create mode 100644 app/src/main/res/layout/activity_rss_artivles.xml diff --git a/app/src/main/java/io/legado/app/data/AppDatabase.kt b/app/src/main/java/io/legado/app/data/AppDatabase.kt index d58a5ccb7..3b17435d5 100644 --- a/app/src/main/java/io/legado/app/data/AppDatabase.kt +++ b/app/src/main/java/io/legado/app/data/AppDatabase.kt @@ -12,7 +12,7 @@ import io.legado.app.data.entities.* @Database( entities = [Book::class, BookGroup::class, BookSource::class, BookChapter::class, ReplaceRule::class, SearchBook::class, - SearchKeyword::class, SourceCookie::class, RssSource::class, Bookmark::class], + SearchKeyword::class, SourceCookie::class, RssSource::class, Bookmark::class, RssArticle::class], version = 1, exportSchema = true ) @@ -58,4 +58,5 @@ abstract class AppDatabase : RoomDatabase() { abstract fun sourceCookieDao(): SourceCookieDao abstract fun rssSourceDao(): RssSourceDao abstract fun bookmarkDao(): BookmarkDao + abstract fun rssArtivleDao(): RssArticleDao } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/data/dao/RssArticleDao.kt b/app/src/main/java/io/legado/app/data/dao/RssArticleDao.kt new file mode 100644 index 000000000..5935d76ce --- /dev/null +++ b/app/src/main/java/io/legado/app/data/dao/RssArticleDao.kt @@ -0,0 +1,14 @@ +package io.legado.app.data.dao + +import androidx.lifecycle.LiveData +import androidx.room.Query +import io.legado.app.data.entities.RssArticle + +interface RssArticleDao { + + + @Query("select * from rssArticles where origin = :origin") + fun liveByOrigin(origin: String): LiveData> + + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt index 3590627a1..9df7a3aeb 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt @@ -1,75 +1,44 @@ package io.legado.app.ui.rss.article -import android.app.ProgressDialog -import android.content.Context import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.BaseAdapter -import androidx.appcompat.app.AppCompatActivity +import androidx.lifecycle.LiveData +import androidx.lifecycle.Observer +import androidx.recyclerview.widget.LinearLayoutManager +import io.legado.app.App import io.legado.app.R +import io.legado.app.base.VMBaseActivity import io.legado.app.data.entities.RssArticle -import io.legado.app.model.rss.RssParser -import io.legado.app.ui.rss.read.ReadRssActivity -import kotlinx.android.synthetic.main.item_rss_article.view.* -import org.jetbrains.anko.listView -import org.jetbrains.anko.sdk27.listeners.onItemClick -import org.jetbrains.anko.startActivity -import java.net.URL +import io.legado.app.lib.theme.ATH +import io.legado.app.utils.getViewModel +import kotlinx.android.synthetic.main.activity_rss_artivles.* -class RssArticlesActivity : AppCompatActivity() { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - if (intent.hasExtra("url")) { - // 处理从 快速添加并预览 跳转到这个页面 - val urlString = intent.getStringExtra("url") - val adapter = ArticleAdapter(mutableListOf(), this) - listView { - this.adapter = adapter - onItemClick { p0, p1, p2, p3 -> - startActivity("description" to adapter.articles[p2].description) - } - } - val loading = ProgressDialog(this@RssArticlesActivity) - loading.setMessage("加载中...") - loading.show() - Thread { - val xml = URL(urlString).readText() - val articles = RssParser.parseXML(xml) - runOnUiThread { - adapter.articles = articles - adapter.notifyDataSetChanged() - loading.dismiss() - } - }.start() - } - } -} +class RssArticlesActivity : VMBaseActivity(R.layout.activity_rss_artivles) { -class ArticleAdapter(var articles: MutableList, var context: Context) : BaseAdapter() { - override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { - val item_rss = LayoutInflater.from(context).inflate(R.layout.item_rss_article, null) - val article = articles[position] - item_rss.title.text = article.title - item_rss.pub_date.text = article.pubDate - if (article.author != null && article.author != "") { - item_rss.author.text = article.author - } else { - item_rss.author.text = article.link - } - return item_rss - } + override val viewModel: RssArticlesViewModel + get() = getViewModel(RssArticlesViewModel::class.java) + + private var adapter: RssArticlesAdapter? = null + private var rssArticlesData: LiveData>? = null - override fun getItem(position: Int): Any { - return articles[position] + override fun onActivityCreated(savedInstanceState: Bundle?) { + initView() + intent.getStringExtra("url")?.let { + initData(it) + } } - override fun getItemId(position: Int): Long { - return 1 + private fun initView() { + ATH.applyEdgeEffectColor(recycler_view) + recycler_view.layoutManager = LinearLayoutManager(this) + adapter = RssArticlesAdapter(this) + recycler_view.adapter = adapter } - override fun getCount(): Int { - return articles.size + private fun initData(origin: String) { + rssArticlesData?.removeObservers(this) + rssArticlesData = App.db.rssArtivleDao().liveByOrigin(origin) + rssArticlesData?.observe(this, Observer { + adapter?.setItems(it) + }) } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesAdapter.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesAdapter.kt new file mode 100644 index 000000000..0e185ab22 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesAdapter.kt @@ -0,0 +1,27 @@ +package io.legado.app.ui.rss.article + +import android.content.Context +import io.legado.app.R +import io.legado.app.base.adapter.ItemViewHolder +import io.legado.app.base.adapter.SimpleRecyclerAdapter +import io.legado.app.data.entities.RssArticle +import kotlinx.android.synthetic.main.item_rss_article.view.* + + +class RssArticlesAdapter(context: Context) : + SimpleRecyclerAdapter(context, R.layout.item_rss_article) { + + override fun convert(holder: ItemViewHolder, item: RssArticle, payloads: MutableList) { + with(holder.itemView) { + title.text = item.title + pub_date.text = item.pubDate + if (item.author.isNullOrBlank()) { + author.text = item.link + } else { + author.text = item.author + } + } + } + + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt new file mode 100644 index 000000000..344b1d098 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt @@ -0,0 +1,10 @@ +package io.legado.app.ui.rss.article + +import android.app.Application +import io.legado.app.base.BaseViewModel + + +class RssArticlesViewModel(application: Application) : BaseViewModel(application) { + + +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_rss_artivles.xml b/app/src/main/res/layout/activity_rss_artivles.xml new file mode 100644 index 000000000..5665c8a24 --- /dev/null +++ b/app/src/main/res/layout/activity_rss_artivles.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + \ No newline at end of file From f40c386ed29ca1e704ba3d00c46fc7bb6b388a3d Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 2 Oct 2019 16:52:45 +0800 Subject: [PATCH 1756/1997] up --- .../legado/app/ui/book/read/ReadBookActivity.kt | 4 ++-- .../app/ui/book/read/config/ReadStyleDialog.kt | 2 +- .../io/legado/app/ui/rss/read/ReadRssActivity.kt | 4 ++-- ...vity_read_book.xml => activity_book_read.xml} | 0 app/src/main/res/layout/activity_read_rss.xml | 10 ---------- app/src/main/res/layout/activity_rss_read.xml | 16 ++++++++++++++++ 6 files changed, 21 insertions(+), 15 deletions(-) rename app/src/main/res/layout/{activity_read_book.xml => activity_book_read.xml} (100%) delete mode 100644 app/src/main/res/layout/activity_read_rss.xml create mode 100644 app/src/main/res/layout/activity_rss_read.xml diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt index 2a3bf10a6..3b2400e56 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt @@ -42,7 +42,7 @@ import io.legado.app.ui.widget.page.PageView import io.legado.app.ui.widget.page.TextChapter import io.legado.app.ui.widget.page.delegate.PageDelegate import io.legado.app.utils.* -import kotlinx.android.synthetic.main.activity_read_book.* +import kotlinx.android.synthetic.main.activity_book_read.* import kotlinx.android.synthetic.main.view_book_page.* import kotlinx.android.synthetic.main.view_read_menu.* import kotlinx.android.synthetic.main.view_title_bar.* @@ -55,7 +55,7 @@ import org.jetbrains.anko.startActivity import org.jetbrains.anko.startActivityForResult import org.jetbrains.anko.toast -class ReadBookActivity : VMBaseActivity(R.layout.activity_read_book), +class ReadBookActivity : VMBaseActivity(R.layout.activity_book_read), PageView.CallBack, ReadMenu.CallBack, ReadAloudDialog.CallBack, diff --git a/app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt index 114552bf6..d64fc4db9 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt @@ -20,7 +20,7 @@ import io.legado.app.ui.book.read.Help import io.legado.app.ui.book.read.ReadBookActivity import io.legado.app.ui.widget.font.FontSelectDialog import io.legado.app.utils.* -import kotlinx.android.synthetic.main.activity_read_book.* +import kotlinx.android.synthetic.main.activity_book_read.* import kotlinx.android.synthetic.main.dialog_read_book_style.* import org.jetbrains.anko.sdk27.listeners.onCheckedChange import org.jetbrains.anko.sdk27.listeners.onClick diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt index e93f1e982..84d36c5eb 100644 --- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt @@ -3,12 +3,12 @@ package io.legado.app.ui.rss.read import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import io.legado.app.R -import kotlinx.android.synthetic.main.activity_read_rss.* +import kotlinx.android.synthetic.main.activity_rss_read.* class ReadRssActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_read_rss) + setContentView(R.layout.activity_rss_read) val description = intent.getStringExtra("description") webView.loadData("$description","text/html", "utf-8") } diff --git a/app/src/main/res/layout/activity_read_book.xml b/app/src/main/res/layout/activity_book_read.xml similarity index 100% rename from app/src/main/res/layout/activity_read_book.xml rename to app/src/main/res/layout/activity_book_read.xml diff --git a/app/src/main/res/layout/activity_read_rss.xml b/app/src/main/res/layout/activity_read_rss.xml deleted file mode 100644 index 0650007cf..000000000 --- a/app/src/main/res/layout/activity_read_rss.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/activity_rss_read.xml b/app/src/main/res/layout/activity_rss_read.xml new file mode 100644 index 000000000..5d403f5fe --- /dev/null +++ b/app/src/main/res/layout/activity_rss_read.xml @@ -0,0 +1,16 @@ + + + + + + + + \ No newline at end of file From 4356e9e30eb0f312d94f186e67deacfef66200e1 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 2 Oct 2019 16:54:05 +0800 Subject: [PATCH 1757/1997] up --- .../java/io/legado/app/ui/rss/article/RssArticlesActivity.kt | 1 + .../java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt | 2 ++ 2 files changed, 3 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt index 9df7a3aeb..a7c09b1a8 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt @@ -24,6 +24,7 @@ class RssArticlesActivity : VMBaseActivity(R.layout.activi initView() intent.getStringExtra("url")?.let { initData(it) + viewModel.loadContent(it) } } diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt index 344b1d098..86894d3a4 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt @@ -6,5 +6,7 @@ import io.legado.app.base.BaseViewModel class RssArticlesViewModel(application: Application) : BaseViewModel(application) { + fun loadContent(url: String) { + } } \ No newline at end of file From 26d040c39b788c73c1fcb59be7775d97097b5066 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 2 Oct 2019 17:05:31 +0800 Subject: [PATCH 1758/1997] up --- .../main/java/io/legado/app/data/dao/RssArticleDao.kt | 7 +++++-- .../java/io/legado/app/data/entities/RssArticle.kt | 1 + .../legado/app/ui/rss/article/RssArticlesViewModel.kt | 10 +++++++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/RssArticleDao.kt b/app/src/main/java/io/legado/app/data/dao/RssArticleDao.kt index 5935d76ce..c90766948 100644 --- a/app/src/main/java/io/legado/app/data/dao/RssArticleDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/RssArticleDao.kt @@ -1,14 +1,17 @@ package io.legado.app.data.dao import androidx.lifecycle.LiveData +import androidx.room.Insert +import androidx.room.OnConflictStrategy import androidx.room.Query import io.legado.app.data.entities.RssArticle interface RssArticleDao { - @Query("select * from rssArticles where origin = :origin") + @Query("select * from rssArticles where origin = :origin order by time desc") fun liveByOrigin(origin: String): LiveData> - + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun insert(vararg rssArticle: RssArticle) } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/data/entities/RssArticle.kt b/app/src/main/java/io/legado/app/data/entities/RssArticle.kt index 6f8773ba3..4f24761e3 100644 --- a/app/src/main/java/io/legado/app/data/entities/RssArticle.kt +++ b/app/src/main/java/io/legado/app/data/entities/RssArticle.kt @@ -7,6 +7,7 @@ import androidx.room.PrimaryKey @Entity(tableName = "rssArticles") data class RssArticle( var origin: String = "", + var time: Long = System.currentTimeMillis(), @PrimaryKey var guid: String? = null, var title: String? = null, diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt index 86894d3a4..9a1b904f0 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt @@ -1,12 +1,20 @@ package io.legado.app.ui.rss.article import android.app.Application +import io.legado.app.App import io.legado.app.base.BaseViewModel +import io.legado.app.model.rss.RssParser +import java.net.URL class RssArticlesViewModel(application: Application) : BaseViewModel(application) { fun loadContent(url: String) { - + execute { + val xml = URL(url).readText() + RssParser.parseXML(xml).let { + App.db.rssArtivleDao().insert(*it.toTypedArray()) + } + } } } \ No newline at end of file From 9dffaf39b4cd6c784f7fbbb476ed518889e674b9 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 2 Oct 2019 17:07:08 +0800 Subject: [PATCH 1759/1997] up --- app/src/main/java/io/legado/app/data/dao/RssArticleDao.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/data/dao/RssArticleDao.kt b/app/src/main/java/io/legado/app/data/dao/RssArticleDao.kt index c90766948..caa2fb293 100644 --- a/app/src/main/java/io/legado/app/data/dao/RssArticleDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/RssArticleDao.kt @@ -1,14 +1,15 @@ package io.legado.app.data.dao import androidx.lifecycle.LiveData +import androidx.room.Dao import androidx.room.Insert import androidx.room.OnConflictStrategy import androidx.room.Query import io.legado.app.data.entities.RssArticle +@Dao interface RssArticleDao { - @Query("select * from rssArticles where origin = :origin order by time desc") fun liveByOrigin(origin: String): LiveData> From 18e6d179a7f6173ad10ffcc99f8771159a60b8b8 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 2 Oct 2019 17:14:40 +0800 Subject: [PATCH 1760/1997] up --- .../java/io/legado/app/data/entities/RssArticle.kt | 12 +++++++++--- .../main/java/io/legado/app/model/rss/RssParser.kt | 3 ++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/RssArticle.kt b/app/src/main/java/io/legado/app/data/entities/RssArticle.kt index 4f24761e3..1c89ff8ca 100644 --- a/app/src/main/java/io/legado/app/data/entities/RssArticle.kt +++ b/app/src/main/java/io/legado/app/data/entities/RssArticle.kt @@ -1,6 +1,7 @@ package io.legado.app.data.entities import androidx.room.Entity +import androidx.room.Ignore import androidx.room.PrimaryKey @@ -9,7 +10,7 @@ data class RssArticle( var origin: String = "", var time: Long = System.currentTimeMillis(), @PrimaryKey - var guid: String? = null, + var guid: String = "", var title: String? = null, var author: String? = null, var link: String? = null, @@ -17,5 +18,10 @@ data class RssArticle( var description: String? = null, var content: String? = null, var image: String? = null, - var categories: MutableList = mutableListOf() -) \ No newline at end of file + var categories: String? = null +) { + + @Ignore + var categoryList: MutableList = mutableListOf() + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/model/rss/RssParser.kt b/app/src/main/java/io/legado/app/model/rss/RssParser.kt index 2696fb26a..accd22de0 100644 --- a/app/src/main/java/io/legado/app/model/rss/RssParser.kt +++ b/app/src/main/java/io/legado/app/model/rss/RssParser.kt @@ -42,7 +42,7 @@ object RssParser { xmlPullParser.name.equals(RSSKeywords.RSS_ITEM_AUTHOR, true) -> if (insideItem) currentArticle.author = xmlPullParser.nextText().trim() xmlPullParser.name.equals(RSSKeywords.RSS_ITEM_CATEGORY, true) -> - if (insideItem) currentArticle.categories.add(xmlPullParser.nextText().trim()) + if (insideItem) currentArticle.categoryList.add(xmlPullParser.nextText().trim()) xmlPullParser.name.equals(RSSKeywords.RSS_ITEM_THUMBNAIL, true) -> if (insideItem) currentArticle.image = xmlPullParser.getAttributeValue(null, RSSKeywords.RSS_ITEM_URL) @@ -92,6 +92,7 @@ object RssParser { ) { // The item is correctly parsed insideItem = false + currentArticle.categories = currentArticle.categoryList.joinToString(",") articleList.add(currentArticle) currentArticle = RssArticle() } From 1c44a4f6e40a958e3437c9e4485132374ad37ed8 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 2 Oct 2019 17:24:43 +0800 Subject: [PATCH 1761/1997] up --- .../java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt index 9a1b904f0..b1f8d70cb 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt @@ -13,6 +13,9 @@ class RssArticlesViewModel(application: Application) : BaseViewModel(application execute { val xml = URL(url).readText() RssParser.parseXML(xml).let { + it.forEach { rssArticle -> + rssArticle.origin = url + } App.db.rssArtivleDao().insert(*it.toTypedArray()) } } From fa01c3781c2e9c47974ba069b819c47b647397ec Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 2 Oct 2019 17:30:52 +0800 Subject: [PATCH 1762/1997] up --- .../app/ui/rss/article/RssArticlesActivity.kt | 5 ++++- .../app/ui/rss/article/RssArticlesViewModel.kt | 4 +++- .../main/res/layout/activity_rss_artivles.xml | 17 +++++++++++++---- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt index a7c09b1a8..0a0168bf5 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt @@ -24,7 +24,9 @@ class RssArticlesActivity : VMBaseActivity(R.layout.activi initView() intent.getStringExtra("url")?.let { initData(it) - viewModel.loadContent(it) + viewModel.loadContent(it) { + refresh_progress_bar.isAutoLoading = false + } } } @@ -33,6 +35,7 @@ class RssArticlesActivity : VMBaseActivity(R.layout.activi recycler_view.layoutManager = LinearLayoutManager(this) adapter = RssArticlesAdapter(this) recycler_view.adapter = adapter + refresh_progress_bar.isAutoLoading = true } private fun initData(origin: String) { diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt index b1f8d70cb..f96478bf6 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt @@ -9,7 +9,7 @@ import java.net.URL class RssArticlesViewModel(application: Application) : BaseViewModel(application) { - fun loadContent(url: String) { + fun loadContent(url: String, onFinally: () -> Unit) { execute { val xml = URL(url).readText() RssParser.parseXML(xml).let { @@ -18,6 +18,8 @@ class RssArticlesViewModel(application: Application) : BaseViewModel(application } App.db.rssArtivleDao().insert(*it.toTypedArray()) } + }.onFinally { + onFinally() } } } \ No newline at end of file diff --git a/app/src/main/res/layout/activity_rss_artivles.xml b/app/src/main/res/layout/activity_rss_artivles.xml index 5665c8a24..43c2e25f8 100644 --- a/app/src/main/res/layout/activity_rss_artivles.xml +++ b/app/src/main/res/layout/activity_rss_artivles.xml @@ -12,15 +12,24 @@ app:contentInsetStartWithNavigation="0dp" app:displayHomeAsUp="true" /> - + android:layout_height="2dp" + app:layout_constraintTop_toBottomOf="@id/title_bar" /> - + + - + \ No newline at end of file From e8f438e84e300f7d773662b4c872afc1f3681312 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 2 Oct 2019 17:40:42 +0800 Subject: [PATCH 1763/1997] up --- .../app/ui/rss/article/RssArticlesActivity.kt | 9 +++++++-- .../app/ui/rss/article/RssArticlesAdapter.kt | 18 ++++++++++++------ app/src/main/res/layout/item_rss_article.xml | 6 +++--- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt index 0a0168bf5..cd0756c35 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt @@ -12,7 +12,8 @@ import io.legado.app.lib.theme.ATH import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_rss_artivles.* -class RssArticlesActivity : VMBaseActivity(R.layout.activity_rss_artivles) { +class RssArticlesActivity : VMBaseActivity(R.layout.activity_rss_artivles), + RssArticlesAdapter.CallBack { override val viewModel: RssArticlesViewModel get() = getViewModel(RssArticlesViewModel::class.java) @@ -33,7 +34,7 @@ class RssArticlesActivity : VMBaseActivity(R.layout.activi private fun initView() { ATH.applyEdgeEffectColor(recycler_view) recycler_view.layoutManager = LinearLayoutManager(this) - adapter = RssArticlesAdapter(this) + adapter = RssArticlesAdapter(this, this) recycler_view.adapter = adapter refresh_progress_bar.isAutoLoading = true } @@ -45,4 +46,8 @@ class RssArticlesActivity : VMBaseActivity(R.layout.activi adapter?.setItems(it) }) } + + override fun readRss(rssArticle: RssArticle) { + + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesAdapter.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesAdapter.kt index 0e185ab22..cb209dc37 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesAdapter.kt @@ -6,22 +6,28 @@ import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.data.entities.RssArticle import kotlinx.android.synthetic.main.item_rss_article.view.* +import org.jetbrains.anko.sdk27.listeners.onClick -class RssArticlesAdapter(context: Context) : +class RssArticlesAdapter(context: Context, val callBack: CallBack) : SimpleRecyclerAdapter(context, R.layout.item_rss_article) { override fun convert(holder: ItemViewHolder, item: RssArticle, payloads: MutableList) { with(holder.itemView) { - title.text = item.title - pub_date.text = item.pubDate + tv_title.text = item.title + tv_pub_date.text = item.pubDate if (item.author.isNullOrBlank()) { - author.text = item.link + tv_author.text = item.link } else { - author.text = item.author + tv_author.text = item.author + } + onClick { + callBack.readRss(item) } } } - + interface CallBack { + fun readRss(rssArticle: RssArticle) + } } \ No newline at end of file diff --git a/app/src/main/res/layout/item_rss_article.xml b/app/src/main/res/layout/item_rss_article.xml index d406fc228..8f9c1d03b 100644 --- a/app/src/main/res/layout/item_rss_article.xml +++ b/app/src/main/res/layout/item_rss_article.xml @@ -14,7 +14,7 @@ android:layout_height="wrap_content"> Date: Wed, 2 Oct 2019 17:42:11 +0800 Subject: [PATCH 1764/1997] up --- .../java/io/legado/app/ui/rss/article/RssArticlesActivity.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt index cd0756c35..b332ecc0e 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt @@ -9,8 +9,10 @@ import io.legado.app.R import io.legado.app.base.VMBaseActivity import io.legado.app.data.entities.RssArticle import io.legado.app.lib.theme.ATH +import io.legado.app.ui.rss.read.ReadRssActivity import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_rss_artivles.* +import org.jetbrains.anko.startActivity class RssArticlesActivity : VMBaseActivity(R.layout.activity_rss_artivles), RssArticlesAdapter.CallBack { @@ -48,6 +50,6 @@ class RssArticlesActivity : VMBaseActivity(R.layout.activi } override fun readRss(rssArticle: RssArticle) { - + startActivity(Pair("description", rssArticle.description)) } } \ No newline at end of file From 8928f4ef2391f26ce439ddc9b31df8cd924d653a Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 2 Oct 2019 17:45:20 +0800 Subject: [PATCH 1765/1997] up --- app/src/main/res/layout/activity_rss_artivles.xml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/src/main/res/layout/activity_rss_artivles.xml b/app/src/main/res/layout/activity_rss_artivles.xml index 43c2e25f8..5eceec843 100644 --- a/app/src/main/res/layout/activity_rss_artivles.xml +++ b/app/src/main/res/layout/activity_rss_artivles.xml @@ -1,5 +1,5 @@ - + app:layout_constraintTop_toTopOf="parent" /> - \ No newline at end of file + \ No newline at end of file From ae7b937cd24932656c75c91188d50f43dbbb6b5a Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 2 Oct 2019 17:46:16 +0800 Subject: [PATCH 1766/1997] up --- .../java/io/legado/app/ui/rss/read/ReadRssActivity.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt index 84d36c5eb..f13f41b61 100644 --- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt @@ -1,15 +1,15 @@ package io.legado.app.ui.rss.read import android.os.Bundle -import androidx.appcompat.app.AppCompatActivity import io.legado.app.R +import io.legado.app.base.BaseActivity import kotlinx.android.synthetic.main.activity_rss_read.* -class ReadRssActivity : AppCompatActivity() { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_rss_read) +class ReadRssActivity : BaseActivity(R.layout.activity_rss_read) { + + override fun onActivityCreated(savedInstanceState: Bundle?) { val description = intent.getStringExtra("description") webView.loadData("$description","text/html", "utf-8") } + } \ No newline at end of file From 8a05d8dde90554d8c0c75c6edfb013bddfe4b16b Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 2 Oct 2019 18:18:34 +0800 Subject: [PATCH 1767/1997] up --- .../io/legado/app/ui/widget/image/FilletImageView.kt | 9 +++++---- app/src/main/res/layout/item_rss.xml | 1 + 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/image/FilletImageView.kt b/app/src/main/java/io/legado/app/ui/widget/image/FilletImageView.kt index bb6a4461e..d1c50fb31 100644 --- a/app/src/main/java/io/legado/app/ui/widget/image/FilletImageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/image/FilletImageView.kt @@ -7,6 +7,7 @@ import android.graphics.Path import android.util.AttributeSet import androidx.appcompat.widget.AppCompatImageView import io.legado.app.R +import kotlin.math.max class FilletImageView : AppCompatImageView { internal var width: Float = 0.toFloat() @@ -62,11 +63,11 @@ class FilletImageView : AppCompatImageView { override fun onDraw(canvas: Canvas) { //这里做下判断,只有图片的宽高大于设置的圆角距离的时候才进行裁剪 - val maxLeft = Math.max(leftTopRadius, leftBottomRadius) - val maxRight = Math.max(rightTopRadius, rightBottomRadius) + val maxLeft = max(leftTopRadius, leftBottomRadius) + val maxRight = max(rightTopRadius, rightBottomRadius) val minWidth = maxLeft + maxRight - val maxTop = Math.max(leftTopRadius, rightTopRadius) - val maxBottom = Math.max(leftBottomRadius, rightBottomRadius) + val maxTop = max(leftTopRadius, rightTopRadius) + val maxBottom = max(leftBottomRadius, rightBottomRadius) val minHeight = maxTop + maxBottom if (width >= minWidth && height > minHeight) { @SuppressLint("DrawAllocation") val path = Path() diff --git a/app/src/main/res/layout/item_rss.xml b/app/src/main/res/layout/item_rss.xml index 1b55a8ed1..6cff479c7 100644 --- a/app/src/main/res/layout/item_rss.xml +++ b/app/src/main/res/layout/item_rss.xml @@ -9,6 +9,7 @@ android:id="@+id/iv_icon" android:layout_width="60dp" android:layout_height="60dp" + android:background="@color/colorPrimary" android:src="@drawable/ic_image" android:scaleType="centerCrop" app:layout_constraintTop_toTopOf="parent" From 9dddc17d5e0cf8b7446f4c2a1428625742d78690 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 2 Oct 2019 18:37:59 +0800 Subject: [PATCH 1768/1997] up --- .../legado/app/ui/book/info/BookInfoActivity.kt | 4 ++-- .../legado/app/ui/book/search/SearchAdapter.kt | 8 ++++---- .../legado/app/ui/explore/ExploreShowAdapter.kt | 4 ++-- .../legado/app/ui/main/bookshelf/BooksAdapter.kt | 4 ++-- .../java/io/legado/app/ui/main/rss/RssAdapter.kt | 2 ++ .../app/ui/widget/anima/RefreshProgressBar.kt | 8 ++++---- ...cover_default.jpg => image_cover_default.jpg} | Bin .../{img_cover_gs.jpg => image_cover_gs.jpg} | Bin app/src/main/res/drawable/image_rss.jpg | Bin 0 -> 9125 bytes .../main/res/layout-land/activity_book_info.xml | 2 +- app/src/main/res/layout/activity_audio_play.xml | 2 +- app/src/main/res/layout/activity_book_info.xml | 2 +- .../main/res/layout/activity_book_info_edit.xml | 2 +- app/src/main/res/layout/item_bookshelf_list.xml | 2 +- app/src/main/res/layout/item_rss.xml | 2 -- app/src/main/res/layout/item_search.xml | 2 +- 16 files changed, 22 insertions(+), 22 deletions(-) rename app/src/main/res/drawable/{img_cover_default.jpg => image_cover_default.jpg} (100%) rename app/src/main/res/drawable/{img_cover_gs.jpg => image_cover_gs.jpg} (100%) create mode 100644 app/src/main/res/drawable/image_rss.jpg diff --git a/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt index 74d3b4495..3f78488de 100644 --- a/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt @@ -88,8 +88,8 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo book.getDisplayIntro() // getString(R.string.intro_show, book.getDisplayIntro()) book.getDisplayCover()?.let { ImageLoader.load(this, it) - .placeholder(R.drawable.img_cover_default) - .error(R.drawable.img_cover_default) + .placeholder(R.drawable.image_cover_default) + .error(R.drawable.image_cover_default) .centerCrop() .setAsDrawable(iv_cover) } diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchAdapter.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchAdapter.kt index a2cb9ad08..38974157d 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchAdapter.kt @@ -84,8 +84,8 @@ class SearchAdapter(val callBack: CallBack) : } searchBook.coverUrl.let { ImageLoader.load(context, it)//Glide自动识别http://和file:// - .placeholder(R.drawable.img_cover_default) - .error(R.drawable.img_cover_default) + .placeholder(R.drawable.image_cover_default) + .error(R.drawable.image_cover_default) .centerCrop() .setAsDrawable(iv_cover) } @@ -100,8 +100,8 @@ class SearchAdapter(val callBack: CallBack) : 1 -> bv_originCount.setBadgeCount(searchBook.originCount) 2 -> searchBook.coverUrl.let { ImageLoader.load(context, it)//Glide自动识别http://和file:// - .placeholder(R.drawable.img_cover_default) - .error(R.drawable.img_cover_default) + .placeholder(R.drawable.image_cover_default) + .error(R.drawable.image_cover_default) .centerCrop() .setAsDrawable(iv_cover) } diff --git a/app/src/main/java/io/legado/app/ui/explore/ExploreShowAdapter.kt b/app/src/main/java/io/legado/app/ui/explore/ExploreShowAdapter.kt index 6510735f5..1a248e736 100644 --- a/app/src/main/java/io/legado/app/ui/explore/ExploreShowAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/explore/ExploreShowAdapter.kt @@ -59,8 +59,8 @@ class ExploreShowAdapter(context: Context, val callBack: CallBack) : } item.coverUrl.let { ImageLoader.load(context, it)//Glide自动识别http://和file:// - .placeholder(R.drawable.img_cover_default) - .error(R.drawable.img_cover_default) + .placeholder(R.drawable.image_cover_default) + .error(R.drawable.image_cover_default) .centerCrop() .setAsDrawable(iv_cover) } diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt index d6df919e0..5152278ca 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt @@ -72,8 +72,8 @@ class BooksAdapter(private val callBack: CallBack) : tv_last.text = book.latestChapterTitle book.getDisplayCover()?.let { ImageLoader.load(context, it)//Glide自动识别http://和file:// - .placeholder(R.drawable.img_cover_default) - .error(R.drawable.img_cover_default) + .placeholder(R.drawable.image_cover_default) + .error(R.drawable.image_cover_default) .centerCrop() .setAsDrawable(iv_cover) } diff --git a/app/src/main/java/io/legado/app/ui/main/rss/RssAdapter.kt b/app/src/main/java/io/legado/app/ui/main/rss/RssAdapter.kt index a5efbf379..b490c8ec8 100644 --- a/app/src/main/java/io/legado/app/ui/main/rss/RssAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/rss/RssAdapter.kt @@ -17,6 +17,8 @@ class RssAdapter(context: Context, val callBack: CallBack) : tv_name.text = item.sourceName ImageLoader.load(context, item.sourceIcon) .centerCrop() + .placeholder(R.drawable.image_rss) + .error(R.drawable.image_rss) .setAsBitmap(iv_icon) onClick { callBack.openRss(item) } } diff --git a/app/src/main/java/io/legado/app/ui/widget/anima/RefreshProgressBar.kt b/app/src/main/java/io/legado/app/ui/widget/anima/RefreshProgressBar.kt index 3eee366be..1095d5889 100644 --- a/app/src/main/java/io/legado/app/ui/widget/anima/RefreshProgressBar.kt +++ b/app/src/main/java/io/legado/app/ui/widget/anima/RefreshProgressBar.kt @@ -16,15 +16,15 @@ class RefreshProgressBar @JvmOverloads constructor( attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : View(context, attrs, defStyleAttr) { - internal var a = 1 - var maxProgress = 100 + private var a = 1 private var durProgress = 0 - var secondMaxProgress = 100 private var secondDurProgress = 0 + var maxProgress = 100 + var secondMaxProgress = 100 var bgColor = 0x00000000 var secondColor = -0x3e3e3f var fontColor = -0xc9c9ca - var speed = 1 + var speed = 2 var secondFinalProgress = 0 private set private var paint: Paint = Paint() diff --git a/app/src/main/res/drawable/img_cover_default.jpg b/app/src/main/res/drawable/image_cover_default.jpg similarity index 100% rename from app/src/main/res/drawable/img_cover_default.jpg rename to app/src/main/res/drawable/image_cover_default.jpg diff --git a/app/src/main/res/drawable/img_cover_gs.jpg b/app/src/main/res/drawable/image_cover_gs.jpg similarity index 100% rename from app/src/main/res/drawable/img_cover_gs.jpg rename to app/src/main/res/drawable/image_cover_gs.jpg diff --git a/app/src/main/res/drawable/image_rss.jpg b/app/src/main/res/drawable/image_rss.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a152df50636b1ba8398bdc90679fc56480a6b1ec GIT binary patch literal 9125 zcmeHsd0bQ1_HPhHYehvsltC(720=h%k|Ck33~eFA7-Gs8nPm!+kRV~Iw<_J#mg0a6DKNgX;UC3Q&Z@L{PVM^7F-`pG9p z<&K{?c2Ys^%ozo_)29_xG*lIp)Rj-4{_Nss>Y7>?bS|7#)w`speMv+6g7$tV5{C~T zK6>P+?9rpL+KQ(Ywg0z|y;lI4BN8GBk)(tg;DC&Tq>RKK6QB%`0349q7x!Ps0V#=t zhYv{}5x3f$lmJLb9*~eaA}x79N^<`Zi35@{2M?W>I%W6;)Js-QE&T42vhKsD)h`== zc^!_%r2qKZ#CuF0_BW%eeP00116Iv{!I@V)>hGW$bF9F#h8 z_@7ezK7@Dx+4IowAG@XGFJJe1QubO-&FJpf;*$E8-g|?9W0K-NWh7+))_@(m|IqRO zQ-51va!gjInuTx9t2Y}P?6mcg_^o@So#Lr_n?1m=bU2>3NCkz}SG?Oi(h|{S3k3y! zo#zNS{Oa(p|9zNZumv^^8#-&CuGEUDtj0s0t+YKr5hCIxr&aEK>fMRpPtA$F(+#+S zTy*V&F`+aw*)A1Lnvu`s2 z&E}V1or%@+pmW`4v0R%qW`myTI(|fL)euJnJm6gpVRuzG171Sa;8>%foMCE;;_#Vvsucj!T)sLg%S*ZpzyNN9K z09lAK>KKBZW9u~}KOfQyDRLIu#>=I@A z$OVnBr@e@Z$=ez{j@xy(#qAFMIar%beL-ggkd+*;v`SC1ZjE^&CWsuE_m!m2`+qmn z6Ax;pBKH9Lr9Sf;!EyH~+l+=sh&_N4ecI2y>gZJ~%WECxSx+w(-xglM73LUymUWzy z5M-Wy`IG;H8~O5FR4p}$OeiFIErbs7;D%u?hO%6=1yEK_5B_B=)NLa9y&9( zTD$&CaXi_Zk|;i=vi+QfA{_=TNT66cLyN|$y0v%x|ZNv$oQ@9 zP7SB`w_Q;oir>8S_4Hhr6$p-{u_Cc=bNjm-XP(``h-H{jYv<`-*yw(fNC|AchB+ZSt})38%~KHU0Wq8Od^qm7y59UNW=5Bq^nt2F2ufr*V)c|j zOHM_nv9fX_Gel}*`$D3-@RR$7iPwqqVFu4R_1-y{OtLZEha#|J55&8pl{v{n5EJ(|* zBx-O9$J`+gll?Z6{B6Mg@8f2x@w`^Y2WJJ!lb3xjbzKn{rk{Th#cKIBJ3EJ^o__v* zf$xa-f*FKL>zE?fZ4Prr)_DS5{nzy?9~q%=Po%AU7czowsSvv011ToHgsl~rsk@Nc zcJ$g}E`Fv*|MowHPV(4y|7bI`^1LxtHeF?C;+iHIS)Dxwx`S`FD|85kIq?TE$Amm8 zZ!)ndp>$}~Lh+?*nmUznhgrEi#pQq_*d|Q4qlo!Jx+}dGkxNj9A{>W^i7PlA%d6e( z!pR2X1^WQ&p{jn4P%&t`2LDp0)v*H4#p#3Vd*Qa>oKp|Hz9snQFx%XU&SbNG^LWkU z^QYcsV5Dwd%5*HuHj=nk?x*}Z`ZzI*Z;tX8%&SZ= zK}p3qiTk9|cRN0#QGVc+_f}re;G;(QeM;Nr6xbakA8#2C&i&ib5XSH z;E66w`v-o+Vvd`cT9g@O*rYdR7(NPiS*tEVe~+~Jh|n%wf~hvQb%hfrl1v73pH7-rtE2bs0kBrqe!9Tc==@JDxS8gcMt2$F3i=nZ8J9Gzn&t} zL_Xsxw<1m9(0*GNuBF41=d~)K_menCEv~(FF}MU125SX{LODlqvsI%*vutQr1yDi#;~Y|^&elwu znlznMoXupmIiy$OZ1W?+ZkN_{RT+S3bmn*p&YbSpAYAaGwpr{ZY0^AQ+-8f|Lq~U= zfu5=JPX+ck!}a-ZFOHB_EqlLlxttoEvaU8(^NDY}`MeSDX4CI?&g_$dI1X$*rjgat zvN`8T5>o4`IOd5l7+yf#S`NWqCvi66ZINMOgbEF5H}*U^!&^61o-?4=4;sX-3OA{! z?i|t`1SG_uTE9Dvtq=;AhdTRfOhu~(+Ew@Iu8pU)eV_*$S9rf@`y>{CJNfDl%=qn6 z>gAY78p4OqWi}(jcMFQQsSQuL@uHdeOy}rplOHdqM4ZrZ7n9ij^~D^UgXMlFPqpL1 zcx7na3N%$Wl@V~_al2+Q88e5%Kos^vr25sc0Ev+OHc6CBqN0y|`r#y&eW_&ES!CQQ;_sZ!Jl z$B=2^-H4dTpS|@=dh(PQjL#i3p%TC0vHnqy zap%*K3;4KiCO#Tj-zZ%!Rf+nhCy3VLkz9#h+A#5~0MBS9<$rZ&JCFAw+MZQ!Z4i9l zV~K0vHI0uJ1?jCm>#INCCG&B3pvF5Zb72lsp%)Ub(- zbg+!;HP3S}x9Molx+r!y6K}jO=Gbdq-6xuOxzmKceZ0>#u|w{N4<5!UVOfK;d=x&E z+YJ&Fr0Z4F`~4|&-UqKoxam5jDm$<4>Jkp5c92c2t5FxY(a69>k#aeEHd7ylW@BvI z@3dU2o3q?e>Ck#n z_`@-0T${UvNpdB!!gdJONvdTzWb%V1P~$6=W;(mGQ9I)wU4ZBMMF{H??yKpw;5H<<)3p z+_+tu8viK>t~auYcc5?VJ4sm?Lqo&tYjxl%r%}pc zwa>2N#NzJ29I`+fMHs07dnETxCXLGuj|f761x}34h26q?dw}TcB76>qH^OIkl>4po zDkF^*I|$Kbt;EDFC|57!#e6*mRZOBVoBG9hfjq3~x)^D{2WS7+iL~RRSEm<-8c^XL zvYm-B<$h~o570cp$!0QAhpB~bg;kWAZg+p5a{O318LfMJF>VP4IXWW(+u!N@u>SH%9Y$fV`AH`zMn~>uE+~d+C7QPr+oulsMkfAyb&l)n>)% z5pgW)=lH?fJxkL=za%S^n6FY`dnE>i#)Opa0ZQa{70K4mE|=P^$}~}ymcR80aTPdj znD;rBD%7cyN_XKyeS$986K1eCJGN)@O-aL@Go-)*{;B!qKDXK7u85zYm7>*^Hhe|8 z-mpK1-aQ#MO}8~%El!QVkNuc+nNJlu3BwJolyL2watuk|vW#RLwwY4$Cou$nk7xGfmKwn#qP z3P_xN0i=d|ZwnIO9=ECZt3S+a!(~R-3M%T#u^zF9kTvN|`^tqyF8&8Y`d#!@&M3WQ zD>AfGmqejzy;QOPqPWmyU#lx9Sbzj;3pbvj`SOGGTlHXPgo-iuOg45hRZul;rW7*_rVtpkRC)X7 zo_%;r)C+D=9>jMMD;n}-#OqD5a4Trmdd@<$+o)ERWtatDW~_1)l|2q2o>ME1hhQL{ z{CCXyHF`Hbe@5$4XEba57vpNLJnEnhg zDLbx=2Gn;VaBj(?(CpGYECgRr($h(p<8(Zh{NbT-O{}!igTK!cU-(nlMgs`v8ao9& z4myWKKh>T@7SrTT^WzZ`%`CVEtx1^5AybIOSAnzE`lfpTNwL}4L@C4&wy0?_(ejbG z!N%OcFnACh>Eu8rh>%qZ>bd3%MkBA1M*lS*@l>VGc12?X`<~SaE6-`Qc-L=(aO7BNywj%YkaffXslSF+;#-w~M{|82irKh;*Ik8$Ytdm~&PeiF zaXsWp`x6{btRv#*((If6iRzCz+O%pK9nI2?G627!L901(ylE;c0zNrM!O$};Ncn`q_l<}%#q#Vxr++b-kPO%;zPCEJ=Lqd6`Y z6kjgY)3d9_8c)GCQ;yjPk_|qGy^?tTVyc*DIy4y78kE8@;yOo|gTk8M5)$Uw*_7oBiC6s%6V_j9HNmc4QW^0$wbTuGVMgX7Ez4kGne=kgHoyle?4lM27>)UdI{RS@DwRQ|&Jd_XBcoQoduYGwF1N+R%~o~5_M;fVHE?Hy!C*w;@IuwcpZglgC zwHUjK$jS{!nYz&DmiCOZJ%{by1xIt>DN+d)oavu{B;2+oI+{u`RyZbfeQEwd-s?P{rxlLc-0VD(6{aQxiFn zJ4t5+;`WID>&p{WM5U1WA}R)+v=LR5R-=2Ouz%fvT|DM|r)?=q7UeP`cE=eT-}D`r zpaCRvmlqt~o0Wd*7-cq<)L_^Y`GiAFr8$aS+S|Jt36BTUBpabNoocJ{(Ct0I(Mh*l;2z-g za70$cLz2)46teVnH*YGe8|m9@M;-mzpK9stanJiK{`$Q?azgS{2l6&O^p=U4Iyo5* zpGjyh!f7G{Q&?A@g>4S>&u`|g7#Xu+VCx50u6DhD5I}eAV4)CZx`df=VAz*6D7|hu z`y-IMuaCXWx!Lu};+6CJWws6FldPP_&F?0vt0OEY2`@e*Kf9yzg3~;dh)p<2E+#XA z5}C|Nm2z&(Rs>>=q!B7Y&9UW&h%nieJ%Ie9h9EVDK5jLpvG_U?aZwCHllJ^Hp$U|hL*WE#r^>f|Pmdl?i3dG5 zy1bGfm%BKaRMK{YNawHE#xI?|P}fy}k2!wC-?3fshV1*>SNBVV|CIe=-d*k;>G@E{ zk7iSZSi@G})1Up_azUhsdiv9~a5)ch0GnuC?v%7}H7+?n{m5p$haO={nBaTHZ(8RF z!0IJzdON_Y&#moDjY%8v${ygj!|TEMZUsHAEz*>doh9FBGuVh8_ArJUcah)*U+Z~` z=gMsB*m0>o#Nv3UaCSb53!7reDu3CpY#NCxn+1}8KP#?mLcTxSc4m6NoO!(ahx##* zMfB*r8@bfo^qlqIP#Y+xDRFq&qTJ=oia+5sO~7wDIQI|97=Rk>`0bRr8~`fl54u;C zj;*UF^}3}Jgj@(+6{oRG8A(idm*?aT!YFI~)WPAKCgFBwVF71IL4xj$fRt#W8;d@a z3unuRrxyJM33KgMQ98`UJr#A>WQ&Ka}NM)9*W#!jOh>OI+p}W=s!;pr5Z?ic*SfMu*v( ze=IZJq-IA$95{#`7t+gjiHlMEO$*B^=)h$Fuh;zW1-%WGJpj_iPQ8f@ogUw2Y-KLb zj~ZoU38;))w6(Uy(oI{t2oZO{Ixx~y`rAf0uxvfyZu-Te=y&3MA4&0+&oMDb7GbY< zI^$l;?Ic&h<_h?Juw7|d=Mc4UZn%rC&Z`A}>c?&PsmA({>@7|`l@9vslc~@Dpfx}V zddN@gCKW^?0o+^DTYVPRf849}3dEtVm`9x`c+~G%8v2mDy+jwsb-=O#oyma#xF?aw z!mgzD$NLI(LhZl65~(23thtjBq{4eS~2I3VtOiFr|ZpMm(()t~k+<>{2)fEYqsD#kaJrn4i^c zk>PempR6Lx;=jQl&Rye8;Mlv*YA~g+NANi~a;*)n3oz)r$noa672dm`PzuM_)gjLU zLW2MjZRWPYuND}a>V?g4P+iyZ917CmYM%F;yS@^z2RMV+Q7baNKr4^ynV&n_xB$04 z@xsa~=aQF`+p(NWH~)F6n7v;xD3F3jDcuK(AXRs+y*yUL$1d$uLaJhsxQhZ?`-RnK>cOoh z*xk{u09fTeZ@Nllj#o|9D4H|aKm|+9JC0FB&t198vR`|^EJES49$Xu^YSV-o^4IBA z+1w19c5uGmmdcHp?E8m5NVE0;*9ujif!5a2A2TemHZxTUrIE0t^S5QD-fdb07}}@& z1h1;X+G#c(3A$w})Eo`VDJ-+4%x0$=35YqN-xq@Ax|J$h&mW+Yi`lRofG<q%=&Rf6Nb<<3mvP>CKKHH;9kyc=E_R=uN~K`thpDR=^vlbDcYV4slnFk20qV_H zB!sju{PVzPI|Dk)rOiZZt8(D_C)ud7xO(}P4ou=-47()xyI`D#|68JGoOo#VaW6!Vg0^p5omQA_;umBRRHTB_(eW_L98nq?uC1ja=USAS70eVz}b^p@5=0m4{K0{ gC-27XM9$`BX&HSc&Hj_8_@n3e|JT1Eus85O0E22~1poj5 literal 0 HcmV?d00001 diff --git a/app/src/main/res/layout-land/activity_book_info.xml b/app/src/main/res/layout-land/activity_book_info.xml index d043d23f7..a284835eb 100644 --- a/app/src/main/res/layout-land/activity_book_info.xml +++ b/app/src/main/res/layout-land/activity_book_info.xml @@ -28,7 +28,7 @@ android:layout_width="86dp" android:layout_height="120dp" android:layout_margin="10dp" - android:src="@drawable/img_cover_default" + android:src="@drawable/image_cover_default" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toBottomOf="@+id/title_bar" /> diff --git a/app/src/main/res/layout/activity_audio_play.xml b/app/src/main/res/layout/activity_audio_play.xml index 2a392be02..ec6bbd556 100644 --- a/app/src/main/res/layout/activity_audio_play.xml +++ b/app/src/main/res/layout/activity_audio_play.xml @@ -25,7 +25,7 @@ android:layout_height="260dp" android:layout_gravity="center" android:contentDescription="@string/img_cover" - android:src="@drawable/img_cover_default" + android:src="@drawable/image_cover_default" app:layout_constraintTop_toBottomOf="@+id/title_bar" app:layout_constraintBottom_toTopOf="@+id/ll_player_progress" app:layout_constraintLeft_toLeftOf="parent" diff --git a/app/src/main/res/layout/activity_book_info.xml b/app/src/main/res/layout/activity_book_info.xml index 0f4028383..9c2887c68 100644 --- a/app/src/main/res/layout/activity_book_info.xml +++ b/app/src/main/res/layout/activity_book_info.xml @@ -19,7 +19,7 @@ android:layout_height="120dp" android:layout_margin="10dp" android:scaleType="centerCrop" - android:src="@drawable/img_cover_default" + android:src="@drawable/image_cover_default" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toBottomOf="@+id/title_bar" /> diff --git a/app/src/main/res/layout/activity_book_info_edit.xml b/app/src/main/res/layout/activity_book_info_edit.xml index 4244c2b89..12328a069 100644 --- a/app/src/main/res/layout/activity_book_info_edit.xml +++ b/app/src/main/res/layout/activity_book_info_edit.xml @@ -34,7 +34,7 @@ android:layout_height="126dp" android:contentDescription="@string/img_cover" android:scaleType="centerCrop" - android:src="@drawable/img_cover_default" /> + android:src="@drawable/image_cover_default" /> Date: Wed, 2 Oct 2019 18:40:52 +0800 Subject: [PATCH 1769/1997] up --- .../main/java/io/legado/app/ui/widget/image/FilletImageView.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/image/FilletImageView.kt b/app/src/main/java/io/legado/app/ui/widget/image/FilletImageView.kt index d1c50fb31..bcb449329 100644 --- a/app/src/main/java/io/legado/app/ui/widget/image/FilletImageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/image/FilletImageView.kt @@ -7,6 +7,7 @@ import android.graphics.Path import android.util.AttributeSet import androidx.appcompat.widget.AppCompatImageView import io.legado.app.R +import io.legado.app.utils.dp import kotlin.math.max class FilletImageView : AppCompatImageView { @@ -30,7 +31,7 @@ class FilletImageView : AppCompatImageView { private fun init(context: Context, attrs: AttributeSet) { // 读取配置 val array = context.obtainStyledAttributes(attrs, R.styleable.FilletImageView) - val defaultRadius = 5 + val defaultRadius = 5.dp val radius = array.getDimensionPixelOffset(R.styleable.FilletImageView_radius, defaultRadius) leftTopRadius = array.getDimensionPixelOffset(R.styleable.FilletImageView_left_top_radius, defaultRadius) rightTopRadius = array.getDimensionPixelOffset(R.styleable.FilletImageView_right_top_radius, defaultRadius) From f3b2e296e767f60081dafa7ae0401fd77344a788 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 2 Oct 2019 22:57:03 +0800 Subject: [PATCH 1770/1997] up --- .../app/ui/rss/article/RssArticlesAdapter.kt | 5 -- app/src/main/res/layout/item_rss_article.xml | 74 +++++++++---------- 2 files changed, 36 insertions(+), 43 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesAdapter.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesAdapter.kt index cb209dc37..f75ad0f21 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesAdapter.kt @@ -16,11 +16,6 @@ class RssArticlesAdapter(context: Context, val callBack: CallBack) : with(holder.itemView) { tv_title.text = item.title tv_pub_date.text = item.pubDate - if (item.author.isNullOrBlank()) { - tv_author.text = item.link - } else { - tv_author.text = item.author - } onClick { callBack.readRss(item) } diff --git a/app/src/main/res/layout/item_rss_article.xml b/app/src/main/res/layout/item_rss_article.xml index 8f9c1d03b..6a9e5aba1 100644 --- a/app/src/main/res/layout/item_rss_article.xml +++ b/app/src/main/res/layout/item_rss_article.xml @@ -1,45 +1,43 @@ - + android:layout_height="100dp" + android:padding="16dp"> - + - + - + - - - - \ No newline at end of file + \ No newline at end of file From b5565a96c5926a70cdf3c7dc97a86ced12346117 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 2 Oct 2019 23:04:37 +0800 Subject: [PATCH 1771/1997] up --- .../io/legado/app/ui/rss/article/RssArticlesAdapter.kt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesAdapter.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesAdapter.kt index f75ad0f21..55e45bfc8 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesAdapter.kt @@ -5,6 +5,9 @@ import io.legado.app.R import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.data.entities.RssArticle +import io.legado.app.help.ImageLoader +import io.legado.app.utils.gone +import io.legado.app.utils.visible import kotlinx.android.synthetic.main.item_rss_article.view.* import org.jetbrains.anko.sdk27.listeners.onClick @@ -19,6 +22,13 @@ class RssArticlesAdapter(context: Context, val callBack: CallBack) : onClick { callBack.readRss(item) } + if (item.image.isNullOrBlank()) { + image_view.gone() + } else { + image_view.visible() + ImageLoader.load(context, item.image) + .setAsBitmap(image_view) + } } } From cbb2ef24aecd0f458ddd9d310915d7be5c953b0d Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 09:40:25 +0800 Subject: [PATCH 1772/1997] up --- .../io/legado/app/data/entities/RssSource.kt | 2 + .../java/io/legado/app/model/rss/RssParser.kt | 3 +- .../legado/app/model/rss/RssParserByRule.kt | 79 +++++++++++++++++++ .../ui/rss/article/RssArticlesViewModel.kt | 14 +++- 4 files changed, 93 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt diff --git a/app/src/main/java/io/legado/app/data/entities/RssSource.kt b/app/src/main/java/io/legado/app/data/entities/RssSource.kt index f15a14696..4537747a1 100644 --- a/app/src/main/java/io/legado/app/data/entities/RssSource.kt +++ b/app/src/main/java/io/legado/app/data/entities/RssSource.kt @@ -14,6 +14,8 @@ data class RssSource( var sourceIcon: String = "", var sourceGroup: String? = null, var enabled: Boolean = true, + //列表规则 + var ruleArticles: String? = null, var ruleGuid: String? = null, var ruleTitle: String? = null, var ruleAuthor: String? = null, diff --git a/app/src/main/java/io/legado/app/model/rss/RssParser.kt b/app/src/main/java/io/legado/app/model/rss/RssParser.kt index accd22de0..7363a349e 100644 --- a/app/src/main/java/io/legado/app/model/rss/RssParser.kt +++ b/app/src/main/java/io/legado/app/model/rss/RssParser.kt @@ -11,7 +11,7 @@ import java.io.StringReader object RssParser { @Throws(XmlPullParserException::class, IOException::class) - fun parseXML(xml: String): MutableList { + fun parseXML(xml: String, sourceUrl: String): MutableList { val articleList = mutableListOf() var currentArticle = RssArticle() @@ -93,6 +93,7 @@ object RssParser { // The item is correctly parsed insideItem = false currentArticle.categories = currentArticle.categoryList.joinToString(",") + currentArticle.origin = sourceUrl articleList.add(currentArticle) currentArticle = RssArticle() } diff --git a/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt b/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt new file mode 100644 index 000000000..6880976ab --- /dev/null +++ b/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt @@ -0,0 +1,79 @@ +package io.legado.app.model.rss + +import io.legado.app.data.entities.RssArticle +import io.legado.app.data.entities.RssSource +import io.legado.app.model.analyzeRule.AnalyzeRule +import org.xmlpull.v1.XmlPullParserException +import java.io.IOException + +object RssParserByRule { + + @Throws(XmlPullParserException::class, IOException::class) + fun parseXML(xml: String, rssSource: RssSource): MutableList { + + val articleList = mutableListOf() + + val analyzeRule = AnalyzeRule() + analyzeRule.setContent(xml) + + rssSource.ruleArticles?.let { ruleArticles -> + val collections = analyzeRule.getElements(ruleArticles) + val ruleGuid = analyzeRule.splitSourceRule(rssSource.ruleGuid ?: "") + val ruleTitle = analyzeRule.splitSourceRule(rssSource.ruleTitle ?: "") + val ruleAuthor = analyzeRule.splitSourceRule(rssSource.ruleAuthor ?: "") + val rulePubDate = analyzeRule.splitSourceRule(rssSource.rulePubDate ?: "") + val ruleCategories = analyzeRule.splitSourceRule(rssSource.ruleCategories ?: "") + val ruleDescription = analyzeRule.splitSourceRule(rssSource.ruleDescription ?: "") + val ruleImage = analyzeRule.splitSourceRule(rssSource.ruleImage ?: "") + val ruleContent = analyzeRule.splitSourceRule(rssSource.ruleContent ?: "") + val ruleLink = analyzeRule.splitSourceRule(rssSource.ruleLink ?: "") + for ((index, item) in collections.withIndex()) { + getItem( + item, + analyzeRule, + index == 0, + ruleGuid, + ruleTitle, + ruleAuthor, + rulePubDate, + ruleCategories, + ruleDescription, + ruleImage, + ruleContent, + ruleLink + ) + } + } ?: let { + return RssParser.parseXML(xml, rssSource.sourceUrl) + } + return articleList + } + + private fun getItem( + item: Any, + analyzeRule: AnalyzeRule, + printLog: Boolean, + ruleGuid: List, + ruleTitle: List, + ruleAuthor: List, + rulePubDate: List, + ruleCategories: List, + ruleDescription: List, + ruleImage: List, + ruleContent: List, + ruleLink: List + ): RssArticle? { + val rssArticle = RssArticle() + analyzeRule.setContent(item) + rssArticle.guid = analyzeRule.getString(ruleGuid) + rssArticle.title = analyzeRule.getString(ruleTitle) + rssArticle.author = analyzeRule.getString(ruleAuthor) + rssArticle.pubDate = analyzeRule.getString(rulePubDate) + rssArticle.categories = analyzeRule.getString(ruleCategories) + rssArticle.description = analyzeRule.getString(ruleDescription) + rssArticle.image = analyzeRule.getString(ruleImage) + rssArticle.content = analyzeRule.getString(ruleContent) + rssArticle.link = analyzeRule.getString(ruleLink) + return rssArticle + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt index f96478bf6..39f0f22e2 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt @@ -4,6 +4,7 @@ import android.app.Application import io.legado.app.App import io.legado.app.base.BaseViewModel import io.legado.app.model.rss.RssParser +import io.legado.app.model.rss.RssParserByRule import java.net.URL @@ -11,15 +12,20 @@ class RssArticlesViewModel(application: Application) : BaseViewModel(application fun loadContent(url: String, onFinally: () -> Unit) { execute { + val rssSource = App.db.rssSourceDao().getByKey(url) val xml = URL(url).readText() - RssParser.parseXML(xml).let { - it.forEach { rssArticle -> - rssArticle.origin = url + if (rssSource == null || rssSource.ruleArticles.isNullOrBlank()) { + RssParser.parseXML(xml, url).let { + App.db.rssArtivleDao().insert(*it.toTypedArray()) + } + } else { + RssParserByRule.parseXML(xml, rssSource).let { + App.db.rssArtivleDao().insert(*it.toTypedArray()) } - App.db.rssArtivleDao().insert(*it.toTypedArray()) } }.onFinally { onFinally() } } + } \ No newline at end of file From 439b78c6ca4649b4c1a035a8ac6897e20ecb3ac7 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 09:52:23 +0800 Subject: [PATCH 1773/1997] up --- .../io/legado/app/ui/rss/article/RssArticlesActivity.kt | 3 +++ .../io/legado/app/ui/rss/article/RssArticlesViewModel.kt | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt index b332ecc0e..f72a98048 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt @@ -25,6 +25,9 @@ class RssArticlesActivity : VMBaseActivity(R.layout.activi override fun onActivityCreated(savedInstanceState: Bundle?) { initView() + viewModel.titleLiveData.observe(this, Observer { + title_bar.title = it + }) intent.getStringExtra("url")?.let { initData(it) viewModel.loadContent(it) { diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt index 39f0f22e2..a4ddecf4d 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt @@ -1,6 +1,7 @@ package io.legado.app.ui.rss.article import android.app.Application +import androidx.lifecycle.MutableLiveData import io.legado.app.App import io.legado.app.base.BaseViewModel import io.legado.app.model.rss.RssParser @@ -10,9 +11,14 @@ import java.net.URL class RssArticlesViewModel(application: Application) : BaseViewModel(application) { + val titleLiveData = MutableLiveData() + fun loadContent(url: String, onFinally: () -> Unit) { execute { val rssSource = App.db.rssSourceDao().getByKey(url) + rssSource?.let { + titleLiveData.postValue(rssSource.sourceName) + } val xml = URL(url).readText() if (rssSource == null || rssSource.ruleArticles.isNullOrBlank()) { RssParser.parseXML(xml, url).let { From f79f999152b2183566beef7aef4868d95add43af Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 09:56:36 +0800 Subject: [PATCH 1774/1997] up --- app/src/main/java/io/legado/app/help/storage/Backup.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/help/storage/Backup.kt b/app/src/main/java/io/legado/app/help/storage/Backup.kt index 97497a854..fa3ad14f9 100644 --- a/app/src/main/java/io/legado/app/help/storage/Backup.kt +++ b/app/src/main/java/io/legado/app/help/storage/Backup.kt @@ -35,7 +35,7 @@ object Backup { fun autoBackup() { doAsync { - val path = defaultPath + File.separator + "autoBackup" + val path = defaultPath backupBookshelf(path) backupBookSource(path) backupRssSource(path) From 5346d3a7217788dbbdb785a471942029eed9fb0e Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 10:14:57 +0800 Subject: [PATCH 1775/1997] up --- app/src/main/res/layout/item_rss_article.xml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/layout/item_rss_article.xml b/app/src/main/res/layout/item_rss_article.xml index 6a9e5aba1..f9ead8598 100644 --- a/app/src/main/res/layout/item_rss_article.xml +++ b/app/src/main/res/layout/item_rss_article.xml @@ -1,6 +1,7 @@ @@ -33,11 +34,13 @@ + android:contentDescription="@string/img_cover" + tools:ignore="RtlHardcoded,RtlSymmetry" /> \ No newline at end of file From 1c4672af7df120488a49f604d7af263dbaf7d1e6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 10:19:01 +0800 Subject: [PATCH 1776/1997] up --- .../io/legado/app/ui/rss/article/RssArticlesActivity.kt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt index f72a98048..7962e6bfd 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt @@ -1,8 +1,10 @@ package io.legado.app.ui.rss.article import android.os.Bundle +import androidx.core.content.ContextCompat import androidx.lifecycle.LiveData import androidx.lifecycle.Observer +import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.App import io.legado.app.R @@ -39,6 +41,12 @@ class RssArticlesActivity : VMBaseActivity(R.layout.activi private fun initView() { ATH.applyEdgeEffectColor(recycler_view) recycler_view.layoutManager = LinearLayoutManager(this) + recycler_view.addItemDecoration( + DividerItemDecoration(this, DividerItemDecoration.VERTICAL).apply { + ContextCompat.getDrawable(baseContext, R.drawable.ic_divider)?.let { + this.setDrawable(it) + } + }) adapter = RssArticlesAdapter(this, this) recycler_view.adapter = adapter refresh_progress_bar.isAutoLoading = true From 2fc65b1bff6c6836c8bc781602ec03b9df18062b Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 10:32:03 +0800 Subject: [PATCH 1777/1997] up --- .../io/legado/app/data/dao/RssSourceDao.kt | 6 +++++ .../ui/rss/source/manage/RssSourceActivity.kt | 8 +++--- .../rss/source/manage/RssSourceViewModel.kt | 27 +++++++++++++++++++ 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt b/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt index 9390b04ac..b33f82b60 100644 --- a/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt @@ -31,6 +31,9 @@ interface RssSourceDao { @Query("update rssSources set enabled = 0 where sourceUrl in (:sourceUrls)") fun disableSection(vararg sourceUrls: String) + @get:Query("select min(customOrder) from rssSources") + val minOrder: Int + @Query("delete from rssSources where sourceUrl in (:sourceUrls)") fun delSection(vararg sourceUrls: String) @@ -40,6 +43,9 @@ interface RssSourceDao { @Update fun update(vararg rssSource: RssSource) + @Delete + fun delete(vararg rssSource: RssSource) + @Query("delete from rssSources where sourceUrl = :sourceUrl") fun delete(sourceUrl: String) } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt index 4ef9c9a0f..5515e4cf1 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt @@ -137,7 +137,7 @@ class RssSourceActivity : VMBaseActivity(R.layout.activity_r } override fun del(source: RssSource) { - + viewModel.del(source) } override fun edit(source: RssSource) { @@ -145,15 +145,15 @@ class RssSourceActivity : VMBaseActivity(R.layout.activity_r } override fun update(vararg source: RssSource) { - + viewModel.update(*source) } override fun toTop(source: RssSource) { - + viewModel.topSource(source) } override fun upOrder() { - + viewModel.upOrder() } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt index 199532d72..8915a6cd8 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt @@ -3,9 +3,36 @@ package io.legado.app.ui.rss.source.manage import android.app.Application import io.legado.app.App import io.legado.app.base.BaseViewModel +import io.legado.app.data.entities.RssSource class RssSourceViewModel(application: Application) : BaseViewModel(application) { + fun topSource(rssSource: RssSource) { + execute { + val minXh = App.db.rssSourceDao().minOrder + rssSource.customOrder = minXh - 1 + App.db.rssSourceDao().insert(rssSource) + } + } + + fun del(rssSource: RssSource) { + execute { App.db.rssSourceDao().delete(rssSource) } + } + + fun update(vararg rssSource: RssSource) { + execute { App.db.rssSourceDao().update(*rssSource) } + } + + fun upOrder() { + execute { + val sources = App.db.rssSourceDao().all + for ((index: Int, source: RssSource) in sources.withIndex()) { + source.customOrder = index + 1 + } + App.db.rssSourceDao().update(*sources.toTypedArray()) + } + } + fun enableSelection(ids: LinkedHashSet) { execute { App.db.rssSourceDao().enableSection(*ids.toTypedArray()) From a583d471a0893383ffd3f51e406f8a438157cca6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 10:40:17 +0800 Subject: [PATCH 1778/1997] up --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 3c95124c7..bfcb4cc7a 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ buildscript { maven { url 'https://plugins.gradle.org/m2/' } } dependencies { - classpath 'com.android.tools.build:gradle:3.5.0' + classpath 'com.android.tools.build:gradle:3.5.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath 'de.timfreiheit.resourceplaceholders:placeholders:0.3' } From fa1137617411f32ff33d9267170ac33617d28e23 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 11:02:09 +0800 Subject: [PATCH 1779/1997] up --- app/src/main/AndroidManifest.xml | 4 ++-- .../io/legado/app/data/dao/BookSourceDao.kt | 3 +++ .../io/legado/app/data/dao/RssSourceDao.kt | 3 +++ .../app/ui/book/info/BookInfoActivity.kt | 4 ++-- .../app/ui/book/read/ReadBookActivity.kt | 4 ++-- ...Activity.kt => BookSourceDebugActivity.kt} | 11 +++++---- ...ugAdapter.kt => BookSourceDebugAdapter.kt} | 2 +- ...eDebugModel.kt => BookSourceDebugModel.kt} | 3 ++- ...tActivity.kt => BookSourceEditActivity.kt} | 24 +++++++++---------- ...ditAdapter.kt => BookSourceEditAdapter.kt} | 2 +- ...iewModel.kt => BookSourceEditViewModel.kt} | 11 +++++---- .../book/source/manage/BookSourceActivity.kt | 6 ++--- .../book/source/manage/BookSourceViewModel.kt | 3 +-- .../app/ui/main/explore/ExploreFragment.kt | 4 ++-- .../rss/source/edit/RssSourceEditActivity.kt | 8 +++---- .../rss/source/edit/RssSourceEditViewModel.kt | 8 ++++++- .../rss/source/manage/RssSourceViewModel.kt | 3 +-- 17 files changed, 57 insertions(+), 46 deletions(-) rename app/src/main/java/io/legado/app/ui/book/source/debug/{SourceDebugActivity.kt => BookSourceDebugActivity.kt} (90%) rename app/src/main/java/io/legado/app/ui/book/source/debug/{SourceDebugAdapter.kt => BookSourceDebugAdapter.kt} (90%) rename app/src/main/java/io/legado/app/ui/book/source/debug/{SourceDebugModel.kt => BookSourceDebugModel.kt} (91%) rename app/src/main/java/io/legado/app/ui/book/source/edit/{SourceEditActivity.kt => BookSourceEditActivity.kt} (95%) rename app/src/main/java/io/legado/app/ui/book/source/edit/{SourceEditAdapter.kt => BookSourceEditAdapter.kt} (96%) rename app/src/main/java/io/legado/app/ui/book/source/edit/{SourceEditViewModel.kt => BookSourceEditViewModel.kt} (83%) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 8c0318cae..39ddc4987 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -46,7 +46,7 @@ android:name=".help.permission.PermissionActivity" android:theme="@style/Activity.Permission" /> @@ -63,7 +63,7 @@ - + diff --git a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt index 334bb7a82..0c8e4d65e 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt @@ -67,4 +67,7 @@ interface BookSourceDao { @get:Query("select min(customOrder) from book_sources") val minOrder: Int + + @get:Query("select max(customOrder) from book_sources") + val maxOrder: Int } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt b/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt index b33f82b60..d30b861da 100644 --- a/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt @@ -34,6 +34,9 @@ interface RssSourceDao { @get:Query("select min(customOrder) from rssSources") val minOrder: Int + @get:Query("select max(customOrder) from rssSources") + val maxOrder: Int + @Query("delete from rssSources where sourceUrl in (:sourceUrls)") fun delSection(vararg sourceUrls: String) diff --git a/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt index 3f78488de..b9bb67838 100644 --- a/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt @@ -14,7 +14,7 @@ import io.legado.app.help.ImageLoader import io.legado.app.lib.theme.ATH import io.legado.app.ui.book.info.edit.BookInfoEditActivity import io.legado.app.ui.book.read.ReadBookActivity -import io.legado.app.ui.book.source.edit.SourceEditActivity +import io.legado.app.ui.book.source.edit.BookSourceEditActivity import io.legado.app.ui.changesource.ChangeSourceDialog import io.legado.app.utils.getCompatDrawable import io.legado.app.utils.getViewModel @@ -190,7 +190,7 @@ class BookInfoActivity : VMBaseActivity(R.layout.activity_boo } tv_origin.onClick { viewModel.bookData.value?.let { - startActivity(Pair("data", it.origin)) + startActivity(Pair("data", it.origin)) } } tv_change_source.onClick { diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt index 3b2400e56..c763ae746 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt @@ -32,7 +32,7 @@ import io.legado.app.service.BaseReadAloudService import io.legado.app.ui.book.read.config.* import io.legado.app.ui.book.read.config.BgTextConfigDialog.Companion.BG_COLOR import io.legado.app.ui.book.read.config.BgTextConfigDialog.Companion.TEXT_COLOR -import io.legado.app.ui.book.source.edit.SourceEditActivity +import io.legado.app.ui.book.source.edit.BookSourceEditActivity import io.legado.app.ui.changesource.ChangeSourceDialog import io.legado.app.ui.chapterlist.ChapterListActivity import io.legado.app.ui.replacerule.ReplaceRuleActivity @@ -114,7 +114,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo private fun initView() { tv_chapter_name.onClick { viewModel.webBook?.let { - startActivityForResult( + startActivityForResult( requestCodeEditSource, Pair("data", it.bookSource.bookSourceUrl) ) diff --git a/app/src/main/java/io/legado/app/ui/book/source/debug/SourceDebugActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/debug/BookSourceDebugActivity.kt similarity index 90% rename from app/src/main/java/io/legado/app/ui/book/source/debug/SourceDebugActivity.kt rename to app/src/main/java/io/legado/app/ui/book/source/debug/BookSourceDebugActivity.kt index de2ef20e7..dafeaa218 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/debug/SourceDebugActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/debug/BookSourceDebugActivity.kt @@ -18,12 +18,13 @@ import kotlinx.coroutines.launch import org.jetbrains.anko.startActivityForResult import org.jetbrains.anko.toast -class SourceDebugActivity : VMBaseActivity(R.layout.activity_source_debug) { +class BookSourceDebugActivity : + VMBaseActivity(R.layout.activity_source_debug) { - override val viewModel: SourceDebugModel - get() = getViewModel(SourceDebugModel::class.java) + override val viewModel: BookSourceDebugModel + get() = getViewModel(BookSourceDebugModel::class.java) - private lateinit var adapter: SourceDebugAdapter + private lateinit var adapter: BookSourceDebugAdapter private val qrRequestCode = 101 override fun onActivityCreated(savedInstanceState: Bundle?) { @@ -42,7 +43,7 @@ class SourceDebugActivity : VMBaseActivity(R.layout.activity_s private fun initRecyclerView() { ATH.applyEdgeEffectColor(recycler_view) - adapter = SourceDebugAdapter(this) + adapter = BookSourceDebugAdapter(this) recycler_view.layoutManager = LinearLayoutManager(this) recycler_view.adapter = adapter rotate_loading.loadingColor = accentColor diff --git a/app/src/main/java/io/legado/app/ui/book/source/debug/SourceDebugAdapter.kt b/app/src/main/java/io/legado/app/ui/book/source/debug/BookSourceDebugAdapter.kt similarity index 90% rename from app/src/main/java/io/legado/app/ui/book/source/debug/SourceDebugAdapter.kt rename to app/src/main/java/io/legado/app/ui/book/source/debug/BookSourceDebugAdapter.kt index 94147a5f1..2ec4e9518 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/debug/SourceDebugAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/debug/BookSourceDebugAdapter.kt @@ -6,7 +6,7 @@ import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter import kotlinx.android.synthetic.main.item_log.view.* -class SourceDebugAdapter(context: Context) : +class BookSourceDebugAdapter(context: Context) : SimpleRecyclerAdapter(context, R.layout.item_log) { override fun convert(holder: ItemViewHolder, item: String, payloads: MutableList) { holder.itemView.apply { diff --git a/app/src/main/java/io/legado/app/ui/book/source/debug/SourceDebugModel.kt b/app/src/main/java/io/legado/app/ui/book/source/debug/BookSourceDebugModel.kt similarity index 91% rename from app/src/main/java/io/legado/app/ui/book/source/debug/SourceDebugModel.kt rename to app/src/main/java/io/legado/app/ui/book/source/debug/BookSourceDebugModel.kt index a17565820..ced985aa9 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/debug/SourceDebugModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/debug/BookSourceDebugModel.kt @@ -6,7 +6,8 @@ import io.legado.app.base.BaseViewModel import io.legado.app.model.WebBook import io.legado.app.model.webbook.SourceDebug -class SourceDebugModel(application: Application) : BaseViewModel(application), SourceDebug.Callback { +class BookSourceDebugModel(application: Application) : BaseViewModel(application), + SourceDebug.Callback { private var webBook: WebBook? = null diff --git a/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt similarity index 95% rename from app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditActivity.kt rename to app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt index 4eb28dcea..e2fdd270f 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt @@ -22,7 +22,7 @@ import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.EditEntity import io.legado.app.data.entities.rule.* import io.legado.app.lib.theme.ATH -import io.legado.app.ui.book.source.debug.SourceDebugActivity +import io.legado.app.ui.book.source.debug.BookSourceDebugActivity import io.legado.app.ui.widget.KeyboardToolPop import io.legado.app.utils.GSON import io.legado.app.utils.getViewModel @@ -32,13 +32,13 @@ import org.jetbrains.anko.startActivity import org.jetbrains.anko.toast import kotlin.math.abs -class SourceEditActivity : - VMBaseActivity(R.layout.activity_book_source_edit, false), +class BookSourceEditActivity : + VMBaseActivity(R.layout.activity_book_source_edit, false), KeyboardToolPop.CallBack { - override val viewModel: SourceEditViewModel - get() = getViewModel(SourceEditViewModel::class.java) + override val viewModel: BookSourceEditViewModel + get() = getViewModel(BookSourceEditViewModel::class.java) - private val adapter = SourceEditAdapter() + private val adapter = BookSourceEditAdapter() private val sourceEntities: ArrayList = ArrayList() private val searchEntities: ArrayList = ArrayList() private val findEntities: ArrayList = ArrayList() @@ -55,11 +55,8 @@ class SourceEditActivity : upRecyclerView(it) }) if (viewModel.sourceLiveData.value == null) { - val sourceID = intent.getStringExtra("data") - if (sourceID == null) { - upRecyclerView(null) - } else { - sourceID.let { viewModel.setBookSource(sourceID) } + intent.getStringExtra("data")?.let { + viewModel.setBookSource(it) } } else { upRecyclerView(viewModel.sourceLiveData.value) @@ -86,7 +83,7 @@ class SourceEditActivity : R.id.menu_debug_source -> { getSource()?.let { viewModel.save(it) { - startActivity(Pair("key", it.bookSourceUrl)) + startActivity(Pair("key", it.bookSourceUrl)) } } } @@ -120,6 +117,7 @@ class SourceEditActivity : setEditEntities(tab?.position) } }) + upRecyclerView(null) } private fun setEditEntities(tabPosition: Int?) { @@ -358,7 +356,7 @@ class SourceEditActivity : val rect = Rect() // 获取当前页面窗口的显示范围 window.decorView.getWindowVisibleDisplayFrame(rect) - val screenHeight = this@SourceEditActivity.displayMetrics.heightPixels + val screenHeight = this@BookSourceEditActivity.displayMetrics.heightPixels val keyboardHeight = screenHeight - rect.bottom // 输入法的高度 val preShowing = mIsSoftKeyBoardShowing if (abs(keyboardHeight) > screenHeight / 5) { diff --git a/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditAdapter.kt b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditAdapter.kt similarity index 96% rename from app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditAdapter.kt rename to app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditAdapter.kt index 434f2071a..37939e803 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditAdapter.kt @@ -10,7 +10,7 @@ import io.legado.app.R import io.legado.app.data.entities.EditEntity import kotlinx.android.synthetic.main.item_source_edit.view.* -class SourceEditAdapter : RecyclerView.Adapter() { +class BookSourceEditAdapter : RecyclerView.Adapter() { var editEntities: ArrayList = ArrayList() set(value) { diff --git a/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditViewModel.kt b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditViewModel.kt similarity index 83% rename from app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditViewModel.kt rename to app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditViewModel.kt index c3af29a6a..8bff89145 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/edit/SourceEditViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditViewModel.kt @@ -9,7 +9,7 @@ import io.legado.app.base.BaseViewModel import io.legado.app.data.entities.BookSource import io.legado.app.help.storage.OldRule -class SourceEditViewModel(application: Application) : BaseViewModel(application) { +class BookSourceEditViewModel(application: Application) : BaseViewModel(application) { val sourceLiveData: MutableLiveData = MutableLiveData() @@ -17,14 +17,17 @@ class SourceEditViewModel(application: Application) : BaseViewModel(application) execute { App.db.bookSourceDao().getBookSource(key)?.let { sourceLiveData.postValue(it) - } ?: sourceLiveData.postValue(BookSource()) + } } } fun save(bookSource: BookSource, finally: (() -> Unit)? = null) { execute { - if (bookSource.customOrder == 0) { - bookSource.customOrder = App.db.bookSourceDao().allCount() + sourceLiveData.value?.let { + bookSource.customOrder = it.customOrder + App.db.bookSourceDao().delete(it) + } ?: let { + bookSource.customOrder = App.db.bookSourceDao().maxOrder + 1 } App.db.bookSourceDao().insert(bookSource) }.onFinally { diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt index 258e8b52d..ecdb0ad7b 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt @@ -28,7 +28,7 @@ import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.primaryTextColor import io.legado.app.lib.theme.view.ATEAutoCompleteTextView import io.legado.app.service.CheckSourceService -import io.legado.app.ui.book.source.edit.SourceEditActivity +import io.legado.app.ui.book.source.edit.BookSourceEditActivity import io.legado.app.ui.qrcode.QrCodeActivity import io.legado.app.utils.ACache import io.legado.app.utils.applyTint @@ -76,7 +76,7 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { R.id.menu_add_book_source -> { - this.startActivity() + this.startActivity() } R.id.menu_import_book_source_qr -> { this.startActivityForResult(qrRequestCode) @@ -212,7 +212,7 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity } override fun edit(bookSource: BookSource) { - startActivity(Pair("data", bookSource.bookSourceUrl)) + startActivity(Pair("data", bookSource.bookSourceUrl)) } override fun upOrder() { diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt index 31accc240..a51b589b3 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt @@ -16,8 +16,7 @@ class BookSourceViewModel(application: Application) : BaseViewModel(application) fun topSource(bookSource: BookSource) { execute { - val minXh = App.db.bookSourceDao().minOrder - bookSource.customOrder = minXh - 1 + bookSource.customOrder = App.db.bookSourceDao().minOrder - 1 App.db.bookSourceDao().insert(bookSource) } } diff --git a/app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt b/app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt index 6889124f3..ea23c0909 100644 --- a/app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/explore/ExploreFragment.kt @@ -12,7 +12,7 @@ import io.legado.app.base.VMBaseFragment import io.legado.app.data.entities.BookSource import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.primaryTextColor -import io.legado.app.ui.book.source.edit.SourceEditActivity +import io.legado.app.ui.book.source.edit.BookSourceEditActivity import io.legado.app.ui.explore.ExploreShowActivity import io.legado.app.utils.getViewModel import io.legado.app.utils.startActivity @@ -88,7 +88,7 @@ class ExploreFragment : VMBaseFragment(R.layout.fragment_find_ } override fun editSource(sourceUrl: String) { - startActivity(Pair("data", sourceUrl)) + startActivity(Pair("data", sourceUrl)) } override fun toTop(source: BookSource) { diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt index 0636afda6..81ff0b823 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt @@ -50,11 +50,8 @@ class RssSourceEditActivity : upRecyclerView(it) }) if (viewModel.sourceLiveData.value == null) { - val sourceID = intent.getStringExtra("data") - if (sourceID == null) { - upRecyclerView(null) - } else { - sourceID.let { viewModel.setSource(sourceID) } + intent.getStringExtra("data")?.let { + viewModel.setSource(it) } } else { upRecyclerView(viewModel.sourceLiveData.value) @@ -105,6 +102,7 @@ class RssSourceEditActivity : window.decorView.viewTreeObserver.addOnGlobalLayoutListener(KeyboardOnGlobalChangeListener()) recycler_view.layoutManager = LinearLayoutManager(this) recycler_view.adapter = adapter + upRecyclerView(null) } private fun upRecyclerView(rssSource: RssSource?) { diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt index 0f002d627..aec9924ea 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt @@ -18,12 +18,18 @@ class RssSourceEditViewModel(application: Application) : BaseViewModel(applicati execute { App.db.rssSourceDao().getByKey(key)?.let { sourceLiveData.postValue(it) - } ?: sourceLiveData.postValue(RssSource()) + } } } fun save(rssSource: RssSource, success: (() -> Unit)) { execute { + sourceLiveData.value?.let { + rssSource.customOrder = it.customOrder + App.db.rssSourceDao().delete(it) + } ?: let { + rssSource.customOrder = App.db.rssSourceDao().maxOrder + 1 + } App.db.rssSourceDao().insert(rssSource) }.onSuccess { success() diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt index 8915a6cd8..b0ad309d6 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt @@ -9,8 +9,7 @@ class RssSourceViewModel(application: Application) : BaseViewModel(application) fun topSource(rssSource: RssSource) { execute { - val minXh = App.db.rssSourceDao().minOrder - rssSource.customOrder = minXh - 1 + rssSource.customOrder = App.db.rssSourceDao().minOrder - 1 App.db.rssSourceDao().insert(rssSource) } } From d4164d89e1f588f4853ef019693892058b0207c0 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 11:38:42 +0800 Subject: [PATCH 1780/1997] up --- .../rss/source/edit/RssSourceEditActivity.kt | 2 ++ app/src/main/res/values/strings.xml | 27 ++++++++++--------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt index 81ff0b823..002818d82 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt @@ -112,6 +112,7 @@ class RssSourceEditActivity : add(EditEntity("sourceUrl", rssSource?.sourceUrl, R.string.rss_source_url)) add(EditEntity("sourceIcon", rssSource?.sourceIcon, R.string.rss_source_icon)) add(EditEntity("sourceGroup", rssSource?.sourceGroup, R.string.rss_source_group)) + add(EditEntity("ruleArticles", rssSource?.ruleArticles, R.string.rss_rule_articles)) add(EditEntity("ruleTitle", rssSource?.ruleTitle, R.string.rss_rule_title)) add(EditEntity("ruleAuthor", rssSource?.ruleAuthor, R.string.rss_rule_author)) add(EditEntity("ruleGuid", rssSource?.ruleGuid, R.string.rss_rule_guid)) @@ -145,6 +146,7 @@ class RssSourceEditActivity : "sourceUrl" -> source.sourceUrl = it.value ?: "" "sourceIcon" -> source.sourceIcon = it.value ?: "" "sourceGroup" -> source.sourceGroup = it.value + "ruleArticles" -> source.ruleArticles = it.value "ruleTitle" -> source.ruleTitle = it.value "ruleAuthor" -> source.ruleAuthor = it.value "ruleGuid" -> source.ruleGuid = it.value diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bfe21f7a4..52525e7cb 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -376,19 +376,20 @@ - 名称 - url - 图标 - 分组 - 标题 - 作者 - guid - 时间 - 类别 - 描述 - 图片url - 内容 - 链接 + 名称(sourceName) + url(sourceUrl) + 图标(sourceIcon) + 分组(sourceGroup) + 列表规则(ruleArticles) + 标题规则(ruleTitle) + 作者规则(ruleAuthor) + guid规则(ruleGuid) + 时间规则(rulePubDate) + 类别规则(ruleCategories) + 描述规则(ruleDescription) + 图片url规则(ruleImage) + 内容规则(ruleContent) + 链接规则(ruleLink) From 63c1b8914ef24318208ca3ad87ab835463bbe3ea Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 11:52:24 +0800 Subject: [PATCH 1781/1997] up --- app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt | 4 ++-- app/src/main/java/io/legado/app/data/entities/RssSource.kt | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt b/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt index d30b861da..8081068ed 100644 --- a/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt @@ -13,10 +13,10 @@ interface RssSourceDao { @get:Query("SELECT * FROM rssSources") val all: List - @Query("SELECT * FROM rssSources") + @Query("SELECT * FROM rssSources order by customOrder") fun liveAll(): LiveData> - @Query("SELECT * FROM rssSources where sourceName like :key or sourceUrl like :key or sourceGroup like :key") + @Query("SELECT * FROM rssSources where sourceName like :key or sourceUrl like :key or sourceGroup like :key order by customOrder") fun liveSearch(key: String): LiveData> @Query("SELECT * FROM rssSources where enabled = 1") diff --git a/app/src/main/java/io/legado/app/data/entities/RssSource.kt b/app/src/main/java/io/legado/app/data/entities/RssSource.kt index 4537747a1..82f0d4863 100644 --- a/app/src/main/java/io/legado/app/data/entities/RssSource.kt +++ b/app/src/main/java/io/legado/app/data/entities/RssSource.kt @@ -2,11 +2,12 @@ package io.legado.app.data.entities import android.os.Parcelable import androidx.room.Entity +import androidx.room.Index import androidx.room.PrimaryKey import kotlinx.android.parcel.Parcelize @Parcelize -@Entity(tableName = "rssSources") +@Entity(tableName = "rssSources", indices = [(Index(value = ["sourceUrl"], unique = false))]) data class RssSource( @PrimaryKey var sourceUrl: String = "", From 8a543ef3b716c751839b4e96674e4c68355c7ea9 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 12:35:29 +0800 Subject: [PATCH 1782/1997] up --- .../java/io/legado/app/ui/replacerule/edit/ReplaceEditDialog.kt | 2 +- .../io/legado/app/ui/replacerule/edit/ReplaceEditViewModel.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/replacerule/edit/ReplaceEditDialog.kt b/app/src/main/java/io/legado/app/ui/replacerule/edit/ReplaceEditDialog.kt index 3fa28cd69..4b11ab39c 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/edit/ReplaceEditDialog.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/edit/ReplaceEditDialog.kt @@ -25,7 +25,7 @@ class ReplaceEditDialog : DialogFragment(), val dialog = ReplaceEditDialog() id?.let { val bundle = Bundle() - bundle.putLong("data", id) + bundle.putLong("id", id) dialog.arguments = bundle } return dialog diff --git a/app/src/main/java/io/legado/app/ui/replacerule/edit/ReplaceEditViewModel.kt b/app/src/main/java/io/legado/app/ui/replacerule/edit/ReplaceEditViewModel.kt index ae8ba8025..281a0ac2d 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/edit/ReplaceEditViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/edit/ReplaceEditViewModel.kt @@ -14,7 +14,7 @@ class ReplaceEditViewModel(application: Application) : BaseViewModel(application fun initData(bundle: Bundle) { execute { replaceRuleData.value ?: let { - val id = bundle.getLong("data") + val id = bundle.getLong("id") if (id > 0) { App.db.replaceRuleDao().findById(id)?.let { replaceRuleData.postValue(it) From 21449396585eea61d96d5a41ddbf91c6e7b8fab0 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 13:49:14 +0800 Subject: [PATCH 1783/1997] up --- .../ui/rss/article/RssArticlesViewModel.kt | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt index a4ddecf4d..b2d052c29 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt @@ -4,9 +4,9 @@ import android.app.Application import androidx.lifecycle.MutableLiveData import io.legado.app.App import io.legado.app.base.BaseViewModel +import io.legado.app.model.analyzeRule.AnalyzeUrl import io.legado.app.model.rss.RssParser import io.legado.app.model.rss.RssParserByRule -import java.net.URL class RssArticlesViewModel(application: Application) : BaseViewModel(application) { @@ -19,14 +19,15 @@ class RssArticlesViewModel(application: Application) : BaseViewModel(application rssSource?.let { titleLiveData.postValue(rssSource.sourceName) } - val xml = URL(url).readText() - if (rssSource == null || rssSource.ruleArticles.isNullOrBlank()) { - RssParser.parseXML(xml, url).let { - App.db.rssArtivleDao().insert(*it.toTypedArray()) - } - } else { - RssParserByRule.parseXML(xml, rssSource).let { - App.db.rssArtivleDao().insert(*it.toTypedArray()) + AnalyzeUrl(url).getResponseAsync().await().body()?.let { xml -> + if (rssSource == null || rssSource.ruleArticles.isNullOrBlank()) { + RssParser.parseXML(xml, url).let { + App.db.rssArtivleDao().insert(*it.toTypedArray()) + } + } else { + RssParserByRule.parseXML(xml, rssSource).let { + App.db.rssArtivleDao().insert(*it.toTypedArray()) + } } } }.onFinally { From 08dcf5de24746ce02bf136b3077353fa00f9b05d Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 14:37:35 +0800 Subject: [PATCH 1784/1997] up --- .../io/legado/app/ui/book/source/edit/BookSourceEditViewModel.kt | 1 + .../io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt | 1 + 2 files changed, 2 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditViewModel.kt b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditViewModel.kt index 8bff89145..2289ea4b1 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditViewModel.kt @@ -29,6 +29,7 @@ class BookSourceEditViewModel(application: Application) : BaseViewModel(applicat } ?: let { bookSource.customOrder = App.db.bookSourceDao().maxOrder + 1 } + sourceLiveData.postValue(bookSource) App.db.bookSourceDao().insert(bookSource) }.onFinally { finally?.let { it() } diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt index aec9924ea..2b8f5e242 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt @@ -30,6 +30,7 @@ class RssSourceEditViewModel(application: Application) : BaseViewModel(applicati } ?: let { rssSource.customOrder = App.db.rssSourceDao().maxOrder + 1 } + sourceLiveData.postValue(rssSource) App.db.rssSourceDao().insert(rssSource) }.onSuccess { success() From be95698ea748e944054088b82cd7a70829c73f69 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 14:40:42 +0800 Subject: [PATCH 1785/1997] up --- app/src/main/java/io/legado/app/ui/about/AboutFragment.kt | 2 +- app/src/main/res/values/pref_key_value.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/about/AboutFragment.kt b/app/src/main/java/io/legado/app/ui/about/AboutFragment.kt index e98523051..093c5a9ec 100644 --- a/app/src/main/java/io/legado/app/ui/about/AboutFragment.kt +++ b/app/src/main/java/io/legado/app/ui/about/AboutFragment.kt @@ -24,7 +24,7 @@ class AboutFragment : PreferenceFragmentCompat() { override fun onPreferenceTreeClick(preference: Preference?): Boolean { when (preference?.key) { "mail" -> openIntent(Intent.ACTION_SENDTO, "mailto:kunfei.ge@gmail.com") - "gitHub" -> openIntent(Intent.ACTION_VIEW, getString(R.string.this_github_url)) + "git" -> openIntent(Intent.ACTION_VIEW, getString(R.string.this_github_url)) } return super.onPreferenceTreeClick(preference) } diff --git a/app/src/main/res/values/pref_key_value.xml b/app/src/main/res/values/pref_key_value.xml index dd706603a..091d276ad 100644 --- a/app/src/main/res/values/pref_key_value.xml +++ b/app/src/main/res/values/pref_key_value.xml @@ -19,7 +19,7 @@ Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.2357.134 Safari/537.36 https://gedoor.github.io/MyBookshelf/sourcerule.html - https://github.com/gedoor/MyBookshelf + https://github.com/gedoor/legado https://gedoor.github.io/MyBookshelf/disclaimer.html https://gedoor.github.io/MyBookshelf/ https://github.com/gedoor/MyBookshelf/releases/latest From f6352d4e9756354ea821f697d9dc4df42eecc583 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 14:48:23 +0800 Subject: [PATCH 1786/1997] up --- .../app/ui/book/source/edit/BookSourceEditActivity.kt | 8 ++------ .../app/ui/rss/source/edit/RssSourceEditActivity.kt | 8 ++------ 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt index e2fdd270f..6362c947f 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt @@ -54,12 +54,8 @@ class BookSourceEditActivity : viewModel.sourceLiveData.observe(this, Observer { upRecyclerView(it) }) - if (viewModel.sourceLiveData.value == null) { - intent.getStringExtra("data")?.let { - viewModel.setBookSource(it) - } - } else { - upRecyclerView(viewModel.sourceLiveData.value) + intent.getStringExtra("data")?.let { + viewModel.setBookSource(it) } } diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt index 002818d82..5eed4540c 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt @@ -49,12 +49,8 @@ class RssSourceEditActivity : viewModel.sourceLiveData.observe(this, Observer { upRecyclerView(it) }) - if (viewModel.sourceLiveData.value == null) { - intent.getStringExtra("data")?.let { - viewModel.setSource(it) - } - } else { - upRecyclerView(viewModel.sourceLiveData.value) + intent.getStringExtra("data")?.let { + viewModel.setSource(it) } } From 5c15dfa5b5de50d35c8568c26ae4b4b734b63060 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 14:49:44 +0800 Subject: [PATCH 1787/1997] up --- .../legado/app/ui/book/source/edit/BookSourceEditViewModel.kt | 2 +- .../io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditViewModel.kt b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditViewModel.kt index 2289ea4b1..8dcfe81ed 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditViewModel.kt @@ -29,8 +29,8 @@ class BookSourceEditViewModel(application: Application) : BaseViewModel(applicat } ?: let { bookSource.customOrder = App.db.bookSourceDao().maxOrder + 1 } - sourceLiveData.postValue(bookSource) App.db.bookSourceDao().insert(bookSource) + sourceLiveData.postValue(bookSource) }.onFinally { finally?.let { it() } } diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt index 2b8f5e242..72f0637b9 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt @@ -30,8 +30,8 @@ class RssSourceEditViewModel(application: Application) : BaseViewModel(applicati } ?: let { rssSource.customOrder = App.db.rssSourceDao().maxOrder + 1 } - sourceLiveData.postValue(rssSource) App.db.rssSourceDao().insert(rssSource) + sourceLiveData.postValue(rssSource) }.onSuccess { success() }.onError { From c028e643e3fe2afbea3dd98c373383f75d9c3b15 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 14:55:56 +0800 Subject: [PATCH 1788/1997] up --- .../io/legado/app/ui/book/source/edit/BookSourceEditViewModel.kt | 1 - .../io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt | 1 - 2 files changed, 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditViewModel.kt b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditViewModel.kt index 8dcfe81ed..9c8a1d8ca 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditViewModel.kt @@ -24,7 +24,6 @@ class BookSourceEditViewModel(application: Application) : BaseViewModel(applicat fun save(bookSource: BookSource, finally: (() -> Unit)? = null) { execute { sourceLiveData.value?.let { - bookSource.customOrder = it.customOrder App.db.bookSourceDao().delete(it) } ?: let { bookSource.customOrder = App.db.bookSourceDao().maxOrder + 1 diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt index 72f0637b9..b6dd3af87 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt @@ -25,7 +25,6 @@ class RssSourceEditViewModel(application: Application) : BaseViewModel(applicati fun save(rssSource: RssSource, success: (() -> Unit)) { execute { sourceLiveData.value?.let { - rssSource.customOrder = it.customOrder App.db.rssSourceDao().delete(it) } ?: let { rssSource.customOrder = App.db.rssSourceDao().maxOrder + 1 From f25a36b8eac94abc0ef44f19d46e72c695e86edd Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 15:06:05 +0800 Subject: [PATCH 1789/1997] up --- .../io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt | 2 +- .../io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt index 6362c947f..b1c659b9b 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt @@ -225,7 +225,7 @@ class BookSourceEditActivity : } private fun getSource(): BookSource? { - val source = viewModel.sourceLiveData.value ?: BookSource() + val source = viewModel.sourceLiveData.value?.copy() ?: BookSource() source.enabled = cb_is_enable.isChecked source.enabledExplore = cb_is_enable_find.isChecked viewModel.sourceLiveData.value?.let { diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt index 5eed4540c..c30e8b9ff 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt @@ -135,7 +135,7 @@ class RssSourceEditActivity : } private fun getRssSource(): RssSource? { - val source = viewModel.sourceLiveData.value ?: RssSource() + val source = viewModel.sourceLiveData.value?.copy() ?: RssSource() sourceEntities.forEach { when (it.key) { "sourceName" -> source.sourceName = it.value ?: "" From 9b6a37e07a83fa1c96ee130aed695a7259d2586d Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 15:08:56 +0800 Subject: [PATCH 1790/1997] up --- .../legado/app/ui/book/source/edit/BookSourceEditViewModel.kt | 4 +++- .../legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditViewModel.kt b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditViewModel.kt index 9c8a1d8ca..910c461a7 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditViewModel.kt @@ -24,7 +24,9 @@ class BookSourceEditViewModel(application: Application) : BaseViewModel(applicat fun save(bookSource: BookSource, finally: (() -> Unit)? = null) { execute { sourceLiveData.value?.let { - App.db.bookSourceDao().delete(it) + if (it.bookSourceUrl != bookSource.bookSourceUrl) { + App.db.bookSourceDao().delete(it) + } } ?: let { bookSource.customOrder = App.db.bookSourceDao().maxOrder + 1 } diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt index b6dd3af87..f87438b9c 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt @@ -25,7 +25,9 @@ class RssSourceEditViewModel(application: Application) : BaseViewModel(applicati fun save(rssSource: RssSource, success: (() -> Unit)) { execute { sourceLiveData.value?.let { - App.db.rssSourceDao().delete(it) + if (it.sourceUrl != rssSource.sourceUrl) { + App.db.rssSourceDao().delete(it) + } } ?: let { rssSource.customOrder = App.db.rssSourceDao().maxOrder + 1 } From 8de1ff85abca226b1fb4812851d8e4edad340a40 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 15:09:38 +0800 Subject: [PATCH 1791/1997] up --- .../io/legado/app/ui/rss/source/debug/RssSourceDebugActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/source/debug/RssSourceDebugActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/debug/RssSourceDebugActivity.kt index 3018a1f1e..3c476c921 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/debug/RssSourceDebugActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/debug/RssSourceDebugActivity.kt @@ -5,7 +5,7 @@ import io.legado.app.R import io.legado.app.base.BaseActivity -class RssSourceDebugActivity : BaseActivity(R.layout.activity_source_debug, false) { +class RssSourceDebugActivity : BaseActivity(R.layout.activity_source_debug) { override fun onActivityCreated(savedInstanceState: Bundle?) { From fa1c8ce18e5a899dfc9bb4707f3d9c5663f89b3f Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 15:29:15 +0800 Subject: [PATCH 1792/1997] up --- app/src/main/java/io/legado/app/model/Rss.kt | 24 +++++++++++++++++++ .../legado/app/model/rss/RssParserByRule.kt | 20 ++++++++++++---- .../ui/rss/article/RssArticlesViewModel.kt | 23 +++++++----------- 3 files changed, 48 insertions(+), 19 deletions(-) create mode 100644 app/src/main/java/io/legado/app/model/Rss.kt diff --git a/app/src/main/java/io/legado/app/model/Rss.kt b/app/src/main/java/io/legado/app/model/Rss.kt new file mode 100644 index 000000000..cd76e24fe --- /dev/null +++ b/app/src/main/java/io/legado/app/model/Rss.kt @@ -0,0 +1,24 @@ +package io.legado.app.model + +import io.legado.app.data.entities.RssArticle +import io.legado.app.data.entities.RssSource +import io.legado.app.help.coroutine.Coroutine +import io.legado.app.model.analyzeRule.AnalyzeUrl +import io.legado.app.model.rss.RssParserByRule +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlin.coroutines.CoroutineContext + +object Rss { + + fun getArticles( + rssSource: RssSource, + scope: CoroutineScope = Coroutine.DEFAULT, + context: CoroutineContext = Dispatchers.IO + ): Coroutine> { + return Coroutine.async(scope, context) { + val response = AnalyzeUrl(rssSource.sourceUrl).getResponseAsync().await() + RssParserByRule.parseXML(response, rssSource) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt b/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt index 6880976ab..c1609c852 100644 --- a/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt +++ b/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt @@ -1,18 +1,28 @@ package io.legado.app.model.rss +import io.legado.app.App +import io.legado.app.R import io.legado.app.data.entities.RssArticle import io.legado.app.data.entities.RssSource import io.legado.app.model.analyzeRule.AnalyzeRule -import org.xmlpull.v1.XmlPullParserException -import java.io.IOException +import retrofit2.Response object RssParserByRule { - @Throws(XmlPullParserException::class, IOException::class) - fun parseXML(xml: String, rssSource: RssSource): MutableList { - + @Throws(Exception::class) + fun parseXML(response: Response, rssSource: RssSource): MutableList { val articleList = mutableListOf() + val xml = response.body() + if (xml.isNullOrBlank()) { + throw Exception( + App.INSTANCE.getString( + R.string.error_get_web_content, + rssSource.sourceUrl + ) + ) + } + val analyzeRule = AnalyzeRule() analyzeRule.setContent(xml) diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt index b2d052c29..5d9470f71 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt @@ -4,9 +4,8 @@ import android.app.Application import androidx.lifecycle.MutableLiveData import io.legado.app.App import io.legado.app.base.BaseViewModel -import io.legado.app.model.analyzeRule.AnalyzeUrl -import io.legado.app.model.rss.RssParser -import io.legado.app.model.rss.RssParserByRule +import io.legado.app.data.entities.RssSource +import io.legado.app.model.Rss class RssArticlesViewModel(application: Application) : BaseViewModel(application) { @@ -15,19 +14,15 @@ class RssArticlesViewModel(application: Application) : BaseViewModel(application fun loadContent(url: String, onFinally: () -> Unit) { execute { - val rssSource = App.db.rssSourceDao().getByKey(url) - rssSource?.let { + var rssSource = App.db.rssSourceDao().getByKey(url) + if (rssSource == null) { + rssSource = RssSource(sourceUrl = url) + } else { titleLiveData.postValue(rssSource.sourceName) } - AnalyzeUrl(url).getResponseAsync().await().body()?.let { xml -> - if (rssSource == null || rssSource.ruleArticles.isNullOrBlank()) { - RssParser.parseXML(xml, url).let { - App.db.rssArtivleDao().insert(*it.toTypedArray()) - } - } else { - RssParserByRule.parseXML(xml, rssSource).let { - App.db.rssArtivleDao().insert(*it.toTypedArray()) - } + Rss.getArticles(rssSource, this).onSuccess { + it?.let { + App.db.rssArtivleDao().insert(*it.toTypedArray()) } } }.onFinally { From a6d2165887c6c96db16c9a67eea07e3f6c01daeb Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 15:33:02 +0800 Subject: [PATCH 1793/1997] up --- .../java/io/legado/app/model/rss/RssParserByRule.kt | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt b/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt index c1609c852..1bd629a50 100644 --- a/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt +++ b/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt @@ -23,10 +23,9 @@ object RssParserByRule { ) } - val analyzeRule = AnalyzeRule() - analyzeRule.setContent(xml) - rssSource.ruleArticles?.let { ruleArticles -> + val analyzeRule = AnalyzeRule() + analyzeRule.setContent(xml) val collections = analyzeRule.getElements(ruleArticles) val ruleGuid = analyzeRule.splitSourceRule(rssSource.ruleGuid ?: "") val ruleTitle = analyzeRule.splitSourceRule(rssSource.ruleTitle ?: "") @@ -51,7 +50,9 @@ object RssParserByRule { ruleImage, ruleContent, ruleLink - ) + )?.let { + articleList.add(it) + } } } ?: let { return RssParser.parseXML(xml, rssSource.sourceUrl) @@ -84,6 +85,9 @@ object RssParserByRule { rssArticle.image = analyzeRule.getString(ruleImage) rssArticle.content = analyzeRule.getString(ruleContent) rssArticle.link = analyzeRule.getString(ruleLink) + if (rssArticle.title.isNullOrBlank()) { + return null + } return rssArticle } } \ No newline at end of file From d29a46c8efe66ac9c591ac9b9c61ce294e72f372 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 15:36:25 +0800 Subject: [PATCH 1794/1997] up --- .../io/legado/app/ui/rss/article/RssArticlesViewModel.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt index 5d9470f71..bd82bdda4 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt @@ -24,9 +24,11 @@ class RssArticlesViewModel(application: Application) : BaseViewModel(application it?.let { App.db.rssArtivleDao().insert(*it.toTypedArray()) } + }.onError { + toast(it.localizedMessage) + }.onFinally { + onFinally() } - }.onFinally { - onFinally() } } From 0dfd83f30fe6d59352d1500eb37d79365c12b7be Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 15:55:52 +0800 Subject: [PATCH 1795/1997] up --- .../io/legado/app/data/dao/BookSourceDao.kt | 3 +++ .../source/edit/BookSourceEditActivity.kt | 2 +- .../source/edit/BookSourceEditViewModel.kt | 22 +++++++++++++------ 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt index 0c8e4d65e..e1864eb5b 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt @@ -65,6 +65,9 @@ interface BookSourceDao { @Delete fun delete(vararg bookSource: BookSource) + @Query("delete from book_sources where bookSourceUrl = :key") + fun delete(key: String) + @get:Query("select min(customOrder) from book_sources") val minOrder: Int diff --git a/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt index b1c659b9b..6362c947f 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt @@ -225,7 +225,7 @@ class BookSourceEditActivity : } private fun getSource(): BookSource? { - val source = viewModel.sourceLiveData.value?.copy() ?: BookSource() + val source = viewModel.sourceLiveData.value ?: BookSource() source.enabled = cb_is_enable.isChecked source.enabledExplore = cb_is_enable_find.isChecked viewModel.sourceLiveData.value?.let { diff --git a/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditViewModel.kt b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditViewModel.kt index 910c461a7..1202f74f2 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditViewModel.kt @@ -12,26 +12,34 @@ import io.legado.app.help.storage.OldRule class BookSourceEditViewModel(application: Application) : BaseViewModel(application) { val sourceLiveData: MutableLiveData = MutableLiveData() + var oldSourceUrl: String? = null - fun setBookSource(key: String) { + fun setBookSource(key: String?) { execute { - App.db.bookSourceDao().getBookSource(key)?.let { + var source: BookSource? = null + if (key != null) { + source = App.db.bookSourceDao().getBookSource(key) + } + source?.let { + oldSourceUrl = it.bookSourceUrl sourceLiveData.postValue(it) + } ?: let { + sourceLiveData.postValue(BookSource().apply { + customOrder = App.db.bookSourceDao().maxOrder + 1 + }) } } } fun save(bookSource: BookSource, finally: (() -> Unit)? = null) { execute { - sourceLiveData.value?.let { - if (it.bookSourceUrl != bookSource.bookSourceUrl) { + oldSourceUrl?.let { + if (oldSourceUrl != bookSource.bookSourceUrl) { App.db.bookSourceDao().delete(it) } - } ?: let { - bookSource.customOrder = App.db.bookSourceDao().maxOrder + 1 } + oldSourceUrl = bookSource.bookSourceUrl App.db.bookSourceDao().insert(bookSource) - sourceLiveData.postValue(bookSource) }.onFinally { finally?.let { it() } } From b5be12b231f0d7ed4b020bb72b84ade2ef707de1 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 15:56:53 +0800 Subject: [PATCH 1796/1997] up --- .../legado/app/ui/book/source/edit/BookSourceEditActivity.kt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt index 6362c947f..153e3fcb8 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt @@ -54,9 +54,7 @@ class BookSourceEditActivity : viewModel.sourceLiveData.observe(this, Observer { upRecyclerView(it) }) - intent.getStringExtra("data")?.let { - viewModel.setBookSource(it) - } + viewModel.setBookSource(intent.getStringExtra("data")) } override fun onDestroy() { @@ -113,7 +111,6 @@ class BookSourceEditActivity : setEditEntities(tab?.position) } }) - upRecyclerView(null) } private fun setEditEntities(tabPosition: Int?) { From a62b75832b552962f1bd1a83a7fe542e0f1609fb Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 15:58:09 +0800 Subject: [PATCH 1797/1997] up --- .../legado/app/ui/book/source/edit/BookSourceEditActivity.kt | 2 +- .../legado/app/ui/book/source/edit/BookSourceEditViewModel.kt | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt index 153e3fcb8..267890628 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt @@ -54,7 +54,7 @@ class BookSourceEditActivity : viewModel.sourceLiveData.observe(this, Observer { upRecyclerView(it) }) - viewModel.setBookSource(intent.getStringExtra("data")) + viewModel.initData(intent) } override fun onDestroy() { diff --git a/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditViewModel.kt b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditViewModel.kt index 1202f74f2..61cc49858 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditViewModel.kt @@ -3,6 +3,7 @@ package io.legado.app.ui.book.source.edit import android.app.Application import android.content.ClipboardManager import android.content.Context +import android.content.Intent import androidx.lifecycle.MutableLiveData import io.legado.app.App import io.legado.app.base.BaseViewModel @@ -14,8 +15,9 @@ class BookSourceEditViewModel(application: Application) : BaseViewModel(applicat val sourceLiveData: MutableLiveData = MutableLiveData() var oldSourceUrl: String? = null - fun setBookSource(key: String?) { + fun initData(intent: Intent) { execute { + val key = intent.getStringExtra("data") var source: BookSource? = null if (key != null) { source = App.db.bookSourceDao().getBookSource(key) From 9fb795206d4a31d3c10b9c0c0b9dcc118bba1dfc Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 16:01:57 +0800 Subject: [PATCH 1798/1997] up --- .../rss/source/edit/RssSourceEditActivity.kt | 5 +--- .../rss/source/edit/RssSourceEditViewModel.kt | 24 +++++++++++++------ 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt index c30e8b9ff..45374b1ea 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt @@ -49,9 +49,7 @@ class RssSourceEditActivity : viewModel.sourceLiveData.observe(this, Observer { upRecyclerView(it) }) - intent.getStringExtra("data")?.let { - viewModel.setSource(it) - } + viewModel.initData(intent) } override fun onDestroy() { @@ -98,7 +96,6 @@ class RssSourceEditActivity : window.decorView.viewTreeObserver.addOnGlobalLayoutListener(KeyboardOnGlobalChangeListener()) recycler_view.layoutManager = LinearLayoutManager(this) recycler_view.adapter = adapter - upRecyclerView(null) } private fun upRecyclerView(rssSource: RssSource?) { diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt index f87438b9c..8b0f2cd11 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt @@ -3,6 +3,7 @@ package io.legado.app.ui.rss.source.edit import android.app.Application import android.content.ClipboardManager import android.content.Context +import android.content.Intent import androidx.lifecycle.MutableLiveData import io.legado.app.App import io.legado.app.base.BaseViewModel @@ -13,26 +14,35 @@ import io.legado.app.utils.fromJsonObject class RssSourceEditViewModel(application: Application) : BaseViewModel(application) { val sourceLiveData: MutableLiveData = MutableLiveData() + var oldSourceUrl: String? = null - fun setSource(key: String) { + fun initData(intent: Intent) { execute { - App.db.rssSourceDao().getByKey(key)?.let { + val key = intent.getStringExtra("data") + var source: RssSource? = null + if (key != null) { + source = App.db.rssSourceDao().getByKey(key) + } + source?.let { + oldSourceUrl = it.sourceUrl sourceLiveData.postValue(it) + } ?: let { + sourceLiveData.postValue(RssSource().apply { + customOrder = App.db.rssSourceDao().maxOrder + 1 + }) } } } fun save(rssSource: RssSource, success: (() -> Unit)) { execute { - sourceLiveData.value?.let { - if (it.sourceUrl != rssSource.sourceUrl) { + oldSourceUrl?.let { + if (oldSourceUrl != rssSource.sourceUrl) { App.db.rssSourceDao().delete(it) } - } ?: let { - rssSource.customOrder = App.db.rssSourceDao().maxOrder + 1 } + oldSourceUrl = rssSource.sourceUrl App.db.rssSourceDao().insert(rssSource) - sourceLiveData.postValue(rssSource) }.onSuccess { success() }.onError { From ff2800ce0a5de6bd574c46e51364e4d34efb79a8 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 16:03:29 +0800 Subject: [PATCH 1799/1997] up --- .../io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt index 45374b1ea..9283744b4 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt @@ -132,7 +132,7 @@ class RssSourceEditActivity : } private fun getRssSource(): RssSource? { - val source = viewModel.sourceLiveData.value?.copy() ?: RssSource() + val source = viewModel.sourceLiveData.value ?: RssSource() sourceEntities.forEach { when (it.key) { "sourceName" -> source.sourceName = it.value ?: "" From 1c74f48d5398997e78a4caa861239b889886df88 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 16:15:12 +0800 Subject: [PATCH 1800/1997] up --- .../app/ui/rss/article/RssArticlesViewModel.kt | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt index bd82bdda4..b24445785 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt @@ -6,6 +6,7 @@ import io.legado.app.App import io.legado.app.base.BaseViewModel import io.legado.app.data.entities.RssSource import io.legado.app.model.Rss +import kotlinx.coroutines.Dispatchers.IO class RssArticlesViewModel(application: Application) : BaseViewModel(application) { @@ -20,15 +21,16 @@ class RssArticlesViewModel(application: Application) : BaseViewModel(application } else { titleLiveData.postValue(rssSource.sourceName) } - Rss.getArticles(rssSource, this).onSuccess { - it?.let { - App.db.rssArtivleDao().insert(*it.toTypedArray()) + Rss.getArticles(rssSource, this) + .onSuccess(IO) { + it?.let { + App.db.rssArtivleDao().insert(*it.toTypedArray()) + } + }.onError { + toast(it.localizedMessage) + }.onFinally { + onFinally() } - }.onError { - toast(it.localizedMessage) - }.onFinally { - onFinally() - } } } From 48eac4955e4593fe13a51d9da08fc78a375fa215 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 16:26:38 +0800 Subject: [PATCH 1801/1997] up --- app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt b/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt index 8081068ed..f280c0fb9 100644 --- a/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt @@ -19,7 +19,7 @@ interface RssSourceDao { @Query("SELECT * FROM rssSources where sourceName like :key or sourceUrl like :key or sourceGroup like :key order by customOrder") fun liveSearch(key: String): LiveData> - @Query("SELECT * FROM rssSources where enabled = 1") + @Query("SELECT * FROM rssSources where enabled = 1 order by customOrder") fun liveEnabled(): LiveData> @Query("select sourceGroup from rssSources where sourceGroup is not null and sourceGroup <> ''") From f0dbf97c961d23a86590dff450876792ea256796 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 18:24:08 +0800 Subject: [PATCH 1802/1997] up --- app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt b/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt index 1bd629a50..f2a40bc01 100644 --- a/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt +++ b/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt @@ -51,6 +51,7 @@ object RssParserByRule { ruleContent, ruleLink )?.let { + it.origin = rssSource.sourceUrl articleList.add(it) } } From cc990cd6138c6cf37589f2a86632d094d8f124f4 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 18:39:17 +0800 Subject: [PATCH 1803/1997] up --- .../io/legado/app/ui/rss/article/RssArticlesActivity.kt | 5 ++++- .../main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt | 7 ++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt index 7962e6bfd..40e943756 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt @@ -61,6 +61,9 @@ class RssArticlesActivity : VMBaseActivity(R.layout.activi } override fun readRss(rssArticle: RssArticle) { - startActivity(Pair("description", rssArticle.description)) + startActivity( + Pair("description", rssArticle.description), + Pair("url", rssArticle.link) + ) } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt index f13f41b61..eb8fa6451 100644 --- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt @@ -9,7 +9,12 @@ class ReadRssActivity : BaseActivity(R.layout.activity_rss_read) { override fun onActivityCreated(savedInstanceState: Bundle?) { val description = intent.getStringExtra("description") - webView.loadData("$description","text/html", "utf-8") + val url = intent.getStringExtra("url") + if (description.isNullOrBlank()) { + webView.loadUrl(url) + } else { + webView.loadData("$description", "text/html", "utf-8") + } } } \ No newline at end of file From 35c01961e5cb23465bb9dc11ea3f701c470e3801 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 19:12:23 +0800 Subject: [PATCH 1804/1997] up --- app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt | 2 +- .../io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt b/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt index f2a40bc01..45bbaf637 100644 --- a/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt +++ b/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt @@ -84,8 +84,8 @@ object RssParserByRule { rssArticle.categories = analyzeRule.getString(ruleCategories) rssArticle.description = analyzeRule.getString(ruleDescription) rssArticle.image = analyzeRule.getString(ruleImage) - rssArticle.content = analyzeRule.getString(ruleContent) rssArticle.link = analyzeRule.getString(ruleLink) + rssArticle.content = analyzeRule.getString(ruleContent) if (rssArticle.title.isNullOrBlank()) { return null } diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt index 9283744b4..10e783e15 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt @@ -125,8 +125,8 @@ class RssSourceEditActivity : ) ) add(EditEntity("ruleImage", rssSource?.ruleImage, R.string.rss_rule_image)) - add(EditEntity("ruleContent", rssSource?.ruleContent, R.string.rss_rule_content)) add(EditEntity("ruleLink", rssSource?.ruleLink, R.string.rss_rule_link)) + add(EditEntity("ruleContent", rssSource?.ruleContent, R.string.rss_rule_content)) } adapter.editEntities = sourceEntities } @@ -147,8 +147,8 @@ class RssSourceEditActivity : "ruleCategories" -> source.ruleCategories = it.value "ruleDescription" -> source.ruleDescription = it.value "ruleImage" -> source.ruleImage = it.value - "ruleContent" -> source.ruleContent = it.value "ruleLink" -> source.ruleLink = it.value + "ruleContent" -> source.ruleContent = it.value } } if (source.sourceName.isBlank() || source.sourceName.isBlank()) { From 1c0bc20cc3e33cebad2870eca0d64933d195f785 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 19:19:10 +0800 Subject: [PATCH 1805/1997] up --- app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt | 2 ++ app/src/main/res/layout/item_rss_article.xml | 1 + 2 files changed, 3 insertions(+) create mode 100644 app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt new file mode 100644 index 000000000..6d43baf9a --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt @@ -0,0 +1,2 @@ +package io.legado.app.ui.rss.read + diff --git a/app/src/main/res/layout/item_rss_article.xml b/app/src/main/res/layout/item_rss_article.xml index f9ead8598..7a28bc6b1 100644 --- a/app/src/main/res/layout/item_rss_article.xml +++ b/app/src/main/res/layout/item_rss_article.xml @@ -13,6 +13,7 @@ android:text="@string/app_name" android:textSize="16sp" android:textStyle="bold" + android:textColor="@color/tv_text_default" android:layout_marginBottom="10dp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" From bb3b689c06a5fdd517b674213981257e22da9ff0 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 19:33:34 +0800 Subject: [PATCH 1806/1997] up --- app/src/main/res/layout/item_rss_article.xml | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/app/src/main/res/layout/item_rss_article.xml b/app/src/main/res/layout/item_rss_article.xml index 7a28bc6b1..293ae0ce3 100644 --- a/app/src/main/res/layout/item_rss_article.xml +++ b/app/src/main/res/layout/item_rss_article.xml @@ -10,15 +10,15 @@ android:id="@+id/tv_title" android:layout_width="0dp" android:layout_height="0dp" + android:layout_marginBottom="10dp" android:text="@string/app_name" + android:textColor="@color/tv_text_default" android:textSize="16sp" android:textStyle="bold" - android:textColor="@color/tv_text_default" - android:layout_marginBottom="10dp" - app:layout_constraintLeft_toLeftOf="parent" - app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toTopOf="@+id/tv_pub_date" - app:layout_constraintRight_toLeftOf="@+id/image_view" /> + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toLeftOf="@+id/image_view" + app:layout_constraintTop_toTopOf="parent" /> \ No newline at end of file From e8bab32b7b88407740323c3904418ba1268e50c8 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 19:38:21 +0800 Subject: [PATCH 1807/1997] up --- app/src/main/java/io/legado/app/data/dao/RssArticleDao.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/data/dao/RssArticleDao.kt b/app/src/main/java/io/legado/app/data/dao/RssArticleDao.kt index caa2fb293..c4ee3467d 100644 --- a/app/src/main/java/io/legado/app/data/dao/RssArticleDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/RssArticleDao.kt @@ -13,6 +13,6 @@ interface RssArticleDao { @Query("select * from rssArticles where origin = :origin order by time desc") fun liveByOrigin(origin: String): LiveData> - @Insert(onConflict = OnConflictStrategy.REPLACE) + @Insert(onConflict = OnConflictStrategy.IGNORE) fun insert(vararg rssArticle: RssArticle) } \ No newline at end of file From 4b42d172fe9b0ea99bc693410ea96839ef01e83c Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 20:06:56 +0800 Subject: [PATCH 1808/1997] up --- app/src/main/java/io/legado/app/data/entities/RssArticle.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/data/entities/RssArticle.kt b/app/src/main/java/io/legado/app/data/entities/RssArticle.kt index 1c89ff8ca..f2deefb1e 100644 --- a/app/src/main/java/io/legado/app/data/entities/RssArticle.kt +++ b/app/src/main/java/io/legado/app/data/entities/RssArticle.kt @@ -18,7 +18,9 @@ data class RssArticle( var description: String? = null, var content: String? = null, var image: String? = null, - var categories: String? = null + var categories: String? = null, + var read: Boolean = false, + var star: Boolean = false ) { @Ignore From 7bd457626e8ef641c9681183d98694a299cfedc7 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 20:12:06 +0800 Subject: [PATCH 1809/1997] up --- app/src/main/java/io/legado/app/data/dao/RssArticleDao.kt | 8 ++++---- .../io/legado/app/ui/rss/article/RssArticlesViewModel.kt | 8 ++++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/RssArticleDao.kt b/app/src/main/java/io/legado/app/data/dao/RssArticleDao.kt index c4ee3467d..0c6290965 100644 --- a/app/src/main/java/io/legado/app/data/dao/RssArticleDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/RssArticleDao.kt @@ -1,10 +1,7 @@ package io.legado.app.data.dao import androidx.lifecycle.LiveData -import androidx.room.Dao -import androidx.room.Insert -import androidx.room.OnConflictStrategy -import androidx.room.Query +import androidx.room.* import io.legado.app.data.entities.RssArticle @Dao @@ -15,4 +12,7 @@ interface RssArticleDao { @Insert(onConflict = OnConflictStrategy.IGNORE) fun insert(vararg rssArticle: RssArticle) + + @Update + fun update(vararg rssArticle: RssArticle) } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt index b24445785..a75e7ae07 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt @@ -4,6 +4,7 @@ import android.app.Application import androidx.lifecycle.MutableLiveData import io.legado.app.App import io.legado.app.base.BaseViewModel +import io.legado.app.data.entities.RssArticle import io.legado.app.data.entities.RssSource import io.legado.app.model.Rss import kotlinx.coroutines.Dispatchers.IO @@ -34,4 +35,11 @@ class RssArticlesViewModel(application: Application) : BaseViewModel(application } } + fun read(rssArticle: RssArticle) { + execute { + rssArticle.read = true + App.db.rssArtivleDao().update(rssArticle) + } + } + } \ No newline at end of file From 223564a8666ec8baddb8dc900af4be1ba2b13c13 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 20:23:17 +0800 Subject: [PATCH 1810/1997] up --- .../io/legado/app/ui/rss/article/RssArticlesActivity.kt | 1 + .../java/io/legado/app/ui/rss/article/RssArticlesAdapter.kt | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt index 40e943756..70137fa22 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt @@ -65,5 +65,6 @@ class RssArticlesActivity : VMBaseActivity(R.layout.activi Pair("description", rssArticle.description), Pair("url", rssArticle.link) ) + viewModel.read(rssArticle) } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesAdapter.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesAdapter.kt index 55e45bfc8..a89af62ba 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesAdapter.kt @@ -10,6 +10,7 @@ import io.legado.app.utils.gone import io.legado.app.utils.visible import kotlinx.android.synthetic.main.item_rss_article.view.* import org.jetbrains.anko.sdk27.listeners.onClick +import org.jetbrains.anko.textColorResource class RssArticlesAdapter(context: Context, val callBack: CallBack) : @@ -29,6 +30,11 @@ class RssArticlesAdapter(context: Context, val callBack: CallBack) : ImageLoader.load(context, item.image) .setAsBitmap(image_view) } + if (item.read) { + tv_title.textColorResource = R.color.tv_text_secondary + } else { + tv_title.textColorResource = R.color.tv_text_default + } } } From 70cc4d308eb5f0a9b6697c4191c1eccc365aa4b8 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 20:28:48 +0800 Subject: [PATCH 1811/1997] up --- .../java/io/legado/app/ui/rss/article/RssArticlesActivity.kt | 2 +- .../java/io/legado/app/ui/rss/article/RssArticlesAdapter.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt index 70137fa22..8ec14de5b 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt @@ -61,10 +61,10 @@ class RssArticlesActivity : VMBaseActivity(R.layout.activi } override fun readRss(rssArticle: RssArticle) { + viewModel.read(rssArticle) startActivity( Pair("description", rssArticle.description), Pair("url", rssArticle.link) ) - viewModel.read(rssArticle) } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesAdapter.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesAdapter.kt index a89af62ba..03546d957 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesAdapter.kt @@ -31,7 +31,7 @@ class RssArticlesAdapter(context: Context, val callBack: CallBack) : .setAsBitmap(image_view) } if (item.read) { - tv_title.textColorResource = R.color.tv_text_secondary + tv_title.textColorResource = R.color.tv_text_summary } else { tv_title.textColorResource = R.color.tv_text_default } From e4dc091a2c5723a194b5ed9e91c0f323114f25c2 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 3 Oct 2019 21:32:59 +0800 Subject: [PATCH 1812/1997] up --- app/src/main/AndroidManifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1cf753157..65c6ad511 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -63,7 +63,7 @@ - + From b3375443998e60cdb25b85b7f04200f557a654a8 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 4 Oct 2019 12:11:03 +0800 Subject: [PATCH 1813/1997] up --- .../main/java/io/legado/app/utils/StringExtensions.kt | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/io/legado/app/utils/StringExtensions.kt b/app/src/main/java/io/legado/app/utils/StringExtensions.kt index a58e17c56..f783373b3 100644 --- a/app/src/main/java/io/legado/app/utils/StringExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/StringExtensions.kt @@ -20,18 +20,12 @@ fun String?.isJson(): Boolean = this?.run { fun String?.isJsonObject(): Boolean = this?.run { val str = this.trim() - when { - str.startsWith("{") && str.endsWith("}") -> true - else -> false - } + str.startsWith("{") && str.endsWith("}") } ?: false fun String?.isJsonArray(): Boolean = this?.run { val str = this.trim() - when { - str.startsWith("[") && str.endsWith("]") -> true - else -> false - } + str.startsWith("[") && str.endsWith("]") } ?: false fun String?.htmlFormat(): String = if (this.isNullOrBlank()) "" else From 5bfde1b6fe750da82ce9e78fdb79d24bfdceded9 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 4 Oct 2019 13:30:43 +0800 Subject: [PATCH 1814/1997] up --- .../io/legado/app/ui/book/search/SearchActivity.kt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt index bc25fa64f..f9124f9fb 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt @@ -23,6 +23,9 @@ import io.legado.app.utils.invisible import io.legado.app.utils.visible import kotlinx.android.synthetic.main.activity_book_search.* import kotlinx.android.synthetic.main.view_search.* +import kotlinx.coroutines.Dispatchers.IO +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import org.jetbrains.anko.sdk27.listeners.onClick import org.jetbrains.anko.startActivity @@ -166,6 +169,12 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se } override fun searchHistory(key: String) { - search_view.setQuery(key, false) + launch { + if (withContext(IO) { App.db.bookDao().findByName(key).isEmpty() }) { + search_view.setQuery(key, true) + } else { + search_view.setQuery(key, false) + } + } } } From f7ad79bd0a401bad3d5e69ac657d7e86a04d1e69 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 4 Oct 2019 22:52:12 +0800 Subject: [PATCH 1815/1997] up --- .../io/legado/app/ui/widget/page/PageView.kt | 3 +- .../app/ui/widget/page/curl/CurlMesh.java | 957 ++++++++++++++++++ .../app/ui/widget/page/curl/CurlPage.java | 195 ++++ .../app/ui/widget/page/curl/CurlRenderer.java | 250 +++++ .../app/ui/widget/page/curl/CurlView.java | 790 +++++++++++++++ .../res/layout/dialog_read_book_style.xml | 12 + 6 files changed, 2206 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/io/legado/app/ui/widget/page/curl/CurlMesh.java create mode 100644 app/src/main/java/io/legado/app/ui/widget/page/curl/CurlPage.java create mode 100644 app/src/main/java/io/legado/app/ui/widget/page/curl/CurlRenderer.java create mode 100644 app/src/main/java/io/legado/app/ui/widget/page/curl/CurlView.java diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 8b348d310..1c293e74e 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -89,7 +89,8 @@ class PageView(context: Context, attrs: AttributeSet) : pageDelegate = when (context.getPrefInt("pageAnim")) { 0 -> CoverPageDelegate(this) 1 -> SlidePageDelegate(this) - 2 -> ScrollPageDelegate(this) + 2 -> SimulationPageDelegate(this) + 3 -> ScrollPageDelegate(this) else -> NoAnimPageDelegate(this) } upContent() diff --git a/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlMesh.java b/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlMesh.java new file mode 100644 index 000000000..448de5bce --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlMesh.java @@ -0,0 +1,957 @@ +package io.legado.app.ui.widget.page.curl; + +import android.graphics.Bitmap; +import android.graphics.Color; +import android.graphics.PointF; +import android.graphics.RectF; +import android.opengl.GLUtils; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; + +import javax.microedition.khronos.opengles.GL10; + +/** + * Class implementing actual curl/page rendering. + * + * @author harism + */ +public class CurlMesh { + + // Flag for rendering some lines used for developing. Shows + // curl position and one for the direction from the + // position given. Comes handy once playing around with different + // ways for following pointer. + private static final boolean DRAW_CURL_POSITION = false; + // Flag for drawing polygon outlines. Using this flag crashes on emulator + // due to reason unknown to me. Leaving it here anyway as seeing polygon + // outlines gives good insight how original rectangle is divided. + private static final boolean DRAW_POLYGON_OUTLINES = false; + // Flag for enabling shadow rendering. + private static final boolean DRAW_SHADOW = true; + // Flag for texture rendering. While this is likely something you + // don't want to do it's been used for development purposes as texture + // rendering is rather slow on emulator. + private static final boolean DRAW_TEXTURE = true; + + // Colors for shadow. Inner one is the color drawn next to surface where + // shadowed area starts and outer one is color shadow ends to. + private static final float[] SHADOW_INNER_COLOR = {0f, 0f, 0f, .5f}; + private static final float[] SHADOW_OUTER_COLOR = {0f, 0f, 0f, .0f}; + + // Let's avoid using 'new' as much as possible. Meaning we introduce arrays + // once here and reuse them on runtime. Doesn't really have very much effect + // but avoids some garbage collections from happening. + private Array mArrDropShadowVertices; + private Array mArrIntersections; + private Array mArrOutputVertices; + private Array mArrRotatedVertices; + private Array mArrScanLines; + private Array mArrSelfShadowVertices; + private Array mArrTempShadowVertices; + private Array mArrTempVertices; + + // Buffers for feeding rasterizer. + private FloatBuffer mBufColors; + private FloatBuffer mBufCurlPositionLines; + private FloatBuffer mBufShadowColors; + private FloatBuffer mBufShadowVertices; + private FloatBuffer mBufTexCoords; + private FloatBuffer mBufVertices; + + private int mCurlPositionLinesCount; + private int mDropShadowCount; + + // Boolean for 'flipping' texture sideways. + private boolean mFlipTexture = false; + // Maximum number of split lines used for creating a curl. + private int mMaxCurlSplits; + + // Bounding rectangle for this mesh. mRectagle[0] = top-left corner, + // mRectangle[1] = bottom-left, mRectangle[2] = top-right and mRectangle[3] + // bottom-right. + private final Vertex[] mRectangle = new Vertex[4]; + private int mSelfShadowCount; + + private boolean mTextureBack = false; + // Texture ids and other variables. + private int[] mTextureIds = null; + private final CurlPage mTexturePage = new CurlPage(); + private final RectF mTextureRectBack = new RectF(); + private final RectF mTextureRectFront = new RectF(); + + private int mVerticesCountBack; + private int mVerticesCountFront; + + /** + * Constructor for mesh object. + * + * @param maxCurlSplits Maximum number curl can be divided into. The bigger the value + * the smoother curl will be. With the cost of having more + * polygons for drawing. + */ + public CurlMesh(int maxCurlSplits) { + // There really is no use for 0 splits. + mMaxCurlSplits = maxCurlSplits < 1 ? 1 : maxCurlSplits; + + mArrScanLines = new Array(maxCurlSplits + 2); + mArrOutputVertices = new Array(7); + mArrRotatedVertices = new Array(4); + mArrIntersections = new Array(2); + mArrTempVertices = new Array(7 + 4); + for (int i = 0; i < 7 + 4; ++i) { + mArrTempVertices.add(new Vertex()); + } + + if (DRAW_SHADOW) { + mArrSelfShadowVertices = new Array( + (mMaxCurlSplits + 2) * 2); + mArrDropShadowVertices = new Array( + (mMaxCurlSplits + 2) * 2); + mArrTempShadowVertices = new Array( + (mMaxCurlSplits + 2) * 2); + for (int i = 0; i < (mMaxCurlSplits + 2) * 2; ++i) { + mArrTempShadowVertices.add(new ShadowVertex()); + } + } + + // Rectangle consists of 4 vertices. Index 0 = top-left, index 1 = + // bottom-left, index 2 = top-right and index 3 = bottom-right. + for (int i = 0; i < 4; ++i) { + mRectangle[i] = new Vertex(); + } + // Set up shadow penumbra direction to each vertex. We do fake 'self + // shadow' calculations based on this information. + mRectangle[0].mPenumbraX = mRectangle[1].mPenumbraX = mRectangle[1].mPenumbraY = mRectangle[3].mPenumbraY = -1; + mRectangle[0].mPenumbraY = mRectangle[2].mPenumbraX = mRectangle[2].mPenumbraY = mRectangle[3].mPenumbraX = 1; + + if (DRAW_CURL_POSITION) { + mCurlPositionLinesCount = 3; + ByteBuffer hvbb = ByteBuffer + .allocateDirect(mCurlPositionLinesCount * 2 * 2 * 4); + hvbb.order(ByteOrder.nativeOrder()); + mBufCurlPositionLines = hvbb.asFloatBuffer(); + mBufCurlPositionLines.position(0); + } + + // There are 4 vertices from bounding rect, max 2 from adding split line + // to two corners and curl consists of max mMaxCurlSplits lines each + // outputting 2 vertices. + int maxVerticesCount = 4 + 2 + (2 * mMaxCurlSplits); + ByteBuffer vbb = ByteBuffer.allocateDirect(maxVerticesCount * 3 * 4); + vbb.order(ByteOrder.nativeOrder()); + mBufVertices = vbb.asFloatBuffer(); + mBufVertices.position(0); + + if (DRAW_TEXTURE) { + ByteBuffer tbb = ByteBuffer + .allocateDirect(maxVerticesCount * 2 * 4); + tbb.order(ByteOrder.nativeOrder()); + mBufTexCoords = tbb.asFloatBuffer(); + mBufTexCoords.position(0); + } + + ByteBuffer cbb = ByteBuffer.allocateDirect(maxVerticesCount * 4 * 4); + cbb.order(ByteOrder.nativeOrder()); + mBufColors = cbb.asFloatBuffer(); + mBufColors.position(0); + + if (DRAW_SHADOW) { + int maxShadowVerticesCount = (mMaxCurlSplits + 2) * 2 * 2; + ByteBuffer scbb = ByteBuffer + .allocateDirect(maxShadowVerticesCount * 4 * 4); + scbb.order(ByteOrder.nativeOrder()); + mBufShadowColors = scbb.asFloatBuffer(); + mBufShadowColors.position(0); + + ByteBuffer sibb = ByteBuffer + .allocateDirect(maxShadowVerticesCount * 3 * 4); + sibb.order(ByteOrder.nativeOrder()); + mBufShadowVertices = sibb.asFloatBuffer(); + mBufShadowVertices.position(0); + + mDropShadowCount = mSelfShadowCount = 0; + } + } + + /** + * Adds vertex to buffers. + */ + private void addVertex(Vertex vertex) { + mBufVertices.put((float) vertex.mPosX); + mBufVertices.put((float) vertex.mPosY); + mBufVertices.put((float) vertex.mPosZ); + mBufColors.put(vertex.mColorFactor * Color.red(vertex.mColor) / 255f); + mBufColors.put(vertex.mColorFactor * Color.green(vertex.mColor) / 255f); + mBufColors.put(vertex.mColorFactor * Color.blue(vertex.mColor) / 255f); + mBufColors.put(Color.alpha(vertex.mColor) / 255f); + if (DRAW_TEXTURE) { + mBufTexCoords.put((float) vertex.mTexX); + mBufTexCoords.put((float) vertex.mTexY); + } + } + + /** + * Sets curl for this mesh. + * + * @param curlPos Position for curl 'center'. Can be any point on line collinear + * to curl. + * @param curlDir Curl direction, should be normalized. + * @param radius Radius of curl. + */ + public synchronized void curl(PointF curlPos, PointF curlDir, double radius) { + + // First add some 'helper' lines used for development. + if (DRAW_CURL_POSITION) { + mBufCurlPositionLines.position(0); + + mBufCurlPositionLines.put(curlPos.x); + mBufCurlPositionLines.put(curlPos.y - 1.0f); + mBufCurlPositionLines.put(curlPos.x); + mBufCurlPositionLines.put(curlPos.y + 1.0f); + mBufCurlPositionLines.put(curlPos.x - 1.0f); + mBufCurlPositionLines.put(curlPos.y); + mBufCurlPositionLines.put(curlPos.x + 1.0f); + mBufCurlPositionLines.put(curlPos.y); + + mBufCurlPositionLines.put(curlPos.x); + mBufCurlPositionLines.put(curlPos.y); + mBufCurlPositionLines.put(curlPos.x + curlDir.x * 2); + mBufCurlPositionLines.put(curlPos.y + curlDir.y * 2); + + mBufCurlPositionLines.position(0); + } + + // Actual 'curl' implementation starts here. + mBufVertices.position(0); + mBufColors.position(0); + if (DRAW_TEXTURE) { + mBufTexCoords.position(0); + } + + // Calculate curl angle from direction. + double curlAngle = Math.acos(curlDir.x); + curlAngle = curlDir.y > 0 ? -curlAngle : curlAngle; + + // Initiate rotated rectangle which's is translated to curlPos and + // rotated so that curl direction heads to right (1,0). Vertices are + // ordered in ascending order based on x -coordinate at the same time. + // And using y -coordinate in very rare case in which two vertices have + // same x -coordinate. + mArrTempVertices.addAll(mArrRotatedVertices); + mArrRotatedVertices.clear(); + for (int i = 0; i < 4; ++i) { + Vertex v = mArrTempVertices.remove(0); + v.set(mRectangle[i]); + v.translate(-curlPos.x, -curlPos.y); + v.rotateZ(-curlAngle); + int j = 0; + for (; j < mArrRotatedVertices.size(); ++j) { + Vertex v2 = mArrRotatedVertices.get(j); + if (v.mPosX > v2.mPosX) { + break; + } + if (v.mPosX == v2.mPosX && v.mPosY > v2.mPosY) { + break; + } + } + mArrRotatedVertices.add(j, v); + } + + // Rotated rectangle lines/vertex indices. We need to find bounding + // lines for rotated rectangle. After sorting vertices according to + // their x -coordinate we don't have to worry about vertices at indices + // 0 and 1. But due to inaccuracy it's possible vertex 3 is not the + // opposing corner from vertex 0. So we are calculating distance from + // vertex 0 to vertices 2 and 3 - and altering line indices if needed. + // Also vertices/lines are given in an order first one has x -coordinate + // at least the latter one. This property is used in getIntersections to + // see if there is an intersection. + int lines[][] = {{0, 1}, {0, 2}, {1, 3}, {2, 3}}; + { + // TODO: There really has to be more 'easier' way of doing this - + // not including extensive use of sqrt. + Vertex v0 = mArrRotatedVertices.get(0); + Vertex v2 = mArrRotatedVertices.get(2); + Vertex v3 = mArrRotatedVertices.get(3); + double dist2 = Math.sqrt((v0.mPosX - v2.mPosX) + * (v0.mPosX - v2.mPosX) + (v0.mPosY - v2.mPosY) + * (v0.mPosY - v2.mPosY)); + double dist3 = Math.sqrt((v0.mPosX - v3.mPosX) + * (v0.mPosX - v3.mPosX) + (v0.mPosY - v3.mPosY) + * (v0.mPosY - v3.mPosY)); + if (dist2 > dist3) { + lines[1][1] = 3; + lines[2][1] = 2; + } + } + + mVerticesCountFront = mVerticesCountBack = 0; + + if (DRAW_SHADOW) { + mArrTempShadowVertices.addAll(mArrDropShadowVertices); + mArrTempShadowVertices.addAll(mArrSelfShadowVertices); + mArrDropShadowVertices.clear(); + mArrSelfShadowVertices.clear(); + } + + // Length of 'curl' curve. + double curlLength = Math.PI * radius; + // Calculate scan lines. + // TODO: Revisit this code one day. There is room for optimization here. + mArrScanLines.clear(); + if (mMaxCurlSplits > 0) { + mArrScanLines.add((double) 0); + } + for (int i = 1; i < mMaxCurlSplits; ++i) { + mArrScanLines.add((-curlLength * i) / (mMaxCurlSplits - 1)); + } + // As mRotatedVertices is ordered regarding x -coordinate, adding + // this scan line produces scan area picking up vertices which are + // rotated completely. One could say 'until infinity'. + mArrScanLines.add(mArrRotatedVertices.get(3).mPosX - 1); + + // Start from right most vertex. Pretty much the same as first scan area + // is starting from 'infinity'. + double scanXmax = mArrRotatedVertices.get(0).mPosX + 1; + + for (int i = 0; i < mArrScanLines.size(); ++i) { + // Once we have scanXmin and scanXmax we have a scan area to start + // working with. + double scanXmin = mArrScanLines.get(i); + // First iterate 'original' rectangle vertices within scan area. + for (int j = 0; j < mArrRotatedVertices.size(); ++j) { + Vertex v = mArrRotatedVertices.get(j); + // Test if vertex lies within this scan area. + // TODO: Frankly speaking, can't remember why equality check was + // added to both ends. Guessing it was somehow related to case + // where radius=0f, which, given current implementation, could + // be handled much more effectively anyway. + if (v.mPosX >= scanXmin && v.mPosX <= scanXmax) { + // Pop out a vertex from temp vertices. + Vertex n = mArrTempVertices.remove(0); + n.set(v); + // This is done solely for triangulation reasons. Given a + // rotated rectangle it has max 2 vertices having + // intersection. + Array intersections = getIntersections( + mArrRotatedVertices, lines, n.mPosX); + // In a sense one could say we're adding vertices always in + // two, positioned at the ends of intersecting line. And for + // triangulation to work properly they are added based on y + // -coordinate. And this if-else is doing it for us. + if (intersections.size() == 1 + && intersections.get(0).mPosY > v.mPosY) { + // In case intersecting vertex is higher add it first. + mArrOutputVertices.addAll(intersections); + mArrOutputVertices.add(n); + } else if (intersections.size() <= 1) { + // Otherwise add original vertex first. + mArrOutputVertices.add(n); + mArrOutputVertices.addAll(intersections); + } else { + // There should never be more than 1 intersecting + // vertex. But if it happens as a fallback simply skip + // everything. + mArrTempVertices.add(n); + mArrTempVertices.addAll(intersections); + } + } + } + + // Search for scan line intersections. + Array intersections = getIntersections(mArrRotatedVertices, + lines, scanXmin); + + // We expect to get 0 or 2 vertices. In rare cases there's only one + // but in general given a scan line intersecting rectangle there + // should be 2 intersecting vertices. + if (intersections.size() == 2) { + // There were two intersections, add them based on y + // -coordinate, higher first, lower last. + Vertex v1 = intersections.get(0); + Vertex v2 = intersections.get(1); + if (v1.mPosY < v2.mPosY) { + mArrOutputVertices.add(v2); + mArrOutputVertices.add(v1); + } else { + mArrOutputVertices.addAll(intersections); + } + } else if (intersections.size() != 0) { + // This happens in a case in which there is a original vertex + // exactly at scan line or something went very much wrong if + // there are 3+ vertices. What ever the reason just return the + // vertices to temp vertices for later use. In former case it + // was handled already earlier once iterating through + // mRotatedVertices, in latter case it's better to avoid doing + // anything with them. + mArrTempVertices.addAll(intersections); + } + + // Add vertices found during this iteration to vertex etc buffers. + while (mArrOutputVertices.size() > 0) { + Vertex v = mArrOutputVertices.remove(0); + mArrTempVertices.add(v); + + // Local texture front-facing flag. + boolean textureFront; + + // Untouched vertices. + if (i == 0) { + textureFront = true; + mVerticesCountFront++; + } + // 'Completely' rotated vertices. + else if (i == mArrScanLines.size() - 1 || curlLength == 0) { + v.mPosX = -(curlLength + v.mPosX); + v.mPosZ = 2 * radius; + v.mPenumbraX = -v.mPenumbraX; + + textureFront = false; + mVerticesCountBack++; + } + // Vertex lies within 'curl'. + else { + // Even though it's not obvious from the if-else clause, + // here v.mPosX is between [-curlLength, 0]. And we can do + // calculations around a half cylinder. + double rotY = Math.PI * (v.mPosX / curlLength); + v.mPosX = radius * Math.sin(rotY); + v.mPosZ = radius - (radius * Math.cos(rotY)); + v.mPenumbraX *= Math.cos(rotY); + // Map color multiplier to [.1f, 1f] range. + v.mColorFactor = (float) (.1f + .9f * Math.sqrt(Math + .sin(rotY) + 1)); + + if (v.mPosZ >= radius) { + textureFront = false; + mVerticesCountBack++; + } else { + textureFront = true; + mVerticesCountFront++; + } + } + + // We use local textureFront for flipping backside texture + // locally. Plus additionally if mesh is in flip texture mode, + // we'll make the procedure "backwards". Also, until this point, + // texture coordinates are within [0, 1] range so we'll adjust + // them to final texture coordinates too. + if (textureFront != mFlipTexture) { + v.mTexX *= mTextureRectFront.right; + v.mTexY *= mTextureRectFront.bottom; + v.mColor = mTexturePage.getColor(CurlPage.SIDE_FRONT); + } else { + v.mTexX *= mTextureRectBack.right; + v.mTexY *= mTextureRectBack.bottom; + v.mColor = mTexturePage.getColor(CurlPage.SIDE_BACK); + } + + // Move vertex back to 'world' coordinates. + v.rotateZ(curlAngle); + v.translate(curlPos.x, curlPos.y); + addVertex(v); + + // Drop shadow is cast 'behind' the curl. + if (DRAW_SHADOW && v.mPosZ > 0 && v.mPosZ <= radius) { + ShadowVertex sv = mArrTempShadowVertices.remove(0); + sv.mPosX = v.mPosX; + sv.mPosY = v.mPosY; + sv.mPosZ = v.mPosZ; + sv.mPenumbraX = (v.mPosZ / 2) * -curlDir.x; + sv.mPenumbraY = (v.mPosZ / 2) * -curlDir.y; + sv.mPenumbraColor = v.mPosZ / radius; + int idx = (mArrDropShadowVertices.size() + 1) / 2; + mArrDropShadowVertices.add(idx, sv); + } + // Self shadow is cast partly over mesh. + if (DRAW_SHADOW && v.mPosZ > radius) { + ShadowVertex sv = mArrTempShadowVertices.remove(0); + sv.mPosX = v.mPosX; + sv.mPosY = v.mPosY; + sv.mPosZ = v.mPosZ; + sv.mPenumbraX = ((v.mPosZ - radius) / 3) * v.mPenumbraX; + sv.mPenumbraY = ((v.mPosZ - radius) / 3) * v.mPenumbraY; + sv.mPenumbraColor = (v.mPosZ - radius) / (2 * radius); + int idx = (mArrSelfShadowVertices.size() + 1) / 2; + mArrSelfShadowVertices.add(idx, sv); + } + } + + // Switch scanXmin as scanXmax for next iteration. + scanXmax = scanXmin; + } + + mBufVertices.position(0); + mBufColors.position(0); + if (DRAW_TEXTURE) { + mBufTexCoords.position(0); + } + + // Add shadow Vertices. + if (DRAW_SHADOW) { + mBufShadowColors.position(0); + mBufShadowVertices.position(0); + mDropShadowCount = 0; + + for (int i = 0; i < mArrDropShadowVertices.size(); ++i) { + ShadowVertex sv = mArrDropShadowVertices.get(i); + mBufShadowVertices.put((float) sv.mPosX); + mBufShadowVertices.put((float) sv.mPosY); + mBufShadowVertices.put((float) sv.mPosZ); + mBufShadowVertices.put((float) (sv.mPosX + sv.mPenumbraX)); + mBufShadowVertices.put((float) (sv.mPosY + sv.mPenumbraY)); + mBufShadowVertices.put((float) sv.mPosZ); + for (int j = 0; j < 4; ++j) { + double color = SHADOW_OUTER_COLOR[j] + + (SHADOW_INNER_COLOR[j] - SHADOW_OUTER_COLOR[j]) + * sv.mPenumbraColor; + mBufShadowColors.put((float) color); + } + mBufShadowColors.put(SHADOW_OUTER_COLOR); + mDropShadowCount += 2; + } + mSelfShadowCount = 0; + for (int i = 0; i < mArrSelfShadowVertices.size(); ++i) { + ShadowVertex sv = mArrSelfShadowVertices.get(i); + mBufShadowVertices.put((float) sv.mPosX); + mBufShadowVertices.put((float) sv.mPosY); + mBufShadowVertices.put((float) sv.mPosZ); + mBufShadowVertices.put((float) (sv.mPosX + sv.mPenumbraX)); + mBufShadowVertices.put((float) (sv.mPosY + sv.mPenumbraY)); + mBufShadowVertices.put((float) sv.mPosZ); + for (int j = 0; j < 4; ++j) { + double color = SHADOW_OUTER_COLOR[j] + + (SHADOW_INNER_COLOR[j] - SHADOW_OUTER_COLOR[j]) + * sv.mPenumbraColor; + mBufShadowColors.put((float) color); + } + mBufShadowColors.put(SHADOW_OUTER_COLOR); + mSelfShadowCount += 2; + } + mBufShadowColors.position(0); + mBufShadowVertices.position(0); + } + } + + /** + * Calculates intersections for given scan line. + */ + private Array getIntersections(Array vertices, + int[][] lineIndices, double scanX) { + mArrIntersections.clear(); + // Iterate through rectangle lines each re-presented as a pair of + // vertices. + for (int j = 0; j < lineIndices.length; j++) { + Vertex v1 = vertices.get(lineIndices[j][0]); + Vertex v2 = vertices.get(lineIndices[j][1]); + // Here we expect that v1.mPosX >= v2.mPosX and wont do intersection + // test the opposite way. + if (v1.mPosX > scanX && v2.mPosX < scanX) { + // There is an intersection, calculate coefficient telling 'how + // far' scanX is from v2. + double c = (scanX - v2.mPosX) / (v1.mPosX - v2.mPosX); + Vertex n = mArrTempVertices.remove(0); + n.set(v2); + n.mPosX = scanX; + n.mPosY += (v1.mPosY - v2.mPosY) * c; + if (DRAW_TEXTURE) { + n.mTexX += (v1.mTexX - v2.mTexX) * c; + n.mTexY += (v1.mTexY - v2.mTexY) * c; + } + if (DRAW_SHADOW) { + n.mPenumbraX += (v1.mPenumbraX - v2.mPenumbraX) * c; + n.mPenumbraY += (v1.mPenumbraY - v2.mPenumbraY) * c; + } + mArrIntersections.add(n); + } + } + return mArrIntersections; + } + + /** + * Getter for textures page for this mesh. + */ + public synchronized CurlPage getTexturePage() { + return mTexturePage; + } + + /** + * Renders our page curl mesh. + */ + public synchronized void onDrawFrame(GL10 gl) { + // First allocate texture if there is not one yet. + if (DRAW_TEXTURE && mTextureIds == null) { + // Generate texture. + mTextureIds = new int[2]; + gl.glGenTextures(2, mTextureIds, 0); + for (int textureId : mTextureIds) { + // Set texture attributes. + gl.glBindTexture(GL10.GL_TEXTURE_2D, textureId); + gl.glTexParameterf(GL10.GL_TEXTURE_2D, + GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST); + gl.glTexParameterf(GL10.GL_TEXTURE_2D, + GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_NEAREST); + gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, + GL10.GL_CLAMP_TO_EDGE); + gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, + GL10.GL_CLAMP_TO_EDGE); + } + } + + if (DRAW_TEXTURE && mTexturePage.getTexturesChanged()) { + gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureIds[0]); + Bitmap texture = mTexturePage.getTexture(mTextureRectFront, + CurlPage.SIDE_FRONT); + GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, texture, 0); + texture.recycle(); + + mTextureBack = mTexturePage.hasBackTexture(); + if (mTextureBack) { + gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureIds[1]); + texture = mTexturePage.getTexture(mTextureRectBack, + CurlPage.SIDE_BACK); + GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, texture, 0); + texture.recycle(); + } else { + mTextureRectBack.set(mTextureRectFront); + } + + mTexturePage.recycle(); + reset(); + } + + // Some 'global' settings. + gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); + + // TODO: Drop shadow drawing is done temporarily here to hide some + // problems with its calculation. + if (DRAW_SHADOW) { + gl.glDisable(GL10.GL_TEXTURE_2D); + gl.glEnable(GL10.GL_BLEND); + gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA); + gl.glEnableClientState(GL10.GL_COLOR_ARRAY); + gl.glColorPointer(4, GL10.GL_FLOAT, 0, mBufShadowColors); + gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mBufShadowVertices); + gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, mDropShadowCount); + gl.glDisableClientState(GL10.GL_COLOR_ARRAY); + gl.glDisable(GL10.GL_BLEND); + } + + if (DRAW_TEXTURE) { + gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); + gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, mBufTexCoords); + } + gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mBufVertices); + // Enable color array. + gl.glEnableClientState(GL10.GL_COLOR_ARRAY); + gl.glColorPointer(4, GL10.GL_FLOAT, 0, mBufColors); + + // Draw front facing blank vertices. + gl.glDisable(GL10.GL_TEXTURE_2D); + gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, mVerticesCountFront); + + // Draw front facing texture. + if (DRAW_TEXTURE) { + gl.glEnable(GL10.GL_BLEND); + gl.glEnable(GL10.GL_TEXTURE_2D); + + if (!mFlipTexture || !mTextureBack) { + gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureIds[0]); + } else { + gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureIds[1]); + } + + gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA); + gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, mVerticesCountFront); + + gl.glDisable(GL10.GL_BLEND); + gl.glDisable(GL10.GL_TEXTURE_2D); + } + + int backStartIdx = Math.max(0, mVerticesCountFront - 2); + int backCount = mVerticesCountFront + mVerticesCountBack - backStartIdx; + + // Draw back facing blank vertices. + gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, backStartIdx, backCount); + + // Draw back facing texture. + if (DRAW_TEXTURE) { + gl.glEnable(GL10.GL_BLEND); + gl.glEnable(GL10.GL_TEXTURE_2D); + + if (mFlipTexture || !mTextureBack) { + gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureIds[0]); + } else { + gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureIds[1]); + } + + gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA); + gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, backStartIdx, backCount); + + gl.glDisable(GL10.GL_BLEND); + gl.glDisable(GL10.GL_TEXTURE_2D); + } + + // Disable textures and color array. + gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY); + gl.glDisableClientState(GL10.GL_COLOR_ARRAY); + + if (DRAW_POLYGON_OUTLINES) { + gl.glEnable(GL10.GL_BLEND); + gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA); + gl.glLineWidth(1.0f); + gl.glColor4f(0.5f, 0.5f, 1.0f, 1.0f); + gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mBufVertices); + gl.glDrawArrays(GL10.GL_LINE_STRIP, 0, mVerticesCountFront); + gl.glDisable(GL10.GL_BLEND); + } + + if (DRAW_CURL_POSITION) { + gl.glEnable(GL10.GL_BLEND); + gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA); + gl.glLineWidth(1.0f); + gl.glColor4f(1.0f, 0.5f, 0.5f, 1.0f); + gl.glVertexPointer(2, GL10.GL_FLOAT, 0, mBufCurlPositionLines); + gl.glDrawArrays(GL10.GL_LINES, 0, mCurlPositionLinesCount * 2); + gl.glDisable(GL10.GL_BLEND); + } + + if (DRAW_SHADOW) { + gl.glEnable(GL10.GL_BLEND); + gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA); + gl.glEnableClientState(GL10.GL_COLOR_ARRAY); + gl.glColorPointer(4, GL10.GL_FLOAT, 0, mBufShadowColors); + gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mBufShadowVertices); + gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, mDropShadowCount, + mSelfShadowCount); + gl.glDisableClientState(GL10.GL_COLOR_ARRAY); + gl.glDisable(GL10.GL_BLEND); + } + + gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); + } + + /** + * Resets mesh to 'initial' state. Meaning this mesh will draw a plain + * textured rectangle after call to this method. + */ + public synchronized void reset() { + mBufVertices.position(0); + mBufColors.position(0); + if (DRAW_TEXTURE) { + mBufTexCoords.position(0); + } + for (int i = 0; i < 4; ++i) { + Vertex tmp = mArrTempVertices.get(0); + tmp.set(mRectangle[i]); + + if (mFlipTexture) { + tmp.mTexX *= mTextureRectBack.right; + tmp.mTexY *= mTextureRectBack.bottom; + tmp.mColor = mTexturePage.getColor(CurlPage.SIDE_BACK); + } else { + tmp.mTexX *= mTextureRectFront.right; + tmp.mTexY *= mTextureRectFront.bottom; + tmp.mColor = mTexturePage.getColor(CurlPage.SIDE_FRONT); + } + + addVertex(tmp); + } + mVerticesCountFront = 4; + mVerticesCountBack = 0; + mBufVertices.position(0); + mBufColors.position(0); + if (DRAW_TEXTURE) { + mBufTexCoords.position(0); + } + + mDropShadowCount = mSelfShadowCount = 0; + } + + /** + * Resets allocated texture id forcing creation of new one. After calling + * this method you most likely want to set bitmap too as it's lost. This + * method should be called only once e.g GL context is re-created as this + * method does not release previous texture id, only makes sure new one is + * requested on next render. + */ + public synchronized void resetTexture() { + mTextureIds = null; + } + + /** + * If true, flips texture sideways. + */ + public synchronized void setFlipTexture(boolean flipTexture) { + mFlipTexture = flipTexture; + if (flipTexture) { + setTexCoords(1f, 0f, 0f, 1f); + } else { + setTexCoords(0f, 0f, 1f, 1f); + } + } + + /** + * Update mesh bounds. + */ + public void setRect(RectF r) { + mRectangle[0].mPosX = r.left; + mRectangle[0].mPosY = r.top; + mRectangle[1].mPosX = r.left; + mRectangle[1].mPosY = r.bottom; + mRectangle[2].mPosX = r.right; + mRectangle[2].mPosY = r.top; + mRectangle[3].mPosX = r.right; + mRectangle[3].mPosY = r.bottom; + } + + /** + * Sets texture coordinates to mRectangle vertices. + */ + private synchronized void setTexCoords(float left, float top, float right, + float bottom) { + mRectangle[0].mTexX = left; + mRectangle[0].mTexY = top; + mRectangle[1].mTexX = left; + mRectangle[1].mTexY = bottom; + mRectangle[2].mTexX = right; + mRectangle[2].mTexY = top; + mRectangle[3].mTexX = right; + mRectangle[3].mTexY = bottom; + } + + /** + * Simple fixed size array implementation. + */ + private class Array { + private Object[] mArray; + private int mCapacity; + private int mSize; + + public Array(int capacity) { + mCapacity = capacity; + mArray = new Object[capacity]; + } + + public void add(int index, T item) { + if (index < 0 || index > mSize || mSize >= mCapacity) { + throw new IndexOutOfBoundsException(); + } + for (int i = mSize; i > index; --i) { + mArray[i] = mArray[i - 1]; + } + mArray[index] = item; + ++mSize; + } + + public void add(T item) { + if (mSize >= mCapacity) { + throw new IndexOutOfBoundsException(); + } + mArray[mSize++] = item; + } + + public void addAll(Array array) { + if (mSize + array.size() > mCapacity) { + throw new IndexOutOfBoundsException(); + } + for (int i = 0; i < array.size(); ++i) { + mArray[mSize++] = array.get(i); + } + } + + public void clear() { + mSize = 0; + } + + @SuppressWarnings("unchecked") + public T get(int index) { + if (index < 0 || index >= mSize) { + throw new IndexOutOfBoundsException(); + } + return (T) mArray[index]; + } + + @SuppressWarnings("unchecked") + public T remove(int index) { + if (index < 0 || index >= mSize) { + throw new IndexOutOfBoundsException(); + } + T item = (T) mArray[index]; + for (int i = index; i < mSize - 1; ++i) { + mArray[i] = mArray[i + 1]; + } + --mSize; + return item; + } + + public int size() { + return mSize; + } + + } + + /** + * Holder for shadow vertex information. + */ + private class ShadowVertex { + public double mPenumbraColor; + public double mPenumbraX; + public double mPenumbraY; + public double mPosX; + public double mPosY; + public double mPosZ; + } + + /** + * Holder for vertex information. + */ + private class Vertex { + public int mColor; + public float mColorFactor; + public double mPenumbraX; + public double mPenumbraY; + public double mPosX; + public double mPosY; + public double mPosZ; + public double mTexX; + public double mTexY; + + public Vertex() { + mPosX = mPosY = mPosZ = mTexX = mTexY = 0; + mColorFactor = 1.0f; + } + + public void rotateZ(double theta) { + double cos = Math.cos(theta); + double sin = Math.sin(theta); + double x = mPosX * cos + mPosY * sin; + double y = mPosX * -sin + mPosY * cos; + mPosX = x; + mPosY = y; + double px = mPenumbraX * cos + mPenumbraY * sin; + double py = mPenumbraX * -sin + mPenumbraY * cos; + mPenumbraX = px; + mPenumbraY = py; + } + + public void set(Vertex vertex) { + mPosX = vertex.mPosX; + mPosY = vertex.mPosY; + mPosZ = vertex.mPosZ; + mTexX = vertex.mTexX; + mTexY = vertex.mTexY; + mPenumbraX = vertex.mPenumbraX; + mPenumbraY = vertex.mPenumbraY; + mColor = vertex.mColor; + mColorFactor = vertex.mColorFactor; + } + + public void translate(double dx, double dy) { + mPosX += dx; + mPosY += dy; + } + } +} diff --git a/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlPage.java b/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlPage.java new file mode 100644 index 000000000..e2ea847db --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlPage.java @@ -0,0 +1,195 @@ +package io.legado.app.ui.widget.page.curl; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.RectF; + +/** + * Storage class for page textures, blend colors and possibly some other values + * in the future. + * + * @author harism + */ +public class CurlPage { + + public static final int SIDE_BACK = 2; + public static final int SIDE_BOTH = 3; + public static final int SIDE_FRONT = 1; + + private int mColorBack; + private int mColorFront; + private Bitmap mTextureBack; + private Bitmap mTextureFront; + private boolean mTexturesChanged; + + /** + * Default constructor. + */ + public CurlPage() { + reset(); + } + + /** + * Getter for color. + */ + public int getColor(int side) { + switch (side) { + case SIDE_FRONT: + return mColorFront; + default: + return mColorBack; + } + } + + /** + * Calculates the next highest power of two for a given integer. + */ + private int getNextHighestPO2(int n) { + n -= 1; + n = n | (n >> 1); + n = n | (n >> 2); + n = n | (n >> 4); + n = n | (n >> 8); + n = n | (n >> 16); + n = n | (n >> 32); + return n + 1; + } + + /** + * Generates nearest power of two sized Bitmap for give Bitmap. Returns this + * new Bitmap using default return statement + original texture coordinates + * are stored into RectF. + */ + private Bitmap getTexture(Bitmap bitmap, RectF textureRect) { + // Bitmap original size. + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + // Bitmap size expanded to next power of two. This is done due to + // the requirement on many devices, texture width and height should + // be power of two. + int newW = getNextHighestPO2(w); + int newH = getNextHighestPO2(h); + + // TODO: Is there another way to create a bigger Bitmap and copy + // original Bitmap to it more efficiently? Immutable bitmap anyone? + Bitmap bitmapTex = Bitmap.createBitmap(newW, newH, bitmap.getConfig()); + Canvas c = new Canvas(bitmapTex); + c.drawBitmap(bitmap, 0, 0, null); + + // Calculate final texture coordinates. + float texX = (float) w / newW; + float texY = (float) h / newH; + textureRect.set(0f, 0f, texX, texY); + + return bitmapTex; + } + + /** + * Getter for textures. Creates Bitmap sized to nearest power of two, copies + * original Bitmap into it and returns it. RectF given as parameter is + * filled with actual texture coordinates in this new upscaled texture + * Bitmap. + */ + public Bitmap getTexture(RectF textureRect, int side) { + switch (side) { + case SIDE_FRONT: + return getTexture(mTextureFront, textureRect); + default: + return getTexture(mTextureBack, textureRect); + } + } + + /** + * Returns true if textures have changed. + */ + public boolean getTexturesChanged() { + return mTexturesChanged; + } + + /** + * Returns true if back siding texture exists and it differs from front + * facing one. + */ + public boolean hasBackTexture() { + return !mTextureFront.equals(mTextureBack); + } + + /** + * Recycles and frees underlying Bitmaps. + */ + public void recycle() { + if (mTextureFront != null) { + mTextureFront.recycle(); + } + mTextureFront = Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565); + mTextureFront.eraseColor(mColorFront); + if (mTextureBack != null) { + mTextureBack.recycle(); + } + mTextureBack = Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565); + mTextureBack.eraseColor(mColorBack); + mTexturesChanged = false; + } + + /** + * Resets this CurlPage into its initial state. + */ + public void reset() { + mColorBack = Color.WHITE; + mColorFront = Color.WHITE; + recycle(); + } + + /** + * Setter blend color. + */ + public void setColor(int color, int side) { + switch (side) { + case SIDE_FRONT: + mColorFront = color; + break; + case SIDE_BACK: + mColorBack = color; + break; + default: + mColorFront = mColorBack = color; + break; + } + } + + /** + * Setter for textures. + */ + public void setTexture(Bitmap texture, int side) { + if (texture == null) { + texture = Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565); + if (side == SIDE_BACK) { + texture.eraseColor(mColorBack); + } else { + texture.eraseColor(mColorFront); + } + } + switch (side) { + case SIDE_FRONT: + if (mTextureFront != null) + mTextureFront.recycle(); + mTextureFront = texture; + break; + case SIDE_BACK: + if (mTextureBack != null) + mTextureBack.recycle(); + mTextureBack = texture; + break; + case SIDE_BOTH: + if (mTextureFront != null) + mTextureFront.recycle(); + if (mTextureBack != null) + mTextureBack.recycle(); + mTextureFront = mTextureBack = texture; + break; + } + mTexturesChanged = true; + } + +} diff --git a/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlRenderer.java b/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlRenderer.java new file mode 100644 index 000000000..7b18c744d --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlRenderer.java @@ -0,0 +1,250 @@ +package io.legado.app.ui.widget.page.curl; + +import android.graphics.Color; +import android.graphics.PointF; +import android.graphics.RectF; +import android.opengl.GLSurfaceView; +import android.opengl.GLU; + +import java.util.Vector; + +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.opengles.GL10; + +/** + * Actual renderer class. + * + * @author harism + */ +public class CurlRenderer implements GLSurfaceView.Renderer { + + // Constant for requesting left page rect. + public static final int PAGE_LEFT = 1; + // Constant for requesting right page rect. + public static final int PAGE_RIGHT = 2; + // Constants for changing view mode. + public static final int SHOW_ONE_PAGE = 1; + public static final int SHOW_TWO_PAGES = 2; + // Set to true for checking quickly how perspective projection looks. + private static final boolean USE_PERSPECTIVE_PROJECTION = false; + // Background fill color. + private int mBackgroundColor; + // Curl meshes used for static and dynamic rendering. + private Vector mCurlMeshes; + private RectF mMargins = new RectF(); + private CurlRenderer.Observer mObserver; + // Page rectangles. + private RectF mPageRectLeft; + private RectF mPageRectRight; + // View mode. + private int mViewMode = SHOW_ONE_PAGE; + // Screen size. + private int mViewportWidth, mViewportHeight; + // Rect for render area. + private RectF mViewRect = new RectF(); + + /** + * Basic constructor. + */ + public CurlRenderer(CurlRenderer.Observer observer) { + mObserver = observer; + mCurlMeshes = new Vector(); + mPageRectLeft = new RectF(); + mPageRectRight = new RectF(); + } + + /** + * Adds CurlMesh to this renderer. + */ + public synchronized void addCurlMesh(CurlMesh mesh) { + removeCurlMesh(mesh); + mCurlMeshes.add(mesh); + } + + /** + * Returns rect reserved for left or right page. Value page should be + * PAGE_LEFT or PAGE_RIGHT. + */ + public RectF getPageRect(int page) { + if (page == PAGE_LEFT) { + return mPageRectLeft; + } else if (page == PAGE_RIGHT) { + return mPageRectRight; + } + return null; + } + + @Override + public synchronized void onDrawFrame(GL10 gl) { + + mObserver.onDrawFrame(); + + gl.glClearColor(Color.red(mBackgroundColor) / 255f, + Color.green(mBackgroundColor) / 255f, + Color.blue(mBackgroundColor) / 255f, + Color.alpha(mBackgroundColor) / 255f); + gl.glClear(GL10.GL_COLOR_BUFFER_BIT); + gl.glLoadIdentity(); + + if (USE_PERSPECTIVE_PROJECTION) { + gl.glTranslatef(0, 0, -6f); + } + + for (int i = 0; i < mCurlMeshes.size(); ++i) { + mCurlMeshes.get(i).onDrawFrame(gl); + } + } + + @Override + public void onSurfaceChanged(GL10 gl, int width, int height) { + gl.glViewport(0, 0, width, height); + mViewportWidth = width; + mViewportHeight = height; + + float ratio = (float) width / height; + mViewRect.top = 1.0f; + mViewRect.bottom = -1.0f; + mViewRect.left = -ratio; + mViewRect.right = ratio; + updatePageRects(); + + gl.glMatrixMode(GL10.GL_PROJECTION); + gl.glLoadIdentity(); + if (USE_PERSPECTIVE_PROJECTION) { + GLU.gluPerspective(gl, 20f, (float) width / height, .1f, 100f); + } else { + GLU.gluOrtho2D(gl, mViewRect.left, mViewRect.right, + mViewRect.bottom, mViewRect.top); + } + + gl.glMatrixMode(GL10.GL_MODELVIEW); + gl.glLoadIdentity(); + } + + @Override + public void onSurfaceCreated(GL10 gl, EGLConfig config) { + gl.glClearColor(0f, 0f, 0f, 1f); + gl.glShadeModel(GL10.GL_SMOOTH); + gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST); + gl.glHint(GL10.GL_LINE_SMOOTH_HINT, GL10.GL_NICEST); + gl.glHint(GL10.GL_POLYGON_SMOOTH_HINT, GL10.GL_NICEST); + gl.glEnable(GL10.GL_LINE_SMOOTH); + gl.glDisable(GL10.GL_DEPTH_TEST); + gl.glDisable(GL10.GL_CULL_FACE); + + mObserver.onSurfaceCreated(); + } + + /** + * Removes CurlMesh from this renderer. + */ + public synchronized void removeCurlMesh(CurlMesh mesh) { + while (mCurlMeshes.remove(mesh)) + ; + } + + /** + * Change background/clear color. + */ + public void setBackgroundColor(int color) { + mBackgroundColor = color; + } + + /** + * Set margins or padding. Note: margins are proportional. Meaning a value + * of .1f will produce a 10% margin. + */ + public synchronized void setMargins(float left, float top, float right, + float bottom) { + mMargins.left = left; + mMargins.top = top; + mMargins.right = right; + mMargins.bottom = bottom; + updatePageRects(); + } + + /** + * Sets visible page count to one or two. Should be either SHOW_ONE_PAGE or + * SHOW_TWO_PAGES. + */ + public synchronized void setViewMode(int viewmode) { + if (viewmode == SHOW_ONE_PAGE) { + mViewMode = viewmode; + updatePageRects(); + } else if (viewmode == SHOW_TWO_PAGES) { + mViewMode = viewmode; + updatePageRects(); + } + } + + /** + * Translates screen coordinates into view coordinates. + */ + public void translate(PointF pt) { + pt.x = mViewRect.left + (mViewRect.width() * pt.x / mViewportWidth); + pt.y = mViewRect.top - (-mViewRect.height() * pt.y / mViewportHeight); + } + + /** + * Recalculates page rectangles. + */ + private void updatePageRects() { + if (mViewRect.width() == 0 || mViewRect.height() == 0) { + return; + } else if (mViewMode == SHOW_ONE_PAGE) { + mPageRectRight.set(mViewRect); + mPageRectRight.left += mViewRect.width() * mMargins.left; + mPageRectRight.right -= mViewRect.width() * mMargins.right; + mPageRectRight.top += mViewRect.height() * mMargins.top; + mPageRectRight.bottom -= mViewRect.height() * mMargins.bottom; + + mPageRectLeft.set(mPageRectRight); + mPageRectLeft.offset(-mPageRectRight.width(), 0); + + int bitmapW = (int) ((mPageRectRight.width() * mViewportWidth) / mViewRect + .width()); + int bitmapH = (int) ((mPageRectRight.height() * mViewportHeight) / mViewRect + .height()); + mObserver.onPageSizeChanged(bitmapW, bitmapH); + } else if (mViewMode == SHOW_TWO_PAGES) { + mPageRectRight.set(mViewRect); + mPageRectRight.left += mViewRect.width() * mMargins.left; + mPageRectRight.right -= mViewRect.width() * mMargins.right; + mPageRectRight.top += mViewRect.height() * mMargins.top; + mPageRectRight.bottom -= mViewRect.height() * mMargins.bottom; + + mPageRectLeft.set(mPageRectRight); + mPageRectLeft.right = (mPageRectLeft.right + mPageRectLeft.left) / 2; + mPageRectRight.left = mPageRectLeft.right; + + int bitmapW = (int) ((mPageRectRight.width() * mViewportWidth) / mViewRect + .width()); + int bitmapH = (int) ((mPageRectRight.height() * mViewportHeight) / mViewRect + .height()); + mObserver.onPageSizeChanged(bitmapW, bitmapH); + } + } + + /** + * Observer for waiting render engine/state updates. + */ + public interface Observer { + /** + * Called from onDrawFrame called before rendering is started. This is + * intended to be used for animation purposes. + */ + public void onDrawFrame(); + + /** + * Called once page size is changed. Width and height tell the page size + * in pixels making it possible to update textures accordingly. + */ + public void onPageSizeChanged(int width, int height); + + /** + * Called from onSurfaceCreated to enable texture re-initialization etc + * what needs to be done when this happens. + */ + public void onSurfaceCreated(); + } +} diff --git a/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlView.java b/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlView.java new file mode 100644 index 000000000..c2428513c --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlView.java @@ -0,0 +1,790 @@ +package io.legado.app.ui.widget.page.curl; + +import android.content.Context; +import android.graphics.PixelFormat; +import android.graphics.PointF; +import android.graphics.RectF; +import android.opengl.GLSurfaceView; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; + +/** + * OpenGL ES View. + * + * @author harism + */ +public class CurlView extends GLSurfaceView implements View.OnTouchListener, + CurlRenderer.Observer { + + // Curl state. We are flipping none, left or right page. + private static final int CURL_LEFT = 1; + private static final int CURL_NONE = 0; + private static final int CURL_RIGHT = 2; + + // Constants for mAnimationTargetEvent. + private static final int SET_CURL_TO_LEFT = 1; + private static final int SET_CURL_TO_RIGHT = 2; + + // Shows one page at the center of view. + public static final int SHOW_ONE_PAGE = 1; + // Shows two pages side by side. + public static final int SHOW_TWO_PAGES = 2; + + private boolean mAllowLastPageCurl = true; + + private boolean mAnimate = false; + private long mAnimationDurationTime = 300; + private PointF mAnimationSource = new PointF(); + private long mAnimationStartTime; + private PointF mAnimationTarget = new PointF(); + private int mAnimationTargetEvent; + + private PointF mCurlDir = new PointF(); + + private PointF mCurlPos = new PointF(); + private int mCurlState = CURL_NONE; + // Current bitmap index. This is always showed as front of right page. + private int mCurrentIndex = 0; + + // Start position for dragging. + private PointF mDragStartPos = new PointF(); + + private boolean mEnableTouchPressure = false; + // Bitmap size. These are updated from renderer once it's initialized. + private int mPageBitmapHeight = -1; + + private int mPageBitmapWidth = -1; + // Page meshes. Left and right meshes are 'static' while curl is used to + // show page flipping. + private CurlMesh mPageCurl; + + private CurlMesh mPageLeft; + private PageProvider mPageProvider; + private CurlMesh mPageRight; + + private PointerPosition mPointerPos = new PointerPosition(); + + private CurlRenderer mRenderer; + private boolean mRenderLeftPage = true; + private SizeChangedObserver mSizeChangedObserver; + + // One page is the default. + private int mViewMode = SHOW_ONE_PAGE; + + /** + * Default constructor. + */ + public CurlView(Context ctx) { + super(ctx); + init(ctx); + } + + /** + * Default constructor. + */ + public CurlView(Context ctx, AttributeSet attrs) { + super(ctx, attrs); + init(ctx); + } + + /** + * Default constructor. + */ + public CurlView(Context ctx, AttributeSet attrs, int defStyle) { + this(ctx, attrs); + } + + /** + * Get current page index. Page indices are zero based values presenting + * page being shown on right side of the book. + */ + public int getCurrentIndex() { + return mCurrentIndex; + } + + /** + * Initialize method. + */ + private void init(Context ctx) { + setEGLConfigChooser(8, 8, 8, 8, 16, 0); + getHolder().setFormat(PixelFormat.TRANSLUCENT); + setZOrderOnTop(true); + mRenderer = new CurlRenderer(this); + setRenderer(mRenderer); + setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); + setOnTouchListener(this); + + // Even though left and right pages are static we have to allocate room + // for curl on them too as we are switching meshes. Another way would be + // to swap texture ids only. + mPageLeft = new CurlMesh(10); + mPageRight = new CurlMesh(10); + mPageCurl = new CurlMesh(10); + mPageLeft.setFlipTexture(true); + mPageRight.setFlipTexture(false); + } + + @Override + public void onDrawFrame() { + // We are not animating. + if (mAnimate == false) { + return; + } + + long currentTime = System.currentTimeMillis(); + // If animation is done. + if (currentTime >= mAnimationStartTime + mAnimationDurationTime) { + if (mAnimationTargetEvent == SET_CURL_TO_RIGHT) { + // Switch curled page to right. + CurlMesh right = mPageCurl; + CurlMesh curl = mPageRight; + right.setRect(mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT)); + right.setFlipTexture(false); + right.reset(); + mRenderer.removeCurlMesh(curl); + mPageCurl = curl; + mPageRight = right; + // If we were curling left page update current index. + if (mCurlState == CURL_LEFT) { + --mCurrentIndex; + } + } else if (mAnimationTargetEvent == SET_CURL_TO_LEFT) { + // Switch curled page to left. + CurlMesh left = mPageCurl; + CurlMesh curl = mPageLeft; + left.setRect(mRenderer.getPageRect(CurlRenderer.PAGE_LEFT)); + left.setFlipTexture(true); + left.reset(); + mRenderer.removeCurlMesh(curl); + if (!mRenderLeftPage) { + mRenderer.removeCurlMesh(left); + } + mPageCurl = curl; + mPageLeft = left; + // If we were curling right page update current index. + if (mCurlState == CURL_RIGHT) { + ++mCurrentIndex; + } + } + mCurlState = CURL_NONE; + mAnimate = false; + requestRender(); + } else { + mPointerPos.mPos.set(mAnimationSource); + float t = 1f - ((float) (currentTime - mAnimationStartTime) / mAnimationDurationTime); + t = 1f - (t * t * t * (3 - 2 * t)); + mPointerPos.mPos.x += (mAnimationTarget.x - mAnimationSource.x) * t; + mPointerPos.mPos.y += (mAnimationTarget.y - mAnimationSource.y) * t; + updateCurlPos(mPointerPos); + } + } + + @Override + public void onPageSizeChanged(int width, int height) { + mPageBitmapWidth = width; + mPageBitmapHeight = height; + updatePages(); + requestRender(); + } + + @Override + public void onSizeChanged(int w, int h, int ow, int oh) { + super.onSizeChanged(w, h, ow, oh); + requestRender(); + if (mSizeChangedObserver != null) { + mSizeChangedObserver.onSizeChanged(w, h); + } + } + + @Override + public void onSurfaceCreated() { + // In case surface is recreated, let page meshes drop allocated texture + // ids and ask for new ones. There's no need to set textures here as + // onPageSizeChanged should be called later on. + mPageLeft.resetTexture(); + mPageRight.resetTexture(); + mPageCurl.resetTexture(); + } + + @Override + public boolean onTouch(View view, MotionEvent me) { + // No dragging during animation at the moment. + // TODO: Stop animation on touch event and return to drag mode. + if (mAnimate || mPageProvider == null) { + return false; + } + + // We need page rects quite extensively so get them for later use. + RectF rightRect = mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT); + RectF leftRect = mRenderer.getPageRect(CurlRenderer.PAGE_LEFT); + + // Store pointer position. + mPointerPos.mPos.set(me.getX(), me.getY()); + mRenderer.translate(mPointerPos.mPos); + if (mEnableTouchPressure) { + mPointerPos.mPressure = me.getPressure(); + } else { + mPointerPos.mPressure = 0.8f; + } + + switch (me.getAction()) { + case MotionEvent.ACTION_DOWN: { + + // Once we receive pointer down event its position is mapped to + // right or left edge of page and that'll be the position from where + // user is holding the paper to make curl happen. + mDragStartPos.set(mPointerPos.mPos); + + // First we make sure it's not over or below page. Pages are + // supposed to be same height so it really doesn't matter do we use + // left or right one. + if (mDragStartPos.y > rightRect.top) { + mDragStartPos.y = rightRect.top; + } else if (mDragStartPos.y < rightRect.bottom) { + mDragStartPos.y = rightRect.bottom; + } + + // Then we have to make decisions for the user whether curl is going + // to happen from left or right, and on which page. + if (mViewMode == SHOW_TWO_PAGES) { + // If we have an open book and pointer is on the left from right + // page we'll mark drag position to left edge of left page. + // Additionally checking mCurrentIndex is higher than zero tells + // us there is a visible page at all. + if (mDragStartPos.x < rightRect.left && mCurrentIndex > 0) { + mDragStartPos.x = leftRect.left; + startCurl(CURL_LEFT); + } + // Otherwise check pointer is on right page's side. + else if (mDragStartPos.x >= rightRect.left + && mCurrentIndex < mPageProvider.getPageCount()) { + mDragStartPos.x = rightRect.right; + if (!mAllowLastPageCurl + && mCurrentIndex >= mPageProvider.getPageCount() - 1) { + return false; + } + startCurl(CURL_RIGHT); + } + } else if (mViewMode == SHOW_ONE_PAGE) { + float halfX = (rightRect.right + rightRect.left) / 2; + if (mDragStartPos.x < halfX && mCurrentIndex > 0) { + mDragStartPos.x = rightRect.left; + startCurl(CURL_LEFT); + } else if (mDragStartPos.x >= halfX + && mCurrentIndex < mPageProvider.getPageCount()) { + mDragStartPos.x = rightRect.right; + if (!mAllowLastPageCurl + && mCurrentIndex >= mPageProvider.getPageCount() - 1) { + return false; + } + startCurl(CURL_RIGHT); + } + } + // If we have are in curl state, let this case clause flow through + // to next one. We have pointer position and drag position defined + // and this will create first render request given these points. + if (mCurlState == CURL_NONE) { + return false; + } + } + case MotionEvent.ACTION_MOVE: { + updateCurlPos(mPointerPos); + break; + } + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: { + if (mCurlState == CURL_LEFT || mCurlState == CURL_RIGHT) { + // Animation source is the point from where animation starts. + // Also it's handled in a way we actually simulate touch events + // meaning the output is exactly the same as if user drags the + // page to other side. While not producing the best looking + // result (which is easier done by altering curl position and/or + // direction directly), this is done in a hope it made code a + // bit more readable and easier to maintain. + mAnimationSource.set(mPointerPos.mPos); + mAnimationStartTime = System.currentTimeMillis(); + + // Given the explanation, here we decide whether to simulate + // drag to left or right end. + if ((mViewMode == SHOW_ONE_PAGE && mPointerPos.mPos.x > (rightRect.left + rightRect.right) / 2) + || mViewMode == SHOW_TWO_PAGES + && mPointerPos.mPos.x > rightRect.left) { + // On right side target is always right page's right border. + mAnimationTarget.set(mDragStartPos); + mAnimationTarget.x = mRenderer + .getPageRect(CurlRenderer.PAGE_RIGHT).right; + mAnimationTargetEvent = SET_CURL_TO_RIGHT; + } else { + // On left side target depends on visible pages. + mAnimationTarget.set(mDragStartPos); + if (mCurlState == CURL_RIGHT || mViewMode == SHOW_TWO_PAGES) { + mAnimationTarget.x = leftRect.left; + } else { + mAnimationTarget.x = rightRect.left; + } + mAnimationTargetEvent = SET_CURL_TO_LEFT; + } + mAnimate = true; + requestRender(); + } + break; + } + } + + return true; + } + + /** + * Allow the last page to curl. + */ + public void setAllowLastPageCurl(boolean allowLastPageCurl) { + mAllowLastPageCurl = allowLastPageCurl; + } + + /** + * Sets mPageCurl curl position. + */ + private void setCurlPos(PointF curlPos, PointF curlDir, double radius) { + + // First reposition curl so that page doesn't 'rip off' from book. + if (mCurlState == CURL_RIGHT + || (mCurlState == CURL_LEFT && mViewMode == SHOW_ONE_PAGE)) { + RectF pageRect = mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT); + if (curlPos.x >= pageRect.right) { + mPageCurl.reset(); + requestRender(); + return; + } + if (curlPos.x < pageRect.left) { + curlPos.x = pageRect.left; + } + if (curlDir.y != 0) { + float diffX = curlPos.x - pageRect.left; + float leftY = curlPos.y + (diffX * curlDir.x / curlDir.y); + if (curlDir.y < 0 && leftY < pageRect.top) { + curlDir.x = curlPos.y - pageRect.top; + curlDir.y = pageRect.left - curlPos.x; + } else if (curlDir.y > 0 && leftY > pageRect.bottom) { + curlDir.x = pageRect.bottom - curlPos.y; + curlDir.y = curlPos.x - pageRect.left; + } + } + } else if (mCurlState == CURL_LEFT) { + RectF pageRect = mRenderer.getPageRect(CurlRenderer.PAGE_LEFT); + if (curlPos.x <= pageRect.left) { + mPageCurl.reset(); + requestRender(); + return; + } + if (curlPos.x > pageRect.right) { + curlPos.x = pageRect.right; + } + if (curlDir.y != 0) { + float diffX = curlPos.x - pageRect.right; + float rightY = curlPos.y + (diffX * curlDir.x / curlDir.y); + if (curlDir.y < 0 && rightY < pageRect.top) { + curlDir.x = pageRect.top - curlPos.y; + curlDir.y = curlPos.x - pageRect.right; + } else if (curlDir.y > 0 && rightY > pageRect.bottom) { + curlDir.x = curlPos.y - pageRect.bottom; + curlDir.y = pageRect.right - curlPos.x; + } + } + } + + // Finally normalize direction vector and do rendering. + double dist = Math.sqrt(curlDir.x * curlDir.x + curlDir.y * curlDir.y); + if (dist != 0) { + curlDir.x /= dist; + curlDir.y /= dist; + mPageCurl.curl(curlPos, curlDir, radius); + } else { + mPageCurl.reset(); + } + + requestRender(); + } + + /** + * Set current page index. Page indices are zero based values presenting + * page being shown on right side of the book. E.g if you set value to 4; + * right side front facing bitmap will be with index 4, back facing 5 and + * for left side page index 3 is front facing, and index 2 back facing (once + * page is on left side it's flipped over). + *

    + * Current index is rounded to closest value divisible with 2. + */ + public void setCurrentIndex(int index) { + if (mPageProvider == null || index < 0) { + mCurrentIndex = 0; + } else { + if (mAllowLastPageCurl) { + mCurrentIndex = Math.min(index, mPageProvider.getPageCount()); + } else { + mCurrentIndex = Math.min(index, + mPageProvider.getPageCount() - 1); + } + } + updatePages(); + requestRender(); + } + + /** + * If set to true, touch event pressure information is used to adjust curl + * radius. The more you press, the flatter the curl becomes. This is + * somewhat experimental and results may vary significantly between devices. + * On emulator pressure information seems to be flat 1.0f which is maximum + * value and therefore not very much of use. + */ + public void setEnableTouchPressure(boolean enableTouchPressure) { + mEnableTouchPressure = enableTouchPressure; + } + + /** + * Set margins (or padding). Note: margins are proportional. Meaning a value + * of .1f will produce a 10% margin. + */ + public void setMargins(float left, float top, float right, float bottom) { + mRenderer.setMargins(left, top, right, bottom); + } + + /** + * Update/set page provider. + */ + public void setPageProvider(PageProvider pageProvider) { + mPageProvider = pageProvider; + mCurrentIndex = 0; + updatePages(); + requestRender(); + } + + /** + * Setter for whether left side page is rendered. This is useful mostly for + * situations where right (main) page is aligned to left side of screen and + * left page is not visible anyway. + */ + public void setRenderLeftPage(boolean renderLeftPage) { + mRenderLeftPage = renderLeftPage; + } + + /** + * Sets SizeChangedObserver for this View. Call back method is called from + * this View's onSizeChanged method. + */ + public void setSizeChangedObserver(SizeChangedObserver observer) { + mSizeChangedObserver = observer; + } + + /** + * Sets view mode. Value can be either SHOW_ONE_PAGE or SHOW_TWO_PAGES. In + * former case right page is made size of display, and in latter case two + * pages are laid on visible area. + */ + public void setViewMode(int viewMode) { + switch (viewMode) { + case SHOW_ONE_PAGE: + mViewMode = viewMode; + mPageLeft.setFlipTexture(true); + mRenderer.setViewMode(CurlRenderer.SHOW_ONE_PAGE); + break; + case SHOW_TWO_PAGES: + mViewMode = viewMode; + mPageLeft.setFlipTexture(false); + mRenderer.setViewMode(CurlRenderer.SHOW_TWO_PAGES); + break; + } + } + + /** + * Switches meshes and loads new bitmaps if available. Updated to support 2 + * pages in landscape + */ + private void startCurl(int page) { + switch (page) { + + // Once right side page is curled, first right page is assigned into + // curled page. And if there are more bitmaps available new bitmap is + // loaded into right side mesh. + case CURL_RIGHT: { + // Remove meshes from renderer. + mRenderer.removeCurlMesh(mPageLeft); + mRenderer.removeCurlMesh(mPageRight); + mRenderer.removeCurlMesh(mPageCurl); + + // We are curling right page. + CurlMesh curl = mPageRight; + mPageRight = mPageCurl; + mPageCurl = curl; + + if (mCurrentIndex > 0) { + mPageLeft.setFlipTexture(true); + mPageLeft + .setRect(mRenderer.getPageRect(CurlRenderer.PAGE_LEFT)); + mPageLeft.reset(); + if (mRenderLeftPage) { + mRenderer.addCurlMesh(mPageLeft); + } + } + if (mCurrentIndex < mPageProvider.getPageCount() - 1) { + updatePage(mPageRight.getTexturePage(), mCurrentIndex + 1); + mPageRight.setRect(mRenderer + .getPageRect(CurlRenderer.PAGE_RIGHT)); + mPageRight.setFlipTexture(false); + mPageRight.reset(); + mRenderer.addCurlMesh(mPageRight); + } + + // Add curled page to renderer. + mPageCurl.setRect(mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT)); + mPageCurl.setFlipTexture(false); + mPageCurl.reset(); + mRenderer.addCurlMesh(mPageCurl); + + mCurlState = CURL_RIGHT; + break; + } + + // On left side curl, left page is assigned to curled page. And if + // there are more bitmaps available before currentIndex, new bitmap + // is loaded into left page. + case CURL_LEFT: { + // Remove meshes from renderer. + mRenderer.removeCurlMesh(mPageLeft); + mRenderer.removeCurlMesh(mPageRight); + mRenderer.removeCurlMesh(mPageCurl); + + // We are curling left page. + CurlMesh curl = mPageLeft; + mPageLeft = mPageCurl; + mPageCurl = curl; + + if (mCurrentIndex > 1) { + updatePage(mPageLeft.getTexturePage(), mCurrentIndex - 2); + mPageLeft.setFlipTexture(true); + mPageLeft + .setRect(mRenderer.getPageRect(CurlRenderer.PAGE_LEFT)); + mPageLeft.reset(); + if (mRenderLeftPage) { + mRenderer.addCurlMesh(mPageLeft); + } + } + + // If there is something to show on right page add it to renderer. + if (mCurrentIndex < mPageProvider.getPageCount()) { + mPageRight.setFlipTexture(false); + mPageRight.setRect(mRenderer + .getPageRect(CurlRenderer.PAGE_RIGHT)); + mPageRight.reset(); + mRenderer.addCurlMesh(mPageRight); + } + + // How dragging previous page happens depends on view mode. + if (mViewMode == SHOW_ONE_PAGE + || (mCurlState == CURL_LEFT && mViewMode == SHOW_TWO_PAGES)) { + mPageCurl.setRect(mRenderer + .getPageRect(CurlRenderer.PAGE_RIGHT)); + mPageCurl.setFlipTexture(false); + } else { + mPageCurl + .setRect(mRenderer.getPageRect(CurlRenderer.PAGE_LEFT)); + mPageCurl.setFlipTexture(true); + } + mPageCurl.reset(); + mRenderer.addCurlMesh(mPageCurl); + + mCurlState = CURL_LEFT; + break; + } + + } + } + + /** + * Updates curl position. + */ + private void updateCurlPos(PointerPosition pointerPos) { + + // Default curl radius. + double radius = mRenderer.getPageRect(CURL_RIGHT).width() / 3; + // TODO: This is not an optimal solution. Based on feedback received so + // far; pressure is not very accurate, it may be better not to map + // coefficient to range [0f, 1f] but something like [.2f, 1f] instead. + // Leaving it as is until get my hands on a real device. On emulator + // this doesn't work anyway. + radius *= Math.max(1f - pointerPos.mPressure, 0f); + // NOTE: Here we set pointerPos to mCurlPos. It might be a bit confusing + // later to see e.g "mCurlPos.x - mDragStartPos.x" used. But it's + // actually pointerPos we are doing calculations against. Why? Simply to + // optimize code a bit with the cost of making it unreadable. Otherwise + // we had to this in both of the next if-else branches. + mCurlPos.set(pointerPos.mPos); + + // If curl happens on right page, or on left page on two page mode, + // we'll calculate curl position from pointerPos. + if (mCurlState == CURL_RIGHT + || (mCurlState == CURL_LEFT && mViewMode == SHOW_TWO_PAGES)) { + + mCurlDir.x = mCurlPos.x - mDragStartPos.x; + mCurlDir.y = mCurlPos.y - mDragStartPos.y; + float dist = (float) Math.sqrt(mCurlDir.x * mCurlDir.x + mCurlDir.y + * mCurlDir.y); + + // Adjust curl radius so that if page is dragged far enough on + // opposite side, radius gets closer to zero. + float pageWidth = mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT) + .width(); + double curlLen = radius * Math.PI; + if (dist > (pageWidth * 2) - curlLen) { + curlLen = Math.max((pageWidth * 2) - dist, 0f); + radius = curlLen / Math.PI; + } + + // Actual curl position calculation. + if (dist >= curlLen) { + double translate = (dist - curlLen) / 2; + if (mViewMode == SHOW_TWO_PAGES) { + mCurlPos.x -= mCurlDir.x * translate / dist; + } else { + float pageLeftX = mRenderer + .getPageRect(CurlRenderer.PAGE_RIGHT).left; + radius = Math.max(Math.min(mCurlPos.x - pageLeftX, radius), + 0f); + } + mCurlPos.y -= mCurlDir.y * translate / dist; + } else { + double angle = Math.PI * Math.sqrt(dist / curlLen); + double translate = radius * Math.sin(angle); + mCurlPos.x += mCurlDir.x * translate / dist; + mCurlPos.y += mCurlDir.y * translate / dist; + } + } + // Otherwise we'll let curl follow pointer position. + else if (mCurlState == CURL_LEFT) { + + // Adjust radius regarding how close to page edge we are. + float pageLeftX = mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT).left; + radius = Math.max(Math.min(mCurlPos.x - pageLeftX, radius), 0f); + + float pageRightX = mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT).right; + mCurlPos.x -= Math.min(pageRightX - mCurlPos.x, radius); + mCurlDir.x = mCurlPos.x + mDragStartPos.x; + mCurlDir.y = mCurlPos.y - mDragStartPos.y; + } + + setCurlPos(mCurlPos, mCurlDir, radius); + } + + /** + * Updates given CurlPage via PageProvider for page located at index. + */ + private void updatePage(CurlPage page, int index) { + // First reset page to initial state. + page.reset(); + // Ask page provider to fill it up with bitmaps and colors. + mPageProvider.updatePage(page, mPageBitmapWidth, mPageBitmapHeight, + index); + } + + /** + * Updates bitmaps for page meshes. + */ + private void updatePages() { + if (mPageProvider == null || mPageBitmapWidth <= 0 + || mPageBitmapHeight <= 0) { + return; + } + + // Remove meshes from renderer. + mRenderer.removeCurlMesh(mPageLeft); + mRenderer.removeCurlMesh(mPageRight); + mRenderer.removeCurlMesh(mPageCurl); + + int leftIdx = mCurrentIndex - 1; + int rightIdx = mCurrentIndex; + int curlIdx = -1; + if (mCurlState == CURL_LEFT) { + curlIdx = leftIdx; + --leftIdx; + } else if (mCurlState == CURL_RIGHT) { + curlIdx = rightIdx; + ++rightIdx; + } + + if (rightIdx >= 0 && rightIdx < mPageProvider.getPageCount()) { + updatePage(mPageRight.getTexturePage(), rightIdx); + mPageRight.setFlipTexture(false); + mPageRight.setRect(mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT)); + mPageRight.reset(); + mRenderer.addCurlMesh(mPageRight); + } + if (leftIdx >= 0 && leftIdx < mPageProvider.getPageCount()) { + updatePage(mPageLeft.getTexturePage(), leftIdx); + mPageLeft.setFlipTexture(true); + mPageLeft.setRect(mRenderer.getPageRect(CurlRenderer.PAGE_LEFT)); + mPageLeft.reset(); + if (mRenderLeftPage) { + mRenderer.addCurlMesh(mPageLeft); + } + } + if (curlIdx >= 0 && curlIdx < mPageProvider.getPageCount()) { + updatePage(mPageCurl.getTexturePage(), curlIdx); + + if (mCurlState == CURL_RIGHT) { + mPageCurl.setFlipTexture(true); + mPageCurl.setRect(mRenderer + .getPageRect(CurlRenderer.PAGE_RIGHT)); + } else { + mPageCurl.setFlipTexture(false); + mPageCurl + .setRect(mRenderer.getPageRect(CurlRenderer.PAGE_LEFT)); + } + + mPageCurl.reset(); + mRenderer.addCurlMesh(mPageCurl); + } + } + + /** + * Provider for feeding 'book' with bitmaps which are used for rendering + * pages. + */ + public interface PageProvider { + + /** + * Return number of pages available. + */ + public int getPageCount(); + + /** + * Called once new bitmaps/textures are needed. Width and height are in + * pixels telling the size it will be drawn on screen and following them + * ensures that aspect ratio remains. But it's possible to return bitmap + * of any size though. You should use provided CurlPage for storing page + * information for requested page number.
    + *
    + * Index is a number between 0 and getBitmapCount() - 1. + */ + public void updatePage(CurlPage page, int width, int height, int index); + } + + /** + * Simple holder for pointer position. + */ + private class PointerPosition { + PointF mPos = new PointF(); + float mPressure; + } + + /** + * Observer interface for handling CurlView size changes. + */ + public interface SizeChangedObserver { + + /** + * Called once CurlView size changes. + */ + public void onSizeChanged(int width, int height); + } + +} diff --git a/app/src/main/res/layout/dialog_read_book_style.xml b/app/src/main/res/layout/dialog_read_book_style.xml index f8c997797..49747179b 100644 --- a/app/src/main/res/layout/dialog_read_book_style.xml +++ b/app/src/main/res/layout/dialog_read_book_style.xml @@ -261,6 +261,18 @@ android:singleLine="true" android:text="@string/page_anim_slide" /> + + Date: Fri, 4 Oct 2019 22:55:28 +0800 Subject: [PATCH 1816/1997] up --- app/src/main/res/layout/dialog_read_book_style.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/layout/dialog_read_book_style.xml b/app/src/main/res/layout/dialog_read_book_style.xml index 49747179b..d246417c6 100644 --- a/app/src/main/res/layout/dialog_read_book_style.xml +++ b/app/src/main/res/layout/dialog_read_book_style.xml @@ -271,7 +271,7 @@ android:button="@null" android:gravity="center" android:singleLine="true" - android:text="@string/page_anim_scroll" /> + android:text="@string/page_anim_simulation" /> Date: Sat, 5 Oct 2019 09:58:27 +0800 Subject: [PATCH 1817/1997] up --- app/src/main/AndroidManifest.xml | 29 +++++++++++++++---- .../app/ui/book/search/SearchActivity.kt | 27 ++++++++++++++--- 2 files changed, 46 insertions(+), 10 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 65c6ad511..1779f9c25 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -57,7 +57,20 @@ android:windowSoftInputMode="adjustResize|stateHidden" /> - + + + + + + + + + + + + @@ -66,11 +79,14 @@ - - - + - + + + + @@ -79,7 +95,8 @@ - + + diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt index f9124f9fb..0812b6706 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt @@ -1,5 +1,7 @@ package io.legado.app.ui.book.search +import android.content.Intent +import android.os.Build import android.os.Bundle import androidx.appcompat.widget.SearchView import androidx.lifecycle.LiveData @@ -49,9 +51,8 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se initSearchView() initOtherView() initData() - intent.getStringExtra("key")?.let { - search_view.setQuery(it, true) - } + initIntent() + upHistory() } private fun initSearchView() { @@ -125,7 +126,25 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se ), 30 ).build() searchBookData?.observe(this, Observer { adapter.submitList(it) }) - upHistory() + } + + private fun initIntent() { + if (Intent.ACTION_SEND == intent.action && intent.type == "text/plain") { + intent.getStringExtra(Intent.EXTRA_TEXT)?.let { + search_view.setQuery(it, true) + } + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M + && Intent.ACTION_PROCESS_TEXT == intent.action + && intent.type == "text/plain" + ) { + intent.getStringExtra(Intent.EXTRA_PROCESS_TEXT)?.let { + search_view.setQuery(it, true) + } + } else { + intent.getStringExtra("key")?.let { + search_view.setQuery(it, true) + } + } } private fun upHistory(key: String? = null) { From b1985d066c921df16d5107143842fcdebb75471f Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 5 Oct 2019 19:36:22 +0800 Subject: [PATCH 1818/1997] up --- .../io/legado/app/ui/main/my/MyFragment.kt | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt b/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt index af839204e..b2747f97e 100644 --- a/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt @@ -91,23 +91,20 @@ class MyFragment : BaseFragment(R.layout.fragment_my_config) { } override fun onPreferenceTreeClick(preference: Preference?): Boolean { - preference?.let { - when (preference.key) { - "bookSourceManage" -> context?.startActivity() - "replaceManage" -> context?.startActivity() - "setting" -> context?.startActivity( - Pair("configType", ConfigViewModel.TYPE_CONFIG) - ) - "web_dav_setting" -> context?.startActivity( - Pair("configType", ConfigViewModel.TYPE_WEB_DAV_CONFIG) - ) - "theme_setting" -> context?.startActivity( - Pair("configType", ConfigViewModel.TYPE_THEME_CONFIG) - ) - "donate" -> context?.startActivity() - "about" -> context?.startActivity() - else -> null - } + when (preference?.key) { + "bookSourceManage" -> context?.startActivity() + "replaceManage" -> context?.startActivity() + "setting" -> context?.startActivity( + Pair("configType", ConfigViewModel.TYPE_CONFIG) + ) + "web_dav_setting" -> context?.startActivity( + Pair("configType", ConfigViewModel.TYPE_WEB_DAV_CONFIG) + ) + "theme_setting" -> context?.startActivity( + Pair("configType", ConfigViewModel.TYPE_THEME_CONFIG) + ) + "donate" -> context?.startActivity() + "about" -> context?.startActivity() } return super.onPreferenceTreeClick(preference) } From 5d1fab40c8fad949190683f7ee4cae275ef91c46 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 5 Oct 2019 19:43:03 +0800 Subject: [PATCH 1819/1997] up --- app/src/main/java/io/legado/app/ui/about/DonateActivity.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/about/DonateActivity.kt b/app/src/main/java/io/legado/app/ui/about/DonateActivity.kt index 6d0671029..5134e1ec2 100644 --- a/app/src/main/java/io/legado/app/ui/about/DonateActivity.kt +++ b/app/src/main/java/io/legado/app/ui/about/DonateActivity.kt @@ -78,8 +78,8 @@ class DonateActivity : BaseActivity(R.layout.activity_donate) { private fun aliDonate(context: Context) { try { val qrCode = URLEncoder.encode("tsx06677nwdk3javroq4ef0", "utf-8") - val aliPayQr = - "alipayqr://platformapi/startapp?saId=10000007&qrcode=https://qr.alipay.com/$qrCode" + val aliPayQr = "alipayqr://platformapi/startapp?" + + "saId=10000007&qrcode=https://qr.alipay.com/$qrCode" val intent = Intent(Intent.ACTION_VIEW, Uri.parse(aliPayQr)) context.startActivity(intent) } catch (e: Exception) { From 2b3a9f8ff4a94318cd0081d57803c9a900cf68b3 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 5 Oct 2019 22:09:58 +0800 Subject: [PATCH 1820/1997] up --- .../io/legado/app/ui/widget/page/PageView.kt | 6 + .../app/ui/widget/page/curl/CurlMesh.java | 16 +- .../app/ui/widget/page/curl/CurlPage.java | 195 ----- .../app/ui/widget/page/curl/CurlPage.kt | 191 +++++ .../app/ui/widget/page/curl/CurlRenderer.java | 250 ------ .../app/ui/widget/page/curl/CurlRenderer.kt | 252 ++++++ .../app/ui/widget/page/curl/CurlView.java | 790 ------------------ .../app/ui/widget/page/curl/CurlView.kt | 768 +++++++++++++++++ .../ui/widget/page/delegate/PageDelegate.kt | 4 +- .../page/delegate/SimulationPageDelegate.kt | 39 + 10 files changed, 1267 insertions(+), 1244 deletions(-) delete mode 100644 app/src/main/java/io/legado/app/ui/widget/page/curl/CurlPage.java create mode 100644 app/src/main/java/io/legado/app/ui/widget/page/curl/CurlPage.kt delete mode 100644 app/src/main/java/io/legado/app/ui/widget/page/curl/CurlRenderer.java create mode 100644 app/src/main/java/io/legado/app/ui/widget/page/curl/CurlRenderer.kt delete mode 100644 app/src/main/java/io/legado/app/ui/widget/page/curl/CurlView.java create mode 100644 app/src/main/java/io/legado/app/ui/widget/page/curl/CurlView.kt diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 1c293e74e..894562639 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -7,6 +7,7 @@ import android.util.AttributeSet import android.view.MotionEvent import android.widget.FrameLayout import io.legado.app.help.ReadBookConfig +import io.legado.app.ui.widget.page.curl.CurlView import io.legado.app.ui.widget.page.delegate.* import io.legado.app.utils.activity import io.legado.app.utils.getPrefInt @@ -23,6 +24,7 @@ class PageView(context: Context, attrs: AttributeSet) : var prevPage: ContentView? = null var curPage: ContentView? = null var nextPage: ContentView? = null + var curlView: CurlView? = null init { callback = activity as? CallBack @@ -85,6 +87,10 @@ class PageView(context: Context, attrs: AttributeSet) : } fun upPageAnim() { + if (curlView != null) { + removeView(curlView) + curlView = null + } pageDelegate = null pageDelegate = when (context.getPrefInt("pageAnim")) { 0 -> CoverPageDelegate(this) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlMesh.java b/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlMesh.java index 448de5bce..6efcf75bf 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlMesh.java +++ b/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlMesh.java @@ -95,21 +95,21 @@ public class CurlMesh { // There really is no use for 0 splits. mMaxCurlSplits = maxCurlSplits < 1 ? 1 : maxCurlSplits; - mArrScanLines = new Array(maxCurlSplits + 2); - mArrOutputVertices = new Array(7); - mArrRotatedVertices = new Array(4); - mArrIntersections = new Array(2); - mArrTempVertices = new Array(7 + 4); + mArrScanLines = new Array<>(maxCurlSplits + 2); + mArrOutputVertices = new Array<>(7); + mArrRotatedVertices = new Array<>(4); + mArrIntersections = new Array<>(2); + mArrTempVertices = new Array<>(7 + 4); for (int i = 0; i < 7 + 4; ++i) { mArrTempVertices.add(new Vertex()); } if (DRAW_SHADOW) { - mArrSelfShadowVertices = new Array( + mArrSelfShadowVertices = new Array<>( (mMaxCurlSplits + 2) * 2); - mArrDropShadowVertices = new Array( + mArrDropShadowVertices = new Array<>( (mMaxCurlSplits + 2) * 2); - mArrTempShadowVertices = new Array( + mArrTempShadowVertices = new Array<>( (mMaxCurlSplits + 2) * 2); for (int i = 0; i < (mMaxCurlSplits + 2) * 2; ++i) { mArrTempShadowVertices.add(new ShadowVertex()); diff --git a/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlPage.java b/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlPage.java deleted file mode 100644 index e2ea847db..000000000 --- a/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlPage.java +++ /dev/null @@ -1,195 +0,0 @@ -package io.legado.app.ui.widget.page.curl; - -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.RectF; - -/** - * Storage class for page textures, blend colors and possibly some other values - * in the future. - * - * @author harism - */ -public class CurlPage { - - public static final int SIDE_BACK = 2; - public static final int SIDE_BOTH = 3; - public static final int SIDE_FRONT = 1; - - private int mColorBack; - private int mColorFront; - private Bitmap mTextureBack; - private Bitmap mTextureFront; - private boolean mTexturesChanged; - - /** - * Default constructor. - */ - public CurlPage() { - reset(); - } - - /** - * Getter for color. - */ - public int getColor(int side) { - switch (side) { - case SIDE_FRONT: - return mColorFront; - default: - return mColorBack; - } - } - - /** - * Calculates the next highest power of two for a given integer. - */ - private int getNextHighestPO2(int n) { - n -= 1; - n = n | (n >> 1); - n = n | (n >> 2); - n = n | (n >> 4); - n = n | (n >> 8); - n = n | (n >> 16); - n = n | (n >> 32); - return n + 1; - } - - /** - * Generates nearest power of two sized Bitmap for give Bitmap. Returns this - * new Bitmap using default return statement + original texture coordinates - * are stored into RectF. - */ - private Bitmap getTexture(Bitmap bitmap, RectF textureRect) { - // Bitmap original size. - int w = bitmap.getWidth(); - int h = bitmap.getHeight(); - // Bitmap size expanded to next power of two. This is done due to - // the requirement on many devices, texture width and height should - // be power of two. - int newW = getNextHighestPO2(w); - int newH = getNextHighestPO2(h); - - // TODO: Is there another way to create a bigger Bitmap and copy - // original Bitmap to it more efficiently? Immutable bitmap anyone? - Bitmap bitmapTex = Bitmap.createBitmap(newW, newH, bitmap.getConfig()); - Canvas c = new Canvas(bitmapTex); - c.drawBitmap(bitmap, 0, 0, null); - - // Calculate final texture coordinates. - float texX = (float) w / newW; - float texY = (float) h / newH; - textureRect.set(0f, 0f, texX, texY); - - return bitmapTex; - } - - /** - * Getter for textures. Creates Bitmap sized to nearest power of two, copies - * original Bitmap into it and returns it. RectF given as parameter is - * filled with actual texture coordinates in this new upscaled texture - * Bitmap. - */ - public Bitmap getTexture(RectF textureRect, int side) { - switch (side) { - case SIDE_FRONT: - return getTexture(mTextureFront, textureRect); - default: - return getTexture(mTextureBack, textureRect); - } - } - - /** - * Returns true if textures have changed. - */ - public boolean getTexturesChanged() { - return mTexturesChanged; - } - - /** - * Returns true if back siding texture exists and it differs from front - * facing one. - */ - public boolean hasBackTexture() { - return !mTextureFront.equals(mTextureBack); - } - - /** - * Recycles and frees underlying Bitmaps. - */ - public void recycle() { - if (mTextureFront != null) { - mTextureFront.recycle(); - } - mTextureFront = Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565); - mTextureFront.eraseColor(mColorFront); - if (mTextureBack != null) { - mTextureBack.recycle(); - } - mTextureBack = Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565); - mTextureBack.eraseColor(mColorBack); - mTexturesChanged = false; - } - - /** - * Resets this CurlPage into its initial state. - */ - public void reset() { - mColorBack = Color.WHITE; - mColorFront = Color.WHITE; - recycle(); - } - - /** - * Setter blend color. - */ - public void setColor(int color, int side) { - switch (side) { - case SIDE_FRONT: - mColorFront = color; - break; - case SIDE_BACK: - mColorBack = color; - break; - default: - mColorFront = mColorBack = color; - break; - } - } - - /** - * Setter for textures. - */ - public void setTexture(Bitmap texture, int side) { - if (texture == null) { - texture = Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565); - if (side == SIDE_BACK) { - texture.eraseColor(mColorBack); - } else { - texture.eraseColor(mColorFront); - } - } - switch (side) { - case SIDE_FRONT: - if (mTextureFront != null) - mTextureFront.recycle(); - mTextureFront = texture; - break; - case SIDE_BACK: - if (mTextureBack != null) - mTextureBack.recycle(); - mTextureBack = texture; - break; - case SIDE_BOTH: - if (mTextureFront != null) - mTextureFront.recycle(); - if (mTextureBack != null) - mTextureBack.recycle(); - mTextureFront = mTextureBack = texture; - break; - } - mTexturesChanged = true; - } - -} diff --git a/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlPage.kt b/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlPage.kt new file mode 100644 index 000000000..5f6ad5bb1 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlPage.kt @@ -0,0 +1,191 @@ +package io.legado.app.ui.widget.page.curl + +import android.graphics.Bitmap +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.RectF + +/** + * Storage class for page textures, blend colors and possibly some other values + * in the future. + * + * @author harism + */ +class CurlPage { + + private var mColorBack: Int = 0 + private var mColorFront: Int = 0 + private var mTextureBack: Bitmap? = null + private var mTextureFront: Bitmap? = null + /** + * Returns true if textures have changed. + */ + var texturesChanged: Boolean = false + private set + + /** + * Default constructor. + */ + init { + reset() + } + + /** + * Getter for color. + */ + fun getColor(side: Int): Int { + return when (side) { + SIDE_FRONT -> mColorFront + else -> mColorBack + } + } + + /** + * Calculates the next highest power of two for a given integer. + */ + private fun getNextHighestPO2(n: Int): Int { + var n1 = n + n1 -= 1 + n1 = n1 or (n1 shr 1) + n1 = n1 or (n1 shr 2) + n1 = n1 or (n1 shr 4) + n1 = n1 or (n1 shr 8) + n1 = n1 or (n1 shr 16) + n1 = n1 or (n1 shr 32) + return n1 + 1 + } + + /** + * Generates nearest power of two sized Bitmap for give Bitmap. Returns this + * new Bitmap using default return statement + original texture coordinates + * are stored into RectF. + */ + private fun getTexture(bitmap: Bitmap, textureRect: RectF): Bitmap { + // Bitmap original size. + val w = bitmap.width + val h = bitmap.height + // Bitmap size expanded to next power of two. This is done due to + // the requirement on many devices, texture width and height should + // be power of two. + val newW = getNextHighestPO2(w) + val newH = getNextHighestPO2(h) + + // TODO: Is there another way to create a bigger Bitmap and copy + // original Bitmap to it more efficiently? Immutable bitmap anyone? + val bitmapTex = Bitmap.createBitmap(newW, newH, bitmap.config) + val c = Canvas(bitmapTex) + c.drawBitmap(bitmap, 0f, 0f, null) + + // Calculate final texture coordinates. + val texX = w.toFloat() / newW + val texY = h.toFloat() / newH + textureRect.set(0f, 0f, texX, texY) + + return bitmapTex + } + + /** + * Getter for textures. Creates Bitmap sized to nearest power of two, copies + * original Bitmap into it and returns it. RectF given as parameter is + * filled with actual texture coordinates in this new upscaled texture + * Bitmap. + */ + fun getTexture(textureRect: RectF, side: Int): Bitmap { + return when (side) { + SIDE_FRONT -> getTexture(mTextureFront!!, textureRect) + else -> getTexture(mTextureBack!!, textureRect) + } + } + + /** + * Returns true if back siding texture exists and it differs from front + * facing one. + */ + fun hasBackTexture(): Boolean { + return mTextureFront != mTextureBack + } + + /** + * Recycles and frees underlying Bitmaps. + */ + fun recycle() { + if (mTextureFront != null) { + mTextureFront!!.recycle() + } + mTextureFront = Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565) + mTextureFront!!.eraseColor(mColorFront) + if (mTextureBack != null) { + mTextureBack!!.recycle() + } + mTextureBack = Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565) + mTextureBack!!.eraseColor(mColorBack) + texturesChanged = false + } + + /** + * Resets this CurlPage into its initial state. + */ + fun reset() { + mColorBack = Color.WHITE + mColorFront = Color.WHITE + recycle() + } + + /** + * Setter blend color. + */ + fun setColor(color: Int, side: Int) { + when (side) { + SIDE_FRONT -> mColorFront = color + SIDE_BACK -> mColorBack = color + else -> { + mColorBack = color + mColorFront = mColorBack + } + } + } + + /** + * Setter for textures. + */ + fun setTexture(texture: Bitmap?, side: Int) { + var texture1 = texture + if (texture1 == null) { + texture1 = Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565) + if (side == SIDE_BACK) { + texture1!!.eraseColor(mColorBack) + } else { + texture1!!.eraseColor(mColorFront) + } + } + when (side) { + SIDE_FRONT -> { + if (mTextureFront != null) + mTextureFront!!.recycle() + mTextureFront = texture1 + } + SIDE_BACK -> { + if (mTextureBack != null) + mTextureBack!!.recycle() + mTextureBack = texture1 + } + SIDE_BOTH -> { + if (mTextureFront != null) + mTextureFront!!.recycle() + if (mTextureBack != null) + mTextureBack!!.recycle() + mTextureBack = texture1 + mTextureFront = mTextureBack + } + } + texturesChanged = true + } + + companion object { + + const val SIDE_BACK = 2 + const val SIDE_BOTH = 3 + const val SIDE_FRONT = 1 + } + +} diff --git a/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlRenderer.java b/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlRenderer.java deleted file mode 100644 index 7b18c744d..000000000 --- a/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlRenderer.java +++ /dev/null @@ -1,250 +0,0 @@ -package io.legado.app.ui.widget.page.curl; - -import android.graphics.Color; -import android.graphics.PointF; -import android.graphics.RectF; -import android.opengl.GLSurfaceView; -import android.opengl.GLU; - -import java.util.Vector; - -import javax.microedition.khronos.egl.EGLConfig; -import javax.microedition.khronos.opengles.GL10; - -/** - * Actual renderer class. - * - * @author harism - */ -public class CurlRenderer implements GLSurfaceView.Renderer { - - // Constant for requesting left page rect. - public static final int PAGE_LEFT = 1; - // Constant for requesting right page rect. - public static final int PAGE_RIGHT = 2; - // Constants for changing view mode. - public static final int SHOW_ONE_PAGE = 1; - public static final int SHOW_TWO_PAGES = 2; - // Set to true for checking quickly how perspective projection looks. - private static final boolean USE_PERSPECTIVE_PROJECTION = false; - // Background fill color. - private int mBackgroundColor; - // Curl meshes used for static and dynamic rendering. - private Vector mCurlMeshes; - private RectF mMargins = new RectF(); - private CurlRenderer.Observer mObserver; - // Page rectangles. - private RectF mPageRectLeft; - private RectF mPageRectRight; - // View mode. - private int mViewMode = SHOW_ONE_PAGE; - // Screen size. - private int mViewportWidth, mViewportHeight; - // Rect for render area. - private RectF mViewRect = new RectF(); - - /** - * Basic constructor. - */ - public CurlRenderer(CurlRenderer.Observer observer) { - mObserver = observer; - mCurlMeshes = new Vector(); - mPageRectLeft = new RectF(); - mPageRectRight = new RectF(); - } - - /** - * Adds CurlMesh to this renderer. - */ - public synchronized void addCurlMesh(CurlMesh mesh) { - removeCurlMesh(mesh); - mCurlMeshes.add(mesh); - } - - /** - * Returns rect reserved for left or right page. Value page should be - * PAGE_LEFT or PAGE_RIGHT. - */ - public RectF getPageRect(int page) { - if (page == PAGE_LEFT) { - return mPageRectLeft; - } else if (page == PAGE_RIGHT) { - return mPageRectRight; - } - return null; - } - - @Override - public synchronized void onDrawFrame(GL10 gl) { - - mObserver.onDrawFrame(); - - gl.glClearColor(Color.red(mBackgroundColor) / 255f, - Color.green(mBackgroundColor) / 255f, - Color.blue(mBackgroundColor) / 255f, - Color.alpha(mBackgroundColor) / 255f); - gl.glClear(GL10.GL_COLOR_BUFFER_BIT); - gl.glLoadIdentity(); - - if (USE_PERSPECTIVE_PROJECTION) { - gl.glTranslatef(0, 0, -6f); - } - - for (int i = 0; i < mCurlMeshes.size(); ++i) { - mCurlMeshes.get(i).onDrawFrame(gl); - } - } - - @Override - public void onSurfaceChanged(GL10 gl, int width, int height) { - gl.glViewport(0, 0, width, height); - mViewportWidth = width; - mViewportHeight = height; - - float ratio = (float) width / height; - mViewRect.top = 1.0f; - mViewRect.bottom = -1.0f; - mViewRect.left = -ratio; - mViewRect.right = ratio; - updatePageRects(); - - gl.glMatrixMode(GL10.GL_PROJECTION); - gl.glLoadIdentity(); - if (USE_PERSPECTIVE_PROJECTION) { - GLU.gluPerspective(gl, 20f, (float) width / height, .1f, 100f); - } else { - GLU.gluOrtho2D(gl, mViewRect.left, mViewRect.right, - mViewRect.bottom, mViewRect.top); - } - - gl.glMatrixMode(GL10.GL_MODELVIEW); - gl.glLoadIdentity(); - } - - @Override - public void onSurfaceCreated(GL10 gl, EGLConfig config) { - gl.glClearColor(0f, 0f, 0f, 1f); - gl.glShadeModel(GL10.GL_SMOOTH); - gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST); - gl.glHint(GL10.GL_LINE_SMOOTH_HINT, GL10.GL_NICEST); - gl.glHint(GL10.GL_POLYGON_SMOOTH_HINT, GL10.GL_NICEST); - gl.glEnable(GL10.GL_LINE_SMOOTH); - gl.glDisable(GL10.GL_DEPTH_TEST); - gl.glDisable(GL10.GL_CULL_FACE); - - mObserver.onSurfaceCreated(); - } - - /** - * Removes CurlMesh from this renderer. - */ - public synchronized void removeCurlMesh(CurlMesh mesh) { - while (mCurlMeshes.remove(mesh)) - ; - } - - /** - * Change background/clear color. - */ - public void setBackgroundColor(int color) { - mBackgroundColor = color; - } - - /** - * Set margins or padding. Note: margins are proportional. Meaning a value - * of .1f will produce a 10% margin. - */ - public synchronized void setMargins(float left, float top, float right, - float bottom) { - mMargins.left = left; - mMargins.top = top; - mMargins.right = right; - mMargins.bottom = bottom; - updatePageRects(); - } - - /** - * Sets visible page count to one or two. Should be either SHOW_ONE_PAGE or - * SHOW_TWO_PAGES. - */ - public synchronized void setViewMode(int viewmode) { - if (viewmode == SHOW_ONE_PAGE) { - mViewMode = viewmode; - updatePageRects(); - } else if (viewmode == SHOW_TWO_PAGES) { - mViewMode = viewmode; - updatePageRects(); - } - } - - /** - * Translates screen coordinates into view coordinates. - */ - public void translate(PointF pt) { - pt.x = mViewRect.left + (mViewRect.width() * pt.x / mViewportWidth); - pt.y = mViewRect.top - (-mViewRect.height() * pt.y / mViewportHeight); - } - - /** - * Recalculates page rectangles. - */ - private void updatePageRects() { - if (mViewRect.width() == 0 || mViewRect.height() == 0) { - return; - } else if (mViewMode == SHOW_ONE_PAGE) { - mPageRectRight.set(mViewRect); - mPageRectRight.left += mViewRect.width() * mMargins.left; - mPageRectRight.right -= mViewRect.width() * mMargins.right; - mPageRectRight.top += mViewRect.height() * mMargins.top; - mPageRectRight.bottom -= mViewRect.height() * mMargins.bottom; - - mPageRectLeft.set(mPageRectRight); - mPageRectLeft.offset(-mPageRectRight.width(), 0); - - int bitmapW = (int) ((mPageRectRight.width() * mViewportWidth) / mViewRect - .width()); - int bitmapH = (int) ((mPageRectRight.height() * mViewportHeight) / mViewRect - .height()); - mObserver.onPageSizeChanged(bitmapW, bitmapH); - } else if (mViewMode == SHOW_TWO_PAGES) { - mPageRectRight.set(mViewRect); - mPageRectRight.left += mViewRect.width() * mMargins.left; - mPageRectRight.right -= mViewRect.width() * mMargins.right; - mPageRectRight.top += mViewRect.height() * mMargins.top; - mPageRectRight.bottom -= mViewRect.height() * mMargins.bottom; - - mPageRectLeft.set(mPageRectRight); - mPageRectLeft.right = (mPageRectLeft.right + mPageRectLeft.left) / 2; - mPageRectRight.left = mPageRectLeft.right; - - int bitmapW = (int) ((mPageRectRight.width() * mViewportWidth) / mViewRect - .width()); - int bitmapH = (int) ((mPageRectRight.height() * mViewportHeight) / mViewRect - .height()); - mObserver.onPageSizeChanged(bitmapW, bitmapH); - } - } - - /** - * Observer for waiting render engine/state updates. - */ - public interface Observer { - /** - * Called from onDrawFrame called before rendering is started. This is - * intended to be used for animation purposes. - */ - public void onDrawFrame(); - - /** - * Called once page size is changed. Width and height tell the page size - * in pixels making it possible to update textures accordingly. - */ - public void onPageSizeChanged(int width, int height); - - /** - * Called from onSurfaceCreated to enable texture re-initialization etc - * what needs to be done when this happens. - */ - public void onSurfaceCreated(); - } -} diff --git a/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlRenderer.kt b/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlRenderer.kt new file mode 100644 index 000000000..9d7913027 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlRenderer.kt @@ -0,0 +1,252 @@ +package io.legado.app.ui.widget.page.curl + +import android.graphics.Color +import android.graphics.PointF +import android.graphics.RectF +import android.opengl.GLSurfaceView +import android.opengl.GLU +import java.util.* +import javax.microedition.khronos.egl.EGLConfig +import javax.microedition.khronos.opengles.GL10 + +/** + * Actual renderer class. + * + * @author harism + */ +class CurlRenderer +/** + * Basic constructor. + */ + (private val mObserver: CurlRenderer.Observer) : GLSurfaceView.Renderer { + // Background fill color. + private var mBackgroundColor: Int = 0 + // Curl meshes used for static and dynamic rendering. + private val mCurlMeshes: Vector = Vector() + private val mMargins = RectF() + // Page rectangles. + private val mPageRectLeft: RectF = RectF() + private val mPageRectRight: RectF = RectF() + // View mode. + private var mViewMode = SHOW_ONE_PAGE + // Screen size. + private var mViewportWidth: Int = 0 + private var mViewportHeight: Int = 0 + // Rect for render area. + private val mViewRect = RectF() + + /** + * Adds CurlMesh to this renderer. + */ + @Synchronized + fun addCurlMesh(mesh: CurlMesh) { + removeCurlMesh(mesh) + mCurlMeshes.add(mesh) + } + + /** + * Returns rect reserved for left or right page. Value page should be + * PAGE_LEFT or PAGE_RIGHT. + */ + fun getPageRect(page: Int): RectF? { + if (page == PAGE_LEFT) { + return mPageRectLeft + } else if (page == PAGE_RIGHT) { + return mPageRectRight + } + return null + } + + @Synchronized + override fun onDrawFrame(gl: GL10) { + + mObserver.onDrawFrame() + + gl.glClearColor( + Color.red(mBackgroundColor) / 255f, + Color.green(mBackgroundColor) / 255f, + Color.blue(mBackgroundColor) / 255f, + Color.alpha(mBackgroundColor) / 255f + ) + gl.glClear(GL10.GL_COLOR_BUFFER_BIT) + gl.glLoadIdentity() + + if (USE_PERSPECTIVE_PROJECTION) { + gl.glTranslatef(0f, 0f, -6f) + } + + for (i in mCurlMeshes.indices) { + mCurlMeshes[i].onDrawFrame(gl) + } + } + + override fun onSurfaceChanged(gl: GL10, width: Int, height: Int) { + gl.glViewport(0, 0, width, height) + mViewportWidth = width + mViewportHeight = height + + val ratio = width.toFloat() / height + mViewRect.top = 1.0f + mViewRect.bottom = -1.0f + mViewRect.left = -ratio + mViewRect.right = ratio + updatePageRects() + + gl.glMatrixMode(GL10.GL_PROJECTION) + gl.glLoadIdentity() + if (USE_PERSPECTIVE_PROJECTION) { + GLU.gluPerspective(gl, 20f, width.toFloat() / height, .1f, 100f) + } else { + GLU.gluOrtho2D( + gl, mViewRect.left, mViewRect.right, + mViewRect.bottom, mViewRect.top + ) + } + + gl.glMatrixMode(GL10.GL_MODELVIEW) + gl.glLoadIdentity() + } + + override fun onSurfaceCreated(gl: GL10, config: EGLConfig) { + gl.glClearColor(0f, 0f, 0f, 1f) + gl.glShadeModel(GL10.GL_SMOOTH) + gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST) + gl.glHint(GL10.GL_LINE_SMOOTH_HINT, GL10.GL_NICEST) + gl.glHint(GL10.GL_POLYGON_SMOOTH_HINT, GL10.GL_NICEST) + gl.glEnable(GL10.GL_LINE_SMOOTH) + gl.glDisable(GL10.GL_DEPTH_TEST) + gl.glDisable(GL10.GL_CULL_FACE) + + mObserver.onSurfaceCreated() + } + + /** + * Removes CurlMesh from this renderer. + */ + @Synchronized + fun removeCurlMesh(mesh: CurlMesh) { + mCurlMeshes.remove(mesh) + } + + /** + * Change background/clear color. + */ + fun setBackgroundColor(color: Int) { + mBackgroundColor = color + } + + /** + * Set margins or padding. Note: margins are proportional. Meaning a value + * of .1f will produce a 10% margin. + */ + @Synchronized + fun setMargins( + left: Float, top: Float, right: Float, + bottom: Float + ) { + mMargins.left = left + mMargins.top = top + mMargins.right = right + mMargins.bottom = bottom + updatePageRects() + } + + /** + * Sets visible page count to one or two. Should be either SHOW_ONE_PAGE or + * SHOW_TWO_PAGES. + */ + @Synchronized + fun setViewMode(viewmode: Int) { + if (viewmode == SHOW_ONE_PAGE) { + mViewMode = viewmode + updatePageRects() + } else if (viewmode == SHOW_TWO_PAGES) { + mViewMode = viewmode + updatePageRects() + } + } + + /** + * Translates screen coordinates into view coordinates. + */ + fun translate(pt: PointF) { + pt.x = mViewRect.left + mViewRect.width() * pt.x / mViewportWidth + pt.y = mViewRect.top - -mViewRect.height() * pt.y / mViewportHeight + } + + /** + * Recalculates page rectangles. + */ + private fun updatePageRects() { + if (mViewRect.width() == 0f || mViewRect.height() == 0f) { + return + } else if (mViewMode == SHOW_ONE_PAGE) { + mPageRectRight.set(mViewRect) + mPageRectRight.left += mViewRect.width() * mMargins.left + mPageRectRight.right -= mViewRect.width() * mMargins.right + mPageRectRight.top += mViewRect.height() * mMargins.top + mPageRectRight.bottom -= mViewRect.height() * mMargins.bottom + + mPageRectLeft.set(mPageRectRight) + mPageRectLeft.offset(-mPageRectRight.width(), 0f) + + val bitmapW = (mPageRectRight.width() * mViewportWidth / mViewRect + .width()).toInt() + val bitmapH = (mPageRectRight.height() * mViewportHeight / mViewRect + .height()).toInt() + mObserver.onPageSizeChanged(bitmapW, bitmapH) + } else if (mViewMode == SHOW_TWO_PAGES) { + mPageRectRight.set(mViewRect) + mPageRectRight.left += mViewRect.width() * mMargins.left + mPageRectRight.right -= mViewRect.width() * mMargins.right + mPageRectRight.top += mViewRect.height() * mMargins.top + mPageRectRight.bottom -= mViewRect.height() * mMargins.bottom + + mPageRectLeft.set(mPageRectRight) + mPageRectLeft.right = (mPageRectLeft.right + mPageRectLeft.left) / 2 + mPageRectRight.left = mPageRectLeft.right + + val bitmapW = (mPageRectRight.width() * mViewportWidth / mViewRect + .width()).toInt() + val bitmapH = (mPageRectRight.height() * mViewportHeight / mViewRect + .height()).toInt() + mObserver.onPageSizeChanged(bitmapW, bitmapH) + } + } + + /** + * Observer for waiting render engine/state updates. + */ + interface Observer { + /** + * Called from onDrawFrame called before rendering is started. This is + * intended to be used for animation purposes. + */ + fun onDrawFrame() + + /** + * Called once page size is changed. Width and height tell the page size + * in pixels making it possible to update textures accordingly. + */ + fun onPageSizeChanged(width: Int, height: Int) + + /** + * Called from onSurfaceCreated to enable texture re-initialization etc + * what needs to be done when this happens. + */ + fun onSurfaceCreated() + } + + companion object { + + // Constant for requesting left page rect. + const val PAGE_LEFT = 1 + // Constant for requesting right page rect. + const val PAGE_RIGHT = 2 + // Constants for changing view mode. + const val SHOW_ONE_PAGE = 1 + const val SHOW_TWO_PAGES = 2 + // Set to true for checking quickly how perspective projection looks. + private const val USE_PERSPECTIVE_PROJECTION = false + } +} diff --git a/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlView.java b/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlView.java deleted file mode 100644 index c2428513c..000000000 --- a/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlView.java +++ /dev/null @@ -1,790 +0,0 @@ -package io.legado.app.ui.widget.page.curl; - -import android.content.Context; -import android.graphics.PixelFormat; -import android.graphics.PointF; -import android.graphics.RectF; -import android.opengl.GLSurfaceView; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.View; - -/** - * OpenGL ES View. - * - * @author harism - */ -public class CurlView extends GLSurfaceView implements View.OnTouchListener, - CurlRenderer.Observer { - - // Curl state. We are flipping none, left or right page. - private static final int CURL_LEFT = 1; - private static final int CURL_NONE = 0; - private static final int CURL_RIGHT = 2; - - // Constants for mAnimationTargetEvent. - private static final int SET_CURL_TO_LEFT = 1; - private static final int SET_CURL_TO_RIGHT = 2; - - // Shows one page at the center of view. - public static final int SHOW_ONE_PAGE = 1; - // Shows two pages side by side. - public static final int SHOW_TWO_PAGES = 2; - - private boolean mAllowLastPageCurl = true; - - private boolean mAnimate = false; - private long mAnimationDurationTime = 300; - private PointF mAnimationSource = new PointF(); - private long mAnimationStartTime; - private PointF mAnimationTarget = new PointF(); - private int mAnimationTargetEvent; - - private PointF mCurlDir = new PointF(); - - private PointF mCurlPos = new PointF(); - private int mCurlState = CURL_NONE; - // Current bitmap index. This is always showed as front of right page. - private int mCurrentIndex = 0; - - // Start position for dragging. - private PointF mDragStartPos = new PointF(); - - private boolean mEnableTouchPressure = false; - // Bitmap size. These are updated from renderer once it's initialized. - private int mPageBitmapHeight = -1; - - private int mPageBitmapWidth = -1; - // Page meshes. Left and right meshes are 'static' while curl is used to - // show page flipping. - private CurlMesh mPageCurl; - - private CurlMesh mPageLeft; - private PageProvider mPageProvider; - private CurlMesh mPageRight; - - private PointerPosition mPointerPos = new PointerPosition(); - - private CurlRenderer mRenderer; - private boolean mRenderLeftPage = true; - private SizeChangedObserver mSizeChangedObserver; - - // One page is the default. - private int mViewMode = SHOW_ONE_PAGE; - - /** - * Default constructor. - */ - public CurlView(Context ctx) { - super(ctx); - init(ctx); - } - - /** - * Default constructor. - */ - public CurlView(Context ctx, AttributeSet attrs) { - super(ctx, attrs); - init(ctx); - } - - /** - * Default constructor. - */ - public CurlView(Context ctx, AttributeSet attrs, int defStyle) { - this(ctx, attrs); - } - - /** - * Get current page index. Page indices are zero based values presenting - * page being shown on right side of the book. - */ - public int getCurrentIndex() { - return mCurrentIndex; - } - - /** - * Initialize method. - */ - private void init(Context ctx) { - setEGLConfigChooser(8, 8, 8, 8, 16, 0); - getHolder().setFormat(PixelFormat.TRANSLUCENT); - setZOrderOnTop(true); - mRenderer = new CurlRenderer(this); - setRenderer(mRenderer); - setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); - setOnTouchListener(this); - - // Even though left and right pages are static we have to allocate room - // for curl on them too as we are switching meshes. Another way would be - // to swap texture ids only. - mPageLeft = new CurlMesh(10); - mPageRight = new CurlMesh(10); - mPageCurl = new CurlMesh(10); - mPageLeft.setFlipTexture(true); - mPageRight.setFlipTexture(false); - } - - @Override - public void onDrawFrame() { - // We are not animating. - if (mAnimate == false) { - return; - } - - long currentTime = System.currentTimeMillis(); - // If animation is done. - if (currentTime >= mAnimationStartTime + mAnimationDurationTime) { - if (mAnimationTargetEvent == SET_CURL_TO_RIGHT) { - // Switch curled page to right. - CurlMesh right = mPageCurl; - CurlMesh curl = mPageRight; - right.setRect(mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT)); - right.setFlipTexture(false); - right.reset(); - mRenderer.removeCurlMesh(curl); - mPageCurl = curl; - mPageRight = right; - // If we were curling left page update current index. - if (mCurlState == CURL_LEFT) { - --mCurrentIndex; - } - } else if (mAnimationTargetEvent == SET_CURL_TO_LEFT) { - // Switch curled page to left. - CurlMesh left = mPageCurl; - CurlMesh curl = mPageLeft; - left.setRect(mRenderer.getPageRect(CurlRenderer.PAGE_LEFT)); - left.setFlipTexture(true); - left.reset(); - mRenderer.removeCurlMesh(curl); - if (!mRenderLeftPage) { - mRenderer.removeCurlMesh(left); - } - mPageCurl = curl; - mPageLeft = left; - // If we were curling right page update current index. - if (mCurlState == CURL_RIGHT) { - ++mCurrentIndex; - } - } - mCurlState = CURL_NONE; - mAnimate = false; - requestRender(); - } else { - mPointerPos.mPos.set(mAnimationSource); - float t = 1f - ((float) (currentTime - mAnimationStartTime) / mAnimationDurationTime); - t = 1f - (t * t * t * (3 - 2 * t)); - mPointerPos.mPos.x += (mAnimationTarget.x - mAnimationSource.x) * t; - mPointerPos.mPos.y += (mAnimationTarget.y - mAnimationSource.y) * t; - updateCurlPos(mPointerPos); - } - } - - @Override - public void onPageSizeChanged(int width, int height) { - mPageBitmapWidth = width; - mPageBitmapHeight = height; - updatePages(); - requestRender(); - } - - @Override - public void onSizeChanged(int w, int h, int ow, int oh) { - super.onSizeChanged(w, h, ow, oh); - requestRender(); - if (mSizeChangedObserver != null) { - mSizeChangedObserver.onSizeChanged(w, h); - } - } - - @Override - public void onSurfaceCreated() { - // In case surface is recreated, let page meshes drop allocated texture - // ids and ask for new ones. There's no need to set textures here as - // onPageSizeChanged should be called later on. - mPageLeft.resetTexture(); - mPageRight.resetTexture(); - mPageCurl.resetTexture(); - } - - @Override - public boolean onTouch(View view, MotionEvent me) { - // No dragging during animation at the moment. - // TODO: Stop animation on touch event and return to drag mode. - if (mAnimate || mPageProvider == null) { - return false; - } - - // We need page rects quite extensively so get them for later use. - RectF rightRect = mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT); - RectF leftRect = mRenderer.getPageRect(CurlRenderer.PAGE_LEFT); - - // Store pointer position. - mPointerPos.mPos.set(me.getX(), me.getY()); - mRenderer.translate(mPointerPos.mPos); - if (mEnableTouchPressure) { - mPointerPos.mPressure = me.getPressure(); - } else { - mPointerPos.mPressure = 0.8f; - } - - switch (me.getAction()) { - case MotionEvent.ACTION_DOWN: { - - // Once we receive pointer down event its position is mapped to - // right or left edge of page and that'll be the position from where - // user is holding the paper to make curl happen. - mDragStartPos.set(mPointerPos.mPos); - - // First we make sure it's not over or below page. Pages are - // supposed to be same height so it really doesn't matter do we use - // left or right one. - if (mDragStartPos.y > rightRect.top) { - mDragStartPos.y = rightRect.top; - } else if (mDragStartPos.y < rightRect.bottom) { - mDragStartPos.y = rightRect.bottom; - } - - // Then we have to make decisions for the user whether curl is going - // to happen from left or right, and on which page. - if (mViewMode == SHOW_TWO_PAGES) { - // If we have an open book and pointer is on the left from right - // page we'll mark drag position to left edge of left page. - // Additionally checking mCurrentIndex is higher than zero tells - // us there is a visible page at all. - if (mDragStartPos.x < rightRect.left && mCurrentIndex > 0) { - mDragStartPos.x = leftRect.left; - startCurl(CURL_LEFT); - } - // Otherwise check pointer is on right page's side. - else if (mDragStartPos.x >= rightRect.left - && mCurrentIndex < mPageProvider.getPageCount()) { - mDragStartPos.x = rightRect.right; - if (!mAllowLastPageCurl - && mCurrentIndex >= mPageProvider.getPageCount() - 1) { - return false; - } - startCurl(CURL_RIGHT); - } - } else if (mViewMode == SHOW_ONE_PAGE) { - float halfX = (rightRect.right + rightRect.left) / 2; - if (mDragStartPos.x < halfX && mCurrentIndex > 0) { - mDragStartPos.x = rightRect.left; - startCurl(CURL_LEFT); - } else if (mDragStartPos.x >= halfX - && mCurrentIndex < mPageProvider.getPageCount()) { - mDragStartPos.x = rightRect.right; - if (!mAllowLastPageCurl - && mCurrentIndex >= mPageProvider.getPageCount() - 1) { - return false; - } - startCurl(CURL_RIGHT); - } - } - // If we have are in curl state, let this case clause flow through - // to next one. We have pointer position and drag position defined - // and this will create first render request given these points. - if (mCurlState == CURL_NONE) { - return false; - } - } - case MotionEvent.ACTION_MOVE: { - updateCurlPos(mPointerPos); - break; - } - case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_UP: { - if (mCurlState == CURL_LEFT || mCurlState == CURL_RIGHT) { - // Animation source is the point from where animation starts. - // Also it's handled in a way we actually simulate touch events - // meaning the output is exactly the same as if user drags the - // page to other side. While not producing the best looking - // result (which is easier done by altering curl position and/or - // direction directly), this is done in a hope it made code a - // bit more readable and easier to maintain. - mAnimationSource.set(mPointerPos.mPos); - mAnimationStartTime = System.currentTimeMillis(); - - // Given the explanation, here we decide whether to simulate - // drag to left or right end. - if ((mViewMode == SHOW_ONE_PAGE && mPointerPos.mPos.x > (rightRect.left + rightRect.right) / 2) - || mViewMode == SHOW_TWO_PAGES - && mPointerPos.mPos.x > rightRect.left) { - // On right side target is always right page's right border. - mAnimationTarget.set(mDragStartPos); - mAnimationTarget.x = mRenderer - .getPageRect(CurlRenderer.PAGE_RIGHT).right; - mAnimationTargetEvent = SET_CURL_TO_RIGHT; - } else { - // On left side target depends on visible pages. - mAnimationTarget.set(mDragStartPos); - if (mCurlState == CURL_RIGHT || mViewMode == SHOW_TWO_PAGES) { - mAnimationTarget.x = leftRect.left; - } else { - mAnimationTarget.x = rightRect.left; - } - mAnimationTargetEvent = SET_CURL_TO_LEFT; - } - mAnimate = true; - requestRender(); - } - break; - } - } - - return true; - } - - /** - * Allow the last page to curl. - */ - public void setAllowLastPageCurl(boolean allowLastPageCurl) { - mAllowLastPageCurl = allowLastPageCurl; - } - - /** - * Sets mPageCurl curl position. - */ - private void setCurlPos(PointF curlPos, PointF curlDir, double radius) { - - // First reposition curl so that page doesn't 'rip off' from book. - if (mCurlState == CURL_RIGHT - || (mCurlState == CURL_LEFT && mViewMode == SHOW_ONE_PAGE)) { - RectF pageRect = mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT); - if (curlPos.x >= pageRect.right) { - mPageCurl.reset(); - requestRender(); - return; - } - if (curlPos.x < pageRect.left) { - curlPos.x = pageRect.left; - } - if (curlDir.y != 0) { - float diffX = curlPos.x - pageRect.left; - float leftY = curlPos.y + (diffX * curlDir.x / curlDir.y); - if (curlDir.y < 0 && leftY < pageRect.top) { - curlDir.x = curlPos.y - pageRect.top; - curlDir.y = pageRect.left - curlPos.x; - } else if (curlDir.y > 0 && leftY > pageRect.bottom) { - curlDir.x = pageRect.bottom - curlPos.y; - curlDir.y = curlPos.x - pageRect.left; - } - } - } else if (mCurlState == CURL_LEFT) { - RectF pageRect = mRenderer.getPageRect(CurlRenderer.PAGE_LEFT); - if (curlPos.x <= pageRect.left) { - mPageCurl.reset(); - requestRender(); - return; - } - if (curlPos.x > pageRect.right) { - curlPos.x = pageRect.right; - } - if (curlDir.y != 0) { - float diffX = curlPos.x - pageRect.right; - float rightY = curlPos.y + (diffX * curlDir.x / curlDir.y); - if (curlDir.y < 0 && rightY < pageRect.top) { - curlDir.x = pageRect.top - curlPos.y; - curlDir.y = curlPos.x - pageRect.right; - } else if (curlDir.y > 0 && rightY > pageRect.bottom) { - curlDir.x = curlPos.y - pageRect.bottom; - curlDir.y = pageRect.right - curlPos.x; - } - } - } - - // Finally normalize direction vector and do rendering. - double dist = Math.sqrt(curlDir.x * curlDir.x + curlDir.y * curlDir.y); - if (dist != 0) { - curlDir.x /= dist; - curlDir.y /= dist; - mPageCurl.curl(curlPos, curlDir, radius); - } else { - mPageCurl.reset(); - } - - requestRender(); - } - - /** - * Set current page index. Page indices are zero based values presenting - * page being shown on right side of the book. E.g if you set value to 4; - * right side front facing bitmap will be with index 4, back facing 5 and - * for left side page index 3 is front facing, and index 2 back facing (once - * page is on left side it's flipped over). - *

    - * Current index is rounded to closest value divisible with 2. - */ - public void setCurrentIndex(int index) { - if (mPageProvider == null || index < 0) { - mCurrentIndex = 0; - } else { - if (mAllowLastPageCurl) { - mCurrentIndex = Math.min(index, mPageProvider.getPageCount()); - } else { - mCurrentIndex = Math.min(index, - mPageProvider.getPageCount() - 1); - } - } - updatePages(); - requestRender(); - } - - /** - * If set to true, touch event pressure information is used to adjust curl - * radius. The more you press, the flatter the curl becomes. This is - * somewhat experimental and results may vary significantly between devices. - * On emulator pressure information seems to be flat 1.0f which is maximum - * value and therefore not very much of use. - */ - public void setEnableTouchPressure(boolean enableTouchPressure) { - mEnableTouchPressure = enableTouchPressure; - } - - /** - * Set margins (or padding). Note: margins are proportional. Meaning a value - * of .1f will produce a 10% margin. - */ - public void setMargins(float left, float top, float right, float bottom) { - mRenderer.setMargins(left, top, right, bottom); - } - - /** - * Update/set page provider. - */ - public void setPageProvider(PageProvider pageProvider) { - mPageProvider = pageProvider; - mCurrentIndex = 0; - updatePages(); - requestRender(); - } - - /** - * Setter for whether left side page is rendered. This is useful mostly for - * situations where right (main) page is aligned to left side of screen and - * left page is not visible anyway. - */ - public void setRenderLeftPage(boolean renderLeftPage) { - mRenderLeftPage = renderLeftPage; - } - - /** - * Sets SizeChangedObserver for this View. Call back method is called from - * this View's onSizeChanged method. - */ - public void setSizeChangedObserver(SizeChangedObserver observer) { - mSizeChangedObserver = observer; - } - - /** - * Sets view mode. Value can be either SHOW_ONE_PAGE or SHOW_TWO_PAGES. In - * former case right page is made size of display, and in latter case two - * pages are laid on visible area. - */ - public void setViewMode(int viewMode) { - switch (viewMode) { - case SHOW_ONE_PAGE: - mViewMode = viewMode; - mPageLeft.setFlipTexture(true); - mRenderer.setViewMode(CurlRenderer.SHOW_ONE_PAGE); - break; - case SHOW_TWO_PAGES: - mViewMode = viewMode; - mPageLeft.setFlipTexture(false); - mRenderer.setViewMode(CurlRenderer.SHOW_TWO_PAGES); - break; - } - } - - /** - * Switches meshes and loads new bitmaps if available. Updated to support 2 - * pages in landscape - */ - private void startCurl(int page) { - switch (page) { - - // Once right side page is curled, first right page is assigned into - // curled page. And if there are more bitmaps available new bitmap is - // loaded into right side mesh. - case CURL_RIGHT: { - // Remove meshes from renderer. - mRenderer.removeCurlMesh(mPageLeft); - mRenderer.removeCurlMesh(mPageRight); - mRenderer.removeCurlMesh(mPageCurl); - - // We are curling right page. - CurlMesh curl = mPageRight; - mPageRight = mPageCurl; - mPageCurl = curl; - - if (mCurrentIndex > 0) { - mPageLeft.setFlipTexture(true); - mPageLeft - .setRect(mRenderer.getPageRect(CurlRenderer.PAGE_LEFT)); - mPageLeft.reset(); - if (mRenderLeftPage) { - mRenderer.addCurlMesh(mPageLeft); - } - } - if (mCurrentIndex < mPageProvider.getPageCount() - 1) { - updatePage(mPageRight.getTexturePage(), mCurrentIndex + 1); - mPageRight.setRect(mRenderer - .getPageRect(CurlRenderer.PAGE_RIGHT)); - mPageRight.setFlipTexture(false); - mPageRight.reset(); - mRenderer.addCurlMesh(mPageRight); - } - - // Add curled page to renderer. - mPageCurl.setRect(mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT)); - mPageCurl.setFlipTexture(false); - mPageCurl.reset(); - mRenderer.addCurlMesh(mPageCurl); - - mCurlState = CURL_RIGHT; - break; - } - - // On left side curl, left page is assigned to curled page. And if - // there are more bitmaps available before currentIndex, new bitmap - // is loaded into left page. - case CURL_LEFT: { - // Remove meshes from renderer. - mRenderer.removeCurlMesh(mPageLeft); - mRenderer.removeCurlMesh(mPageRight); - mRenderer.removeCurlMesh(mPageCurl); - - // We are curling left page. - CurlMesh curl = mPageLeft; - mPageLeft = mPageCurl; - mPageCurl = curl; - - if (mCurrentIndex > 1) { - updatePage(mPageLeft.getTexturePage(), mCurrentIndex - 2); - mPageLeft.setFlipTexture(true); - mPageLeft - .setRect(mRenderer.getPageRect(CurlRenderer.PAGE_LEFT)); - mPageLeft.reset(); - if (mRenderLeftPage) { - mRenderer.addCurlMesh(mPageLeft); - } - } - - // If there is something to show on right page add it to renderer. - if (mCurrentIndex < mPageProvider.getPageCount()) { - mPageRight.setFlipTexture(false); - mPageRight.setRect(mRenderer - .getPageRect(CurlRenderer.PAGE_RIGHT)); - mPageRight.reset(); - mRenderer.addCurlMesh(mPageRight); - } - - // How dragging previous page happens depends on view mode. - if (mViewMode == SHOW_ONE_PAGE - || (mCurlState == CURL_LEFT && mViewMode == SHOW_TWO_PAGES)) { - mPageCurl.setRect(mRenderer - .getPageRect(CurlRenderer.PAGE_RIGHT)); - mPageCurl.setFlipTexture(false); - } else { - mPageCurl - .setRect(mRenderer.getPageRect(CurlRenderer.PAGE_LEFT)); - mPageCurl.setFlipTexture(true); - } - mPageCurl.reset(); - mRenderer.addCurlMesh(mPageCurl); - - mCurlState = CURL_LEFT; - break; - } - - } - } - - /** - * Updates curl position. - */ - private void updateCurlPos(PointerPosition pointerPos) { - - // Default curl radius. - double radius = mRenderer.getPageRect(CURL_RIGHT).width() / 3; - // TODO: This is not an optimal solution. Based on feedback received so - // far; pressure is not very accurate, it may be better not to map - // coefficient to range [0f, 1f] but something like [.2f, 1f] instead. - // Leaving it as is until get my hands on a real device. On emulator - // this doesn't work anyway. - radius *= Math.max(1f - pointerPos.mPressure, 0f); - // NOTE: Here we set pointerPos to mCurlPos. It might be a bit confusing - // later to see e.g "mCurlPos.x - mDragStartPos.x" used. But it's - // actually pointerPos we are doing calculations against. Why? Simply to - // optimize code a bit with the cost of making it unreadable. Otherwise - // we had to this in both of the next if-else branches. - mCurlPos.set(pointerPos.mPos); - - // If curl happens on right page, or on left page on two page mode, - // we'll calculate curl position from pointerPos. - if (mCurlState == CURL_RIGHT - || (mCurlState == CURL_LEFT && mViewMode == SHOW_TWO_PAGES)) { - - mCurlDir.x = mCurlPos.x - mDragStartPos.x; - mCurlDir.y = mCurlPos.y - mDragStartPos.y; - float dist = (float) Math.sqrt(mCurlDir.x * mCurlDir.x + mCurlDir.y - * mCurlDir.y); - - // Adjust curl radius so that if page is dragged far enough on - // opposite side, radius gets closer to zero. - float pageWidth = mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT) - .width(); - double curlLen = radius * Math.PI; - if (dist > (pageWidth * 2) - curlLen) { - curlLen = Math.max((pageWidth * 2) - dist, 0f); - radius = curlLen / Math.PI; - } - - // Actual curl position calculation. - if (dist >= curlLen) { - double translate = (dist - curlLen) / 2; - if (mViewMode == SHOW_TWO_PAGES) { - mCurlPos.x -= mCurlDir.x * translate / dist; - } else { - float pageLeftX = mRenderer - .getPageRect(CurlRenderer.PAGE_RIGHT).left; - radius = Math.max(Math.min(mCurlPos.x - pageLeftX, radius), - 0f); - } - mCurlPos.y -= mCurlDir.y * translate / dist; - } else { - double angle = Math.PI * Math.sqrt(dist / curlLen); - double translate = radius * Math.sin(angle); - mCurlPos.x += mCurlDir.x * translate / dist; - mCurlPos.y += mCurlDir.y * translate / dist; - } - } - // Otherwise we'll let curl follow pointer position. - else if (mCurlState == CURL_LEFT) { - - // Adjust radius regarding how close to page edge we are. - float pageLeftX = mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT).left; - radius = Math.max(Math.min(mCurlPos.x - pageLeftX, radius), 0f); - - float pageRightX = mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT).right; - mCurlPos.x -= Math.min(pageRightX - mCurlPos.x, radius); - mCurlDir.x = mCurlPos.x + mDragStartPos.x; - mCurlDir.y = mCurlPos.y - mDragStartPos.y; - } - - setCurlPos(mCurlPos, mCurlDir, radius); - } - - /** - * Updates given CurlPage via PageProvider for page located at index. - */ - private void updatePage(CurlPage page, int index) { - // First reset page to initial state. - page.reset(); - // Ask page provider to fill it up with bitmaps and colors. - mPageProvider.updatePage(page, mPageBitmapWidth, mPageBitmapHeight, - index); - } - - /** - * Updates bitmaps for page meshes. - */ - private void updatePages() { - if (mPageProvider == null || mPageBitmapWidth <= 0 - || mPageBitmapHeight <= 0) { - return; - } - - // Remove meshes from renderer. - mRenderer.removeCurlMesh(mPageLeft); - mRenderer.removeCurlMesh(mPageRight); - mRenderer.removeCurlMesh(mPageCurl); - - int leftIdx = mCurrentIndex - 1; - int rightIdx = mCurrentIndex; - int curlIdx = -1; - if (mCurlState == CURL_LEFT) { - curlIdx = leftIdx; - --leftIdx; - } else if (mCurlState == CURL_RIGHT) { - curlIdx = rightIdx; - ++rightIdx; - } - - if (rightIdx >= 0 && rightIdx < mPageProvider.getPageCount()) { - updatePage(mPageRight.getTexturePage(), rightIdx); - mPageRight.setFlipTexture(false); - mPageRight.setRect(mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT)); - mPageRight.reset(); - mRenderer.addCurlMesh(mPageRight); - } - if (leftIdx >= 0 && leftIdx < mPageProvider.getPageCount()) { - updatePage(mPageLeft.getTexturePage(), leftIdx); - mPageLeft.setFlipTexture(true); - mPageLeft.setRect(mRenderer.getPageRect(CurlRenderer.PAGE_LEFT)); - mPageLeft.reset(); - if (mRenderLeftPage) { - mRenderer.addCurlMesh(mPageLeft); - } - } - if (curlIdx >= 0 && curlIdx < mPageProvider.getPageCount()) { - updatePage(mPageCurl.getTexturePage(), curlIdx); - - if (mCurlState == CURL_RIGHT) { - mPageCurl.setFlipTexture(true); - mPageCurl.setRect(mRenderer - .getPageRect(CurlRenderer.PAGE_RIGHT)); - } else { - mPageCurl.setFlipTexture(false); - mPageCurl - .setRect(mRenderer.getPageRect(CurlRenderer.PAGE_LEFT)); - } - - mPageCurl.reset(); - mRenderer.addCurlMesh(mPageCurl); - } - } - - /** - * Provider for feeding 'book' with bitmaps which are used for rendering - * pages. - */ - public interface PageProvider { - - /** - * Return number of pages available. - */ - public int getPageCount(); - - /** - * Called once new bitmaps/textures are needed. Width and height are in - * pixels telling the size it will be drawn on screen and following them - * ensures that aspect ratio remains. But it's possible to return bitmap - * of any size though. You should use provided CurlPage for storing page - * information for requested page number.
    - *
    - * Index is a number between 0 and getBitmapCount() - 1. - */ - public void updatePage(CurlPage page, int width, int height, int index); - } - - /** - * Simple holder for pointer position. - */ - private class PointerPosition { - PointF mPos = new PointF(); - float mPressure; - } - - /** - * Observer interface for handling CurlView size changes. - */ - public interface SizeChangedObserver { - - /** - * Called once CurlView size changes. - */ - public void onSizeChanged(int width, int height); - } - -} diff --git a/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlView.kt b/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlView.kt new file mode 100644 index 000000000..f7dfd14f7 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlView.kt @@ -0,0 +1,768 @@ +package io.legado.app.ui.widget.page.curl + +import android.content.Context +import android.graphics.PointF +import android.opengl.GLSurfaceView +import android.util.AttributeSet +import android.view.MotionEvent +import android.view.View +import kotlin.math.max +import kotlin.math.min +import kotlin.math.sin +import kotlin.math.sqrt + +/** + * OpenGL ES View. + * + * @author harism + */ +class CurlView : GLSurfaceView, View.OnTouchListener, CurlRenderer.Observer { + + private var mAllowLastPageCurl = true + + private var mAnimate = false + private val mAnimationDurationTime: Long = 300 + private val mAnimationSource = PointF() + private var mAnimationStartTime: Long = 0 + private val mAnimationTarget = PointF() + private var mAnimationTargetEvent: Int = 0 + + private val mCurlDir = PointF() + + private val mCurlPos = PointF() + private var mCurlState = CURL_NONE + // Current bitmap index. This is always showed as front of right page. + private var mCurrentIndex = 0 + + // Start position for dragging. + private val mDragStartPos = PointF() + + private var mEnableTouchPressure = false + // Bitmap size. These are updated from renderer once it's initialized. + private var mPageBitmapHeight = -1 + + private var mPageBitmapWidth = -1 + // Page meshes. Left and right meshes are 'static' while curl is used to + // show page flipping. + private var mPageCurl: CurlMesh + private var mPageLeft: CurlMesh + private var mPageRight: CurlMesh + + private var mPageProvider: PageProvider? = null + + private val mPointerPos = PointerPosition() + + private var mRenderer: CurlRenderer = CurlRenderer(this) + private var mRenderLeftPage = true + private var mSizeChangedObserver: SizeChangedObserver? = null + + // One page is the default. + private var mViewMode = SHOW_ONE_PAGE + + /** + * Get current page index. Page indices are zero based values presenting + * page being shown on right side of the book. + */ + /** + * Set current page index. Page indices are zero based values presenting + * page being shown on right side of the book. E.g if you set value to 4; + * right side front facing bitmap will be with index 4, back facing 5 and + * for left side page index 3 is front facing, and index 2 back facing (once + * page is on left side it's flipped over). + * + * + * Current index is rounded to closest value divisible with 2. + */ + var currentIndex: Int + get() = mCurrentIndex + set(index) { + mCurrentIndex = if (mPageProvider == null || index < 0) { + 0 + } else { + if (mAllowLastPageCurl) { + min(index, mPageProvider!!.pageCount) + } else { + min( + index, + mPageProvider!!.pageCount - 1 + ) + } + } + updatePages() + requestRender() + } + + /** + * Default constructor. + */ + constructor(ctx: Context) : super(ctx) + + /** + * Default constructor. + */ + constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs) + + /** + * Default constructor. + */ + constructor(ctx: Context, attrs: AttributeSet, defStyle: Int) : this(ctx, attrs) + + /** + * Initialize method. + */ + init { + setRenderer(mRenderer) + renderMode = RENDERMODE_WHEN_DIRTY + setOnTouchListener(this) + + // Even though left and right pages are static we have to allocate room + // for curl on them too as we are switching meshes. Another way would be + // to swap texture ids only. + mPageLeft = CurlMesh(10) + mPageRight = CurlMesh(10) + mPageCurl = CurlMesh(10) + mPageLeft.setFlipTexture(true) + mPageRight.setFlipTexture(false) + } + + override fun onDrawFrame() { + // We are not animating. + if (!mAnimate) { + return + } + + val currentTime = System.currentTimeMillis() + // If animation is done. + if (currentTime >= mAnimationStartTime + mAnimationDurationTime) { + if (mAnimationTargetEvent == SET_CURL_TO_RIGHT) { + // Switch curled page to right. + val right = mPageCurl + val curl = mPageRight + right.setRect(mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT)!!) + right.setFlipTexture(false) + right.reset() + mRenderer.removeCurlMesh(curl) + mPageCurl = curl + mPageRight = right + // If we were curling left page update current index. + if (mCurlState == CURL_LEFT) { + --mCurrentIndex + } + } else if (mAnimationTargetEvent == SET_CURL_TO_LEFT) { + // Switch curled page to left. + val left = mPageCurl + val curl = mPageLeft + left.setRect(mRenderer.getPageRect(CurlRenderer.PAGE_LEFT)!!) + left.setFlipTexture(true) + left.reset() + mRenderer.removeCurlMesh(curl) + if (!mRenderLeftPage) { + mRenderer.removeCurlMesh(left) + } + mPageCurl = curl + mPageLeft = left + // If we were curling right page update current index. + if (mCurlState == CURL_RIGHT) { + ++mCurrentIndex + } + } + mCurlState = CURL_NONE + mAnimate = false + requestRender() + } else { + mPointerPos.mPos.set(mAnimationSource) + var t = 1f - (currentTime - mAnimationStartTime).toFloat() / mAnimationDurationTime + t = 1f - t * t * t * (3 - 2 * t) + mPointerPos.mPos.x += (mAnimationTarget.x - mAnimationSource.x) * t + mPointerPos.mPos.y += (mAnimationTarget.y - mAnimationSource.y) * t + updateCurlPos(mPointerPos) + } + } + + override fun onPageSizeChanged(width: Int, height: Int) { + mPageBitmapWidth = width + mPageBitmapHeight = height + updatePages() + requestRender() + } + + public override fun onSizeChanged(w: Int, h: Int, ow: Int, oh: Int) { + super.onSizeChanged(w, h, ow, oh) + requestRender() + if (mSizeChangedObserver != null) { + mSizeChangedObserver!!.onSizeChanged(w, h) + } + } + + override fun onSurfaceCreated() { + // In case surface is recreated, let page meshes drop allocated texture + // ids and ask for new ones. There's no need to set textures here as + // onPageSizeChanged should be called later on. + mPageLeft.resetTexture() + mPageRight.resetTexture() + mPageCurl.resetTexture() + } + + override fun onTouch(view: View, me: MotionEvent): Boolean { + // No dragging during animation at the moment. + if (mAnimate || mPageProvider == null) { + return false + } + + // We need page rects quite extensively so get them for later use. + val rightRect = mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT) + val leftRect = mRenderer.getPageRect(CurlRenderer.PAGE_LEFT) + + // Store pointer position. + mPointerPos.mPos.set(me.x, me.y) + mRenderer.translate(mPointerPos.mPos) + if (mEnableTouchPressure) { + mPointerPos.mPressure = me.pressure + } else { + mPointerPos.mPressure = 0.8f + } + + when (me.action) { + MotionEvent.ACTION_DOWN -> { + run { + + // Once we receive pointer down event its position is mapped to + // right or left edge of page and that'll be the position from where + // user is holding the paper to make curl happen. + mDragStartPos.set(mPointerPos.mPos) + + // First we make sure it's not over or below page. Pages are + // supposed to be same height so it really doesn't matter do we use + // left or right one. + if (mDragStartPos.y > rightRect!!.top) { + mDragStartPos.y = rightRect.top + } else if (mDragStartPos.y < rightRect.bottom) { + mDragStartPos.y = rightRect.bottom + } + + // Then we have to make decisions for the user whether curl is going + // to happen from left or right, and on which page. + if (mViewMode == SHOW_TWO_PAGES) { + // If we have an open book and pointer is on the left from right + // page we'll mark drag position to left edge of left page. + // Additionally checking mCurrentIndex is higher than zero tells + // us there is a visible page at all. + if (mDragStartPos.x < rightRect.left && mCurrentIndex > 0) { + mDragStartPos.x = leftRect!!.left + startCurl(CURL_LEFT) + } else if (mDragStartPos.x >= rightRect.left && mCurrentIndex < mPageProvider!!.pageCount) { + mDragStartPos.x = rightRect.right + if (!mAllowLastPageCurl && mCurrentIndex >= mPageProvider!!.pageCount - 1) { + return false + } + startCurl(CURL_RIGHT) + }// Otherwise check pointer is on right page's side. + } else if (mViewMode == SHOW_ONE_PAGE) { + val halfX = (rightRect.right + rightRect.left) / 2 + if (mDragStartPos.x < halfX && mCurrentIndex > 0) { + mDragStartPos.x = rightRect.left + startCurl(CURL_LEFT) + } else if (mDragStartPos.x >= halfX && mCurrentIndex < mPageProvider!!.pageCount) { + mDragStartPos.x = rightRect.right + if (!mAllowLastPageCurl && mCurrentIndex >= mPageProvider!!.pageCount - 1) { + return false + } + startCurl(CURL_RIGHT) + } + } + // If we have are in curl state, let this case clause flow through + // to next one. We have pointer position and drag position defined + // and this will create first render request given these points. + if (mCurlState == CURL_NONE) { + return false + } + } + updateCurlPos(mPointerPos) + } + MotionEvent.ACTION_MOVE -> { + updateCurlPos(mPointerPos) + } + MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_UP -> { + if (mCurlState == CURL_LEFT || mCurlState == CURL_RIGHT) { + // Animation source is the point from where animation starts. + // Also it's handled in a way we actually simulate touch events + // meaning the output is exactly the same as if user drags the + // page to other side. While not producing the best looking + // result (which is easier done by altering curl position and/or + // direction directly), this is done in a hope it made code a + // bit more readable and easier to maintain. + mAnimationSource.set(mPointerPos.mPos) + mAnimationStartTime = System.currentTimeMillis() + + // Given the explanation, here we decide whether to simulate + // drag to left or right end. + if (mViewMode == SHOW_ONE_PAGE && mPointerPos.mPos.x > (rightRect!!.left + rightRect.right) / 2 || mViewMode == SHOW_TWO_PAGES && mPointerPos.mPos.x > rightRect!!.left) { + // On right side target is always right page's right border. + mAnimationTarget.set(mDragStartPos) + mAnimationTarget.x = mRenderer + .getPageRect(CurlRenderer.PAGE_RIGHT)!!.right + mAnimationTargetEvent = SET_CURL_TO_RIGHT + } else { + // On left side target depends on visible pages. + mAnimationTarget.set(mDragStartPos) + if (mCurlState == CURL_RIGHT || mViewMode == SHOW_TWO_PAGES) { + mAnimationTarget.x = leftRect!!.left + } else { + mAnimationTarget.x = rightRect!!.left + } + mAnimationTargetEvent = SET_CURL_TO_LEFT + } + mAnimate = true + requestRender() + } + } + } + + return true + } + + /** + * Allow the last page to curl. + */ + fun setAllowLastPageCurl(allowLastPageCurl: Boolean) { + mAllowLastPageCurl = allowLastPageCurl + } + + /** + * Sets mPageCurl curl position. + */ + private fun setCurlPos(curlPos: PointF, curlDir: PointF, radius: Double) { + + // First reposition curl so that page doesn't 'rip off' from book. + if (mCurlState == CURL_RIGHT || mCurlState == CURL_LEFT && mViewMode == SHOW_ONE_PAGE) { + val pageRect = mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT) + if (curlPos.x >= pageRect!!.right) { + mPageCurl.reset() + requestRender() + return + } + if (curlPos.x < pageRect.left) { + curlPos.x = pageRect.left + } + if (curlDir.y != 0f) { + val diffX = curlPos.x - pageRect.left + val leftY = curlPos.y + diffX * curlDir.x / curlDir.y + if (curlDir.y < 0 && leftY < pageRect.top) { + curlDir.x = curlPos.y - pageRect.top + curlDir.y = pageRect.left - curlPos.x + } else if (curlDir.y > 0 && leftY > pageRect.bottom) { + curlDir.x = pageRect.bottom - curlPos.y + curlDir.y = curlPos.x - pageRect.left + } + } + } else if (mCurlState == CURL_LEFT) { + val pageRect = mRenderer.getPageRect(CurlRenderer.PAGE_LEFT) + if (curlPos.x <= pageRect!!.left) { + mPageCurl.reset() + requestRender() + return + } + if (curlPos.x > pageRect.right) { + curlPos.x = pageRect.right + } + if (curlDir.y != 0f) { + val diffX = curlPos.x - pageRect.right + val rightY = curlPos.y + diffX * curlDir.x / curlDir.y + if (curlDir.y < 0 && rightY < pageRect.top) { + curlDir.x = pageRect.top - curlPos.y + curlDir.y = curlPos.x - pageRect.right + } else if (curlDir.y > 0 && rightY > pageRect.bottom) { + curlDir.x = curlPos.y - pageRect.bottom + curlDir.y = pageRect.right - curlPos.x + } + } + } + + // Finally normalize direction vector and do rendering. + val dist = sqrt((curlDir.x * curlDir.x + curlDir.y * curlDir.y).toDouble()) + if (dist != 0.0) { + curlDir.x /= dist.toFloat() + curlDir.y /= dist.toFloat() + mPageCurl.curl(curlPos, curlDir, radius) + } else { + mPageCurl.reset() + } + + requestRender() + } + + /** + * If set to true, touch event pressure information is used to adjust curl + * radius. The more you press, the flatter the curl becomes. This is + * somewhat experimental and results may vary significantly between devices. + * On emulator pressure information seems to be flat 1.0f which is maximum + * value and therefore not very much of use. + */ + fun setEnableTouchPressure(enableTouchPressure: Boolean) { + mEnableTouchPressure = enableTouchPressure + } + + /** + * Set margins (or padding). Note: margins are proportional. Meaning a value + * of .1f will produce a 10% margin. + */ + fun setMargins(left: Float, top: Float, right: Float, bottom: Float) { + mRenderer.setMargins(left, top, right, bottom) + } + + /** + * Update/set page provider. + */ + fun setPageProvider(pageProvider: PageProvider) { + mPageProvider = pageProvider + mCurrentIndex = 0 + updatePages() + requestRender() + } + + /** + * Setter for whether left side page is rendered. This is useful mostly for + * situations where right (main) page is aligned to left side of screen and + * left page is not visible anyway. + */ + fun setRenderLeftPage(renderLeftPage: Boolean) { + mRenderLeftPage = renderLeftPage + } + + /** + * Sets SizeChangedObserver for this View. Call back method is called from + * this View's onSizeChanged method. + */ + fun setSizeChangedObserver(observer: SizeChangedObserver) { + mSizeChangedObserver = observer + } + + /** + * Sets view mode. Value can be either SHOW_ONE_PAGE or SHOW_TWO_PAGES. In + * former case right page is made size of display, and in latter case two + * pages are laid on visible area. + */ + fun setViewMode(viewMode: Int) { + when (viewMode) { + SHOW_ONE_PAGE -> { + mViewMode = viewMode + mPageLeft.setFlipTexture(true) + mRenderer.setViewMode(CurlRenderer.SHOW_ONE_PAGE) + } + SHOW_TWO_PAGES -> { + mViewMode = viewMode + mPageLeft.setFlipTexture(false) + mRenderer.setViewMode(CurlRenderer.SHOW_TWO_PAGES) + } + } + } + + /** + * Switches meshes and loads new bitmaps if available. Updated to support 2 + * pages in landscape + */ + private fun startCurl(page: Int) { + when (page) { + + // Once right side page is curled, first right page is assigned into + // curled page. And if there are more bitmaps available new bitmap is + // loaded into right side mesh. + CURL_RIGHT -> { + // Remove meshes from renderer. + mRenderer.removeCurlMesh(mPageLeft) + mRenderer.removeCurlMesh(mPageRight) + mRenderer.removeCurlMesh(mPageCurl) + + // We are curling right page. + val curl = mPageRight + mPageRight = mPageCurl + mPageCurl = curl + + if (mCurrentIndex > 0) { + mPageLeft.setFlipTexture(true) + mPageLeft.setRect(mRenderer.getPageRect(CurlRenderer.PAGE_LEFT)!!) + mPageLeft.reset() + if (mRenderLeftPage) { + mRenderer.addCurlMesh(mPageLeft) + } + } + if (mCurrentIndex < mPageProvider!!.pageCount - 1) { + updatePage(mPageRight.texturePage, mCurrentIndex + 1) + mPageRight.setRect( + mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT)!! + ) + mPageRight.setFlipTexture(false) + mPageRight.reset() + mRenderer.addCurlMesh(mPageRight) + } + + // Add curled page to renderer. + mPageCurl.setRect(mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT)!!) + mPageCurl.setFlipTexture(false) + mPageCurl.reset() + mRenderer.addCurlMesh(mPageCurl) + + mCurlState = CURL_RIGHT + } + + // On left side curl, left page is assigned to curled page. And if + // there are more bitmaps available before currentIndex, new bitmap + // is loaded into left page. + CURL_LEFT -> { + // Remove meshes from renderer. + mRenderer.removeCurlMesh(mPageLeft) + mRenderer.removeCurlMesh(mPageRight) + mRenderer.removeCurlMesh(mPageCurl) + + // We are curling left page. + val curl = mPageLeft + mPageLeft = mPageCurl + mPageCurl = curl + + if (mCurrentIndex > 1) { + updatePage(mPageLeft.texturePage, mCurrentIndex - 2) + mPageLeft.setFlipTexture(true) + mPageLeft + .setRect(mRenderer.getPageRect(CurlRenderer.PAGE_LEFT)!!) + mPageLeft.reset() + if (mRenderLeftPage) { + mRenderer.addCurlMesh(mPageLeft) + } + } + + // If there is something to show on right page add it to renderer. + if (mCurrentIndex < mPageProvider!!.pageCount) { + mPageRight.setFlipTexture(false) + mPageRight.setRect( + mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT)!! + ) + mPageRight.reset() + mRenderer.addCurlMesh(mPageRight) + } + + // How dragging previous page happens depends on view mode. + if (mViewMode == SHOW_ONE_PAGE || mCurlState == CURL_LEFT && mViewMode == SHOW_TWO_PAGES) { + mPageCurl.setRect( + mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT)!! + ) + mPageCurl.setFlipTexture(false) + } else { + mPageCurl.setRect(mRenderer.getPageRect(CurlRenderer.PAGE_LEFT)!!) + mPageCurl.setFlipTexture(true) + } + mPageCurl.reset() + mRenderer.addCurlMesh(mPageCurl) + + mCurlState = CURL_LEFT + } + } + } + + /** + * Updates curl position. + */ + private fun updateCurlPos(pointerPos: PointerPosition) { + + // Default curl radius. + var radius = (mRenderer.getPageRect(CURL_RIGHT)!!.width() / 3).toDouble() + // TODO: This is not an optimal solution. Based on feedback received so + // far; pressure is not very accurate, it may be better not to map + // coefficient to range [0f, 1f] but something like [.2f, 1f] instead. + // Leaving it as is until get my hands on a real device. On emulator + // this doesn't work anyway. + radius *= max(1f - pointerPos.mPressure, 0f).toDouble() + // NOTE: Here we set pointerPos to mCurlPos. It might be a bit confusing + // later to see e.g "mCurlPos.x - mDragStartPos.x" used. But it's + // actually pointerPos we are doing calculations against. Why? Simply to + // optimize code a bit with the cost of making it unreadable. Otherwise + // we had to this in both of the next if-else branches. + mCurlPos.set(pointerPos.mPos) + + // If curl happens on right page, or on left page on two page mode, + // we'll calculate curl position from pointerPos. + if (mCurlState == CURL_RIGHT || mCurlState == CURL_LEFT && mViewMode == SHOW_TWO_PAGES) { + + mCurlDir.x = mCurlPos.x - mDragStartPos.x + mCurlDir.y = mCurlPos.y - mDragStartPos.y + val dist = + sqrt((mCurlDir.x * mCurlDir.x + mCurlDir.y * mCurlDir.y).toDouble()).toFloat() + + // Adjust curl radius so that if page is dragged far enough on + // opposite side, radius gets closer to zero. + val pageWidth = mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT)!! + .width() + var curlLen = radius * Math.PI + if (dist > pageWidth * 2 - curlLen) { + curlLen = max(pageWidth * 2 - dist, 0f).toDouble() + radius = curlLen / Math.PI + } + + // Actual curl position calculation. + if (dist >= curlLen) { + val translate = (dist - curlLen) / 2 + if (mViewMode == SHOW_TWO_PAGES) { + mCurlPos.x -= (mCurlDir.x * translate / dist).toFloat() + } else { + val pageLeftX = mRenderer + .getPageRect(CurlRenderer.PAGE_RIGHT)!!.left + radius = max( + min((mCurlPos.x - pageLeftX).toDouble(), radius), + 0.0 + ) + } + mCurlPos.y -= (mCurlDir.y * translate / dist).toFloat() + } else { + val angle = Math.PI * sqrt(dist / curlLen) + val translate = radius * sin(angle) + mCurlPos.x += (mCurlDir.x * translate / dist).toFloat() + mCurlPos.y += (mCurlDir.y * translate / dist).toFloat() + } + } else if (mCurlState == CURL_LEFT) { + + // Adjust radius regarding how close to page edge we are. + val pageLeftX = mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT)!!.left + radius = max(min((mCurlPos.x - pageLeftX).toDouble(), radius), 0.0) + + val pageRightX = mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT)!!.right + mCurlPos.x -= min((pageRightX - mCurlPos.x).toDouble(), radius).toFloat() + mCurlDir.x = mCurlPos.x + mDragStartPos.x + mCurlDir.y = mCurlPos.y - mDragStartPos.y + }// Otherwise we'll let curl follow pointer position. + + setCurlPos(mCurlPos, mCurlDir, radius) + } + + /** + * Updates given CurlPage via PageProvider for page located at index. + */ + private fun updatePage(page: CurlPage, index: Int) { + // First reset page to initial state. + page.reset() + // Ask page provider to fill it up with bitmaps and colors. + mPageProvider!!.updatePage( + page, mPageBitmapWidth, mPageBitmapHeight, + index + ) + } + + /** + * Updates bitmaps for page meshes. + */ + private fun updatePages() { + if (mPageProvider == null || mPageBitmapWidth <= 0 + || mPageBitmapHeight <= 0 + ) { + return + } + + // Remove meshes from renderer. + mRenderer.removeCurlMesh(mPageLeft) + mRenderer.removeCurlMesh(mPageRight) + mRenderer.removeCurlMesh(mPageCurl) + + var leftIdx = mCurrentIndex - 1 + var rightIdx = mCurrentIndex + var curlIdx = -1 + if (mCurlState == CURL_LEFT) { + curlIdx = leftIdx + --leftIdx + } else if (mCurlState == CURL_RIGHT) { + curlIdx = rightIdx + ++rightIdx + } + + if (rightIdx >= 0 && rightIdx < mPageProvider!!.pageCount) { + updatePage(mPageRight.texturePage, rightIdx) + mPageRight.setFlipTexture(false) + mPageRight.setRect(mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT)!!) + mPageRight.reset() + mRenderer.addCurlMesh(mPageRight) + } + if (leftIdx >= 0 && leftIdx < mPageProvider!!.pageCount) { + updatePage(mPageLeft.texturePage, leftIdx) + mPageLeft.setFlipTexture(true) + mPageLeft.setRect(mRenderer.getPageRect(CurlRenderer.PAGE_LEFT)!!) + mPageLeft.reset() + if (mRenderLeftPage) { + mRenderer.addCurlMesh(mPageLeft) + } + } + if (curlIdx >= 0 && curlIdx < mPageProvider!!.pageCount) { + updatePage(mPageCurl.texturePage, curlIdx) + + if (mCurlState == CURL_RIGHT) { + mPageCurl.setFlipTexture(true) + mPageCurl.setRect( + mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT)!! + ) + } else { + mPageCurl.setFlipTexture(false) + mPageCurl + .setRect(mRenderer.getPageRect(CurlRenderer.PAGE_LEFT)!!) + } + + mPageCurl.reset() + mRenderer.addCurlMesh(mPageCurl) + } + } + + /** + * Provider for feeding 'book' with bitmaps which are used for rendering + * pages. + */ + interface PageProvider { + + /** + * Return number of pages available. + */ + val pageCount: Int + + /** + * Called once new bitmaps/textures are needed. Width and height are in + * pixels telling the size it will be drawn on screen and following them + * ensures that aspect ratio remains. But it's possible to return bitmap + * of any size though. You should use provided CurlPage for storing page + * information for requested page number.

    + *

    + * Index is a number between 0 and getBitmapCount() - 1. + */ + fun updatePage(page: CurlPage, width: Int, height: Int, index: Int) + } + + /** + * Simple holder for pointer position. + */ + private inner class PointerPosition { + internal var mPos = PointF() + internal var mPressure: Float = 0.toFloat() + } + + /** + * Observer interface for handling CurlView size changes. + */ + interface SizeChangedObserver { + + /** + * Called once CurlView size changes. + */ + fun onSizeChanged(width: Int, height: Int) + } + + companion object { + + // Curl state. We are flipping none, left or right page. + private const val CURL_LEFT = 1 + private const val CURL_NONE = 0 + private const val CURL_RIGHT = 2 + + // Constants for mAnimationTargetEvent. + private const val SET_CURL_TO_LEFT = 1 + private const val SET_CURL_TO_RIGHT = 2 + + // Shows one page at the center of view. + const val SHOW_ONE_PAGE = 1 + // Shows two pages side by side. + const val SHOW_TWO_PAGES = 2 + } + +} diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt index a7f690890..93174923d 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt @@ -6,6 +6,7 @@ import android.graphics.RectF import android.view.GestureDetector import android.view.MotionEvent import android.widget.Scroller +import androidx.annotation.CallSuper import androidx.interpolator.view.animation.FastOutLinearInInterpolator import io.legado.app.ui.widget.page.ContentView import io.legado.app.ui.widget.page.PageView @@ -173,7 +174,8 @@ abstract class PageDelegate(protected val pageView: PageView) { /** * 触摸事件处理 */ - fun onTouch(event: MotionEvent): Boolean { + @CallSuper + open fun onTouch(event: MotionEvent): Boolean { if (isStarted) return false if (curPage?.isTextSelected() == true) { curPage?.dispatchTouchEvent(event) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt index 2020e3a60..186fc8c97 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt @@ -1,9 +1,29 @@ package io.legado.app.ui.widget.page.delegate import android.graphics.Canvas +import android.view.MotionEvent import io.legado.app.ui.widget.page.PageView +import io.legado.app.ui.widget.page.curl.CurlPage +import io.legado.app.ui.widget.page.curl.CurlView +import io.legado.app.utils.screenshot class SimulationPageDelegate(pageView: PageView) : PageDelegate(pageView) { + + init { + pageView.curlView ?: let { + pageView.curlView = CurlView(pageView.context) + pageView.addView(pageView.curlView) + pageView.curlView?.setPageProvider(PageProvider()) + pageView.curlView?.setSizeChangedObserver(SizeChangedObserver()) + pageView.curlView?.currentIndex = 0 + } + } + + override fun onTouch(event: MotionEvent): Boolean { + pageView.curlView?.dispatchTouchEvent(event) + return super.onTouch(event) + } + override fun onScrollStart() { } @@ -12,4 +32,23 @@ class SimulationPageDelegate(pageView: PageView) : PageDelegate(pageView) { override fun onScrollStop() { } + + private inner class PageProvider : CurlView.PageProvider { + + override val pageCount: Int + get() = 1 + + override fun updatePage(page: CurlPage, width: Int, height: Int, index: Int) { + val front = curPage?.screenshot() + page.setTexture(front, CurlPage.SIDE_BOTH) + } + } + + // 定义书籍尺寸的变化监听器 + private inner class SizeChangedObserver : CurlView.SizeChangedObserver { + override fun onSizeChanged(w: Int, h: Int) { + pageView.curlView?.setViewMode(CurlView.SHOW_ONE_PAGE) + pageView.curlView?.setMargins(0f, 0f, 0f, 0f) + } + } } \ No newline at end of file From e03171443681efb177e338e10ca4b2ea28f130e6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 6 Oct 2019 16:19:44 +0800 Subject: [PATCH 1821/1997] up --- .../java/io/legado/app/ui/widget/page/curl/CurlMesh.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlMesh.java b/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlMesh.java index 6efcf75bf..3c733588c 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlMesh.java +++ b/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlMesh.java @@ -268,7 +268,7 @@ public class CurlMesh { // Also vertices/lines are given in an order first one has x -coordinate // at least the latter one. This property is used in getIntersections to // see if there is an intersection. - int lines[][] = {{0, 1}, {0, 2}, {1, 3}, {2, 3}}; + int[][] lines = {{0, 1}, {0, 2}, {1, 3}, {2, 3}}; { // TODO: There really has to be more 'easier' way of doing this - // not including extensive use of sqrt. @@ -543,9 +543,9 @@ public class CurlMesh { mArrIntersections.clear(); // Iterate through rectangle lines each re-presented as a pair of // vertices. - for (int j = 0; j < lineIndices.length; j++) { - Vertex v1 = vertices.get(lineIndices[j][0]); - Vertex v2 = vertices.get(lineIndices[j][1]); + for (int[] lineIndex : lineIndices) { + Vertex v1 = vertices.get(lineIndex[0]); + Vertex v2 = vertices.get(lineIndex[1]); // Here we expect that v1.mPosX >= v2.mPosX and wont do intersection // test the opposite way. if (v1.mPosX > scanX && v2.mPosX < scanX) { From 262d9c0b42bbdb04c529eb0e8d4a586458127cf2 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 6 Oct 2019 16:53:29 +0800 Subject: [PATCH 1822/1997] up --- .../main/java/io/legado/app/ui/widget/page/curl/CurlView.kt | 5 +---- .../app/ui/widget/page/delegate/SimulationPageDelegate.kt | 3 +-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlView.kt b/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlView.kt index f7dfd14f7..96f15eac9 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlView.kt @@ -82,10 +82,7 @@ class CurlView : GLSurfaceView, View.OnTouchListener, CurlRenderer.Observer { if (mAllowLastPageCurl) { min(index, mPageProvider!!.pageCount) } else { - min( - index, - mPageProvider!!.pageCount - 1 - ) + min(index, mPageProvider!!.pageCount - 1) } } updatePages() diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt index 186fc8c97..4b96fb6cd 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt @@ -39,8 +39,7 @@ class SimulationPageDelegate(pageView: PageView) : PageDelegate(pageView) { get() = 1 override fun updatePage(page: CurlPage, width: Int, height: Int, index: Int) { - val front = curPage?.screenshot() - page.setTexture(front, CurlPage.SIDE_BOTH) + page.setTexture(curPage?.screenshot(), CurlPage.SIDE_BOTH) } } From 483bf92003b22a0a63fa205b4b0ac8ed93e08b32 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 6 Oct 2019 17:19:30 +0800 Subject: [PATCH 1823/1997] up --- .../io/legado/app/ui/widget/page/PageView.kt | 1 + .../app/ui/widget/page/curl/CurlView.kt | 22 ++++++++----------- .../ui/widget/page/delegate/PageDelegate.kt | 3 +++ .../page/delegate/SimulationPageDelegate.kt | 6 ++++- 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt index 894562639..e1e865830 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/PageView.kt @@ -122,6 +122,7 @@ class PageView(context: Context, attrs: AttributeSet) : prevPage?.scrollToBottom() } } + pageDelegate?.onPageUp() } fun moveToPrevPage(noAnim: Boolean = true) { diff --git a/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlView.kt b/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlView.kt index 96f15eac9..086894434 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlView.kt @@ -48,8 +48,6 @@ class CurlView : GLSurfaceView, View.OnTouchListener, CurlRenderer.Observer { private var mPageLeft: CurlMesh private var mPageRight: CurlMesh - private var mPageProvider: PageProvider? = null - private val mPointerPos = PointerPosition() private var mRenderer: CurlRenderer = CurlRenderer(this) @@ -59,6 +57,14 @@ class CurlView : GLSurfaceView, View.OnTouchListener, CurlRenderer.Observer { // One page is the default. private var mViewMode = SHOW_ONE_PAGE + var mPageProvider: PageProvider? = null + set(value) { + field = value + mCurrentIndex = 0 + updatePages() + requestRender() + } + /** * Get current page index. Page indices are zero based values presenting * page being shown on right side of the book. @@ -407,16 +413,6 @@ class CurlView : GLSurfaceView, View.OnTouchListener, CurlRenderer.Observer { mRenderer.setMargins(left, top, right, bottom) } - /** - * Update/set page provider. - */ - fun setPageProvider(pageProvider: PageProvider) { - mPageProvider = pageProvider - mCurrentIndex = 0 - updatePages() - requestRender() - } - /** * Setter for whether left side page is rendered. This is useful mostly for * situations where right (main) page is aligned to left side of screen and @@ -645,7 +641,7 @@ class CurlView : GLSurfaceView, View.OnTouchListener, CurlRenderer.Observer { /** * Updates bitmaps for page meshes. */ - private fun updatePages() { + fun updatePages() { if (mPageProvider == null || mPageBitmapWidth <= 0 || mPageBitmapHeight <= 0 ) { diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt index 93174923d..a59a6a86b 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt @@ -209,6 +209,9 @@ abstract class PageDelegate(protected val pageView: PageView) { open fun onScroll() {//移动contentView, slidePage } + open fun onPageUp() { + } + enum class Direction { NONE, PREV, NEXT } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt index 4b96fb6cd..0c552bb75 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt @@ -13,7 +13,7 @@ class SimulationPageDelegate(pageView: PageView) : PageDelegate(pageView) { pageView.curlView ?: let { pageView.curlView = CurlView(pageView.context) pageView.addView(pageView.curlView) - pageView.curlView?.setPageProvider(PageProvider()) + pageView.curlView?.mPageProvider = PageProvider() pageView.curlView?.setSizeChangedObserver(SizeChangedObserver()) pageView.curlView?.currentIndex = 0 } @@ -33,6 +33,10 @@ class SimulationPageDelegate(pageView: PageView) : PageDelegate(pageView) { override fun onScrollStop() { } + override fun onPageUp() { + pageView.curlView?.updatePages() + } + private inner class PageProvider : CurlView.PageProvider { override val pageCount: Int From ac18cdcad73cb8ae967502b87d0410d705dfc9f6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 6 Oct 2019 17:22:38 +0800 Subject: [PATCH 1824/1997] up --- .../app/ui/widget/page/delegate/SimulationPageDelegate.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt index 0c552bb75..d64bf4741 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt @@ -40,10 +40,14 @@ class SimulationPageDelegate(pageView: PageView) : PageDelegate(pageView) { private inner class PageProvider : CurlView.PageProvider { override val pageCount: Int - get() = 1 + get() = 3 override fun updatePage(page: CurlPage, width: Int, height: Int, index: Int) { - page.setTexture(curPage?.screenshot(), CurlPage.SIDE_BOTH) + when (index) { + 0 -> page.setTexture(prevPage?.screenshot(), CurlPage.SIDE_BOTH) + 1 -> page.setTexture(curPage?.screenshot(), CurlPage.SIDE_BOTH) + 2 -> page.setTexture(nextPage?.screenshot(), CurlPage.SIDE_BOTH) + } } } From 1da735ec5ec20c23ea6a4e881981b4440dad5b62 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 6 Oct 2019 17:23:48 +0800 Subject: [PATCH 1825/1997] up --- .../app/ui/widget/page/delegate/SimulationPageDelegate.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt index d64bf4741..4086da380 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt @@ -15,7 +15,7 @@ class SimulationPageDelegate(pageView: PageView) : PageDelegate(pageView) { pageView.addView(pageView.curlView) pageView.curlView?.mPageProvider = PageProvider() pageView.curlView?.setSizeChangedObserver(SizeChangedObserver()) - pageView.curlView?.currentIndex = 0 + pageView.curlView?.currentIndex = 1 } } From 94077098803d8843803e98fece31e6d76be3f621 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 6 Oct 2019 18:51:53 +0800 Subject: [PATCH 1826/1997] up --- .../legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt index 4086da380..c705fded2 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt @@ -35,6 +35,7 @@ class SimulationPageDelegate(pageView: PageView) : PageDelegate(pageView) { override fun onPageUp() { pageView.curlView?.updatePages() + pageView.curlView?.invalidate() } private inner class PageProvider : CurlView.PageProvider { From a01a2ac7a69194d9c14f18a63bd66c1fea7906ee Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 6 Oct 2019 18:56:02 +0800 Subject: [PATCH 1827/1997] up --- .../app/ui/widget/page/delegate/SimulationPageDelegate.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt index c705fded2..7722b790e 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt @@ -35,7 +35,7 @@ class SimulationPageDelegate(pageView: PageView) : PageDelegate(pageView) { override fun onPageUp() { pageView.curlView?.updatePages() - pageView.curlView?.invalidate() + pageView.curlView?.requestRender() } private inner class PageProvider : CurlView.PageProvider { From beb5850010f0ff87c02b490eb14d59d88ba1e758 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 6 Oct 2019 19:18:17 +0800 Subject: [PATCH 1828/1997] up --- .../widget/page/delegate/CoverPageDelegate.kt | 2 +- .../page/delegate/HorizontalPageDelegate.kt | 53 +++++++++++ .../page/delegate/NoAnimPageDelegate.kt | 2 +- .../ui/widget/page/delegate/PageDelegate.kt | 87 +++---------------- .../page/delegate/ScrollPageDelegate.kt | 56 ++++++++++++ .../page/delegate/SimulationPageDelegate.kt | 4 +- .../widget/page/delegate/SlidePageDelegate.kt | 2 +- 7 files changed, 127 insertions(+), 79 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/widget/page/delegate/HorizontalPageDelegate.kt diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/CoverPageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/CoverPageDelegate.kt index dd4f8d185..10ac07abd 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/CoverPageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/CoverPageDelegate.kt @@ -5,7 +5,7 @@ import android.graphics.Matrix import android.graphics.drawable.GradientDrawable import io.legado.app.ui.widget.page.PageView -class CoverPageDelegate(pageView: PageView) : PageDelegate(pageView) { +class CoverPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageView) { private val shadowDrawableR: GradientDrawable private val bitmapMatrix = Matrix() diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/HorizontalPageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/HorizontalPageDelegate.kt new file mode 100644 index 000000000..1f2b3fa42 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/HorizontalPageDelegate.kt @@ -0,0 +1,53 @@ +package io.legado.app.ui.widget.page.delegate + +import android.view.MotionEvent +import io.legado.app.ui.widget.page.PageView +import io.legado.app.utils.screenshot +import kotlin.math.abs + +abstract class HorizontalPageDelegate(pageView: PageView) : PageDelegate(pageView) { + + override fun onScroll( + e1: MotionEvent, + e2: MotionEvent, + distanceX: Float, + distanceY: Float + ): Boolean { + if (!isMoved) { + val event = e1.toAction(MotionEvent.ACTION_UP) + curPage?.dispatchTouchEvent(event) + event.recycle() + if (abs(distanceX) > abs(distanceY)) { + if (distanceX < 0) { + //如果上一页不存在 + if (!hasPrev()) { + noNext = true + return true + } + //上一页截图 + bitmap = prevPage?.screenshot() + } else { + //如果不存在表示没有下一页了 + if (!hasNext()) { + noNext = true + return true + } + //下一页截图 + bitmap = nextPage?.screenshot() + } + isMoved = true + } + } + if (isMoved) { + isCancel = if (pageView.isScrollDelegate) { + if (direction == Direction.NEXT) distanceY < 0 else distanceY > 0 + } else { + if (direction == Direction.NEXT) distanceX < 0 else distanceX > 0 + } + isRunning = true + //设置触摸点 + setTouchPoint(e2.x, e2.y) + } + return isMoved + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/NoAnimPageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/NoAnimPageDelegate.kt index 7d19a25ed..7008455b8 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/NoAnimPageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/NoAnimPageDelegate.kt @@ -3,7 +3,7 @@ package io.legado.app.ui.widget.page.delegate import android.graphics.Canvas import io.legado.app.ui.widget.page.PageView -class NoAnimPageDelegate(pageView: PageView) : PageDelegate(pageView) { +class NoAnimPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageView) { override fun onScrollStart() { startScroll(touchX.toInt(), 0, 0, 0) } diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt index a59a6a86b..b70a1ac6d 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt @@ -56,8 +56,8 @@ abstract class PageDelegate(protected val pageView: PageView) { ) } - private var isMoved = false - private var noNext = true + var isMoved = false + var noNext = true //移动方向 var direction = Direction.NONE @@ -212,6 +212,13 @@ abstract class PageDelegate(protected val pageView: PageView) { open fun onPageUp() { } + abstract fun onScroll( + e1: MotionEvent, + e2: MotionEvent, + distanceX: Float, + distanceY: Float + ): Boolean + enum class Direction { NONE, PREV, NEXT } @@ -271,87 +278,17 @@ abstract class PageDelegate(protected val pageView: PageView) { distanceX: Float, distanceY: Float ): Boolean { - if (pageView.isScrollDelegate) { - if (!isMoved && abs(distanceX) < abs(distanceY)) { - if (distanceY < 0) { - if (atTop) { - val event = e1.toAction(MotionEvent.ACTION_UP) - curPage?.dispatchTouchEvent(event) - event.recycle() - //如果上一页不存在 - if (!hasPrev()) { - noNext = true - return true - } - //上一页截图 - bitmap = prevPage?.screenshot() - } - } else { - if (atBottom) { - val event = e1.toAction(MotionEvent.ACTION_UP) - curPage?.dispatchTouchEvent(event) - event.recycle() - //如果不存在表示没有下一页了 - if (!hasNext()) { - noNext = true - return true - } - //下一页截图 - bitmap = nextPage?.screenshot() - } - } - isMoved = true - } - if ((atTop && direction != Direction.PREV) || (atBottom && direction != Direction.NEXT) || direction == Direction.NONE) { - //传递触摸事件到textView - curPage?.dispatchTouchEvent(e2) - } - } else if (!isMoved) { - val event = e1.toAction(MotionEvent.ACTION_UP) - curPage?.dispatchTouchEvent(event) - event.recycle() - if (abs(distanceX) > abs(distanceY)) { - if (distanceX < 0) { - //如果上一页不存在 - if (!hasPrev()) { - noNext = true - return true - } - //上一页截图 - bitmap = prevPage?.screenshot() - } else { - //如果不存在表示没有下一页了 - if (!hasNext()) { - noNext = true - return true - } - //下一页截图 - bitmap = nextPage?.screenshot() - } - isMoved = true - } - } - if (isMoved) { - isCancel = if (pageView.isScrollDelegate) { - if (direction == Direction.NEXT) distanceY < 0 else distanceY > 0 - } else { - if (direction == Direction.NEXT) distanceX < 0 else distanceX > 0 - } - isRunning = true - //设置触摸点 - setTouchPoint(e2.x, e2.y) - } - return isMoved + return this@PageDelegate.onScroll(e1, e2, distanceX, distanceY) } } - private fun hasPrev(): Boolean { + fun hasPrev(): Boolean { //上一页的参数配置 direction = Direction.PREV return pageView.pageFactory?.hasPrev() == true } - private fun hasNext(): Boolean { + fun hasNext(): Boolean { //进行下一页的配置 direction = Direction.NEXT return pageView.pageFactory?.hasNext() == true diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/ScrollPageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/ScrollPageDelegate.kt index a2d900529..4e333bd1c 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/ScrollPageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/ScrollPageDelegate.kt @@ -2,7 +2,10 @@ package io.legado.app.ui.widget.page.delegate import android.graphics.Canvas import android.graphics.Matrix +import android.view.MotionEvent import io.legado.app.ui.widget.page.PageView +import io.legado.app.utils.screenshot +import kotlin.math.abs class ScrollPageDelegate(pageView: PageView) : PageDelegate(pageView) { @@ -65,4 +68,57 @@ class ScrollPageDelegate(pageView: PageView) : PageDelegate(pageView) { } } + override fun onScroll( + e1: MotionEvent, + e2: MotionEvent, + distanceX: Float, + distanceY: Float + ): Boolean { + if (!isMoved && abs(distanceX) < abs(distanceY)) { + if (distanceY < 0) { + if (atTop) { + val event = e1.toAction(MotionEvent.ACTION_UP) + curPage?.dispatchTouchEvent(event) + event.recycle() + //如果上一页不存在 + if (!hasPrev()) { + noNext = true + return true + } + //上一页截图 + bitmap = prevPage?.screenshot() + } + } else { + if (atBottom) { + val event = e1.toAction(MotionEvent.ACTION_UP) + curPage?.dispatchTouchEvent(event) + event.recycle() + //如果不存在表示没有下一页了 + if (!hasNext()) { + noNext = true + return true + } + //下一页截图 + bitmap = nextPage?.screenshot() + } + } + isMoved = true + } + if ((atTop && direction != Direction.PREV) || (atBottom && direction != Direction.NEXT) || direction == Direction.NONE) { + //传递触摸事件到textView + curPage?.dispatchTouchEvent(e2) + } + if (isMoved) { + isCancel = if (pageView.isScrollDelegate) { + if (direction == Direction.NEXT) distanceY < 0 else distanceY > 0 + } else { + if (direction == Direction.NEXT) distanceX < 0 else distanceX > 0 + } + isRunning = true + //设置触摸点 + setTouchPoint(e2.x, e2.y) + } + return isMoved + } + } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt index 7722b790e..9b42a3edd 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt @@ -5,13 +5,15 @@ import android.view.MotionEvent import io.legado.app.ui.widget.page.PageView import io.legado.app.ui.widget.page.curl.CurlPage import io.legado.app.ui.widget.page.curl.CurlView +import io.legado.app.utils.invisible import io.legado.app.utils.screenshot -class SimulationPageDelegate(pageView: PageView) : PageDelegate(pageView) { +class SimulationPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageView) { init { pageView.curlView ?: let { pageView.curlView = CurlView(pageView.context) + pageView.curlView?.invisible() pageView.addView(pageView.curlView) pageView.curlView?.mPageProvider = PageProvider() pageView.curlView?.setSizeChangedObserver(SizeChangedObserver()) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/SlidePageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/SlidePageDelegate.kt index 60cc351f6..2615976e6 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/SlidePageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/SlidePageDelegate.kt @@ -4,7 +4,7 @@ import android.graphics.Canvas import android.graphics.Matrix import io.legado.app.ui.widget.page.PageView -class SlidePageDelegate(pageView: PageView) : PageDelegate(pageView) { +class SlidePageDelegate(pageView: PageView) : HorizontalPageDelegate(pageView) { private val bitmapMatrix = Matrix() From 4cbff042091d430606684a75f9d70d5fd0a13d4f Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 6 Oct 2019 19:40:29 +0800 Subject: [PATCH 1829/1997] up --- .../app/ui/widget/page/delegate/SimulationPageDelegate.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt index 9b42a3edd..f3533de53 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt @@ -5,7 +5,6 @@ import android.view.MotionEvent import io.legado.app.ui.widget.page.PageView import io.legado.app.ui.widget.page.curl.CurlPage import io.legado.app.ui.widget.page.curl.CurlView -import io.legado.app.utils.invisible import io.legado.app.utils.screenshot class SimulationPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageView) { @@ -13,7 +12,6 @@ class SimulationPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageVi init { pageView.curlView ?: let { pageView.curlView = CurlView(pageView.context) - pageView.curlView?.invisible() pageView.addView(pageView.curlView) pageView.curlView?.mPageProvider = PageProvider() pageView.curlView?.setSizeChangedObserver(SizeChangedObserver()) From 4408cc2e2634dd9d2ac1615b21770acd2bfc8ced Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 6 Oct 2019 20:04:05 +0800 Subject: [PATCH 1830/1997] up --- .../main/java/io/legado/app/ui/widget/page/curl/CurlRenderer.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlRenderer.kt b/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlRenderer.kt index 9d7913027..dc0e124d5 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlRenderer.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlRenderer.kt @@ -18,7 +18,7 @@ class CurlRenderer /** * Basic constructor. */ - (private val mObserver: CurlRenderer.Observer) : GLSurfaceView.Renderer { + (private val mObserver: Observer) : GLSurfaceView.Renderer { // Background fill color. private var mBackgroundColor: Int = 0 // Curl meshes used for static and dynamic rendering. From 19cb9bd1fe60bc8caf8ee4decbde6b5fbde6bc99 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 7 Oct 2019 10:34:39 +0800 Subject: [PATCH 1831/1997] up --- .../java/io/legado/app/ui/rss/read/ReadRssActivity.kt | 8 ++++++-- .../java/io/legado/app/ui/rss/read/ReadRssViewModel.kt | 6 ++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt index eb8fa6451..bece90c6c 100644 --- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt @@ -2,10 +2,14 @@ package io.legado.app.ui.rss.read import android.os.Bundle import io.legado.app.R -import io.legado.app.base.BaseActivity +import io.legado.app.base.VMBaseActivity +import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_rss_read.* -class ReadRssActivity : BaseActivity(R.layout.activity_rss_read) { +class ReadRssActivity : VMBaseActivity(R.layout.activity_rss_read) { + + override val viewModel: ReadRssViewModel + get() = getViewModel(ReadRssViewModel::class.java) override fun onActivityCreated(savedInstanceState: Bundle?) { val description = intent.getStringExtra("description") diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt index 6d43baf9a..57874ef07 100644 --- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt @@ -1,2 +1,8 @@ package io.legado.app.ui.rss.read +import android.app.Application +import io.legado.app.base.BaseViewModel + +class ReadRssViewModel(application: Application) : BaseViewModel(application) { + +} \ No newline at end of file From 0a6685c55db8fa45f1649209ac146f730cdeb716 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 7 Oct 2019 15:03:48 +0800 Subject: [PATCH 1832/1997] up --- .../io/legado/app/data/dao/RssArticleDao.kt | 3 +++ .../app/ui/rss/article/RssArticlesActivity.kt | 5 +---- .../legado/app/ui/rss/read/ReadRssActivity.kt | 20 ++++++++++++------- .../app/ui/rss/read/ReadRssViewModel.kt | 20 +++++++++++++++++++ 4 files changed, 37 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/RssArticleDao.kt b/app/src/main/java/io/legado/app/data/dao/RssArticleDao.kt index 0c6290965..fdcd309c8 100644 --- a/app/src/main/java/io/legado/app/data/dao/RssArticleDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/RssArticleDao.kt @@ -7,6 +7,9 @@ import io.legado.app.data.entities.RssArticle @Dao interface RssArticleDao { + @Query("select * from rssArticles where guid = :key") + fun get(key: String): RssArticle? + @Query("select * from rssArticles where origin = :origin order by time desc") fun liveByOrigin(origin: String): LiveData> diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt index 8ec14de5b..59eb5a77a 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt @@ -62,9 +62,6 @@ class RssArticlesActivity : VMBaseActivity(R.layout.activi override fun readRss(rssArticle: RssArticle) { viewModel.read(rssArticle) - startActivity( - Pair("description", rssArticle.description), - Pair("url", rssArticle.link) - ) + startActivity(Pair("guid", rssArticle.guid)) } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt index bece90c6c..9640d501b 100644 --- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt @@ -1,6 +1,7 @@ package io.legado.app.ui.rss.read import android.os.Bundle +import androidx.lifecycle.Observer import io.legado.app.R import io.legado.app.base.VMBaseActivity import io.legado.app.utils.getViewModel @@ -12,13 +13,18 @@ class ReadRssActivity : VMBaseActivity(R.layout.activity_rss_r get() = getViewModel(ReadRssViewModel::class.java) override fun onActivityCreated(savedInstanceState: Bundle?) { - val description = intent.getStringExtra("description") - val url = intent.getStringExtra("url") - if (description.isNullOrBlank()) { - webView.loadUrl(url) - } else { - webView.loadData("$description", "text/html", "utf-8") - } + initLiveData() + viewModel.initData(intent) + + } + + private fun initLiveData() { + viewModel.contentLiveData.observe(this, Observer { + webView.loadData("$it", "text/html", "utf-8") + }) + viewModel.urlLiveData.observe(this, Observer { + webView.loadUrl(it) + }) } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt index 57874ef07..d1a7f3542 100644 --- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt @@ -1,8 +1,28 @@ package io.legado.app.ui.rss.read import android.app.Application +import android.content.Intent +import androidx.lifecycle.MutableLiveData +import io.legado.app.App import io.legado.app.base.BaseViewModel class ReadRssViewModel(application: Application) : BaseViewModel(application) { + val contentLiveData = MutableLiveData() + val urlLiveData = MutableLiveData() + + fun initData(intent: Intent) { + execute { + intent.getStringExtra("guid")?.let { + val rssArticle = App.db.rssArtivleDao().get(it) + if (rssArticle != null) { + if (!rssArticle.description.isNullOrBlank()) { + contentLiveData.postValue(rssArticle.description) + } + } + } + } + + } + } \ No newline at end of file From aede1cd826ccd837eb8ceb9e005eb5e9920f7101 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 7 Oct 2019 16:18:25 +0800 Subject: [PATCH 1833/1997] up --- .../app/ui/rss/read/ReadRssViewModel.kt | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt index d1a7f3542..7310b819f 100644 --- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt @@ -5,6 +5,9 @@ import android.content.Intent import androidx.lifecycle.MutableLiveData import io.legado.app.App import io.legado.app.base.BaseViewModel +import io.legado.app.data.entities.RssArticle +import io.legado.app.model.analyzeRule.AnalyzeRule +import io.legado.app.model.analyzeRule.AnalyzeUrl class ReadRssViewModel(application: Application) : BaseViewModel(application) { @@ -18,6 +21,17 @@ class ReadRssViewModel(application: Application) : BaseViewModel(application) { if (rssArticle != null) { if (!rssArticle.description.isNullOrBlank()) { contentLiveData.postValue(rssArticle.description) + } else { + App.db.rssSourceDao().getByKey(rssArticle.origin)?.let { source -> + val ruleContent = source.ruleContent + if (!ruleContent.isNullOrBlank()) { + loadContent(rssArticle, ruleContent) + } else { + urlLiveData.postValue(rssArticle.link) + } + } ?: let { + urlLiveData.postValue(rssArticle.link) + } } } } @@ -25,4 +39,18 @@ class ReadRssViewModel(application: Application) : BaseViewModel(application) { } + private fun loadContent(rssArticle: RssArticle, ruleContent: String) { + execute { + rssArticle.link?.let { + AnalyzeUrl(it).getResponseAsync().await().body()?.let { body -> + AnalyzeRule().apply { + setContent(body) + getString(ruleContent)?.let { content -> + contentLiveData.postValue(content) + } + } + } + } + } + } } \ No newline at end of file From 5a675edaa68d38f3bb032203a94a4082c73fae45 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 7 Oct 2019 18:09:05 +0800 Subject: [PATCH 1834/1997] up --- app/src/main/res/layout/fragment_rss.xml | 2 ++ app/src/main/res/layout/item_rss.xml | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/layout/fragment_rss.xml b/app/src/main/res/layout/fragment_rss.xml index f5a3b374c..f1469fbd7 100644 --- a/app/src/main/res/layout/fragment_rss.xml +++ b/app/src/main/res/layout/fragment_rss.xml @@ -11,8 +11,10 @@ android:layout_height="wrap_content" app:attachToActivity="false" app:title="@string/rss" /> + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_rss.xml b/app/src/main/res/layout/item_rss.xml index 8bf74003e..dba2c0119 100644 --- a/app/src/main/res/layout/item_rss.xml +++ b/app/src/main/res/layout/item_rss.xml @@ -7,8 +7,8 @@ Date: Tue, 8 Oct 2019 10:32:23 +0800 Subject: [PATCH 1835/1997] up --- app/src/main/java/io/legado/app/data/entities/RssSource.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/data/entities/RssSource.kt b/app/src/main/java/io/legado/app/data/entities/RssSource.kt index 82f0d4863..eac9d20ba 100644 --- a/app/src/main/java/io/legado/app/data/entities/RssSource.kt +++ b/app/src/main/java/io/legado/app/data/entities/RssSource.kt @@ -17,7 +17,6 @@ data class RssSource( var enabled: Boolean = true, //列表规则 var ruleArticles: String? = null, - var ruleGuid: String? = null, var ruleTitle: String? = null, var ruleAuthor: String? = null, var rulePubDate: String? = null, From 655c979c52386c906f301bda21ce444448fe83e3 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 8 Oct 2019 10:33:11 +0800 Subject: [PATCH 1836/1997] up --- app/src/main/java/io/legado/app/data/entities/RssSource.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/data/entities/RssSource.kt b/app/src/main/java/io/legado/app/data/entities/RssSource.kt index eac9d20ba..e9988a9d9 100644 --- a/app/src/main/java/io/legado/app/data/entities/RssSource.kt +++ b/app/src/main/java/io/legado/app/data/entities/RssSource.kt @@ -25,7 +25,7 @@ data class RssSource( //描述 var ruleDescription: String? = null, var ruleImage: String? = null, - var ruleContent: String? = null, var ruleLink: String? = null, + var ruleContent: String? = null, var customOrder: Int = 0 ) : Parcelable \ No newline at end of file From 97ba539a77fe907f993e588acdf4dbd95f1178ab Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 8 Oct 2019 10:34:40 +0800 Subject: [PATCH 1837/1997] up --- app/src/main/java/io/legado/app/data/entities/RssSource.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/data/entities/RssSource.kt b/app/src/main/java/io/legado/app/data/entities/RssSource.kt index e9988a9d9..5eaa61999 100644 --- a/app/src/main/java/io/legado/app/data/entities/RssSource.kt +++ b/app/src/main/java/io/legado/app/data/entities/RssSource.kt @@ -22,7 +22,7 @@ data class RssSource( var rulePubDate: String? = null, //类别 var ruleCategories: String? = null, - //描述 + //webView规则 var ruleDescription: String? = null, var ruleImage: String? = null, var ruleLink: String? = null, From e1e25a6d7d2be5889c41e7bb252bb84366de4380 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 8 Oct 2019 10:37:43 +0800 Subject: [PATCH 1838/1997] up --- app/src/main/java/io/legado/app/data/entities/RssSource.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/data/entities/RssSource.kt b/app/src/main/java/io/legado/app/data/entities/RssSource.kt index 5eaa61999..f4fa0b838 100644 --- a/app/src/main/java/io/legado/app/data/entities/RssSource.kt +++ b/app/src/main/java/io/legado/app/data/entities/RssSource.kt @@ -20,7 +20,7 @@ data class RssSource( var ruleTitle: String? = null, var ruleAuthor: String? = null, var rulePubDate: String? = null, - //类别 + //类别规则 var ruleCategories: String? = null, //webView规则 var ruleDescription: String? = null, From 5b107871f6f0d9f14c3cce4ee673985ff67ca33d Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 8 Oct 2019 10:42:45 +0800 Subject: [PATCH 1839/1997] up --- .../io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt index 10e783e15..5b30243b5 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt @@ -108,7 +108,6 @@ class RssSourceEditActivity : add(EditEntity("ruleArticles", rssSource?.ruleArticles, R.string.rss_rule_articles)) add(EditEntity("ruleTitle", rssSource?.ruleTitle, R.string.rss_rule_title)) add(EditEntity("ruleAuthor", rssSource?.ruleAuthor, R.string.rss_rule_author)) - add(EditEntity("ruleGuid", rssSource?.ruleGuid, R.string.rss_rule_guid)) add(EditEntity("rulePubDate", rssSource?.rulePubDate, R.string.rss_rule_date)) add( EditEntity( @@ -142,7 +141,6 @@ class RssSourceEditActivity : "ruleArticles" -> source.ruleArticles = it.value "ruleTitle" -> source.ruleTitle = it.value "ruleAuthor" -> source.ruleAuthor = it.value - "ruleGuid" -> source.ruleGuid = it.value "rulePubDate" -> source.rulePubDate = it.value "ruleCategories" -> source.ruleCategories = it.value "ruleDescription" -> source.ruleDescription = it.value From 82435f601c6aa29627a750fca8afaf6e23ac29f4 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 8 Oct 2019 11:55:50 +0800 Subject: [PATCH 1840/1997] up --- .../java/io/legado/app/data/entities/RssArticle.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/RssArticle.kt b/app/src/main/java/io/legado/app/data/entities/RssArticle.kt index f2deefb1e..ffb91892f 100644 --- a/app/src/main/java/io/legado/app/data/entities/RssArticle.kt +++ b/app/src/main/java/io/legado/app/data/entities/RssArticle.kt @@ -2,16 +2,16 @@ package io.legado.app.data.entities import androidx.room.Entity import androidx.room.Ignore -import androidx.room.PrimaryKey -@Entity(tableName = "rssArticles") +@Entity( + tableName = "rssArticles", + primaryKeys = ["origin", "title"] +) data class RssArticle( var origin: String = "", - var time: Long = System.currentTimeMillis(), - @PrimaryKey - var guid: String = "", var title: String? = null, + var time: Long = System.currentTimeMillis(), var author: String? = null, var link: String? = null, var pubDate: String? = null, From 0feab3459e55b4ec53825bfd02f52862ad3b35de Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 8 Oct 2019 13:50:57 +0800 Subject: [PATCH 1841/1997] up --- app/src/main/java/io/legado/app/data/dao/RssArticleDao.kt | 6 +++--- app/src/main/java/io/legado/app/data/entities/RssArticle.kt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/RssArticleDao.kt b/app/src/main/java/io/legado/app/data/dao/RssArticleDao.kt index fdcd309c8..44c333ac7 100644 --- a/app/src/main/java/io/legado/app/data/dao/RssArticleDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/RssArticleDao.kt @@ -7,10 +7,10 @@ import io.legado.app.data.entities.RssArticle @Dao interface RssArticleDao { - @Query("select * from rssArticles where guid = :key") - fun get(key: String): RssArticle? + @Query("select * from rssArticles where origin = :origin and title = :title") + fun get(origin: String, title: String): RssArticle? - @Query("select * from rssArticles where origin = :origin order by time desc") + @Query("select * from rssArticles where origin = :origin order by `order` desc") fun liveByOrigin(origin: String): LiveData> @Insert(onConflict = OnConflictStrategy.IGNORE) diff --git a/app/src/main/java/io/legado/app/data/entities/RssArticle.kt b/app/src/main/java/io/legado/app/data/entities/RssArticle.kt index ffb91892f..b3c664fcd 100644 --- a/app/src/main/java/io/legado/app/data/entities/RssArticle.kt +++ b/app/src/main/java/io/legado/app/data/entities/RssArticle.kt @@ -11,7 +11,7 @@ import androidx.room.Ignore data class RssArticle( var origin: String = "", var title: String? = null, - var time: Long = System.currentTimeMillis(), + var order: Long = 0, var author: String? = null, var link: String? = null, var pubDate: String? = null, From 4d8b48299965ae17339a37bd17b87ee826b8f99c Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 8 Oct 2019 14:02:16 +0800 Subject: [PATCH 1842/1997] up --- .../java/io/legado/app/model/rss/RssParser.kt | 5 ++-- .../legado/app/model/rss/RssParserByRule.kt | 27 ++++++++++++------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/rss/RssParser.kt b/app/src/main/java/io/legado/app/model/rss/RssParser.kt index 7363a349e..8efa0d7c3 100644 --- a/app/src/main/java/io/legado/app/model/rss/RssParser.kt +++ b/app/src/main/java/io/legado/app/model/rss/RssParser.kt @@ -84,8 +84,6 @@ object RssParser { } xmlPullParser.name.equals(RSSKeywords.RSS_ITEM_TIME, true) -> if (insideItem) currentArticle.pubDate = xmlPullParser.nextText() - xmlPullParser.name.equals(RSSKeywords.RSS_ITEM_GUID, true) -> - if (insideItem) currentArticle.guid = xmlPullParser.nextText().trim() } } else if (eventType == XmlPullParser.END_TAG && xmlPullParser.name.equals("item", true) @@ -99,6 +97,9 @@ object RssParser { } eventType = xmlPullParser.next() } + for ((index: Int, item: RssArticle) in articleList.withIndex()) { + item.order = System.currentTimeMillis() + index + } return articleList } diff --git a/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt b/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt index 45bbaf637..8ff17f063 100644 --- a/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt +++ b/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt @@ -11,7 +11,6 @@ object RssParserByRule { @Throws(Exception::class) fun parseXML(response: Response, rssSource: RssSource): MutableList { - val articleList = mutableListOf() val xml = response.body() if (xml.isNullOrBlank()) { @@ -22,12 +21,19 @@ object RssParserByRule { ) ) } - - rssSource.ruleArticles?.let { ruleArticles -> + var ruleArticles = rssSource.ruleArticles + if (ruleArticles.isNullOrBlank()) { + return RssParser.parseXML(xml, rssSource.sourceUrl) + } else { + val articleList = mutableListOf() val analyzeRule = AnalyzeRule() analyzeRule.setContent(xml) + var reverse = false + if (ruleArticles.startsWith("-")) { + reverse = true + ruleArticles = ruleArticles.substring(1) + } val collections = analyzeRule.getElements(ruleArticles) - val ruleGuid = analyzeRule.splitSourceRule(rssSource.ruleGuid ?: "") val ruleTitle = analyzeRule.splitSourceRule(rssSource.ruleTitle ?: "") val ruleAuthor = analyzeRule.splitSourceRule(rssSource.ruleAuthor ?: "") val rulePubDate = analyzeRule.splitSourceRule(rssSource.rulePubDate ?: "") @@ -41,7 +47,6 @@ object RssParserByRule { item, analyzeRule, index == 0, - ruleGuid, ruleTitle, ruleAuthor, rulePubDate, @@ -55,17 +60,20 @@ object RssParserByRule { articleList.add(it) } } - } ?: let { - return RssParser.parseXML(xml, rssSource.sourceUrl) + if (reverse) { + articleList.reverse() + } + for ((index: Int, item: RssArticle) in articleList.withIndex()) { + item.order = System.currentTimeMillis() + index + } + return articleList } - return articleList } private fun getItem( item: Any, analyzeRule: AnalyzeRule, printLog: Boolean, - ruleGuid: List, ruleTitle: List, ruleAuthor: List, rulePubDate: List, @@ -77,7 +85,6 @@ object RssParserByRule { ): RssArticle? { val rssArticle = RssArticle() analyzeRule.setContent(item) - rssArticle.guid = analyzeRule.getString(ruleGuid) rssArticle.title = analyzeRule.getString(ruleTitle) rssArticle.author = analyzeRule.getString(ruleAuthor) rssArticle.pubDate = analyzeRule.getString(rulePubDate) From a39d4557d850585aec634faf8f73aa902895c347 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 8 Oct 2019 14:04:38 +0800 Subject: [PATCH 1843/1997] up --- app/src/main/java/io/legado/app/data/entities/RssArticle.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/data/entities/RssArticle.kt b/app/src/main/java/io/legado/app/data/entities/RssArticle.kt index b3c664fcd..c9d7edcf7 100644 --- a/app/src/main/java/io/legado/app/data/entities/RssArticle.kt +++ b/app/src/main/java/io/legado/app/data/entities/RssArticle.kt @@ -10,7 +10,7 @@ import androidx.room.Ignore ) data class RssArticle( var origin: String = "", - var title: String? = null, + var title: String? = "", var order: Long = 0, var author: String? = null, var link: String? = null, From d312b5be516e057565a3e661a52223cb9b24637a Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 8 Oct 2019 14:06:05 +0800 Subject: [PATCH 1844/1997] up --- .../java/io/legado/app/ui/rss/article/RssArticlesActivity.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt index 59eb5a77a..beeb737d1 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt @@ -62,6 +62,9 @@ class RssArticlesActivity : VMBaseActivity(R.layout.activi override fun readRss(rssArticle: RssArticle) { viewModel.read(rssArticle) - startActivity(Pair("guid", rssArticle.guid)) + startActivity( + Pair("origin", rssArticle.origin), + Pair("title", rssArticle.title) + ) } } \ No newline at end of file From ad7774a9c0bd3e55e9a801b000610b667213f9d1 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 8 Oct 2019 14:10:06 +0800 Subject: [PATCH 1845/1997] up --- app/src/main/java/io/legado/app/data/entities/RssArticle.kt | 2 +- .../main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/RssArticle.kt b/app/src/main/java/io/legado/app/data/entities/RssArticle.kt index c9d7edcf7..e3810036f 100644 --- a/app/src/main/java/io/legado/app/data/entities/RssArticle.kt +++ b/app/src/main/java/io/legado/app/data/entities/RssArticle.kt @@ -10,7 +10,7 @@ import androidx.room.Ignore ) data class RssArticle( var origin: String = "", - var title: String? = "", + var title: String = "", var order: Long = 0, var author: String? = null, var link: String? = null, diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt index 7310b819f..db4191674 100644 --- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt @@ -16,8 +16,10 @@ class ReadRssViewModel(application: Application) : BaseViewModel(application) { fun initData(intent: Intent) { execute { - intent.getStringExtra("guid")?.let { - val rssArticle = App.db.rssArtivleDao().get(it) + val origin = intent.getStringExtra("origin") + val title = intent.getStringExtra("title") + if (origin != null && title != null) { + val rssArticle = App.db.rssArtivleDao().get(origin, title) if (rssArticle != null) { if (!rssArticle.description.isNullOrBlank()) { contentLiveData.postValue(rssArticle.description) From 278cc0f5f5d4fe79d0f36e7f4de13ca404871e97 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 8 Oct 2019 14:25:35 +0800 Subject: [PATCH 1846/1997] up --- app/src/main/res/menu/rss_articles.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 app/src/main/res/menu/rss_articles.xml diff --git a/app/src/main/res/menu/rss_articles.xml b/app/src/main/res/menu/rss_articles.xml new file mode 100644 index 000000000..cd68daa0f --- /dev/null +++ b/app/src/main/res/menu/rss_articles.xml @@ -0,0 +1,10 @@ + +

    + + + + \ No newline at end of file From e1f0afc69291d41f3e64fe3087e40a672932886e Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 8 Oct 2019 14:43:36 +0800 Subject: [PATCH 1847/1997] up --- .../io/legado/app/data/dao/RssArticleDao.kt | 3 +++ .../app/ui/rss/article/RssArticlesActivity.kt | 21 +++++++++++++++++++ .../ui/rss/article/RssArticlesViewModel.kt | 6 ++++++ 3 files changed, 30 insertions(+) diff --git a/app/src/main/java/io/legado/app/data/dao/RssArticleDao.kt b/app/src/main/java/io/legado/app/data/dao/RssArticleDao.kt index 44c333ac7..a38fa15d9 100644 --- a/app/src/main/java/io/legado/app/data/dao/RssArticleDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/RssArticleDao.kt @@ -18,4 +18,7 @@ interface RssArticleDao { @Update fun update(vararg rssArticle: RssArticle) + + @Query("delete from rssArticles where origin = :origin") + fun delete(origin: String) } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt index beeb737d1..6b97443fb 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt @@ -1,6 +1,8 @@ package io.legado.app.ui.rss.article import android.os.Bundle +import android.view.Menu +import android.view.MenuItem import androidx.core.content.ContextCompat import androidx.lifecycle.LiveData import androidx.lifecycle.Observer @@ -38,6 +40,25 @@ class RssArticlesActivity : VMBaseActivity(R.layout.activi } } + override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { + menuInflater.inflate(R.menu.rss_articles, menu) + return super.onCompatCreateOptionsMenu(menu) + } + + override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.menu_clear -> { + intent.getStringExtra("url")?.let { + refresh_progress_bar.isAutoLoading = true + viewModel.loadContent(it) { + refresh_progress_bar.isAutoLoading = false + } + } + } + } + return super.onCompatOptionsItemSelected(item) + } + private fun initView() { ATH.applyEdgeEffectColor(recycler_view) recycler_view.layoutManager = LinearLayoutManager(this) diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt index a75e7ae07..ccc939105 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt @@ -42,4 +42,10 @@ class RssArticlesViewModel(application: Application) : BaseViewModel(application } } + fun clear(url: String, onFinally: () -> Unit) { + execute { + App.db.rssArtivleDao().delete(url) + loadContent(url, onFinally) + } + } } \ No newline at end of file From 4006d87059dba83be83d88e2cd559c50fa835363 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 8 Oct 2019 14:50:43 +0800 Subject: [PATCH 1848/1997] up --- app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt b/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt index 8ff17f063..f2dfa547d 100644 --- a/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt +++ b/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt @@ -93,7 +93,7 @@ object RssParserByRule { rssArticle.image = analyzeRule.getString(ruleImage) rssArticle.link = analyzeRule.getString(ruleLink) rssArticle.content = analyzeRule.getString(ruleContent) - if (rssArticle.title.isNullOrBlank()) { + if (rssArticle.title.isBlank()) { return null } return rssArticle From 9b7537c0c15f1e35280b8e251e918785114a1409 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 8 Oct 2019 14:54:14 +0800 Subject: [PATCH 1849/1997] up --- .../java/io/legado/app/ui/rss/article/RssArticlesActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt index 6b97443fb..c735e12c3 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt @@ -34,7 +34,7 @@ class RssArticlesActivity : VMBaseActivity(R.layout.activi }) intent.getStringExtra("url")?.let { initData(it) - viewModel.loadContent(it) { + viewModel.clear(it) { refresh_progress_bar.isAutoLoading = false } } From 5a1ecaceb9689b4954bf99d40508fe8574ef4a06 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 8 Oct 2019 15:07:35 +0800 Subject: [PATCH 1850/1997] up --- app/src/main/java/io/legado/app/model/rss/RssParser.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/model/rss/RssParser.kt b/app/src/main/java/io/legado/app/model/rss/RssParser.kt index 8efa0d7c3..b8d56b939 100644 --- a/app/src/main/java/io/legado/app/model/rss/RssParser.kt +++ b/app/src/main/java/io/legado/app/model/rss/RssParser.kt @@ -97,6 +97,7 @@ object RssParser { } eventType = xmlPullParser.next() } + articleList.reverse() for ((index: Int, item: RssArticle) in articleList.withIndex()) { item.order = System.currentTimeMillis() + index } From 91653a61504ab06aaa9bf18f89eef4792e0f4bf4 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 8 Oct 2019 15:08:54 +0800 Subject: [PATCH 1851/1997] up --- app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt b/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt index f2dfa547d..ba21a4a6c 100644 --- a/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt +++ b/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt @@ -28,9 +28,9 @@ object RssParserByRule { val articleList = mutableListOf() val analyzeRule = AnalyzeRule() analyzeRule.setContent(xml) - var reverse = false + var reverse = true if (ruleArticles.startsWith("-")) { - reverse = true + reverse = false ruleArticles = ruleArticles.substring(1) } val collections = analyzeRule.getElements(ruleArticles) From 2fbf6e94eb26534d47a460d7b234b1bc4701c7d7 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 8 Oct 2019 15:18:55 +0800 Subject: [PATCH 1852/1997] up --- .../io/legado/app/ui/rss/read/ReadRssViewModel.kt | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt index db4191674..dcb363c9b 100644 --- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt @@ -8,6 +8,7 @@ import io.legado.app.base.BaseViewModel import io.legado.app.data.entities.RssArticle import io.legado.app.model.analyzeRule.AnalyzeRule import io.legado.app.model.analyzeRule.AnalyzeUrl +import io.legado.app.utils.NetworkUtils class ReadRssViewModel(application: Application) : BaseViewModel(application) { @@ -29,22 +30,26 @@ class ReadRssViewModel(application: Application) : BaseViewModel(application) { if (!ruleContent.isNullOrBlank()) { loadContent(rssArticle, ruleContent) } else { - urlLiveData.postValue(rssArticle.link) + loadUrl(rssArticle) } - } ?: let { - urlLiveData.postValue(rssArticle.link) - } + } ?: loadUrl(rssArticle) } } } } + } + private fun loadUrl(rssArticle: RssArticle) { + rssArticle.link?.let { + urlLiveData.postValue(NetworkUtils.getAbsoluteURL(rssArticle.origin, it)) + } } private fun loadContent(rssArticle: RssArticle, ruleContent: String) { execute { rssArticle.link?.let { - AnalyzeUrl(it).getResponseAsync().await().body()?.let { body -> + AnalyzeUrl(it, baseUrl = rssArticle.origin).getResponseAsync().await().body() + ?.let { body -> AnalyzeRule().apply { setContent(body) getString(ruleContent)?.let { content -> From db05963ed3724f7537196888f382f30e3e97e55e Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 8 Oct 2019 15:46:16 +0800 Subject: [PATCH 1853/1997] up --- .../main/java/io/legado/app/constant/AppConst.kt | 14 ++++++++++++++ .../app/ui/main/bookshelf/BookshelfFragment.kt | 4 ++-- .../app/ui/main/bookshelf/GroupManageDialog.kt | 13 ++++++++----- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/io/legado/app/constant/AppConst.kt b/app/src/main/java/io/legado/app/constant/AppConst.kt index 99dcb17cb..6503839bc 100644 --- a/app/src/main/java/io/legado/app/constant/AppConst.kt +++ b/app/src/main/java/io/legado/app/constant/AppConst.kt @@ -4,6 +4,8 @@ import android.annotation.SuppressLint import io.legado.app.App import io.legado.app.R import io.legado.app.data.entities.BookGroup +import io.legado.app.utils.getPrefBoolean +import io.legado.app.utils.putPrefBoolean import java.text.SimpleDateFormat import javax.script.ScriptEngine import javax.script.ScriptEngineManager @@ -41,4 +43,16 @@ object AppConst { val bookGroupAll = BookGroup(-1, App.INSTANCE.getString(R.string.all)) val bookGroupLocal = BookGroup(-2, App.INSTANCE.getString(R.string.local)) val bookGroupAudio = BookGroup(-3, App.INSTANCE.getString(R.string.audio)) + + var bookGroupLocalShow: Boolean + get() = App.INSTANCE.getPrefBoolean("bookGroupLocal", false) + set(value) { + App.INSTANCE.putPrefBoolean("bookGroupLocal", value) + } + + var bookGroupAudioShow: Boolean + get() = App.INSTANCE.getPrefBoolean("bookGroupAudio", false) + set(value) { + App.INSTANCE.putPrefBoolean("bookGroupAudio", value) + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index 797ef096d..9f97521b7 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -87,10 +87,10 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b synchronized(this) { bookGroups.clear() bookGroups.add(AppConst.bookGroupAll) - if (getPrefBoolean("bookGroupLocal", true)) { + if (AppConst.bookGroupLocalShow) { bookGroups.add(AppConst.bookGroupLocal) } - if (getPrefBoolean("bookGroupAudio", true)) { + if (AppConst.bookGroupAudioShow) { bookGroups.add(AppConst.bookGroupAudio) } bookGroups.addAll(it) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageDialog.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageDialog.kt index f6151edaf..1f3423853 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageDialog.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageDialog.kt @@ -20,13 +20,16 @@ import io.legado.app.App import io.legado.app.R import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter +import io.legado.app.constant.AppConst import io.legado.app.data.entities.BookGroup import io.legado.app.help.ItemTouchCallback import io.legado.app.lib.dialogs.alert import io.legado.app.lib.dialogs.customView import io.legado.app.lib.dialogs.noButton import io.legado.app.lib.dialogs.yesButton -import io.legado.app.utils.* +import io.legado.app.utils.applyTint +import io.legado.app.utils.getViewModel +import io.legado.app.utils.requestInputMethod import kotlinx.android.synthetic.main.dialog_edit_text.view.* import kotlinx.android.synthetic.main.dialog_recycler_view.* import kotlinx.android.synthetic.main.item_group_manage.view.* @@ -65,9 +68,9 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { tool_bar.menu.applyTint(requireContext(), false) tool_bar.setOnMenuItemClickListener(this) tool_bar.menu.findItem(R.id.menu_group_local) - .isChecked = getPrefBoolean("bookGroupLocal", true) + .isChecked = AppConst.bookGroupLocalShow tool_bar.menu.findItem(R.id.menu_group_audio) - .isChecked = getPrefBoolean("bookGroupAudio", true) + .isChecked = AppConst.bookGroupAudioShow adapter = GroupAdapter(requireContext()) recycler_view.layoutManager = LinearLayoutManager(requireContext()) recycler_view.addItemDecoration( @@ -88,12 +91,12 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { R.id.menu_add -> addGroup() R.id.menu_group_local -> { item.isChecked = !item.isChecked - putPrefBoolean("bookGroupLocal", item.isChecked) + AppConst.bookGroupLocalShow = item.isChecked callBack?.upGroup() } R.id.menu_group_audio -> { item.isChecked = !item.isChecked - putPrefBoolean("bookGroupAudio", item.isChecked) + AppConst.bookGroupAudioShow = item.isChecked callBack?.upGroup() } } From f1063bac0ece4fcc1d046d5bcacb75b37f87670f Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 9 Oct 2019 11:49:00 +0800 Subject: [PATCH 1854/1997] up --- .../io/legado/app/ui/rss/read/ReadRssActivity.kt | 8 +++++++- .../legado/app/ui/rss/read/ReadRssViewModel.kt | 16 ++++++++-------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt index 9640d501b..06551c8bf 100644 --- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt @@ -20,7 +20,13 @@ class ReadRssActivity : VMBaseActivity(R.layout.activity_rss_r private fun initLiveData() { viewModel.contentLiveData.observe(this, Observer { - webView.loadData("$it", "text/html", "utf-8") + webView.loadDataWithBaseURL( + viewModel.rssArticle?.link, + "$it", + "text/html", + "utf-8", + viewModel.rssArticle?.link + ) }) viewModel.urlLiveData.observe(this, Observer { webView.loadUrl(it) diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt index dcb363c9b..e1b4b85e8 100644 --- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt @@ -11,7 +11,7 @@ import io.legado.app.model.analyzeRule.AnalyzeUrl import io.legado.app.utils.NetworkUtils class ReadRssViewModel(application: Application) : BaseViewModel(application) { - + var rssArticle: RssArticle? = null val contentLiveData = MutableLiveData() val urlLiveData = MutableLiveData() @@ -20,8 +20,8 @@ class ReadRssViewModel(application: Application) : BaseViewModel(application) { val origin = intent.getStringExtra("origin") val title = intent.getStringExtra("title") if (origin != null && title != null) { - val rssArticle = App.db.rssArtivleDao().get(origin, title) - if (rssArticle != null) { + rssArticle = App.db.rssArtivleDao().get(origin, title) + rssArticle?.let { rssArticle -> if (!rssArticle.description.isNullOrBlank()) { contentLiveData.postValue(rssArticle.description) } else { @@ -50,13 +50,13 @@ class ReadRssViewModel(application: Application) : BaseViewModel(application) { rssArticle.link?.let { AnalyzeUrl(it, baseUrl = rssArticle.origin).getResponseAsync().await().body() ?.let { body -> - AnalyzeRule().apply { - setContent(body) - getString(ruleContent)?.let { content -> - contentLiveData.postValue(content) + AnalyzeRule().apply { + setContent(body) + getString(ruleContent)?.let { content -> + contentLiveData.postValue(content) + } } } - } } } } From c4a950b039c8e3b8a6bb54ee0d413b3253b1bbcb Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 9 Oct 2019 15:49:09 +0800 Subject: [PATCH 1855/1997] up --- app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt | 2 +- app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt b/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt index ba21a4a6c..476c6a49e 100644 --- a/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt +++ b/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt @@ -27,7 +27,7 @@ object RssParserByRule { } else { val articleList = mutableListOf() val analyzeRule = AnalyzeRule() - analyzeRule.setContent(xml) + analyzeRule.setContent(xml, rssSource.sourceUrl) var reverse = true if (ruleArticles.startsWith("-")) { reverse = false diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt index e1b4b85e8..89a1e0825 100644 --- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt @@ -51,7 +51,7 @@ class ReadRssViewModel(application: Application) : BaseViewModel(application) { AnalyzeUrl(it, baseUrl = rssArticle.origin).getResponseAsync().await().body() ?.let { body -> AnalyzeRule().apply { - setContent(body) + setContent(body, NetworkUtils.getAbsoluteURL(rssArticle.origin, it)) getString(ruleContent)?.let { content -> contentLiveData.postValue(content) } From 00de6183df488dc4e704b65f742f3f1c14a2fd98 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 9 Oct 2019 15:58:51 +0800 Subject: [PATCH 1856/1997] up --- app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt index 06551c8bf..3096a432e 100644 --- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt @@ -14,8 +14,8 @@ class ReadRssActivity : VMBaseActivity(R.layout.activity_rss_r override fun onActivityCreated(savedInstanceState: Bundle?) { initLiveData() + title = intent.getStringExtra("title") viewModel.initData(intent) - } private fun initLiveData() { From b934c7cb709239eca3827384ecec0d033c98e1dc Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 9 Oct 2019 19:44:34 +0800 Subject: [PATCH 1857/1997] up --- app/src/main/java/io/legado/app/data/entities/BookSource.kt | 2 +- app/src/main/java/io/legado/app/help/storage/OldRule.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/BookSource.kt b/app/src/main/java/io/legado/app/data/entities/BookSource.kt index a8a88e4cb..6a373bdef 100644 --- a/app/src/main/java/io/legado/app/data/entities/BookSource.kt +++ b/app/src/main/java/io/legado/app/data/entities/BookSource.kt @@ -68,7 +68,7 @@ data class BookSource( fun getHeaderMap(): Map { val headerMap = HashMap() - headerMap["user_agent"] = App.INSTANCE.getPrefString("user_agent") ?: userAgent + headerMap["User-Agent"] = App.INSTANCE.getPrefString("user_agent") ?: userAgent header?.let { GSON.fromJsonObject>(header)?.let { headerMap.putAll(it) diff --git a/app/src/main/java/io/legado/app/help/storage/OldRule.kt b/app/src/main/java/io/legado/app/help/storage/OldRule.kt index 9295aaa0d..7418ea6c6 100644 --- a/app/src/main/java/io/legado/app/help/storage/OldRule.kt +++ b/app/src/main/java/io/legado/app/help/storage/OldRule.kt @@ -131,7 +131,7 @@ object OldRule { private fun uaToHeader(ua: String?): String? { if (ua.isNullOrEmpty()) return null - val map = mapOf(Pair("user_agent", ua)) + val map = mapOf(Pair("User-Agent", ua)) return GSON.toJson(map) } From e035fd06b8eaaef07094119f6bf4c3dec218796c Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 10 Oct 2019 11:13:32 +0800 Subject: [PATCH 1858/1997] up --- app/src/main/java/io/legado/app/data/entities/BookSource.kt | 2 +- app/src/main/java/io/legado/app/help/storage/OldRule.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/BookSource.kt b/app/src/main/java/io/legado/app/data/entities/BookSource.kt index 6a373bdef..ff4eaa533 100644 --- a/app/src/main/java/io/legado/app/data/entities/BookSource.kt +++ b/app/src/main/java/io/legado/app/data/entities/BookSource.kt @@ -68,7 +68,7 @@ data class BookSource( fun getHeaderMap(): Map { val headerMap = HashMap() - headerMap["User-Agent"] = App.INSTANCE.getPrefString("user_agent") ?: userAgent + headerMap["user-agent"] = App.INSTANCE.getPrefString("user_agent") ?: userAgent header?.let { GSON.fromJsonObject>(header)?.let { headerMap.putAll(it) diff --git a/app/src/main/java/io/legado/app/help/storage/OldRule.kt b/app/src/main/java/io/legado/app/help/storage/OldRule.kt index 7418ea6c6..135d604b9 100644 --- a/app/src/main/java/io/legado/app/help/storage/OldRule.kt +++ b/app/src/main/java/io/legado/app/help/storage/OldRule.kt @@ -131,7 +131,7 @@ object OldRule { private fun uaToHeader(ua: String?): String? { if (ua.isNullOrEmpty()) return null - val map = mapOf(Pair("User-Agent", ua)) + val map = mapOf(Pair("user-agent", ua)) return GSON.toJson(map) } From 3de1fcdba3b5e0da874ca0053acb0ee2a432c635 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 10 Oct 2019 12:02:36 +0800 Subject: [PATCH 1859/1997] up --- app/src/main/java/io/legado/app/data/entities/BookSource.kt | 2 +- app/src/main/java/io/legado/app/help/storage/OldRule.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/BookSource.kt b/app/src/main/java/io/legado/app/data/entities/BookSource.kt index ff4eaa533..6a373bdef 100644 --- a/app/src/main/java/io/legado/app/data/entities/BookSource.kt +++ b/app/src/main/java/io/legado/app/data/entities/BookSource.kt @@ -68,7 +68,7 @@ data class BookSource( fun getHeaderMap(): Map { val headerMap = HashMap() - headerMap["user-agent"] = App.INSTANCE.getPrefString("user_agent") ?: userAgent + headerMap["User-Agent"] = App.INSTANCE.getPrefString("user_agent") ?: userAgent header?.let { GSON.fromJsonObject>(header)?.let { headerMap.putAll(it) diff --git a/app/src/main/java/io/legado/app/help/storage/OldRule.kt b/app/src/main/java/io/legado/app/help/storage/OldRule.kt index 135d604b9..7418ea6c6 100644 --- a/app/src/main/java/io/legado/app/help/storage/OldRule.kt +++ b/app/src/main/java/io/legado/app/help/storage/OldRule.kt @@ -131,7 +131,7 @@ object OldRule { private fun uaToHeader(ua: String?): String? { if (ua.isNullOrEmpty()) return null - val map = mapOf(Pair("user-agent", ua)) + val map = mapOf(Pair("User-Agent", ua)) return GSON.toJson(map) } From db6ea924fce458e58c0fc55ced1d3bc517cca488 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 10 Oct 2019 17:15:18 +0800 Subject: [PATCH 1860/1997] up --- .../legado/app/ui/rss/read/ReadRssActivity.kt | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt index 3096a432e..4220d7575 100644 --- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt @@ -4,6 +4,7 @@ import android.os.Bundle import androidx.lifecycle.Observer import io.legado.app.R import io.legado.app.base.VMBaseActivity +import io.legado.app.utils.NetworkUtils import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_rss_read.* @@ -19,14 +20,17 @@ class ReadRssActivity : VMBaseActivity(R.layout.activity_rss_r } private fun initLiveData() { - viewModel.contentLiveData.observe(this, Observer { - webView.loadDataWithBaseURL( - viewModel.rssArticle?.link, - "$it", - "text/html", - "utf-8", - viewModel.rssArticle?.link - ) + viewModel.contentLiveData.observe(this, Observer { content -> + viewModel.rssArticle?.let { + val url = NetworkUtils.getAbsoluteURL(it.origin, it.link ?: "") + webView.loadDataWithBaseURL( + url, + "$content", + "text/html", + "utf-8", + url + ) + } }) viewModel.urlLiveData.observe(this, Observer { webView.loadUrl(it) From 7fbc96be346bc65d095579414995aed641b438e1 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 10 Oct 2019 17:20:50 +0800 Subject: [PATCH 1861/1997] up --- .../java/io/legado/app/ui/rss/article/RssArticlesActivity.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt index c735e12c3..f2291a141 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt @@ -34,7 +34,7 @@ class RssArticlesActivity : VMBaseActivity(R.layout.activi }) intent.getStringExtra("url")?.let { initData(it) - viewModel.clear(it) { + viewModel.loadContent(it) { refresh_progress_bar.isAutoLoading = false } } @@ -50,7 +50,7 @@ class RssArticlesActivity : VMBaseActivity(R.layout.activi R.id.menu_clear -> { intent.getStringExtra("url")?.let { refresh_progress_bar.isAutoLoading = true - viewModel.loadContent(it) { + viewModel.clear(it) { refresh_progress_bar.isAutoLoading = false } } From 7f6eadd8dcb4abf80a0f53603c5feb81602e5636 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 10 Oct 2019 17:28:34 +0800 Subject: [PATCH 1862/1997] up --- .../java/io/legado/app/ui/rss/read/ReadRssActivity.kt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt index 4220d7575..fabb34ef9 100644 --- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt @@ -1,6 +1,7 @@ package io.legado.app.ui.rss.read import android.os.Bundle +import android.webkit.WebViewClient import androidx.lifecycle.Observer import io.legado.app.R import io.legado.app.base.VMBaseActivity @@ -14,11 +15,16 @@ class ReadRssActivity : VMBaseActivity(R.layout.activity_rss_r get() = getViewModel(ReadRssViewModel::class.java) override fun onActivityCreated(savedInstanceState: Bundle?) { - initLiveData() title = intent.getStringExtra("title") + initWebView() + initLiveData() viewModel.initData(intent) } + private fun initWebView() { + webView.webViewClient = WebViewClient() + } + private fun initLiveData() { viewModel.contentLiveData.observe(this, Observer { content -> viewModel.rssArticle?.let { From 14a14a60fe9752aec972c441aece3a42dcf05ea1 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 10 Oct 2019 17:37:51 +0800 Subject: [PATCH 1863/1997] up --- app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt index fabb34ef9..117d601df 100644 --- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt @@ -22,6 +22,7 @@ class ReadRssActivity : VMBaseActivity(R.layout.activity_rss_r } private fun initWebView() { + webView.settings.javaScriptEnabled = true webView.webViewClient = WebViewClient() } From c441b8621628e744a9216817dc65cbb2f81ea6c0 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 11 Oct 2019 09:00:49 +0800 Subject: [PATCH 1864/1997] up --- .../main/java/io/legado/app/data/AppDatabase.kt | 2 +- .../java/io/legado/app/data/entities/RssSource.kt | 1 + .../app/ui/rss/article/RssArticlesActivity.kt | 2 +- .../app/ui/rss/article/RssArticlesViewModel.kt | 6 +++--- .../io/legado/app/ui/rss/read/ReadRssActivity.kt | 14 ++++++++------ .../io/legado/app/ui/rss/read/ReadRssViewModel.kt | 12 +++++++++--- 6 files changed, 23 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/AppDatabase.kt b/app/src/main/java/io/legado/app/data/AppDatabase.kt index 3b17435d5..630925c89 100644 --- a/app/src/main/java/io/legado/app/data/AppDatabase.kt +++ b/app/src/main/java/io/legado/app/data/AppDatabase.kt @@ -58,5 +58,5 @@ abstract class AppDatabase : RoomDatabase() { abstract fun sourceCookieDao(): SourceCookieDao abstract fun rssSourceDao(): RssSourceDao abstract fun bookmarkDao(): BookmarkDao - abstract fun rssArtivleDao(): RssArticleDao + abstract fun rssArticleDao(): RssArticleDao } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/data/entities/RssSource.kt b/app/src/main/java/io/legado/app/data/entities/RssSource.kt index f4fa0b838..79e74a496 100644 --- a/app/src/main/java/io/legado/app/data/entities/RssSource.kt +++ b/app/src/main/java/io/legado/app/data/entities/RssSource.kt @@ -27,5 +27,6 @@ data class RssSource( var ruleImage: String? = null, var ruleLink: String? = null, var ruleContent: String? = null, + var enableJs: Boolean = false, var customOrder: Int = 0 ) : Parcelable \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt index f2291a141..46825ee16 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt @@ -75,7 +75,7 @@ class RssArticlesActivity : VMBaseActivity(R.layout.activi private fun initData(origin: String) { rssArticlesData?.removeObservers(this) - rssArticlesData = App.db.rssArtivleDao().liveByOrigin(origin) + rssArticlesData = App.db.rssArticleDao().liveByOrigin(origin) rssArticlesData?.observe(this, Observer { adapter?.setItems(it) }) diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt index ccc939105..745216ba4 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt @@ -25,7 +25,7 @@ class RssArticlesViewModel(application: Application) : BaseViewModel(application Rss.getArticles(rssSource, this) .onSuccess(IO) { it?.let { - App.db.rssArtivleDao().insert(*it.toTypedArray()) + App.db.rssArticleDao().insert(*it.toTypedArray()) } }.onError { toast(it.localizedMessage) @@ -38,13 +38,13 @@ class RssArticlesViewModel(application: Application) : BaseViewModel(application fun read(rssArticle: RssArticle) { execute { rssArticle.read = true - App.db.rssArtivleDao().update(rssArticle) + App.db.rssArticleDao().update(rssArticle) } } fun clear(url: String, onFinally: () -> Unit) { execute { - App.db.rssArtivleDao().delete(url) + App.db.rssArticleDao().delete(url) loadContent(url, onFinally) } } diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt index 117d601df..f5f8a2d98 100644 --- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt @@ -1,5 +1,6 @@ package io.legado.app.ui.rss.read +import android.annotation.SuppressLint import android.os.Bundle import android.webkit.WebViewClient import androidx.lifecycle.Observer @@ -16,17 +17,18 @@ class ReadRssActivity : VMBaseActivity(R.layout.activity_rss_r override fun onActivityCreated(savedInstanceState: Bundle?) { title = intent.getStringExtra("title") - initWebView() + webView.webViewClient = WebViewClient() initLiveData() viewModel.initData(intent) } - private fun initWebView() { - webView.settings.javaScriptEnabled = true - webView.webViewClient = WebViewClient() - } - + @SuppressLint("SetJavaScriptEnabled") private fun initLiveData() { + viewModel.rssSourceLiveData.observe(this, Observer { + if (it.enableJs) { + webView.settings.javaScriptEnabled = true + } + }) viewModel.contentLiveData.observe(this, Observer { content -> viewModel.rssArticle?.let { val url = NetworkUtils.getAbsoluteURL(it.origin, it.link ?: "") diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt index 89a1e0825..3e8737a35 100644 --- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt @@ -6,12 +6,14 @@ import androidx.lifecycle.MutableLiveData import io.legado.app.App import io.legado.app.base.BaseViewModel import io.legado.app.data.entities.RssArticle +import io.legado.app.data.entities.RssSource import io.legado.app.model.analyzeRule.AnalyzeRule import io.legado.app.model.analyzeRule.AnalyzeUrl import io.legado.app.utils.NetworkUtils class ReadRssViewModel(application: Application) : BaseViewModel(application) { var rssArticle: RssArticle? = null + val rssSourceLiveData = MutableLiveData() val contentLiveData = MutableLiveData() val urlLiveData = MutableLiveData() @@ -19,14 +21,18 @@ class ReadRssViewModel(application: Application) : BaseViewModel(application) { execute { val origin = intent.getStringExtra("origin") val title = intent.getStringExtra("title") + val rssSource = App.db.rssSourceDao().getByKey(origin) + rssSource?.let { + rssSourceLiveData.postValue(it) + } if (origin != null && title != null) { - rssArticle = App.db.rssArtivleDao().get(origin, title) + rssArticle = App.db.rssArticleDao().get(origin, title) rssArticle?.let { rssArticle -> if (!rssArticle.description.isNullOrBlank()) { contentLiveData.postValue(rssArticle.description) } else { - App.db.rssSourceDao().getByKey(rssArticle.origin)?.let { source -> - val ruleContent = source.ruleContent + rssSource?.let { + val ruleContent = rssSource.ruleContent if (!ruleContent.isNullOrBlank()) { loadContent(rssArticle, ruleContent) } else { From 348b5d23b1f7708e786adbf5be4e28159720437a Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 11 Oct 2019 09:17:09 +0800 Subject: [PATCH 1865/1997] up --- .../rss/source/edit/RssSourceEditActivity.kt | 8 ++++++- .../res/layout/activity_rss_source_edit.xml | 21 +++++++++++++++++++ app/src/main/res/values/strings.xml | 1 + 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt index 5b30243b5..9233ef8fa 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt @@ -24,7 +24,7 @@ import io.legado.app.ui.rss.source.debug.RssSourceDebugActivity import io.legado.app.ui.widget.KeyboardToolPop import io.legado.app.utils.GSON import io.legado.app.utils.getViewModel -import kotlinx.android.synthetic.main.activity_book_source_edit.* +import kotlinx.android.synthetic.main.activity_rss_source_edit.* import org.jetbrains.anko.displayMetrics import org.jetbrains.anko.startActivity import org.jetbrains.anko.toast @@ -99,6 +99,10 @@ class RssSourceEditActivity : } private fun upRecyclerView(rssSource: RssSource?) { + rssSource?.let { + cb_is_enable.isChecked = rssSource.enabled + cb_enable_js.isChecked = rssSource.enableJs + } sourceEntities.clear() sourceEntities.apply { add(EditEntity("sourceName", rssSource?.sourceName, R.string.rss_source_name)) @@ -132,6 +136,8 @@ class RssSourceEditActivity : private fun getRssSource(): RssSource? { val source = viewModel.sourceLiveData.value ?: RssSource() + source.enabled = cb_is_enable.isChecked + source.enableJs = cb_enable_js.isChecked sourceEntities.forEach { when (it.key) { "sourceName" -> source.sourceName = it.value ?: "" diff --git a/app/src/main/res/layout/activity_rss_source_edit.xml b/app/src/main/res/layout/activity_rss_source_edit.xml index dd2545faf..c60fce039 100644 --- a/app/src/main/res/layout/activity_rss_source_edit.xml +++ b/app/src/main/res/layout/activity_rss_source_edit.xml @@ -15,6 +15,27 @@ app:fitStatusBar="false" app:title="@string/rss_source_edit" /> + + + + + + + + 音乐 音频 启用 + 启用JS 全部书源 输入不能为空 清空发现缓存 From f2a6d29cc9ec8df46977762e53b9eb0eb6936880 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 11 Oct 2019 09:20:09 +0800 Subject: [PATCH 1866/1997] up --- app/src/main/res/layout/activity_rss_source_edit.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/layout/activity_rss_source_edit.xml b/app/src/main/res/layout/activity_rss_source_edit.xml index c60fce039..e5dc91e60 100644 --- a/app/src/main/res/layout/activity_rss_source_edit.xml +++ b/app/src/main/res/layout/activity_rss_source_edit.xml @@ -32,7 +32,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:checked="true" - android:text="@string/is_enable" /> + android:text="@string/enable_js" />
    From 2985be85d109eec2c002433394fa354c23f33dfa Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 11 Oct 2019 09:34:53 +0800 Subject: [PATCH 1867/1997] up --- app/src/main/res/layout/item_rss.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/layout/item_rss.xml b/app/src/main/res/layout/item_rss.xml index dba2c0119..b06e2e37b 100644 --- a/app/src/main/res/layout/item_rss.xml +++ b/app/src/main/res/layout/item_rss.xml @@ -10,6 +10,7 @@ android:layout_width="50dp" android:layout_height="50dp" android:scaleType="centerCrop" + app:radius="12dp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" /> From 18e60ec985b325ac17f955c70e7563e6ee3ca6c1 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 11 Oct 2019 09:39:35 +0800 Subject: [PATCH 1868/1997] up --- app/src/main/res/layout/activity_rss_source_edit.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/layout/activity_rss_source_edit.xml b/app/src/main/res/layout/activity_rss_source_edit.xml index e5dc91e60..c7ce22473 100644 --- a/app/src/main/res/layout/activity_rss_source_edit.xml +++ b/app/src/main/res/layout/activity_rss_source_edit.xml @@ -31,7 +31,7 @@ android:id="@+id/cb_enable_js" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:checked="true" + android:checked="false" android:text="@string/enable_js" /> From ac773c87494111e2cb077f197d039d945879f607 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 11 Oct 2019 14:57:58 +0800 Subject: [PATCH 1869/1997] up --- .../java/io/legado/app/ui/rss/read/ReadRssActivity.kt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt index f5f8a2d98..40419697a 100644 --- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt @@ -2,6 +2,7 @@ package io.legado.app.ui.rss.read import android.annotation.SuppressLint import android.os.Bundle +import android.webkit.WebSettings import android.webkit.WebViewClient import androidx.lifecycle.Observer import io.legado.app.R @@ -17,11 +18,16 @@ class ReadRssActivity : VMBaseActivity(R.layout.activity_rss_r override fun onActivityCreated(savedInstanceState: Bundle?) { title = intent.getStringExtra("title") - webView.webViewClient = WebViewClient() + initWebView() initLiveData() viewModel.initData(intent) } + private fun initWebView() { + webView.webViewClient = WebViewClient() + webView.settings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW + } + @SuppressLint("SetJavaScriptEnabled") private fun initLiveData() { viewModel.rssSourceLiveData.observe(this, Observer { From 8f9a93236a33aa2ed48c59456b42a0e0b996c965 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 11 Oct 2019 15:06:44 +0800 Subject: [PATCH 1870/1997] up --- app/src/main/java/io/legado/app/help/JsExtensions.kt | 4 ++-- app/src/main/java/io/legado/app/help/ReadBookConfig.kt | 4 ++-- .../java/io/legado/app/model/analyzeRule/AnalyzeRule.kt | 2 +- .../java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt | 2 +- .../legado/app/ui/widget/recycler/scroller/FastScroller.kt | 7 ++++--- .../io/legado/app/utils/{BitmapUtil.kt => BitmapUtils.kt} | 2 +- .../io/legado/app/utils/{ColorUtil.kt => ColorUtils.kt} | 5 +++-- .../io/legado/app/utils/{Encoder.kt => EncoderUtils.kt} | 2 +- app/src/main/java/io/legado/app/utils/TimeUtils.kt | 2 ++ 9 files changed, 17 insertions(+), 13 deletions(-) rename app/src/main/java/io/legado/app/utils/{BitmapUtil.kt => BitmapUtils.kt} (99%) rename app/src/main/java/io/legado/app/utils/{ColorUtil.kt => ColorUtils.kt} (94%) rename app/src/main/java/io/legado/app/utils/{Encoder.kt => EncoderUtils.kt} (97%) create mode 100644 app/src/main/java/io/legado/app/utils/TimeUtils.kt diff --git a/app/src/main/java/io/legado/app/help/JsExtensions.kt b/app/src/main/java/io/legado/app/help/JsExtensions.kt index 643630121..d449d553c 100644 --- a/app/src/main/java/io/legado/app/help/JsExtensions.kt +++ b/app/src/main/java/io/legado/app/help/JsExtensions.kt @@ -1,7 +1,7 @@ package io.legado.app.help import io.legado.app.model.analyzeRule.AnalyzeUrl -import io.legado.app.utils.Encoder +import io.legado.app.utils.EncoderUtils import io.legado.app.utils.StringUtils import java.util.regex.Pattern @@ -27,7 +27,7 @@ class JsExtensions { * js实现解码,不能删 */ fun base64Decoder(str: String): String { - return Encoder.base64Decoder(str) + return EncoderUtils.base64Decoder(str) } /** diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index 9238c1341..89899d3cc 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -176,7 +176,7 @@ object ReadBookConfig { 1 -> { BitmapDrawable( resources, - BitmapUtil.decodeBitmap( + BitmapUtils.decodeBitmap( App.INSTANCE, "bg" + File.separator + bgStr(), width, @@ -186,7 +186,7 @@ object ReadBookConfig { } else -> BitmapDrawable( resources, - BitmapUtil.decodeBitmap(bgStr(), width, height) + BitmapUtils.decodeBitmap(bgStr(), width, height) ) } } catch (e: Exception) { diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt index c04981cdd..328d6cab4 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt @@ -547,7 +547,7 @@ class AnalyzeRule(private var book: BaseBook? = null) { * js实现解码,不能删 */ fun base64Decoder(str: String): String { - return Encoder.base64Decoder(str) + return EncoderUtils.base64Decoder(str) } /** diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt index 654882cc2..bc45a46f9 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt @@ -179,7 +179,7 @@ class AnalyzeUrl( fieldMap[queryM[0]] = URLEncoder.encode(value, "UTF-8") } } else if (charset == "escape") { - fieldMap[queryM[0]] = Encoder.escape(value) + fieldMap[queryM[0]] = EncoderUtils.escape(value) } else { fieldMap[queryM[0]] = URLEncoder.encode(value, charset) } diff --git a/app/src/main/java/io/legado/app/ui/widget/recycler/scroller/FastScroller.kt b/app/src/main/java/io/legado/app/ui/widget/recycler/scroller/FastScroller.kt index 9086f50db..25af39c6a 100644 --- a/app/src/main/java/io/legado/app/ui/widget/recycler/scroller/FastScroller.kt +++ b/app/src/main/java/io/legado/app/ui/widget/recycler/scroller/FastScroller.kt @@ -26,7 +26,7 @@ import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.StaggeredGridLayoutManager import io.legado.app.R import io.legado.app.lib.theme.accentColor -import io.legado.app.utils.ColorUtil +import io.legado.app.utils.ColorUtils import io.legado.app.utils.getCompatColor import kotlin.math.max import kotlin.math.min @@ -472,10 +472,11 @@ class FastScroller : LinearLayout { mHandleView = findViewById(R.id.fastscroll_handle) mTrackView = findViewById(R.id.fastscroll_track) mScrollbar = findViewById(R.id.fastscroll_scrollbar) - @ColorInt var bubbleColor = ColorUtil.adjustAlpha(context.accentColor, 0.8f) + @ColorInt var bubbleColor = ColorUtils.adjustAlpha(context.accentColor, 0.8f) @ColorInt var handleColor = context.accentColor @ColorInt var trackColor = context.getCompatColor(R.color.transparent30) - @ColorInt var textColor = if (ColorUtil.isColorLight(bubbleColor)) Color.BLACK else Color.WHITE + @ColorInt var textColor = + if (ColorUtils.isColorLight(bubbleColor)) Color.BLACK else Color.WHITE var fadeScrollbar = true var showBubble = false var showTrack = true diff --git a/app/src/main/java/io/legado/app/utils/BitmapUtil.kt b/app/src/main/java/io/legado/app/utils/BitmapUtils.kt similarity index 99% rename from app/src/main/java/io/legado/app/utils/BitmapUtil.kt rename to app/src/main/java/io/legado/app/utils/BitmapUtils.kt index 2b72e17db..00f1d4c58 100644 --- a/app/src/main/java/io/legado/app/utils/BitmapUtil.kt +++ b/app/src/main/java/io/legado/app/utils/BitmapUtils.kt @@ -19,7 +19,7 @@ import kotlin.math.sqrt @Suppress("unused", "WeakerAccess") -object BitmapUtil { +object BitmapUtils { /** * 从path中获取图片信息,在通过BitmapFactory.decodeFile(String path)方法将突破转成Bitmap时, * 遇到大一些的图片,我们经常会遇到OOM(Out Of Memory)的问题。所以用到了我们上面提到的BitmapFactory.Options这个类。 diff --git a/app/src/main/java/io/legado/app/utils/ColorUtil.kt b/app/src/main/java/io/legado/app/utils/ColorUtils.kt similarity index 94% rename from app/src/main/java/io/legado/app/utils/ColorUtil.kt rename to app/src/main/java/io/legado/app/utils/ColorUtils.kt index bce3ea27c..b592bb6c9 100644 --- a/app/src/main/java/io/legado/app/utils/ColorUtil.kt +++ b/app/src/main/java/io/legado/app/utils/ColorUtils.kt @@ -5,7 +5,7 @@ import android.graphics.Color import androidx.annotation.ColorInt import androidx.annotation.FloatRange -object ColorUtil { +object ColorUtils { fun intToString(intColor: Int): String { return String.format("#%06X", 0xFFFFFF and intColor) @@ -37,7 +37,8 @@ object ColorUtil { } fun isColorLight(@ColorInt color: Int): Boolean { - val darkness = 1 - (0.299 * Color.red(color) + 0.587 * Color.green(color) + 0.114 * Color.blue(color)) / 255 + val darkness = + 1 - (0.299 * Color.red(color) + 0.587 * Color.green(color) + 0.114 * Color.blue(color)) / 255 return darkness < 0.4 } diff --git a/app/src/main/java/io/legado/app/utils/Encoder.kt b/app/src/main/java/io/legado/app/utils/EncoderUtils.kt similarity index 97% rename from app/src/main/java/io/legado/app/utils/Encoder.kt rename to app/src/main/java/io/legado/app/utils/EncoderUtils.kt index f14785af9..112ac65f9 100644 --- a/app/src/main/java/io/legado/app/utils/Encoder.kt +++ b/app/src/main/java/io/legado/app/utils/EncoderUtils.kt @@ -3,7 +3,7 @@ package io.legado.app.utils import android.util.Base64 import java.nio.charset.StandardCharsets -object Encoder { +object EncoderUtils { fun escape(src: String): String { val tmp = StringBuilder() diff --git a/app/src/main/java/io/legado/app/utils/TimeUtils.kt b/app/src/main/java/io/legado/app/utils/TimeUtils.kt new file mode 100644 index 000000000..656da42d1 --- /dev/null +++ b/app/src/main/java/io/legado/app/utils/TimeUtils.kt @@ -0,0 +1,2 @@ +package io.legado.app.utils + From 705fb7a00bd29b4346c0c5fdb33929fde16af312 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 11 Oct 2019 15:10:04 +0800 Subject: [PATCH 1871/1997] up --- app/src/main/java/io/legado/app/utils/TimeUtils.kt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/src/main/java/io/legado/app/utils/TimeUtils.kt b/app/src/main/java/io/legado/app/utils/TimeUtils.kt index 656da42d1..d350fd0c3 100644 --- a/app/src/main/java/io/legado/app/utils/TimeUtils.kt +++ b/app/src/main/java/io/legado/app/utils/TimeUtils.kt @@ -1,2 +1,11 @@ package io.legado.app.utils +object TimeUtils { + + fun stringTimeToLong(time: String): Long { + + + return System.currentTimeMillis() + } + +} \ No newline at end of file From 433fa3cba41827f18c3c8c4db402deaa14adfe0b Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 11 Oct 2019 22:12:09 +0800 Subject: [PATCH 1872/1997] up --- .../main/java/io/legado/app/utils/TimeUtils.kt | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/utils/TimeUtils.kt b/app/src/main/java/io/legado/app/utils/TimeUtils.kt index d350fd0c3..456892361 100644 --- a/app/src/main/java/io/legado/app/utils/TimeUtils.kt +++ b/app/src/main/java/io/legado/app/utils/TimeUtils.kt @@ -1,10 +1,23 @@ package io.legado.app.utils +import android.annotation.SuppressLint +import java.text.SimpleDateFormat + object TimeUtils { - fun stringTimeToLong(time: String): Long { + private val formatArray = arrayOf("") + @SuppressLint("SimpleDateFormat") + fun stringTimeToLong(time: String): Long { + for (str in formatArray) { + try { + val df = SimpleDateFormat(str) + val d = df.parse(time) + return d.time + } catch (e: Exception) { + } + } return System.currentTimeMillis() } From 8c8cc7952473a8e5b7b4f3ea0511384691058bc2 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 12 Oct 2019 11:37:14 +0800 Subject: [PATCH 1873/1997] up --- .../book/source/manage/BookSourceActivity.kt | 8 +++--- .../ui/rss/source/manage/RssSourceActivity.kt | 25 +++++++++++++++++++ .../rss/source/manage/RssSourceViewModel.kt | 18 +++++++++++++ .../java/io/legado/app/utils/TimeUtils.kt | 24 ------------------ app/src/main/res/menu/book_source.xml | 8 +++--- app/src/main/res/menu/replace_rule.xml | 6 ++--- app/src/main/res/menu/rss_source.xml | 8 +++--- 7 files changed, 58 insertions(+), 39 deletions(-) delete mode 100644 app/src/main/java/io/legado/app/utils/TimeUtils.kt diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt index bc9da05fb..d27c4b036 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt @@ -80,22 +80,22 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity R.id.menu_add_book_source -> { this.startActivity() } - R.id.menu_import_book_source_qr -> { + R.id.menu_import_source_qr -> { this.startActivityForResult(qrRequestCode) } R.id.menu_group_manage -> GroupManageDialog().show( supportFragmentManager, "groupManage" ) - R.id.menu_import_book_source_local -> Restore.importYueDuData(this) + R.id.menu_import_source_local -> Restore.importYueDuData(this) R.id.menu_select_all -> adapter.selectAll() R.id.menu_revert_selection -> adapter.revertSelection() R.id.menu_enable_selection -> viewModel.enableSelection(adapter.getSelectionIds()) R.id.menu_disable_selection -> viewModel.disableSelection(adapter.getSelectionIds()) R.id.menu_del_selection -> viewModel.delSelection(adapter.getSelectionIds()) - R.id.menu_check_book_source -> + R.id.menu_check_source -> startService(Pair("data", adapter.getSelectionIds())) - R.id.menu_import_book_source_onLine -> showImportDialog() + R.id.menu_import_source_onLine -> showImportDialog() } if (item.groupId == R.id.source_group) { search_view.setQuery(item.title, true) diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt index 5515e4cf1..6c6bc269d 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt @@ -1,5 +1,7 @@ package io.legado.app.ui.rss.source.manage +import android.app.Activity +import android.content.Intent import android.os.Bundle import android.view.Menu import android.view.MenuItem @@ -20,6 +22,7 @@ import io.legado.app.help.ItemTouchCallback import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.primaryTextColor import io.legado.app.ui.rss.source.edit.RssSourceEditActivity +import io.legado.app.utils.FileUtils import io.legado.app.utils.getViewModel import io.legado.app.utils.splitNotBlank import kotlinx.android.synthetic.main.activity_rss_source.* @@ -34,6 +37,7 @@ class RssSourceActivity : VMBaseActivity(R.layout.activity_r override val viewModel: RssSourceViewModel get() = getViewModel(RssSourceViewModel::class.java) + private val import_source = 13141 private lateinit var adapter: RssSourceAdapter private var sourceLiveData: LiveData>? = null private var groups = hashSetOf() @@ -66,6 +70,7 @@ class RssSourceActivity : VMBaseActivity(R.layout.activity_r R.id.menu_enable_selection -> viewModel.enableSelection(adapter.getSelectionIds()) R.id.menu_disable_selection -> viewModel.disableSelection(adapter.getSelectionIds()) R.id.menu_del_selection -> viewModel.delSelection(adapter.getSelectionIds()) + R.id.menu_import_source_local -> selectFile() } return super.onCompatOptionsItemSelected(item) } @@ -136,6 +141,26 @@ class RssSourceActivity : VMBaseActivity(R.layout.activity_r }) } + private fun selectFile() { + val intent = Intent(Intent.ACTION_GET_CONTENT) + intent.addCategory(Intent.CATEGORY_OPENABLE) + intent.type = "text/*"//设置类型 + startActivityForResult(intent, import_source) + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + when (requestCode) { + import_source -> if (resultCode == Activity.RESULT_OK) { + data?.data?.let { + FileUtils.getPath(this, it)?.let { path -> + viewModel.importSourceFromFilePath(path) + } + } + } + } + } + override fun del(source: RssSource) { viewModel.del(source) } diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt index b0ad309d6..76aa384c0 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt @@ -4,6 +4,9 @@ import android.app.Application import io.legado.app.App import io.legado.app.base.BaseViewModel import io.legado.app.data.entities.RssSource +import io.legado.app.utils.GSON +import io.legado.app.utils.fromJsonArray +import java.io.File class RssSourceViewModel(application: Application) : BaseViewModel(application) { @@ -49,4 +52,19 @@ class RssSourceViewModel(application: Application) : BaseViewModel(application) App.db.rssSourceDao().delSection(*ids.toTypedArray()) } } + + fun importSourceFromFilePath(path: String) { + execute { + val file = File(path) + if (file.exists()) { + GSON.fromJsonArray(file.readText())?.let { + App.db.rssSourceDao().insert(*it.toTypedArray()) + } + } + } + } + + fun importSource(sourceStr: String) { + + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/utils/TimeUtils.kt b/app/src/main/java/io/legado/app/utils/TimeUtils.kt deleted file mode 100644 index 456892361..000000000 --- a/app/src/main/java/io/legado/app/utils/TimeUtils.kt +++ /dev/null @@ -1,24 +0,0 @@ -package io.legado.app.utils - -import android.annotation.SuppressLint -import java.text.SimpleDateFormat - -object TimeUtils { - - private val formatArray = arrayOf("") - - @SuppressLint("SimpleDateFormat") - fun stringTimeToLong(time: String): Long { - - for (str in formatArray) { - try { - val df = SimpleDateFormat(str) - val d = df.parse(time) - return d.time - } catch (e: Exception) { - } - } - return System.currentTimeMillis() - } - -} \ No newline at end of file diff --git a/app/src/main/res/menu/book_source.xml b/app/src/main/res/menu/book_source.xml index 6900e82ae..7569e2fe9 100644 --- a/app/src/main/res/menu/book_source.xml +++ b/app/src/main/res/menu/book_source.xml @@ -97,25 +97,25 @@ app:showAsAction="never" /> diff --git a/app/src/main/res/menu/replace_rule.xml b/app/src/main/res/menu/replace_rule.xml index eec4b7abd..1efeaa4f7 100644 --- a/app/src/main/res/menu/replace_rule.xml +++ b/app/src/main/res/menu/replace_rule.xml @@ -69,19 +69,19 @@ app:showAsAction="never" /> diff --git a/app/src/main/res/menu/rss_source.xml b/app/src/main/res/menu/rss_source.xml index 45ef06792..c64fea473 100644 --- a/app/src/main/res/menu/rss_source.xml +++ b/app/src/main/res/menu/rss_source.xml @@ -97,25 +97,25 @@ app:showAsAction="never" /> From c513db1005b1c8f234ff8011d4188a2957dcb609 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 12 Oct 2019 11:52:01 +0800 Subject: [PATCH 1874/1997] up --- .../book/source/manage/BookSourceActivity.kt | 27 ++++++++++++------- .../book/source/manage/BookSourceViewModel.kt | 10 +++++++ .../ui/rss/source/manage/RssSourceActivity.kt | 6 ++--- 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt index d27c4b036..4d1fe668b 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt @@ -1,6 +1,7 @@ package io.legado.app.ui.book.source.manage import android.annotation.SuppressLint +import android.app.Activity import android.content.Intent import android.os.Bundle import android.view.Menu @@ -19,7 +20,6 @@ import io.legado.app.R import io.legado.app.base.VMBaseActivity import io.legado.app.data.entities.BookSource import io.legado.app.help.ItemTouchCallback -import io.legado.app.help.storage.Restore import io.legado.app.lib.dialogs.alert import io.legado.app.lib.dialogs.cancelButton import io.legado.app.lib.dialogs.customView @@ -30,10 +30,7 @@ import io.legado.app.lib.theme.view.ATEAutoCompleteTextView import io.legado.app.service.CheckSourceService import io.legado.app.ui.book.source.edit.BookSourceEditActivity import io.legado.app.ui.qrcode.QrCodeActivity -import io.legado.app.utils.ACache -import io.legado.app.utils.applyTint -import io.legado.app.utils.getViewModel -import io.legado.app.utils.splitNotBlank +import io.legado.app.utils.* import kotlinx.android.synthetic.main.activity_book_source.* import kotlinx.android.synthetic.main.dialog_edit_text.view.* import kotlinx.android.synthetic.main.view_search.* @@ -50,6 +47,7 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity get() = getViewModel(BookSourceViewModel::class.java) private val qrRequestCode = 101 + private val importSource = 13141 private lateinit var adapter: BookSourceAdapter private var bookSourceLiveDate: LiveData>? = null private var groups = hashSetOf() @@ -87,7 +85,7 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity supportFragmentManager, "groupManage" ) - R.id.menu_import_source_local -> Restore.importYueDuData(this) + R.id.menu_import_source_local -> selectFile() R.id.menu_select_all -> adapter.selectAll() R.id.menu_revert_selection -> adapter.revertSelection() R.id.menu_enable_selection -> viewModel.enableSelection(adapter.getSelectionIds()) @@ -207,6 +205,12 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity }.show().applyTint() } + private fun selectFile() { + val intent = Intent(Intent.ACTION_GET_CONTENT) + intent.addCategory(Intent.CATEGORY_OPENABLE) + intent.type = "text/*"//设置类型 + startActivityForResult(intent, importSource) + } override fun onQueryTextChange(newText: String?): Boolean { newText?.let { @@ -242,10 +246,15 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) when (requestCode) { - qrRequestCode -> { - if (resultCode == RESULT_OK) { - data?.getStringExtra("result")?.let { + qrRequestCode -> if (resultCode == RESULT_OK) { + data?.getStringExtra("result")?.let { + } + } + importSource -> if (resultCode == Activity.RESULT_OK) { + data?.data?.let { + FileUtils.getPath(this, it)?.let { path -> + viewModel.importSourceFromFilePath(path) } } } diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt index a51b589b3..7a3b5bb91 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt @@ -11,6 +11,7 @@ import io.legado.app.help.http.HttpHelper import io.legado.app.help.storage.OldRule import io.legado.app.help.storage.Restore.jsonPath import io.legado.app.utils.* +import java.io.File class BookSourceViewModel(application: Application) : BaseViewModel(application) { @@ -97,6 +98,15 @@ class BookSourceViewModel(application: Application) : BaseViewModel(application) } } + fun importSourceFromFilePath(path: String) { + execute { + val file = File(path) + if (file.exists()) { + importSource(file.readText()) + } + } + } + fun importSource(text: String) { execute { val text1 = text.trim() diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt index 6c6bc269d..aa3f3413d 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt @@ -37,7 +37,7 @@ class RssSourceActivity : VMBaseActivity(R.layout.activity_r override val viewModel: RssSourceViewModel get() = getViewModel(RssSourceViewModel::class.java) - private val import_source = 13141 + private val importSource = 13141 private lateinit var adapter: RssSourceAdapter private var sourceLiveData: LiveData>? = null private var groups = hashSetOf() @@ -145,13 +145,13 @@ class RssSourceActivity : VMBaseActivity(R.layout.activity_r val intent = Intent(Intent.ACTION_GET_CONTENT) intent.addCategory(Intent.CATEGORY_OPENABLE) intent.type = "text/*"//设置类型 - startActivityForResult(intent, import_source) + startActivityForResult(intent, importSource) } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) when (requestCode) { - import_source -> if (resultCode == Activity.RESULT_OK) { + importSource -> if (resultCode == Activity.RESULT_OK) { data?.data?.let { FileUtils.getPath(this, it)?.let { path -> viewModel.importSourceFromFilePath(path) From a65e2d3f0b9d0af3df127774e4678f2617f95e50 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 12 Oct 2019 12:36:45 +0800 Subject: [PATCH 1875/1997] up --- .../app/ui/rss/article/RssArticlesActivity.kt | 6 ++++ .../ui/rss/article/RssArticlesViewModel.kt | 30 ++++++++++--------- app/src/main/res/menu/rss_articles.xml | 5 ++++ app/src/main/res/values/strings.xml | 1 + 4 files changed, 28 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt index 46825ee16..50d2676d3 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt @@ -14,9 +14,11 @@ import io.legado.app.base.VMBaseActivity import io.legado.app.data.entities.RssArticle import io.legado.app.lib.theme.ATH import io.legado.app.ui.rss.read.ReadRssActivity +import io.legado.app.ui.rss.source.edit.RssSourceEditActivity import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_rss_artivles.* import org.jetbrains.anko.startActivity +import org.jetbrains.anko.startActivityForResult class RssArticlesActivity : VMBaseActivity(R.layout.activity_rss_artivles), RssArticlesAdapter.CallBack { @@ -24,6 +26,7 @@ class RssArticlesActivity : VMBaseActivity(R.layout.activi override val viewModel: RssArticlesViewModel get() = getViewModel(RssArticlesViewModel::class.java) + private val editSource = 12319 private var adapter: RssArticlesAdapter? = null private var rssArticlesData: LiveData>? = null @@ -47,6 +50,9 @@ class RssArticlesActivity : VMBaseActivity(R.layout.activi override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { + R.id.menu_edit_source -> viewModel.rssSource?.sourceUrl?.let { + startActivityForResult(editSource, Pair("data", it)) + } R.id.menu_clear -> { intent.getStringExtra("url")?.let { refresh_progress_bar.isAutoLoading = true diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt index 745216ba4..8fc44c1c9 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt @@ -11,27 +11,29 @@ import kotlinx.coroutines.Dispatchers.IO class RssArticlesViewModel(application: Application) : BaseViewModel(application) { - + var rssSource: RssSource? = null val titleLiveData = MutableLiveData() fun loadContent(url: String, onFinally: () -> Unit) { execute { - var rssSource = App.db.rssSourceDao().getByKey(url) - if (rssSource == null) { + rssSource = App.db.rssSourceDao().getByKey(url) + rssSource?.let { + titleLiveData.postValue(it.sourceName) + } ?: let { rssSource = RssSource(sourceUrl = url) - } else { - titleLiveData.postValue(rssSource.sourceName) } - Rss.getArticles(rssSource, this) - .onSuccess(IO) { - it?.let { - App.db.rssArticleDao().insert(*it.toTypedArray()) + rssSource?.let { + Rss.getArticles(it, this) + .onSuccess(IO) { + it?.let { + App.db.rssArticleDao().insert(*it.toTypedArray()) + } + }.onError { + toast(it.localizedMessage) + }.onFinally { + onFinally() } - }.onError { - toast(it.localizedMessage) - }.onFinally { - onFinally() - } + } } } diff --git a/app/src/main/res/menu/rss_articles.xml b/app/src/main/res/menu/rss_articles.xml index cd68daa0f..03d187bcd 100644 --- a/app/src/main/res/menu/rss_articles.xml +++ b/app/src/main/res/menu/rss_articles.xml @@ -2,6 +2,11 @@ + + 朗读停止 清除缓存 保存 + 编辑源 编辑书源 禁用书源 新建书源 From 975fac27727ef64d31764a66cffd1846d21b4759 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 12 Oct 2019 14:34:47 +0800 Subject: [PATCH 1876/1997] up --- .../io/legado/app/data/entities/RssSource.kt | 2 +- .../legado/app/model/rss/RssParserByRule.kt | 10 +------- .../legado/app/ui/rss/read/ReadRssActivity.kt | 23 +++++++++++++------ .../rss/source/edit/RssSourceEditActivity.kt | 4 ++-- .../res/layout/activity_rss_source_edit.xml | 19 ++++++++++++++- app/src/main/res/values/strings.xml | 1 + 6 files changed, 39 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/RssSource.kt b/app/src/main/java/io/legado/app/data/entities/RssSource.kt index 79e74a496..89c25d75a 100644 --- a/app/src/main/java/io/legado/app/data/entities/RssSource.kt +++ b/app/src/main/java/io/legado/app/data/entities/RssSource.kt @@ -18,7 +18,6 @@ data class RssSource( //列表规则 var ruleArticles: String? = null, var ruleTitle: String? = null, - var ruleAuthor: String? = null, var rulePubDate: String? = null, //类别规则 var ruleCategories: String? = null, @@ -28,5 +27,6 @@ data class RssSource( var ruleLink: String? = null, var ruleContent: String? = null, var enableJs: Boolean = false, + var loadWithBaseUrl: Boolean = true, var customOrder: Int = 0 ) : Parcelable \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt b/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt index 476c6a49e..d5fea37fd 100644 --- a/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt +++ b/app/src/main/java/io/legado/app/model/rss/RssParserByRule.kt @@ -35,12 +35,10 @@ object RssParserByRule { } val collections = analyzeRule.getElements(ruleArticles) val ruleTitle = analyzeRule.splitSourceRule(rssSource.ruleTitle ?: "") - val ruleAuthor = analyzeRule.splitSourceRule(rssSource.ruleAuthor ?: "") val rulePubDate = analyzeRule.splitSourceRule(rssSource.rulePubDate ?: "") val ruleCategories = analyzeRule.splitSourceRule(rssSource.ruleCategories ?: "") val ruleDescription = analyzeRule.splitSourceRule(rssSource.ruleDescription ?: "") val ruleImage = analyzeRule.splitSourceRule(rssSource.ruleImage ?: "") - val ruleContent = analyzeRule.splitSourceRule(rssSource.ruleContent ?: "") val ruleLink = analyzeRule.splitSourceRule(rssSource.ruleLink ?: "") for ((index, item) in collections.withIndex()) { getItem( @@ -48,12 +46,10 @@ object RssParserByRule { analyzeRule, index == 0, ruleTitle, - ruleAuthor, rulePubDate, ruleCategories, ruleDescription, ruleImage, - ruleContent, ruleLink )?.let { it.origin = rssSource.sourceUrl @@ -75,24 +71,20 @@ object RssParserByRule { analyzeRule: AnalyzeRule, printLog: Boolean, ruleTitle: List, - ruleAuthor: List, rulePubDate: List, ruleCategories: List, ruleDescription: List, ruleImage: List, - ruleContent: List, ruleLink: List ): RssArticle? { val rssArticle = RssArticle() analyzeRule.setContent(item) rssArticle.title = analyzeRule.getString(ruleTitle) - rssArticle.author = analyzeRule.getString(ruleAuthor) rssArticle.pubDate = analyzeRule.getString(rulePubDate) rssArticle.categories = analyzeRule.getString(ruleCategories) rssArticle.description = analyzeRule.getString(ruleDescription) - rssArticle.image = analyzeRule.getString(ruleImage) + rssArticle.image = analyzeRule.getString(ruleImage, true) rssArticle.link = analyzeRule.getString(ruleLink) - rssArticle.content = analyzeRule.getString(ruleContent) if (rssArticle.title.isBlank()) { return null } diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt index 40419697a..5813ec48d 100644 --- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt @@ -26,6 +26,7 @@ class ReadRssActivity : VMBaseActivity(R.layout.activity_rss_r private fun initWebView() { webView.webViewClient = WebViewClient() webView.settings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW + webView.settings.domStorageEnabled = true } @SuppressLint("SetJavaScriptEnabled") @@ -38,13 +39,21 @@ class ReadRssActivity : VMBaseActivity(R.layout.activity_rss_r viewModel.contentLiveData.observe(this, Observer { content -> viewModel.rssArticle?.let { val url = NetworkUtils.getAbsoluteURL(it.origin, it.link ?: "") - webView.loadDataWithBaseURL( - url, - "$content", - "text/html", - "utf-8", - url - ) + if (viewModel.rssSourceLiveData.value?.loadWithBaseUrl == true) { + webView.loadDataWithBaseURL( + url, + "$content", + "text/html", + "utf-8", + url + ) + } else { + webView.loadData( + "$content", + "text/html", + "utf-8" + ) + } } }) viewModel.urlLiveData.observe(this, Observer { diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt index 9233ef8fa..a27b81025 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditActivity.kt @@ -102,6 +102,7 @@ class RssSourceEditActivity : rssSource?.let { cb_is_enable.isChecked = rssSource.enabled cb_enable_js.isChecked = rssSource.enableJs + cb_enable_base_url.isChecked = rssSource.loadWithBaseUrl } sourceEntities.clear() sourceEntities.apply { @@ -111,7 +112,6 @@ class RssSourceEditActivity : add(EditEntity("sourceGroup", rssSource?.sourceGroup, R.string.rss_source_group)) add(EditEntity("ruleArticles", rssSource?.ruleArticles, R.string.rss_rule_articles)) add(EditEntity("ruleTitle", rssSource?.ruleTitle, R.string.rss_rule_title)) - add(EditEntity("ruleAuthor", rssSource?.ruleAuthor, R.string.rss_rule_author)) add(EditEntity("rulePubDate", rssSource?.rulePubDate, R.string.rss_rule_date)) add( EditEntity( @@ -138,6 +138,7 @@ class RssSourceEditActivity : val source = viewModel.sourceLiveData.value ?: RssSource() source.enabled = cb_is_enable.isChecked source.enableJs = cb_enable_js.isChecked + source.loadWithBaseUrl = cb_enable_base_url.isChecked sourceEntities.forEach { when (it.key) { "sourceName" -> source.sourceName = it.value ?: "" @@ -146,7 +147,6 @@ class RssSourceEditActivity : "sourceGroup" -> source.sourceGroup = it.value "ruleArticles" -> source.ruleArticles = it.value "ruleTitle" -> source.ruleTitle = it.value - "ruleAuthor" -> source.ruleAuthor = it.value "rulePubDate" -> source.rulePubDate = it.value "ruleCategories" -> source.ruleCategories = it.value "ruleDescription" -> source.ruleDescription = it.value diff --git a/app/src/main/res/layout/activity_rss_source_edit.xml b/app/src/main/res/layout/activity_rss_source_edit.xml index c7ce22473..2f78c1006 100644 --- a/app/src/main/res/layout/activity_rss_source_edit.xml +++ b/app/src/main/res/layout/activity_rss_source_edit.xml @@ -1,6 +1,7 @@ + android:orientation="horizontal" + android:layout_gravity="center_vertical"> + + + + 音频 启用 启用JS + 加载BaseUrl 全部书源 输入不能为空 清空发现缓存 From 80fa33c6dff51653edad990fd86221f4cc428b75 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 12 Oct 2019 15:39:00 +0800 Subject: [PATCH 1877/1997] up --- app/src/main/java/io/legado/app/data/entities/RssSource.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/data/entities/RssSource.kt b/app/src/main/java/io/legado/app/data/entities/RssSource.kt index 89c25d75a..3c2dd17b4 100644 --- a/app/src/main/java/io/legado/app/data/entities/RssSource.kt +++ b/app/src/main/java/io/legado/app/data/entities/RssSource.kt @@ -27,6 +27,6 @@ data class RssSource( var ruleLink: String? = null, var ruleContent: String? = null, var enableJs: Boolean = false, - var loadWithBaseUrl: Boolean = true, + var loadWithBaseUrl: Boolean = false, var customOrder: Int = 0 ) : Parcelable \ No newline at end of file From fecb37c2b27c8571a410cf0d48a10b417bd7fff5 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 12 Oct 2019 17:09:52 +0800 Subject: [PATCH 1878/1997] up --- app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt index ce3908021..3cad86893 100644 --- a/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt +++ b/app/src/main/java/io/legado/app/receiver/MediaButtonReceiver.kt @@ -7,7 +7,6 @@ import android.view.KeyEvent import io.legado.app.constant.Bus import io.legado.app.help.ActivityHelp import io.legado.app.ui.book.read.ReadBookActivity -import io.legado.app.utils.LogUtils import io.legado.app.utils.postEvent @@ -23,7 +22,6 @@ class MediaButtonReceiver : BroadcastReceiver() { fun handleIntent(context: Context, intent: Intent): Boolean { val intentAction = intent.action val keyEventAction = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT)?.action - LogUtils.d("耳机按键", "$intentAction $keyEventAction") if (Intent.ACTION_MEDIA_BUTTON == intentAction) { if (keyEventAction == KeyEvent.ACTION_DOWN) { readAloud(context) From a0a9be33582237b409ac1139b4826a700e97fc1e Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 12 Oct 2019 17:27:05 +0800 Subject: [PATCH 1879/1997] up --- .../book/source/manage/BookSourceActivity.kt | 10 ++-- .../ui/rss/source/manage/RssSourceActivity.kt | 53 +++++++++++++++++-- 2 files changed, 53 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt index 4d1fe668b..db9405b0d 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt @@ -75,12 +75,8 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { - R.id.menu_add_book_source -> { - this.startActivity() - } - R.id.menu_import_source_qr -> { - this.startActivityForResult(qrRequestCode) - } + R.id.menu_add_book_source -> startActivity() + R.id.menu_import_source_qr -> startActivityForResult(qrRequestCode) R.id.menu_group_manage -> GroupManageDialog().show( supportFragmentManager, "groupManage" @@ -248,7 +244,7 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity when (requestCode) { qrRequestCode -> if (resultCode == RESULT_OK) { data?.getStringExtra("result")?.let { - + viewModel.importSource(it) } } importSource -> if (resultCode == Activity.RESULT_OK) { diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt index aa3f3413d..7c9aaa35b 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt @@ -1,5 +1,6 @@ package io.legado.app.ui.rss.source.manage +import android.annotation.SuppressLint import android.app.Activity import android.content.Intent import android.os.Bundle @@ -19,16 +20,22 @@ import io.legado.app.R import io.legado.app.base.VMBaseActivity import io.legado.app.data.entities.RssSource import io.legado.app.help.ItemTouchCallback +import io.legado.app.lib.dialogs.alert +import io.legado.app.lib.dialogs.cancelButton +import io.legado.app.lib.dialogs.customView +import io.legado.app.lib.dialogs.okButton import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.primaryTextColor +import io.legado.app.lib.theme.view.ATEAutoCompleteTextView +import io.legado.app.ui.qrcode.QrCodeActivity import io.legado.app.ui.rss.source.edit.RssSourceEditActivity -import io.legado.app.utils.FileUtils -import io.legado.app.utils.getViewModel -import io.legado.app.utils.splitNotBlank +import io.legado.app.utils.* import kotlinx.android.synthetic.main.activity_rss_source.* +import kotlinx.android.synthetic.main.dialog_edit_text.view.* import kotlinx.android.synthetic.main.view_search.* import kotlinx.android.synthetic.main.view_title_bar.* import org.jetbrains.anko.startActivity +import org.jetbrains.anko.startActivityForResult class RssSourceActivity : VMBaseActivity(R.layout.activity_rss_source), @@ -37,6 +44,7 @@ class RssSourceActivity : VMBaseActivity(R.layout.activity_r override val viewModel: RssSourceViewModel get() = getViewModel(RssSourceViewModel::class.java) + private val qrRequestCode = 101 private val importSource = 13141 private lateinit var adapter: RssSourceAdapter private var sourceLiveData: LiveData>? = null @@ -71,6 +79,8 @@ class RssSourceActivity : VMBaseActivity(R.layout.activity_r R.id.menu_disable_selection -> viewModel.disableSelection(adapter.getSelectionIds()) R.id.menu_del_selection -> viewModel.delSelection(adapter.getSelectionIds()) R.id.menu_import_source_local -> selectFile() + R.id.menu_import_source_onLine -> showImportDialog() + R.id.menu_import_source_qr -> startActivityForResult(qrRequestCode) } return super.onCompatOptionsItemSelected(item) } @@ -141,6 +151,38 @@ class RssSourceActivity : VMBaseActivity(R.layout.activity_r }) } + @SuppressLint("InflateParams") + private fun showImportDialog() { + val aCache = ACache.get(this, cacheDir = false) + val cacheUrls: MutableList = aCache + .getAsString("sourceUrl") + ?.splitNotBlank(",") + ?.toMutableList() ?: mutableListOf() + alert(titleResource = R.string.import_book_source_on_line) { + var editText: ATEAutoCompleteTextView? = null + customView { + layoutInflater.inflate(R.layout.dialog_edit_text, null).apply { + editText = edit_view + edit_view.setFilterValues(cacheUrls) { + cacheUrls.remove(it) + aCache.put("sourceUrl", cacheUrls.joinToString(",")) + } + } + } + okButton { + val text = editText?.text?.toString() + text?.let { + if (!cacheUrls.contains(it)) { + cacheUrls.add(0, it) + aCache.put("sourceUrl", cacheUrls.joinToString(",")) + } + viewModel.importSource(it) + } + } + cancelButton() + }.show().applyTint() + } + private fun selectFile() { val intent = Intent(Intent.ACTION_GET_CONTENT) intent.addCategory(Intent.CATEGORY_OPENABLE) @@ -158,6 +200,11 @@ class RssSourceActivity : VMBaseActivity(R.layout.activity_r } } } + qrRequestCode -> if (resultCode == RESULT_OK) { + data?.getStringExtra("result")?.let { + viewModel.importSource(it) + } + } } } From 4745042330568cf6b876b4b7dbd36abeab677bda Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 12 Oct 2019 19:42:42 +0800 Subject: [PATCH 1880/1997] up --- .../main/java/io/legado/app/ui/rss/source/manage/DiffCallBack.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/DiffCallBack.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/DiffCallBack.kt index 4260febe4..a623d55be 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/manage/DiffCallBack.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/DiffCallBack.kt @@ -26,6 +26,7 @@ class DiffCallBack( val oldItem = oldItems[oldItemPosition] val newItem = newItems[newItemPosition] return oldItem.sourceName == newItem.sourceName + && oldItem.sourceGroup == newItem.sourceGroup && oldItem.enabled == newItem.enabled } From 07845fab8ca2df4cbb46b79ee00e2cf61efff4f6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 12 Oct 2019 20:43:07 +0800 Subject: [PATCH 1881/1997] up --- .../io/legado/app/ui/rss/source/manage/RssSourceActivity.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt index 7c9aaa35b..ad739b5c2 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt @@ -82,6 +82,9 @@ class RssSourceActivity : VMBaseActivity(R.layout.activity_r R.id.menu_import_source_onLine -> showImportDialog() R.id.menu_import_source_qr -> startActivityForResult(qrRequestCode) } + if (item.groupId == R.id.source_group) { + search_view.setQuery(item.title, true) + } return super.onCompatOptionsItemSelected(item) } @@ -113,6 +116,7 @@ class RssSourceActivity : VMBaseActivity(R.layout.activity_r } override fun onQueryTextChange(newText: String?): Boolean { + initLiveDataSource(newText) return false } }) From 8ee85510c55a22dd4e050478179241c46719b720 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 12 Oct 2019 21:06:37 +0800 Subject: [PATCH 1882/1997] up --- .../main/java/io/legado/app/help/ReadBookConfig.kt | 14 ++++++++------ .../main/java/io/legado/app/help/storage/Backup.kt | 11 +++++++++++ .../java/io/legado/app/help/storage/Restore.kt | 12 ++++++++++++ .../java/io/legado/app/help/storage/WebDavHelp.kt | 14 +++++++++----- 4 files changed, 40 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index 89899d3cc..8c0266c63 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -19,8 +19,8 @@ import java.io.IOException * 阅读界面配置 */ object ReadBookConfig { - private const val fileName = "readConfig.json" - private val configList: ArrayList = arrayListOf() + const val readConfigFileName = "readConfig.json" + val configList: ArrayList = arrayListOf() .apply { upConfig(this) } @@ -35,11 +35,12 @@ object ReadBookConfig { } fun upConfig(list: ArrayList = configList) { - val configFile = File(App.INSTANCE.filesDir.absolutePath + File.separator + fileName) + val configFile = + File(App.INSTANCE.filesDir.absolutePath + File.separator + readConfigFileName) val json = if (configFile.exists()) { String(configFile.readBytes()) } else { - String(App.INSTANCE.assets.open(fileName).readBytes()) + String(App.INSTANCE.assets.open(readConfigFileName).readBytes()) } try { GSON.fromJsonArray(json)?.let { @@ -63,7 +64,8 @@ object ReadBookConfig { fun save() { GlobalScope.launch(IO) { val json = GSON.toJson(configList) - val configFile = File(App.INSTANCE.filesDir.absolutePath + File.separator + fileName) + val configFile = + File(App.INSTANCE.filesDir.absolutePath + File.separator + readConfigFileName) //获取流并存储 try { BufferedWriter(FileWriter(configFile)).use { writer -> @@ -78,7 +80,7 @@ object ReadBookConfig { fun reset() { try { - val json = String(App.INSTANCE.assets.open(fileName).readBytes()) + val json = String(App.INSTANCE.assets.open(readConfigFileName).readBytes()) GSON.fromJsonArray(json)?.let { configList.clear() configList.addAll(it) diff --git a/app/src/main/java/io/legado/app/help/storage/Backup.kt b/app/src/main/java/io/legado/app/help/storage/Backup.kt index fa3ad14f9..0ac19a1e8 100644 --- a/app/src/main/java/io/legado/app/help/storage/Backup.kt +++ b/app/src/main/java/io/legado/app/help/storage/Backup.kt @@ -3,6 +3,7 @@ package io.legado.app.help.storage import io.legado.app.App import io.legado.app.R import io.legado.app.help.FileHelp +import io.legado.app.help.ReadBookConfig import io.legado.app.utils.FileUtils import io.legado.app.utils.GSON import org.jetbrains.anko.defaultSharedPreferences @@ -25,6 +26,7 @@ object Backup { backupBookSource(path) backupRssSource(path) backupReplaceRule(path) + backupReadConfig(path) backupPreference(path) WebDavHelp.backUpWebDav(path) uiThread { @@ -40,6 +42,8 @@ object Backup { backupBookSource(path) backupRssSource(path) backupReplaceRule(path) + backupReadConfig(path) + backupPreference(path) WebDavHelp.backUpWebDav(path) } } @@ -84,6 +88,13 @@ object Backup { } } + private fun backupReadConfig(path: String) { + GSON.toJson(ReadBookConfig.configList)?.let { + FileHelp.getFile(path + File.separator + ReadBookConfig.readConfigFileName) + .writeText(it) + } + } + private fun backupPreference(path: String) { Preferences.getSharedPreferences(App.INSTANCE, path, "config")?.let { sp -> val edit = sp.edit() diff --git a/app/src/main/java/io/legado/app/help/storage/Restore.kt b/app/src/main/java/io/legado/app/help/storage/Restore.kt index 593bbec5e..06543c388 100644 --- a/app/src/main/java/io/legado/app/help/storage/Restore.kt +++ b/app/src/main/java/io/legado/app/help/storage/Restore.kt @@ -13,6 +13,7 @@ import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.ReplaceRule import io.legado.app.data.entities.RssSource import io.legado.app.help.FileHelp +import io.legado.app.help.ReadBookConfig import io.legado.app.help.storage.Backup.defaultPath import io.legado.app.utils.* import org.jetbrains.anko.defaultSharedPreferences @@ -68,6 +69,17 @@ object Restore { } catch (e: Exception) { e.printStackTrace() } + try { + val file = + FileHelp.getFile(path + File.separator + ReadBookConfig.readConfigFileName) + val configFile = + File(App.INSTANCE.filesDir.absolutePath + File.separator + ReadBookConfig.readConfigFileName) + if (file.exists()) { + file.copyTo(configFile, true) + } + } catch (e: Exception) { + e.printStackTrace() + } Preferences.getSharedPreferences(App.INSTANCE, path, "config")?.all?.map { val edit = App.INSTANCE.defaultSharedPreferences.edit() when (val value = it.value) { diff --git a/app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt b/app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt index 3d82b5320..898c2d8d3 100644 --- a/app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt +++ b/app/src/main/java/io/legado/app/help/storage/WebDavHelp.kt @@ -3,6 +3,7 @@ package io.legado.app.help.storage import android.content.Context import io.legado.app.App import io.legado.app.help.FileHelp +import io.legado.app.help.ReadBookConfig import io.legado.app.lib.webdav.WebDav import io.legado.app.lib.webdav.http.HttpAuth import io.legado.app.utils.ZipUtils @@ -80,11 +81,14 @@ object WebDavHelp { fun backUpWebDav(path: String) { if (initWebDav()) { - val paths = arrayListOf() - paths.add(path + File.separator + "bookshelf.json") - paths.add(path + File.separator + "bookSource.json") - paths.add(path + File.separator + "rssSource.json") - paths.add(path + File.separator + "replaceRule.json") + val paths = arrayListOf( + path + File.separator + "bookshelf.json", + path + File.separator + "bookSource.json", + path + File.separator + "rssSource.json", + path + File.separator + "replaceRule.json", + path + File.separator + "config.xml", + path + File.separator + ReadBookConfig.readConfigFileName + ) FileHelp.deleteFile(zipFilePath) if (ZipUtils.zipFiles(paths, zipFilePath)) { WebDav(getWebDavUrl() + "legado").makeAsDir() From 8906dd3e82a02c2fc382bf336773a3e8069be26a Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 12 Oct 2019 22:14:41 +0800 Subject: [PATCH 1883/1997] up --- app/src/main/java/io/legado/app/help/storage/Restore.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/help/storage/Restore.kt b/app/src/main/java/io/legado/app/help/storage/Restore.kt index 06543c388..cc18a7238 100644 --- a/app/src/main/java/io/legado/app/help/storage/Restore.kt +++ b/app/src/main/java/io/legado/app/help/storage/Restore.kt @@ -76,6 +76,7 @@ object Restore { File(App.INSTANCE.filesDir.absolutePath + File.separator + ReadBookConfig.readConfigFileName) if (file.exists()) { file.copyTo(configFile, true) + ReadBookConfig.upConfig() } } catch (e: Exception) { e.printStackTrace() From 118f779eaa2ad2b3b9a5d2e9fee036b21a84fc52 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 12 Oct 2019 22:18:57 +0800 Subject: [PATCH 1884/1997] up --- app/src/main/java/io/legado/app/data/AppDatabase.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/AppDatabase.kt b/app/src/main/java/io/legado/app/data/AppDatabase.kt index 630925c89..be65f7730 100644 --- a/app/src/main/java/io/legado/app/data/AppDatabase.kt +++ b/app/src/main/java/io/legado/app/data/AppDatabase.kt @@ -11,8 +11,9 @@ import io.legado.app.data.entities.* @Database( - entities = [Book::class, BookGroup::class, BookSource::class, BookChapter::class, ReplaceRule::class, SearchBook::class, - SearchKeyword::class, SourceCookie::class, RssSource::class, Bookmark::class, RssArticle::class], + entities = [Book::class, BookGroup::class, BookSource::class, BookChapter::class, ReplaceRule::class, + SearchBook::class, SearchKeyword::class, SourceCookie::class, RssSource::class, Bookmark::class, + RssArticle::class], version = 1, exportSchema = true ) From a6b9992c7f0c698ede11e41dc5f80bb6759b2c4f Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 12 Oct 2019 22:27:50 +0800 Subject: [PATCH 1885/1997] up --- .../io/legado/app/ui/main/rss/RssFragment.kt | 26 +---------------- app/src/main/res/drawable/ic_star.xml | 9 ++++++ app/src/main/res/menu/main_rss.xml | 13 +++++---- app/src/main/res/menu/rss_source.xml | 28 ------------------- app/src/main/res/values/strings.xml | 1 + 5 files changed, 19 insertions(+), 58 deletions(-) create mode 100644 app/src/main/res/drawable/ic_star.xml diff --git a/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt b/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt index 0dddd4426..13ac93c20 100644 --- a/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt @@ -1,22 +1,15 @@ package io.legado.app.ui.main.rss import android.os.Bundle -import android.util.Log -import android.view.Gravity import android.view.Menu import android.view.MenuItem import android.view.View -import android.widget.EditText -import android.widget.LinearLayout import androidx.lifecycle.Observer import androidx.recyclerview.widget.GridLayoutManager import io.legado.app.App import io.legado.app.R import io.legado.app.base.BaseFragment import io.legado.app.data.entities.RssSource -import io.legado.app.lib.dialogs.alert -import io.legado.app.lib.dialogs.cancelButton -import io.legado.app.lib.dialogs.yesButton import io.legado.app.lib.theme.ATH import io.legado.app.ui.rss.article.RssArticlesActivity import io.legado.app.ui.rss.source.manage.RssSourceActivity @@ -43,24 +36,7 @@ class RssFragment : BaseFragment(R.layout.fragment_rss), super.onCompatOptionsItemSelected(item) when (item.itemId) { R.id.menu_rss_config -> startActivity() - R.id.menu_rss_add -> { - alert { - title = "快速添加并预览" - val layout = LinearLayout(activity) - val urlEdit = EditText(activity) - urlEdit.hint = "输入RSS地址" - urlEdit.width = 800 - layout.gravity = Gravity.CENTER - layout.addView(urlEdit) - customView = layout - cancelButton{ - Log.i("RSS","Quick Add URL cancel") - } - yesButton{ - Log.i("RSS","Quick Add URL: ${urlEdit.text}") - startActivity("url" to urlEdit.text.toString().trim()) - } - }.show() + R.id.menu_rss_star -> { } } } diff --git a/app/src/main/res/drawable/ic_star.xml b/app/src/main/res/drawable/ic_star.xml new file mode 100644 index 000000000..a2ebf3532 --- /dev/null +++ b/app/src/main/res/drawable/ic_star.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/menu/main_rss.xml b/app/src/main/res/menu/main_rss.xml index f1e39cae2..4403621bd 100644 --- a/app/src/main/res/menu/main_rss.xml +++ b/app/src/main/res/menu/main_rss.xml @@ -1,16 +1,19 @@ - + + app:showAsAction="always" + tools:ignore="AlwaysShowAction" /> \ No newline at end of file diff --git a/app/src/main/res/menu/rss_source.xml b/app/src/main/res/menu/rss_source.xml index c64fea473..f46fd512c 100644 --- a/app/src/main/res/menu/rss_source.xml +++ b/app/src/main/res/menu/rss_source.xml @@ -54,34 +54,6 @@ android:id="@+id/menu_group_manage" android:title="@string/group_manage" /> - - - - - - - - - - - - - - - diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0d4bd3286..21f6e3e19 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -34,6 +34,7 @@ 启用 替换净化-搜索 书架 + 收藏 订阅 全部 最近阅读 From d45abb8ffcbdc9018b313226cd21a4ce8041e37c Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 12 Oct 2019 22:38:04 +0800 Subject: [PATCH 1886/1997] up --- .../io/legado/app/data/dao/RssSourceDao.kt | 6 + .../ui/rss/source/manage/GroupManageDialog.kt | 140 ++++++++++++++++++ .../rss/source/manage/RssSourceViewModel.kt | 44 ++++++ 3 files changed, 190 insertions(+) create mode 100644 app/src/main/java/io/legado/app/ui/rss/source/manage/GroupManageDialog.kt diff --git a/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt b/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt index f280c0fb9..6a70e4666 100644 --- a/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt @@ -51,4 +51,10 @@ interface RssSourceDao { @Query("delete from rssSources where sourceUrl = :sourceUrl") fun delete(sourceUrl: String) + + @get:Query("select * from rssSources where sourceGroup is null or sourceGroup = ''") + val noGroup: List + + @Query("select * from rssSources where sourceGroup like '%' || :group || '%'") + fun getByGroup(group: String): List } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/GroupManageDialog.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/GroupManageDialog.kt new file mode 100644 index 000000000..673cdae33 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/GroupManageDialog.kt @@ -0,0 +1,140 @@ +package io.legado.app.ui.rss.source.manage + +import android.annotation.SuppressLint +import android.content.Context +import android.os.Bundle +import android.util.DisplayMetrics +import android.view.LayoutInflater +import android.view.MenuItem +import android.view.View +import android.view.ViewGroup +import android.widget.EditText +import androidx.appcompat.widget.Toolbar +import androidx.fragment.app.DialogFragment +import androidx.lifecycle.Observer +import androidx.recyclerview.widget.DividerItemDecoration +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import io.legado.app.App +import io.legado.app.R +import io.legado.app.base.adapter.ItemViewHolder +import io.legado.app.base.adapter.SimpleRecyclerAdapter +import io.legado.app.lib.dialogs.alert +import io.legado.app.lib.dialogs.customView +import io.legado.app.lib.dialogs.noButton +import io.legado.app.lib.dialogs.yesButton +import io.legado.app.utils.applyTint +import io.legado.app.utils.getViewModelOfActivity +import io.legado.app.utils.requestInputMethod +import io.legado.app.utils.splitNotBlank +import kotlinx.android.synthetic.main.dialog_edit_text.view.* +import kotlinx.android.synthetic.main.dialog_recycler_view.* +import kotlinx.android.synthetic.main.item_group_manage.view.* +import org.jetbrains.anko.sdk27.listeners.onClick + +class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { + private lateinit var viewModel: RssSourceViewModel + private lateinit var adapter: GroupAdapter + + override fun onStart() { + super.onStart() + val dm = DisplayMetrics() + activity?.windowManager?.defaultDisplay?.getMetrics(dm) + dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.9).toInt()) + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + viewModel = getViewModelOfActivity(RssSourceViewModel::class.java) + return inflater.inflate(R.layout.dialog_recycler_view, container) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + initData() + } + + private fun initData() { + tool_bar.title = getString(R.string.group_manage) + tool_bar.inflateMenu(R.menu.group_manage) + tool_bar.menu.applyTint(requireContext(), false) + tool_bar.setOnMenuItemClickListener(this) + adapter = GroupAdapter(requireContext()) + recycler_view.layoutManager = LinearLayoutManager(requireContext()) + recycler_view.addItemDecoration( + DividerItemDecoration(requireContext(), RecyclerView.VERTICAL) + ) + recycler_view.adapter = adapter + App.db.bookSourceDao().liveGroup().observe(viewLifecycleOwner, Observer { + val groups = linkedSetOf() + it.map { group -> + groups.addAll(group.splitNotBlank(",", ";")) + } + adapter.setItems(groups.toList()) + }) + } + + override fun onMenuItemClick(item: MenuItem?): Boolean { + when (item?.itemId) { + R.id.menu_add -> addGroup() + } + return true + } + + @SuppressLint("InflateParams") + private fun addGroup() { + alert(title = getString(R.string.add_group)) { + var editText: EditText? = null + customView { + layoutInflater.inflate(R.layout.dialog_edit_text, null).apply { + editText = edit_view.apply { + hint = "分组名称" + } + } + } + yesButton { + editText?.text?.toString()?.let { + if (it.isNotBlank()) { + viewModel.addGroup(it) + } + } + } + noButton() + }.show().applyTint().requestInputMethod() + } + + @SuppressLint("InflateParams") + private fun editGroup(group: String) { + alert(title = getString(R.string.group_edit)) { + var editText: EditText? = null + customView { + layoutInflater.inflate(R.layout.dialog_edit_text, null).apply { + editText = edit_view.apply { + hint = "分组名称" + setText(group) + } + } + } + yesButton { + viewModel.upGroup(group, editText?.text?.toString()) + } + noButton() + }.show().applyTint().requestInputMethod() + } + + private inner class GroupAdapter(context: Context) : + SimpleRecyclerAdapter(context, R.layout.item_group_manage) { + + override fun convert(holder: ItemViewHolder, item: String, payloads: MutableList) { + with(holder.itemView) { + tv_group.text = item + tv_edit.onClick { editGroup(item) } + tv_del.onClick { viewModel.delGroup(item) } + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt index 76aa384c0..79e1befe8 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt @@ -1,11 +1,13 @@ package io.legado.app.ui.rss.source.manage import android.app.Application +import android.text.TextUtils import io.legado.app.App import io.legado.app.base.BaseViewModel import io.legado.app.data.entities.RssSource import io.legado.app.utils.GSON import io.legado.app.utils.fromJsonArray +import io.legado.app.utils.splitNotBlank import java.io.File class RssSourceViewModel(application: Application) : BaseViewModel(application) { @@ -53,6 +55,48 @@ class RssSourceViewModel(application: Application) : BaseViewModel(application) } } + + fun addGroup(group: String) { + execute { + val sources = App.db.rssSourceDao().noGroup + sources.map { source -> + source.sourceGroup = group + } + App.db.rssSourceDao().update(*sources.toTypedArray()) + } + } + + fun upGroup(oldGroup: String, newGroup: String?) { + execute { + val sources = App.db.rssSourceDao().getByGroup(oldGroup) + sources.map { source -> + source.sourceGroup?.splitNotBlank(",")?.toHashSet()?.let { + it.remove(oldGroup) + if (!newGroup.isNullOrEmpty()) + it.add(newGroup) + source.sourceGroup = TextUtils.join(",", it) + } + } + App.db.rssSourceDao().update(*sources.toTypedArray()) + } + } + + fun delGroup(group: String) { + execute { + execute { + val sources = App.db.rssSourceDao().getByGroup(group) + sources.map { source -> + source.sourceGroup?.splitNotBlank(",")?.toHashSet()?.let { + it.remove(group) + source.sourceGroup = TextUtils.join(",", it) + } + } + App.db.rssSourceDao().update(*sources.toTypedArray()) + } + } + } + + fun importSourceFromFilePath(path: String) { execute { val file = File(path) From 423f69254b45ad740f9e1e70d0b50c1a7118c886 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 12 Oct 2019 22:49:55 +0800 Subject: [PATCH 1887/1997] up --- .../io/legado/app/ui/rss/source/manage/GroupManageDialog.kt | 2 +- .../io/legado/app/ui/rss/source/manage/RssSourceActivity.kt | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/GroupManageDialog.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/GroupManageDialog.kt index 673cdae33..27c5fd45f 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/manage/GroupManageDialog.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/GroupManageDialog.kt @@ -68,7 +68,7 @@ class GroupManageDialog : DialogFragment(), Toolbar.OnMenuItemClickListener { DividerItemDecoration(requireContext(), RecyclerView.VERTICAL) ) recycler_view.adapter = adapter - App.db.bookSourceDao().liveGroup().observe(viewLifecycleOwner, Observer { + App.db.rssSourceDao().liveGroup().observe(viewLifecycleOwner, Observer { val groups = linkedSetOf() it.map { group -> groups.addAll(group.splitNotBlank(",", ";")) diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt index ad739b5c2..e34a56418 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt @@ -81,6 +81,8 @@ class RssSourceActivity : VMBaseActivity(R.layout.activity_r R.id.menu_import_source_local -> selectFile() R.id.menu_import_source_onLine -> showImportDialog() R.id.menu_import_source_qr -> startActivityForResult(qrRequestCode) + R.id.menu_group_manage -> GroupManageDialog() + .show(supportFragmentManager, "rssGroupManage") } if (item.groupId == R.id.source_group) { search_view.setQuery(item.title, true) From 9172f53ee9acc5a2062f36fa45ccd3807ec7c743 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 13 Oct 2019 12:42:16 +0800 Subject: [PATCH 1888/1997] up --- app/src/main/AndroidManifest.xml | 3 +- .../app/ui/book/read/ReadBookActivity.kt | 30 +++++++++++++++---- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1779f9c25..3e9c54ca2 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -35,7 +35,8 @@ + android:resource="@xml/shortcuts" + android:launchMode="singleTask" /> (R.layout.activity_boo override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { when (keyCode) { KeyEvent.KEYCODE_BACK -> { - if (readAloudStatus == Status.PLAY) { - ReadAloud.pause(this) - toast(R.string.read_aloud_pause) - return true - } + event?.startTracking() } KeyEvent.KEYCODE_VOLUME_UP -> { if (volumeKeyPage(PageDelegate.Direction.PREV)) { @@ -216,6 +213,18 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo return super.onKeyDown(keyCode, event) } + override fun onKeyLongPress(keyCode: Int, event: KeyEvent?): Boolean { + when (keyCode) { + KeyEvent.KEYCODE_BACK -> { + page_view.snackbar("转到后台", "确定") { + startActivity() + } + return true + } + } + return super.onKeyLongPress(keyCode, event) + } + override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean { when (keyCode) { KeyEvent.KEYCODE_VOLUME_UP, KeyEvent.KEYCODE_VOLUME_DOWN -> { @@ -223,6 +232,17 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo return true } } + KeyEvent.KEYCODE_BACK -> { + event?.let { + if ((event.flags and KeyEvent.FLAG_CANCELED_LONG_PRESS == 0)) { + if (readAloudStatus == Status.PLAY) { + ReadAloud.pause(this) + toast(R.string.read_aloud_pause) + return true + } + } + } + } } return super.onKeyUp(keyCode, event) } From eb180060ef58672df8dc60f0cd862d52ab5277cf Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 13 Oct 2019 14:15:30 +0800 Subject: [PATCH 1889/1997] up --- .../io/legado/app/ui/rss/read/ReadRssActivity.kt | 15 +++++++++++++++ app/src/main/res/menu/rss_read.xml | 11 +++++++++++ 2 files changed, 26 insertions(+) create mode 100644 app/src/main/res/menu/rss_read.xml diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt index 5813ec48d..ce7812fe9 100644 --- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt @@ -2,6 +2,8 @@ package io.legado.app.ui.rss.read import android.annotation.SuppressLint import android.os.Bundle +import android.view.Menu +import android.view.MenuItem import android.webkit.WebSettings import android.webkit.WebViewClient import androidx.lifecycle.Observer @@ -23,6 +25,19 @@ class ReadRssActivity : VMBaseActivity(R.layout.activity_rss_r viewModel.initData(intent) } + override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { + menuInflater.inflate(R.menu.rss_read, menu) + return super.onCompatCreateOptionsMenu(menu) + } + + override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.menu_rss_star -> { + } + } + return super.onCompatOptionsItemSelected(item) + } + private fun initWebView() { webView.webViewClient = WebViewClient() webView.settings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW diff --git a/app/src/main/res/menu/rss_read.xml b/app/src/main/res/menu/rss_read.xml new file mode 100644 index 000000000..de8867dd7 --- /dev/null +++ b/app/src/main/res/menu/rss_read.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file From ee8bbb98fc262b38b4bbd9b2dbeecdcded142596 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 13 Oct 2019 14:24:52 +0800 Subject: [PATCH 1890/1997] up --- app/src/main/res/drawable/ic_star_border.xml | 9 +++++++++ app/src/main/res/menu/rss_read.xml | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 app/src/main/res/drawable/ic_star_border.xml diff --git a/app/src/main/res/drawable/ic_star_border.xml b/app/src/main/res/drawable/ic_star_border.xml new file mode 100644 index 000000000..c452e47ec --- /dev/null +++ b/app/src/main/res/drawable/ic_star_border.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/menu/rss_read.xml b/app/src/main/res/menu/rss_read.xml index de8867dd7..29f3087ba 100644 --- a/app/src/main/res/menu/rss_read.xml +++ b/app/src/main/res/menu/rss_read.xml @@ -5,7 +5,7 @@ \ No newline at end of file From de9f04bd2d20d0eb3f92de877e55ed532e49efe0 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 13 Oct 2019 14:25:23 +0800 Subject: [PATCH 1891/1997] up --- app/src/main/res/menu/main_my.xml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/menu/main_my.xml b/app/src/main/res/menu/main_my.xml index e2cceece0..dbac0ab96 100644 --- a/app/src/main/res/menu/main_my.xml +++ b/app/src/main/res/menu/main_my.xml @@ -1,12 +1,14 @@ -
    + app:showAsAction="always" + tools:ignore="AlwaysShowAction" /> Date: Sun, 13 Oct 2019 14:25:59 +0800 Subject: [PATCH 1892/1997] up --- app/src/main/res/menu/main_my.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/menu/main_my.xml b/app/src/main/res/menu/main_my.xml index dbac0ab96..db1161c28 100644 --- a/app/src/main/res/menu/main_my.xml +++ b/app/src/main/res/menu/main_my.xml @@ -12,13 +12,13 @@ From 7bd59483d11a9d8c029e9d97b2c894997a4eb946 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 13 Oct 2019 14:41:38 +0800 Subject: [PATCH 1893/1997] up --- .../legado/app/ui/rss/read/ReadRssActivity.kt | 20 +++++++++++++++++-- .../app/ui/rss/read/ReadRssViewModel.kt | 12 ++++++++--- app/src/main/res/values/strings.xml | 2 ++ 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt index ce7812fe9..cef3e5361 100644 --- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt @@ -18,6 +18,8 @@ class ReadRssActivity : VMBaseActivity(R.layout.activity_rss_r override val viewModel: ReadRssViewModel get() = getViewModel(ReadRssViewModel::class.java) + private var starMenuItem: MenuItem? = null + override fun onActivityCreated(savedInstanceState: Bundle?) { title = intent.getStringExtra("title") initWebView() @@ -27,12 +29,16 @@ class ReadRssActivity : VMBaseActivity(R.layout.activity_rss_r override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { menuInflater.inflate(R.menu.rss_read, menu) + starMenuItem = menu.findItem(R.id.menu_rss_star) + upStarMenu() return super.onCompatCreateOptionsMenu(menu) } override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { - R.id.menu_rss_star -> { + R.id.menu_rss_star -> viewModel.rssArticleLiveData.value?.let { + it.star = !it.star + viewModel.upRssArticle(it) } } return super.onCompatOptionsItemSelected(item) @@ -46,13 +52,14 @@ class ReadRssActivity : VMBaseActivity(R.layout.activity_rss_r @SuppressLint("SetJavaScriptEnabled") private fun initLiveData() { + viewModel.rssArticleLiveData.observe(this, Observer { upStarMenu() }) viewModel.rssSourceLiveData.observe(this, Observer { if (it.enableJs) { webView.settings.javaScriptEnabled = true } }) viewModel.contentLiveData.observe(this, Observer { content -> - viewModel.rssArticle?.let { + viewModel.rssArticleLiveData.value?.let { val url = NetworkUtils.getAbsoluteURL(it.origin, it.link ?: "") if (viewModel.rssSourceLiveData.value?.loadWithBaseUrl == true) { webView.loadDataWithBaseURL( @@ -76,4 +83,13 @@ class ReadRssActivity : VMBaseActivity(R.layout.activity_rss_r }) } + private fun upStarMenu() { + if (viewModel.rssArticleLiveData.value?.star == true) { + starMenuItem?.setIcon(R.drawable.ic_star) + starMenuItem?.setTitle(R.string.y_store_up) + } else { + starMenuItem?.setIcon(R.drawable.ic_star_border) + starMenuItem?.setTitle(R.string.w_store_up) + } + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt index 3e8737a35..0e063d42b 100644 --- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt @@ -12,7 +12,7 @@ import io.legado.app.model.analyzeRule.AnalyzeUrl import io.legado.app.utils.NetworkUtils class ReadRssViewModel(application: Application) : BaseViewModel(application) { - var rssArticle: RssArticle? = null + var rssArticleLiveData = MutableLiveData() val rssSourceLiveData = MutableLiveData() val contentLiveData = MutableLiveData() val urlLiveData = MutableLiveData() @@ -26,8 +26,8 @@ class ReadRssViewModel(application: Application) : BaseViewModel(application) { rssSourceLiveData.postValue(it) } if (origin != null && title != null) { - rssArticle = App.db.rssArticleDao().get(origin, title) - rssArticle?.let { rssArticle -> + App.db.rssArticleDao().get(origin, title)?.let { rssArticle -> + rssArticleLiveData.postValue(rssArticle) if (!rssArticle.description.isNullOrBlank()) { contentLiveData.postValue(rssArticle.description) } else { @@ -66,4 +66,10 @@ class ReadRssViewModel(application: Application) : BaseViewModel(application) { } } } + + fun upRssArticle(rssArticle: RssArticle) { + execute { + App.db.rssArticleDao().update(rssArticle) + } + } } \ 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 21f6e3e19..4347783a4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -35,6 +35,8 @@ 替换净化-搜索 书架 收藏 + 已收藏 + 未收藏 订阅 全部 最近阅读 From 1f3297d08da89d71e2d5ee1ba4099f9d5251b77b Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 13 Oct 2019 14:43:07 +0800 Subject: [PATCH 1894/1997] up --- .../main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt | 2 +- .../main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt index cef3e5361..8c8e0b5a2 100644 --- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt @@ -38,7 +38,7 @@ class ReadRssActivity : VMBaseActivity(R.layout.activity_rss_r when (item.itemId) { R.id.menu_rss_star -> viewModel.rssArticleLiveData.value?.let { it.star = !it.star - viewModel.upRssArticle(it) + viewModel.upRssArticle(it) { upStarMenu() } } } return super.onCompatOptionsItemSelected(item) diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt index 0e063d42b..a8c0d2963 100644 --- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt @@ -67,9 +67,11 @@ class ReadRssViewModel(application: Application) : BaseViewModel(application) { } } - fun upRssArticle(rssArticle: RssArticle) { + fun upRssArticle(rssArticle: RssArticle, success: () -> Unit) { execute { App.db.rssArticleDao().update(rssArticle) + }.onSuccess { + success() } } } \ No newline at end of file From ac07667336fab815caa013c15e74a731fc1bd7e1 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 13 Oct 2019 14:48:25 +0800 Subject: [PATCH 1895/1997] up --- app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt index 8c8e0b5a2..fd493ee3b 100644 --- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt @@ -9,6 +9,8 @@ import android.webkit.WebViewClient import androidx.lifecycle.Observer import io.legado.app.R import io.legado.app.base.VMBaseActivity +import io.legado.app.lib.theme.DrawableUtils +import io.legado.app.lib.theme.primaryTextColor import io.legado.app.utils.NetworkUtils import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_rss_read.* @@ -91,5 +93,6 @@ class ReadRssActivity : VMBaseActivity(R.layout.activity_rss_r starMenuItem?.setIcon(R.drawable.ic_star_border) starMenuItem?.setTitle(R.string.w_store_up) } + DrawableUtils.setTint(starMenuItem?.icon, primaryTextColor) } } \ No newline at end of file From c6d09c7aa17d9f16ebc47a128c5eb3d5d944aa56 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 13 Oct 2019 15:42:42 +0800 Subject: [PATCH 1896/1997] up --- app/src/main/AndroidManifest.xml | 29 ++++----- .../app/receiver/ReceivingSharedActivity.kt | 61 +++++++++++++++++++ .../app/ui/book/search/SearchActivity.kt | 19 +----- .../io/legado/app/ui/config/ConfigFragment.kt | 29 +++++++++ 4 files changed, 107 insertions(+), 31 deletions(-) create mode 100644 app/src/main/java/io/legado/app/receiver/ReceivingSharedActivity.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3e9c54ca2..e2f33b7c6 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -58,20 +58,7 @@ android:windowSoftInputMode="adjustResize|stateHidden" /> - - - - - - - - - - - - + @@ -97,6 +84,20 @@ + + + + + + + + + + + + diff --git a/app/src/main/java/io/legado/app/receiver/ReceivingSharedActivity.kt b/app/src/main/java/io/legado/app/receiver/ReceivingSharedActivity.kt new file mode 100644 index 000000000..807002ef9 --- /dev/null +++ b/app/src/main/java/io/legado/app/receiver/ReceivingSharedActivity.kt @@ -0,0 +1,61 @@ +package io.legado.app.receiver + +import android.content.Intent +import android.os.Build +import android.os.Bundle +import android.os.PersistableBundle +import androidx.appcompat.app.AppCompatActivity +import io.legado.app.ui.book.search.SearchActivity +import io.legado.app.ui.main.MainActivity +import org.jetbrains.anko.startActivity + +class ReceivingSharedActivity : AppCompatActivity() { + + private val receivingType = "text/plain" + + override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) { + super.onCreate(savedInstanceState, persistentState) + initIntent() + } + + private fun initIntent() { + if (Intent.ACTION_SEND == intent.action && intent.type == receivingType) { + intent.getStringExtra(Intent.EXTRA_TEXT)?.let { + if (openUrl(it)) { + startActivity(Pair("key", it)) + } + finish() + } + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M + && Intent.ACTION_PROCESS_TEXT == intent.action + && intent.type == receivingType + ) { + intent.getStringExtra(Intent.EXTRA_PROCESS_TEXT)?.let { + if (openUrl(it)) { + startActivity(Pair("key", it)) + } + finish() + } + } + } + + private fun openUrl(text: String): Boolean { + if (text.isBlank()) { + return false + } + val urls = text.split("\\s".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() + val result = StringBuilder() + for (url in urls) { + if (url.matches("http.+".toRegex())) + result.append("\n").append(url.trim { it <= ' ' }) + } + return if (result.length > 1) { + val intent = Intent() + intent.setClass(this@ReceivingSharedActivity, MainActivity::class.java) + this.startActivity(intent) + false + } else { + true + } + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt index 0812b6706..03b6755b3 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt @@ -1,7 +1,5 @@ package io.legado.app.ui.book.search -import android.content.Intent -import android.os.Build import android.os.Bundle import androidx.appcompat.widget.SearchView import androidx.lifecycle.LiveData @@ -129,21 +127,8 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se } private fun initIntent() { - if (Intent.ACTION_SEND == intent.action && intent.type == "text/plain") { - intent.getStringExtra(Intent.EXTRA_TEXT)?.let { - search_view.setQuery(it, true) - } - } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M - && Intent.ACTION_PROCESS_TEXT == intent.action - && intent.type == "text/plain" - ) { - intent.getStringExtra(Intent.EXTRA_PROCESS_TEXT)?.let { - search_view.setQuery(it, true) - } - } else { - intent.getStringExtra("key")?.let { - search_view.setQuery(it, true) - } + intent.getStringExtra("key")?.let { + search_view.setQuery(it, true) } } diff --git a/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt index fd957e433..f01bd6079 100644 --- a/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt @@ -1,6 +1,8 @@ package io.legado.app.ui.config +import android.content.ComponentName import android.content.SharedPreferences +import android.content.pm.PackageManager import android.os.Bundle import android.view.View import androidx.preference.ListPreference @@ -10,6 +12,7 @@ import io.legado.app.App import io.legado.app.R import io.legado.app.help.BookHelp import io.legado.app.lib.theme.ATH +import io.legado.app.ui.book.search.SearchActivity import io.legado.app.utils.LogUtils import io.legado.app.utils.getPrefString @@ -17,6 +20,12 @@ import io.legado.app.utils.getPrefString class ConfigFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChangeListener, SharedPreferences.OnSharedPreferenceChangeListener { + private val packageManager = App.INSTANCE.packageManager + private val componentName = ComponentName( + App.INSTANCE, + SearchActivity::class.java.name + ) + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { addPreferencesFromResource(R.xml.pref_config) bindPreferenceSummaryToValue(findPreference("downloadPath")) @@ -41,6 +50,9 @@ class ConfigFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChange when (key) { "downloadPath" -> BookHelp.upDownloadPath() "recordLog" -> LogUtils.upLevel() + "process_text" -> sharedPreferences?.let { + setProcessTextEnable(it.getBoolean("process_text", true)) + } } } @@ -77,4 +89,21 @@ class ConfigFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChange } } + private fun isProcessTextEnabled(): Boolean { + return packageManager.getComponentEnabledSetting(componentName) != PackageManager.COMPONENT_ENABLED_STATE_DISABLED + } + + private fun setProcessTextEnable(enable: Boolean) { + if (enable) { + packageManager.setComponentEnabledSetting( + componentName, + PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP + ) + } else { + packageManager.setComponentEnabledSetting( + componentName, + PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP + ) + } + } } \ No newline at end of file From b3d30a4d06b07813661c658a487abe2014a421d2 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 13 Oct 2019 15:43:44 +0800 Subject: [PATCH 1897/1997] up --- app/src/main/AndroidManifest.xml | 2 +- .../{ReceivingSharedActivity.kt => SharedReceiverActivity.kt} | 4 ++-- app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) rename app/src/main/java/io/legado/app/receiver/{ReceivingSharedActivity.kt => SharedReceiverActivity.kt} (93%) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e2f33b7c6..dc9705e30 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -85,7 +85,7 @@ diff --git a/app/src/main/java/io/legado/app/receiver/ReceivingSharedActivity.kt b/app/src/main/java/io/legado/app/receiver/SharedReceiverActivity.kt similarity index 93% rename from app/src/main/java/io/legado/app/receiver/ReceivingSharedActivity.kt rename to app/src/main/java/io/legado/app/receiver/SharedReceiverActivity.kt index 807002ef9..11ff854e5 100644 --- a/app/src/main/java/io/legado/app/receiver/ReceivingSharedActivity.kt +++ b/app/src/main/java/io/legado/app/receiver/SharedReceiverActivity.kt @@ -9,7 +9,7 @@ import io.legado.app.ui.book.search.SearchActivity import io.legado.app.ui.main.MainActivity import org.jetbrains.anko.startActivity -class ReceivingSharedActivity : AppCompatActivity() { +class SharedReceiverActivity : AppCompatActivity() { private val receivingType = "text/plain" @@ -51,7 +51,7 @@ class ReceivingSharedActivity : AppCompatActivity() { } return if (result.length > 1) { val intent = Intent() - intent.setClass(this@ReceivingSharedActivity, MainActivity::class.java) + intent.setClass(this@SharedReceiverActivity, MainActivity::class.java) this.startActivity(intent) false } else { diff --git a/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt index f01bd6079..faf414e9c 100644 --- a/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt @@ -12,7 +12,7 @@ import io.legado.app.App import io.legado.app.R import io.legado.app.help.BookHelp import io.legado.app.lib.theme.ATH -import io.legado.app.ui.book.search.SearchActivity +import io.legado.app.receiver.SharedReceiverActivity import io.legado.app.utils.LogUtils import io.legado.app.utils.getPrefString @@ -23,7 +23,7 @@ class ConfigFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChange private val packageManager = App.INSTANCE.packageManager private val componentName = ComponentName( App.INSTANCE, - SearchActivity::class.java.name + SharedReceiverActivity::class.java.name ) override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { From 91dfb5a15b729684b4929c9873a0bdb1e8581203 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 13 Oct 2019 15:45:08 +0800 Subject: [PATCH 1898/1997] up --- app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt index faf414e9c..5269ac291 100644 --- a/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/ConfigFragment.kt @@ -15,6 +15,7 @@ import io.legado.app.lib.theme.ATH import io.legado.app.receiver.SharedReceiverActivity import io.legado.app.utils.LogUtils import io.legado.app.utils.getPrefString +import io.legado.app.utils.putPrefBoolean class ConfigFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChangeListener, @@ -27,6 +28,7 @@ class ConfigFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChange ) override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + putPrefBoolean("process_text", isProcessTextEnabled()) addPreferencesFromResource(R.xml.pref_config) bindPreferenceSummaryToValue(findPreference("downloadPath")) } From 885a437389f5331199f948245a624a3a4668aec3 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 13 Oct 2019 16:01:05 +0800 Subject: [PATCH 1899/1997] up --- .../main/java/io/legado/app/receiver/SharedReceiverActivity.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/receiver/SharedReceiverActivity.kt b/app/src/main/java/io/legado/app/receiver/SharedReceiverActivity.kt index 11ff854e5..bdda26939 100644 --- a/app/src/main/java/io/legado/app/receiver/SharedReceiverActivity.kt +++ b/app/src/main/java/io/legado/app/receiver/SharedReceiverActivity.kt @@ -16,6 +16,7 @@ class SharedReceiverActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) { super.onCreate(savedInstanceState, persistentState) initIntent() + finish() } private fun initIntent() { From 865e6acd7a2180c5bf6f46f2fc382b7c5fb790bf Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 13 Oct 2019 18:04:22 +0800 Subject: [PATCH 1900/1997] up --- .../java/io/legado/app/receiver/SharedReceiverActivity.kt | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/receiver/SharedReceiverActivity.kt b/app/src/main/java/io/legado/app/receiver/SharedReceiverActivity.kt index bdda26939..39118dc5f 100644 --- a/app/src/main/java/io/legado/app/receiver/SharedReceiverActivity.kt +++ b/app/src/main/java/io/legado/app/receiver/SharedReceiverActivity.kt @@ -3,7 +3,6 @@ package io.legado.app.receiver import android.content.Intent import android.os.Build import android.os.Bundle -import android.os.PersistableBundle import androidx.appcompat.app.AppCompatActivity import io.legado.app.ui.book.search.SearchActivity import io.legado.app.ui.main.MainActivity @@ -13,8 +12,8 @@ class SharedReceiverActivity : AppCompatActivity() { private val receivingType = "text/plain" - override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) { - super.onCreate(savedInstanceState, persistentState) + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) initIntent() finish() } @@ -25,7 +24,6 @@ class SharedReceiverActivity : AppCompatActivity() { if (openUrl(it)) { startActivity(Pair("key", it)) } - finish() } } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Intent.ACTION_PROCESS_TEXT == intent.action @@ -35,7 +33,6 @@ class SharedReceiverActivity : AppCompatActivity() { if (openUrl(it)) { startActivity(Pair("key", it)) } - finish() } } } From 357bc48453ce8bff0dda19fa42b95c00bb23d5a4 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 13 Oct 2019 18:09:18 +0800 Subject: [PATCH 1901/1997] up --- .../java/io/legado/app/receiver/SharedReceiverActivity.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/receiver/SharedReceiverActivity.kt b/app/src/main/java/io/legado/app/receiver/SharedReceiverActivity.kt index 39118dc5f..e6b78f0f5 100644 --- a/app/src/main/java/io/legado/app/receiver/SharedReceiverActivity.kt +++ b/app/src/main/java/io/legado/app/receiver/SharedReceiverActivity.kt @@ -48,9 +48,7 @@ class SharedReceiverActivity : AppCompatActivity() { result.append("\n").append(url.trim { it <= ' ' }) } return if (result.length > 1) { - val intent = Intent() - intent.setClass(this@SharedReceiverActivity, MainActivity::class.java) - this.startActivity(intent) + startActivity() false } else { true From d359655a1c176026a7de3df72f92dbd9471040aa Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 13 Oct 2019 18:43:54 +0800 Subject: [PATCH 1902/1997] up --- .../java/io/legado/app/model/analyzeRule/AnalyzeRule.kt | 2 +- .../main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt index 328d6cab4..efdb0397e 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt @@ -534,7 +534,7 @@ class AnalyzeRule(private var book: BaseBook? = null) { */ fun ajax(urlStr: String): String? { return try { - val analyzeUrl = AnalyzeUrl(urlStr, null, null, null, null, null) + val analyzeUrl = AnalyzeUrl(urlStr, null, null, null, baseUrl, book) val call = analyzeUrl.getResponse() val response = call.execute() response.body() diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt index bc45a46f9..c857134c2 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt @@ -7,7 +7,7 @@ import io.legado.app.constant.AppConst.SCRIPT_ENGINE import io.legado.app.constant.Pattern.EXP_PATTERN import io.legado.app.data.api.IHttpGetApi import io.legado.app.data.api.IHttpPostApi -import io.legado.app.data.entities.Book +import io.legado.app.data.entities.BaseBook import io.legado.app.help.http.HttpHelper import io.legado.app.utils.* import kotlinx.coroutines.Deferred @@ -35,7 +35,7 @@ class AnalyzeUrl( page: Int? = null, headerMapF: Map? = null, baseUrl: String? = null, - book: Book? = null + book: BaseBook? = null ) { companion object { private val pagePattern = Pattern.compile("<(.*?)>") @@ -80,7 +80,7 @@ class AnalyzeUrl( /** * 替换关键字,页数,JS */ - private fun replaceKeyPageJs(key: String?, page: Int?, book: Book?) { + private fun replaceKeyPageJs(key: String?, page: Int?, book: BaseBook?) { //page page?.let { val matcher = pagePattern.matcher(ruleUrl) From 401b55883dd33b1eab115a47f7a4bb277a808993 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 13 Oct 2019 19:15:35 +0800 Subject: [PATCH 1903/1997] up --- .../app/model/analyzeRule/AnalyzeUrl.kt | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt index c857134c2..5608f6e9d 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt @@ -5,6 +5,7 @@ import android.text.TextUtils import androidx.annotation.Keep import io.legado.app.constant.AppConst.SCRIPT_ENGINE import io.legado.app.constant.Pattern.EXP_PATTERN +import io.legado.app.constant.Pattern.JS_PATTERN import io.legado.app.data.api.IHttpGetApi import io.legado.app.data.api.IHttpPostApi import io.legado.app.data.entities.BaseBook @@ -72,11 +73,45 @@ class AnalyzeUrl( } headerMapF?.let { headerMap.putAll(it) } //替换参数 + analyzeJs(key, page, book) replaceKeyPageJs(key, page, book) //处理URL initUrl() } + private fun analyzeJs(key: String?, page: Int?, book: BaseBook?) { + val ruleList = arrayListOf() + var start = 0 + var tmp: String + val jsMatcher = JS_PATTERN.matcher(ruleUrl) + while (jsMatcher.find()) { + if (jsMatcher.start() > start) { + tmp = + ruleUrl.substring(start, jsMatcher.start()).replace("\n", "").trim { it <= ' ' } + if (!TextUtils.isEmpty(tmp)) { + ruleList.add(tmp) + } + } + ruleList.add(jsMatcher.group()) + start = jsMatcher.end() + } + if (ruleUrl.length > start) { + tmp = ruleUrl.substring(start).replace("\n", "").trim { it <= ' ' } + if (!TextUtils.isEmpty(tmp)) { + ruleList.add(tmp) + } + } + for (rule in ruleList) { + var ruleStr = rule + if (ruleStr.startsWith("")) { + ruleStr = ruleStr.substring(4, ruleStr.lastIndexOf("<")) + ruleUrl = evalJS(ruleStr, ruleUrl, page, key, book) as String + } else { + ruleUrl = ruleStr.replace("@result", ruleUrl) + } + } + } + /** * 替换关键字,页数,JS */ @@ -186,6 +221,27 @@ class AnalyzeUrl( } } + /** + * 执行JS + */ + @Throws(Exception::class) + private fun evalJS( + jsStr: String, + result: Any?, + page: Int?, + key: String?, + book: BaseBook? + ): Any { + val bindings = SimpleBindings() + bindings["java"] = this + bindings["page"] = page + bindings["key"] = key + bindings["book"] = book + bindings["result"] = result + bindings["baseUrl"] = baseUrl + return SCRIPT_ENGINE.eval(jsStr, bindings) + } + enum class Method { GET, POST } From fc64ceed60da3adc34687e377b654b48896bbd23 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 13 Oct 2019 19:28:41 +0800 Subject: [PATCH 1904/1997] up --- .../io/legado/app/model/analyzeRule/AnalyzeUrl.kt | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt index 5608f6e9d..c2ecf699b 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt @@ -103,11 +103,16 @@ class AnalyzeUrl( } for (rule in ruleList) { var ruleStr = rule - if (ruleStr.startsWith("")) { - ruleStr = ruleStr.substring(4, ruleStr.lastIndexOf("<")) - ruleUrl = evalJS(ruleStr, ruleUrl, page, key, book) as String - } else { - ruleUrl = ruleStr.replace("@result", ruleUrl) + when { + ruleStr.startsWith("") -> { + ruleStr = ruleStr.substring(4, ruleStr.lastIndexOf("<")) + ruleUrl = evalJS(ruleStr, ruleUrl, page, key, book) as String + } + ruleStr.startsWith("@js", true) -> { + ruleStr = ruleStr.substring(4) + ruleUrl = evalJS(ruleStr, ruleUrl, page, key, book) as String + } + else -> ruleUrl = ruleStr } } } From c323a438998f1a127ac74e08e77bb5c36ad4bf21 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 13 Oct 2019 19:31:46 +0800 Subject: [PATCH 1905/1997] up --- app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt index c2ecf699b..714b49418 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt @@ -112,7 +112,7 @@ class AnalyzeUrl( ruleStr = ruleStr.substring(4) ruleUrl = evalJS(ruleStr, ruleUrl, page, key, book) as String } - else -> ruleUrl = ruleStr + else -> ruleUrl = ruleStr.replace("@result", ruleUrl) } } } From c1c5b3b90ad01dcff2519d1c7b3c5ea3771b5462 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 13 Oct 2019 19:43:07 +0800 Subject: [PATCH 1906/1997] up --- .../io/legado/app/ui/main/MainViewModel.kt | 39 +++++++++++-------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt b/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt index 992ed6a16..ca5c2f2f9 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt @@ -7,6 +7,7 @@ import io.legado.app.constant.BookType import io.legado.app.constant.Bus import io.legado.app.help.storage.Restore import io.legado.app.model.WebBook +import io.legado.app.utils.LogUtils import io.legado.app.utils.postEvent import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.delay @@ -25,25 +26,29 @@ class MainViewModel(application: Application) : BaseViewModel(application) { execute { App.db.bookDao().allBooks.forEach { book -> if (book.origin != BookType.local) { - App.db.bookSourceDao().getBookSource(book.origin)?.let { bookSource -> - synchronized(this) { - updateList.add(book.bookUrl) - postEvent(Bus.UP_BOOK, book.bookUrl) - } - WebBook(bookSource).getChapterList(book) - .onSuccess(IO) { - it?.let { - App.db.bookDao().update(book) - App.db.bookChapterDao().delByBook(book.bookUrl) - App.db.bookChapterDao().insert(*it.toTypedArray()) - } + if (!updateList.contains(book.bookUrl)) { + App.db.bookSourceDao().getBookSource(book.origin)?.let { bookSource -> + synchronized(this) { + updateList.add(book.bookUrl) + LogUtils.d("updateAdd", book.name) + postEvent(Bus.UP_BOOK, book.bookUrl) } - .onFinally { - synchronized(this) { - updateList.remove(book.bookUrl) - postEvent(Bus.UP_BOOK, book.bookUrl) + WebBook(bookSource).getChapterList(book) + .onSuccess(IO) { + it?.let { + App.db.bookDao().update(book) + App.db.bookChapterDao().delByBook(book.bookUrl) + App.db.bookChapterDao().insert(*it.toTypedArray()) + } } - } + .onFinally { + synchronized(this) { + updateList.remove(book.bookUrl) + LogUtils.d("updateRemove", book.name) + postEvent(Bus.UP_BOOK, book.bookUrl) + } + } + } } } delay(50) From e441680da10ecaa328f6b96ee5e7d6f663421dfe Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 13 Oct 2019 19:49:06 +0800 Subject: [PATCH 1907/1997] up --- .../io/legado/app/ui/main/bookshelf/BooksFragment.kt | 8 ++------ .../io/legado/app/ui/main/bookshelf/BooksViewModel.kt | 9 --------- 2 files changed, 2 insertions(+), 15 deletions(-) delete mode 100644 app/src/main/java/io/legado/app/ui/main/bookshelf/BooksViewModel.kt diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt index 47d168562..f867948d1 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt @@ -11,7 +11,7 @@ import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.App import io.legado.app.R -import io.legado.app.base.VMBaseFragment +import io.legado.app.base.BaseFragment import io.legado.app.constant.Bus import io.legado.app.data.entities.Book import io.legado.app.lib.theme.ATH @@ -19,14 +19,13 @@ import io.legado.app.lib.theme.accentColor import io.legado.app.ui.book.info.BookInfoActivity import io.legado.app.ui.book.read.ReadBookActivity import io.legado.app.ui.main.MainViewModel -import io.legado.app.utils.getViewModel import io.legado.app.utils.getViewModelOfActivity import io.legado.app.utils.observeEvent import kotlinx.android.synthetic.main.fragment_books.* import org.jetbrains.anko.startActivity -class BooksFragment : VMBaseFragment(R.layout.fragment_books), +class BooksFragment : BaseFragment(R.layout.fragment_books), BooksAdapter.CallBack { companion object { @@ -39,9 +38,6 @@ class BooksFragment : VMBaseFragment(R.layout.fragment_books), } } - override val viewModel: BooksViewModel - get() = getViewModel(BooksViewModel::class.java) - private lateinit var activityViewModel: MainViewModel private lateinit var booksAdapter: BooksAdapter private var bookshelfLiveData: LiveData>? = null diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksViewModel.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksViewModel.kt deleted file mode 100644 index 19fa12c04..000000000 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksViewModel.kt +++ /dev/null @@ -1,9 +0,0 @@ -package io.legado.app.ui.main.bookshelf - -import android.app.Application -import io.legado.app.base.BaseViewModel - - -class BooksViewModel(application: Application) : BaseViewModel(application) { - -} \ No newline at end of file From d75b049fcfdfaa95281e6bf5f107a1c35231024e Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 13 Oct 2019 19:52:52 +0800 Subject: [PATCH 1908/1997] up --- .../main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt index 5152278ca..3bdbaf24e 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt @@ -11,6 +11,7 @@ import io.legado.app.constant.BookType import io.legado.app.data.entities.Book import io.legado.app.help.ImageLoader import io.legado.app.lib.theme.ThemeStore +import io.legado.app.utils.LogUtils import io.legado.app.utils.getCompatColor import io.legado.app.utils.invisible import kotlinx.android.synthetic.main.item_bookshelf_list.view.* @@ -38,6 +39,7 @@ class BooksAdapter(private val callBack: CallBack) : for (i in 0 until itemCount) { getItem(i)?.let { if (it.bookUrl == bookUrl) { + LogUtils.d("up", it.name) notifyItemChanged(i) return } From 799a8380157e7f705d77df7072e0a9b6c790c6e9 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 13 Oct 2019 19:57:46 +0800 Subject: [PATCH 1909/1997] up --- app/src/main/java/io/legado/app/utils/LogUtils.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/utils/LogUtils.kt b/app/src/main/java/io/legado/app/utils/LogUtils.kt index 3dd8f3dfe..1662974a7 100644 --- a/app/src/main/java/io/legado/app/utils/LogUtils.kt +++ b/app/src/main/java/io/legado/app/utils/LogUtils.kt @@ -34,7 +34,7 @@ object LogUtils { FileHelp.getFolder(logFolder) FileHandler( logFolder + File.separator + "app.log", - 2048, + 10240, 10 ).apply { formatter = object : Formatter() { From 43dce8abe4bc59656c7b6a823cee70d169d24053 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 13 Oct 2019 20:25:52 +0800 Subject: [PATCH 1910/1997] up --- .../java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt | 6 ++---- .../java/io/legado/app/ui/main/explore/ExploreAdapter.kt | 2 ++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt index 3bdbaf24e..9adb7c1ca 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt @@ -10,9 +10,8 @@ import io.legado.app.R import io.legado.app.constant.BookType import io.legado.app.data.entities.Book import io.legado.app.help.ImageLoader -import io.legado.app.lib.theme.ThemeStore +import io.legado.app.lib.theme.ATH import io.legado.app.utils.LogUtils -import io.legado.app.utils.getCompatColor import io.legado.app.utils.invisible import kotlinx.android.synthetic.main.item_bookshelf_list.view.* import org.jetbrains.anko.sdk27.listeners.onClick @@ -63,11 +62,10 @@ class BooksAdapter(private val callBack: CallBack) : class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { init { - itemView.setBackgroundColor(ThemeStore.backgroundColor(itemView.context)) + ATH.applyBackgroundTint(itemView) } fun bind(book: Book, callBack: CallBack) = with(itemView) { - this.setBackgroundColor(context.getCompatColor(R.color.background)) tv_name.text = book.name tv_author.text = book.author tv_read.text = book.durChapterTitle diff --git a/app/src/main/java/io/legado/app/ui/main/explore/ExploreAdapter.kt b/app/src/main/java/io/legado/app/ui/main/explore/ExploreAdapter.kt index 0bc6c0891..15c4ecfdb 100644 --- a/app/src/main/java/io/legado/app/ui/main/explore/ExploreAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/explore/ExploreAdapter.kt @@ -9,6 +9,7 @@ import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.data.entities.BookSource import io.legado.app.help.coroutine.Coroutine +import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.accentColor import io.legado.app.utils.ACache import io.legado.app.utils.gone @@ -28,6 +29,7 @@ class ExploreAdapter(context: Context, private val scope: CoroutineScope, val ca override fun convert(holder: ItemViewHolder, item: BookSource, payloads: MutableList) { with(holder.itemView) { if (payloads.isEmpty()) { + ATH.applyBackgroundTint(ll_title) tv_name.text = item.bookSourceName ll_title.onClick { val oldEx = exIndex From 0b934074d9a39da4d4cdae461a26fdb052b12c48 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 13 Oct 2019 20:35:29 +0800 Subject: [PATCH 1911/1997] up --- .../main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt index 9adb7c1ca..1884e0c85 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt @@ -82,6 +82,7 @@ class BooksAdapter(private val callBack: CallBack) : callBack.openBookInfo(book) true } + LogUtils.d(book.name, callBack.isUpdate(book.bookUrl).toString()) if (book.origin != BookType.local && callBack.isUpdate(book.bookUrl)) { bv_unread.invisible() rl_loading.show() From 198a0bd5027722dbaa30e02a6ff65a194b76edda Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 13 Oct 2019 21:49:57 +0800 Subject: [PATCH 1912/1997] up --- app/src/main/java/io/legado/app/ui/main/MainViewModel.kt | 3 --- .../main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt b/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt index ca5c2f2f9..564939819 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt @@ -7,7 +7,6 @@ import io.legado.app.constant.BookType import io.legado.app.constant.Bus import io.legado.app.help.storage.Restore import io.legado.app.model.WebBook -import io.legado.app.utils.LogUtils import io.legado.app.utils.postEvent import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.delay @@ -30,7 +29,6 @@ class MainViewModel(application: Application) : BaseViewModel(application) { App.db.bookSourceDao().getBookSource(book.origin)?.let { bookSource -> synchronized(this) { updateList.add(book.bookUrl) - LogUtils.d("updateAdd", book.name) postEvent(Bus.UP_BOOK, book.bookUrl) } WebBook(bookSource).getChapterList(book) @@ -44,7 +42,6 @@ class MainViewModel(application: Application) : BaseViewModel(application) { .onFinally { synchronized(this) { updateList.remove(book.bookUrl) - LogUtils.d("updateRemove", book.name) postEvent(Bus.UP_BOOK, book.bookUrl) } } diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt index 1884e0c85..ccb7731d6 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt @@ -38,7 +38,6 @@ class BooksAdapter(private val callBack: CallBack) : for (i in 0 until itemCount) { getItem(i)?.let { if (it.bookUrl == bookUrl) { - LogUtils.d("up", it.name) notifyItemChanged(i) return } @@ -82,11 +81,12 @@ class BooksAdapter(private val callBack: CallBack) : callBack.openBookInfo(book) true } - LogUtils.d(book.name, callBack.isUpdate(book.bookUrl).toString()) if (book.origin != BookType.local && callBack.isUpdate(book.bookUrl)) { + LogUtils.d(book.name, "loading") bv_unread.invisible() rl_loading.show() } else { + LogUtils.d(book.name, "loadingHide") rl_loading.hide() bv_unread.setBadgeCount(book.getUnreadChapterNum()) bv_unread.setHighlight(book.lastCheckCount > 0) From ae3bcf98ec7a40ee9eed4030b48f4c900265a02b Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 14 Oct 2019 08:33:50 +0800 Subject: [PATCH 1913/1997] up --- .../app/ui/main/bookshelf/BooksAdapter.kt | 34 +++++++++++++++++-- .../app/ui/main/bookshelf/BooksFragment.kt | 6 ++-- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt index ccb7731d6..00e8a81a8 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt @@ -28,9 +28,10 @@ class BooksAdapter(private val callBack: CallBack) : override fun areContentsTheSame(oldItem: Book, newItem: Book): Boolean = oldItem.durChapterTitle == newItem.durChapterTitle + && oldItem.name == newItem.name + && oldItem.getDisplayCover() == newItem.getDisplayCover() && oldItem.latestChapterTitle == newItem.latestChapterTitle - && oldItem.durChapterTime == newItem.durChapterTime - && oldItem.lastCheckTime == newItem.lastCheckTime + && oldItem.durChapterTitle == newItem.durChapterTitle } } @@ -38,7 +39,7 @@ class BooksAdapter(private val callBack: CallBack) : for (i in 0 until itemCount) { getItem(i)?.let { if (it.bookUrl == bookUrl) { - notifyItemChanged(i) + notifyItemChanged(i, 5) return } } @@ -52,6 +53,16 @@ class BooksAdapter(private val callBack: CallBack) : ) } + override fun onBindViewHolder(holder: MyViewHolder, position: Int, payloads: MutableList) { + if (payloads.isEmpty()) { + super.onBindViewHolder(holder, position, payloads) + } else { + currentList?.get(position)?.let { + holder.bind(it, callBack, payloads[0]) + } + } + } + override fun onBindViewHolder(holder: MyViewHolder, position: Int) { currentList?.get(position)?.let { holder.bind(it, callBack) @@ -92,6 +103,23 @@ class BooksAdapter(private val callBack: CallBack) : bv_unread.setHighlight(book.lastCheckCount > 0) } } + + fun bind(book: Book, callBack: CallBack, payload: Any) = with(itemView) { + when (payload) { + 5 -> { + if (book.origin != BookType.local && callBack.isUpdate(book.bookUrl)) { + LogUtils.d(book.name, "loading") + bv_unread.invisible() + rl_loading.show() + } else { + LogUtils.d(book.name, "loadingHide") + rl_loading.hide() + bv_unread.setBadgeCount(book.getUnreadChapterNum()) + bv_unread.setHighlight(book.lastCheckCount > 0) + } + } + } + } } interface CallBack { diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt index f867948d1..6575d4933 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt @@ -78,15 +78,15 @@ class BooksFragment : BaseFragment(R.layout.fragment_books), when (groupId) { -1 -> { bookshelfLiveData = - LivePagedListBuilder(App.db.bookDao().observeAll(), 10).build() + LivePagedListBuilder(App.db.bookDao().observeAll(), 100).build() } -2 -> { bookshelfLiveData = - LivePagedListBuilder(App.db.bookDao().observeLocal(), 10).build() + LivePagedListBuilder(App.db.bookDao().observeLocal(), 100).build() } -3 -> { bookshelfLiveData = - LivePagedListBuilder(App.db.bookDao().observeAudio(), 10).build() + LivePagedListBuilder(App.db.bookDao().observeAudio(), 100).build() } else -> { bookshelfLiveData = From 61144577b06358f51ab1c3c7d7af8c89ee4ba43b Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 15 Oct 2019 10:52:55 +0800 Subject: [PATCH 1914/1997] up --- app/src/main/java/io/legado/app/data/dao/BookChapterDao.kt | 1 - .../java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt | 7 +++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/data/dao/BookChapterDao.kt b/app/src/main/java/io/legado/app/data/dao/BookChapterDao.kt index 8ed58cadf..9a4db0cb1 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookChapterDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookChapterDao.kt @@ -25,7 +25,6 @@ interface BookChapterDao { @Insert(onConflict = OnConflictStrategy.REPLACE) fun insert(vararg bookChapter: BookChapter) - @Query("delete from chapters where bookUrl = :bookUrl") fun delByBook(bookUrl: String) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt index 00e8a81a8..a6de9bad6 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt @@ -32,6 +32,13 @@ class BooksAdapter(private val callBack: CallBack) : && oldItem.getDisplayCover() == newItem.getDisplayCover() && oldItem.latestChapterTitle == newItem.latestChapterTitle && oldItem.durChapterTitle == newItem.durChapterTitle + + override fun getChangePayload(oldItem: Book, newItem: Book): Any? { + if (oldItem.bookUrl != newItem.bookUrl) { + return null + } + return super.getChangePayload(oldItem, newItem) + } } } From 4e97ef576dafca35477ff00a11651d212f3d1083 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 15 Oct 2019 11:30:21 +0800 Subject: [PATCH 1915/1997] up --- .../io/legado/app/ui/widget/anima/RotateLoading.kt | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/anima/RotateLoading.kt b/app/src/main/java/io/legado/app/ui/widget/anima/RotateLoading.kt index 9aac789c2..82df0124f 100644 --- a/app/src/main/java/io/legado/app/ui/widget/anima/RotateLoading.kt +++ b/app/src/main/java/io/legado/app/ui/widget/anima/RotateLoading.kt @@ -208,15 +208,8 @@ class RotateLoading : View { private fun stopAnimator() { animate().cancel() - animate().scaleX(0.0f) - .scaleY(0.0f) - .setListener(object : AnimatorListenerAdapter() { - override fun onAnimationEnd(animation: Animator) { - isStarted = false - visibility = GONE - } - }) - .start() + isStarted = false + visibility = GONE } companion object { From fff0788b8d1892fa1f2de332ac46d45791bfb0bf Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 15 Oct 2019 11:54:51 +0800 Subject: [PATCH 1916/1997] up --- .../io/legado/app/ui/main/bookshelf/BooksFragment.kt | 8 ++++++-- .../io/legado/app/ui/main/bookshelf/BooksViewModel.kt | 10 ++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/main/bookshelf/BooksViewModel.kt diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt index 6575d4933..e9b5051b2 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt @@ -11,7 +11,7 @@ import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.App import io.legado.app.R -import io.legado.app.base.BaseFragment +import io.legado.app.base.VMBaseFragment import io.legado.app.constant.Bus import io.legado.app.data.entities.Book import io.legado.app.lib.theme.ATH @@ -19,15 +19,19 @@ import io.legado.app.lib.theme.accentColor import io.legado.app.ui.book.info.BookInfoActivity import io.legado.app.ui.book.read.ReadBookActivity import io.legado.app.ui.main.MainViewModel +import io.legado.app.utils.getViewModel import io.legado.app.utils.getViewModelOfActivity import io.legado.app.utils.observeEvent import kotlinx.android.synthetic.main.fragment_books.* import org.jetbrains.anko.startActivity -class BooksFragment : BaseFragment(R.layout.fragment_books), +class BooksFragment : VMBaseFragment(R.layout.fragment_books), BooksAdapter.CallBack { + override val viewModel: BooksViewModel + get() = getViewModel(BooksViewModel::class.java) + companion object { fun newInstance(position: Int): BooksFragment { return BooksFragment().apply { diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksViewModel.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksViewModel.kt new file mode 100644 index 000000000..ef6d08fbb --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksViewModel.kt @@ -0,0 +1,10 @@ +package io.legado.app.ui.main.bookshelf + +import android.app.Application +import io.legado.app.base.BaseViewModel + + +class BooksViewModel(application: Application) : BaseViewModel(application) { + + +} \ No newline at end of file From 091d2508fd98c1eede9d38f94f569cdb9d76493a Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 15 Oct 2019 13:17:04 +0800 Subject: [PATCH 1917/1997] up --- .../app/base/adapter/CommonRecyclerAdapter.kt | 13 +- .../java/io/legado/app/data/dao/BookDao.kt | 9 +- .../book/source/manage/BookSourceActivity.kt | 2 +- .../ui/changesource/ChangeSourceViewModel.kt | 2 +- .../app/ui/main/bookshelf/BooksAdapter.kt | 131 ++++++------------ .../app/ui/main/bookshelf/BooksFragment.kt | 35 ++--- .../app/ui/replacerule/ReplaceRuleActivity.kt | 2 +- .../ui/rss/source/manage/RssSourceActivity.kt | 2 +- 8 files changed, 58 insertions(+), 138 deletions(-) diff --git a/app/src/main/java/io/legado/app/base/adapter/CommonRecyclerAdapter.kt b/app/src/main/java/io/legado/app/base/adapter/CommonRecyclerAdapter.kt index a83b97374..41c709057 100644 --- a/app/src/main/java/io/legado/app/base/adapter/CommonRecyclerAdapter.kt +++ b/app/src/main/java/io/legado/app/base/adapter/CommonRecyclerAdapter.kt @@ -122,18 +122,7 @@ abstract class CommonRecyclerAdapter(protected val context: Context) : Rec } } - fun setItemsNoNotify(items: List?) { - synchronized(lock) { - if (this.items.isNotEmpty()) { - this.items.clear() - } - if (items != null) { - this.items.addAll(items) - } - } - } - - fun setItems(items: List?) { + fun setItems(items: List?, notify: Boolean = true) { synchronized(lock) { if (this.items.isNotEmpty()) { this.items.clear() diff --git a/app/src/main/java/io/legado/app/data/dao/BookDao.kt b/app/src/main/java/io/legado/app/data/dao/BookDao.kt index c74172c37..70091e69d 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookDao.kt @@ -1,7 +1,6 @@ package io.legado.app.data.dao import androidx.lifecycle.LiveData -import androidx.paging.DataSource import androidx.room.* import io.legado.app.constant.BookType import io.legado.app.data.entities.Book @@ -10,16 +9,16 @@ import io.legado.app.data.entities.Book interface BookDao { @Query("SELECT * FROM books order by durChapterTime desc") - fun observeAll(): DataSource.Factory + fun observeAll(): LiveData> @Query("SELECT * FROM books WHERE type = ${BookType.audio} order by durChapterTime desc") - fun observeAudio(): DataSource.Factory + fun observeAudio(): LiveData> @Query("SELECT * FROM books WHERE origin = '${BookType.local}' order by durChapterTime desc") - fun observeLocal(): DataSource.Factory + fun observeLocal(): LiveData> @Query("SELECT * FROM books WHERE `group` = :group") - fun observeByGroup(group: Int): DataSource.Factory + fun observeByGroup(group: Int): LiveData> @Query("SELECT bookUrl FROM books WHERE `group` = :group") fun observeUrlsByGroup(group: Int): LiveData> diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt index db9405b0d..ec1359b63 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt @@ -147,7 +147,7 @@ class BookSourceActivity : VMBaseActivity(R.layout.activity search_view.queryHint = getString(R.string.search_book_source_num, it.size) val diffResult = DiffUtil .calculateDiff(DiffCallBack(adapter.getItems(), it)) - adapter.setItemsNoNotify(it) + adapter.setItems(it, false) diffResult.dispatchUpdatesTo(adapter) }) } diff --git a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt index 44483aa07..2a81ae398 100644 --- a/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/changesource/ChangeSourceViewModel.kt @@ -44,7 +44,7 @@ class ChangeSourceViewModel(application: Application) : BaseViewModel(applicatio val diffResult = DiffUtil.calculateDiff(DiffCallBack(it.getItems(), books)) withContext(Main) { synchronized(this) { - it.setItemsNoNotify(books) + it.setItems(books, false) diffResult.dispatchUpdatesTo(it) } } diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt index a6de9bad6..9b3ec6530 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksAdapter.kt @@ -1,12 +1,9 @@ package io.legado.app.ui.main.bookshelf -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.paging.PagedListAdapter -import androidx.recyclerview.widget.DiffUtil -import androidx.recyclerview.widget.RecyclerView +import android.content.Context import io.legado.app.R +import io.legado.app.base.adapter.ItemViewHolder +import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.constant.BookType import io.legado.app.data.entities.Book import io.legado.app.help.ImageLoader @@ -17,116 +14,66 @@ import kotlinx.android.synthetic.main.item_bookshelf_list.view.* import org.jetbrains.anko.sdk27.listeners.onClick import org.jetbrains.anko.sdk27.listeners.onLongClick -class BooksAdapter(private val callBack: CallBack) : - PagedListAdapter(DIFF_CALLBACK) { +class BooksAdapter(context: Context, private val callBack: CallBack) : + SimpleRecyclerAdapter(context, R.layout.item_bookshelf_list) { - companion object { - @JvmField - val DIFF_CALLBACK = object : DiffUtil.ItemCallback() { - override fun areItemsTheSame(oldItem: Book, newItem: Book): Boolean = - oldItem.bookUrl == newItem.bookUrl - - override fun areContentsTheSame(oldItem: Book, newItem: Book): Boolean = - oldItem.durChapterTitle == newItem.durChapterTitle - && oldItem.name == newItem.name - && oldItem.getDisplayCover() == newItem.getDisplayCover() - && oldItem.latestChapterTitle == newItem.latestChapterTitle - && oldItem.durChapterTitle == newItem.durChapterTitle - - override fun getChangePayload(oldItem: Book, newItem: Book): Any? { - if (oldItem.bookUrl != newItem.bookUrl) { - return null - } - return super.getChangePayload(oldItem, newItem) - } - } - } - - fun notification(bookUrl: String) { - for (i in 0 until itemCount) { - getItem(i)?.let { - if (it.bookUrl == bookUrl) { - notifyItemChanged(i, 5) - return - } - } - } - } - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { - return MyViewHolder( - LayoutInflater.from(parent.context) - .inflate(R.layout.item_bookshelf_list, parent, false) - ) - } - - override fun onBindViewHolder(holder: MyViewHolder, position: Int, payloads: MutableList) { + override fun convert(holder: ItemViewHolder, item: Book, payloads: MutableList) = + with(holder.itemView) { if (payloads.isEmpty()) { - super.onBindViewHolder(holder, position, payloads) - } else { - currentList?.get(position)?.let { - holder.bind(it, callBack, payloads[0]) - } - } - } - - override fun onBindViewHolder(holder: MyViewHolder, position: Int) { - currentList?.get(position)?.let { - holder.bind(it, callBack) - } - } - - class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { - - init { - ATH.applyBackgroundTint(itemView) - } - - fun bind(book: Book, callBack: CallBack) = with(itemView) { - tv_name.text = book.name - tv_author.text = book.author - tv_read.text = book.durChapterTitle - tv_last.text = book.latestChapterTitle - book.getDisplayCover()?.let { + ATH.applyBackgroundTint(this) + tv_name.text = item.name + tv_author.text = item.author + tv_read.text = item.durChapterTitle + tv_last.text = item.latestChapterTitle + item.getDisplayCover()?.let { ImageLoader.load(context, it)//Glide自动识别http://和file:// .placeholder(R.drawable.image_cover_default) .error(R.drawable.image_cover_default) .centerCrop() .setAsDrawable(iv_cover) } - itemView.onClick { callBack.open(book) } - itemView.onLongClick { - callBack.openBookInfo(book) + onClick { callBack.open(item) } + onLongClick { + callBack.openBookInfo(item) true } - if (book.origin != BookType.local && callBack.isUpdate(book.bookUrl)) { - LogUtils.d(book.name, "loading") + if (item.origin != BookType.local && callBack.isUpdate(item.bookUrl)) { + LogUtils.d(item.name, "loading") bv_unread.invisible() rl_loading.show() } else { - LogUtils.d(book.name, "loadingHide") + LogUtils.d(item.name, "loadingHide") rl_loading.hide() - bv_unread.setBadgeCount(book.getUnreadChapterNum()) - bv_unread.setHighlight(book.lastCheckCount > 0) + bv_unread.setBadgeCount(item.getUnreadChapterNum()) + bv_unread.setHighlight(item.lastCheckCount > 0) } - } - - fun bind(book: Book, callBack: CallBack, payload: Any) = with(itemView) { - when (payload) { + } else { + when (payloads[0]) { 5 -> { - if (book.origin != BookType.local && callBack.isUpdate(book.bookUrl)) { - LogUtils.d(book.name, "loading") + if (item.origin != BookType.local && callBack.isUpdate(item.bookUrl)) { + LogUtils.d(item.name, "loading") bv_unread.invisible() rl_loading.show() } else { - LogUtils.d(book.name, "loadingHide") + LogUtils.d(item.name, "loadingHide") rl_loading.hide() - bv_unread.setBadgeCount(book.getUnreadChapterNum()) - bv_unread.setHighlight(book.lastCheckCount > 0) + bv_unread.setBadgeCount(item.getUnreadChapterNum()) + bv_unread.setHighlight(item.lastCheckCount > 0) } } } } + } + + fun notification(bookUrl: String) { + for (i in 0 until itemCount) { + getItem(i)?.let { + if (it.bookUrl == bookUrl) { + notifyItemChanged(i, 5) + return + } + } + } } interface CallBack { diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt index e9b5051b2..9c20f526b 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt @@ -5,8 +5,6 @@ import android.view.View import androidx.core.content.ContextCompat import androidx.lifecycle.LiveData import androidx.lifecycle.Observer -import androidx.paging.LivePagedListBuilder -import androidx.paging.PagedList import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.App @@ -44,7 +42,7 @@ class BooksFragment : VMBaseFragment(R.layout.fragment_books), private lateinit var activityViewModel: MainViewModel private lateinit var booksAdapter: BooksAdapter - private var bookshelfLiveData: LiveData>? = null + private var bookshelfLiveData: LiveData>? = null private var groupId = -1 override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -73,36 +71,23 @@ class BooksFragment : VMBaseFragment(R.layout.fragment_books), this.setDrawable(it) } }) - booksAdapter = BooksAdapter(this) + booksAdapter = BooksAdapter(requireContext(), this) rv_bookshelf.adapter = booksAdapter } private fun upRecyclerData() { bookshelfLiveData?.removeObservers(this) - when (groupId) { - -1 -> { - bookshelfLiveData = - LivePagedListBuilder(App.db.bookDao().observeAll(), 100).build() - } - -2 -> { - bookshelfLiveData = - LivePagedListBuilder(App.db.bookDao().observeLocal(), 100).build() - } - -3 -> { - bookshelfLiveData = - LivePagedListBuilder(App.db.bookDao().observeAudio(), 100).build() - } - else -> { - bookshelfLiveData = - LivePagedListBuilder( - App.db.bookDao().observeByGroup(groupId), - 10 - ).build() - } + bookshelfLiveData = when (groupId) { + -1 -> App.db.bookDao().observeAll() + -2 -> App.db.bookDao().observeLocal() + -3 -> App.db.bookDao().observeAudio() + else -> App.db.bookDao().observeByGroup(groupId) } bookshelfLiveData?.observe( this, - Observer { pageList -> booksAdapter.submitList(pageList) }) + Observer { + booksAdapter.setItems(it) + }) } override fun open(book: Book) { diff --git a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt index ad7d9e28a..e335bfb1b 100644 --- a/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt +++ b/app/src/main/java/io/legado/app/ui/replacerule/ReplaceRuleActivity.kt @@ -104,7 +104,7 @@ class ReplaceRuleActivity : VMBaseActivity(R.layout.activi } replaceRuleLiveData?.observe(this, Observer { val diffResult = DiffUtil.calculateDiff(DiffCallBack(adapter.getItems(), it)) - adapter.setItemsNoNotify(it) + adapter.setItems(it, false) diffResult.dispatchUpdatesTo(adapter) }) } diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt index e34a56418..dce6b21cf 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt @@ -152,7 +152,7 @@ class RssSourceActivity : VMBaseActivity(R.layout.activity_r sourceLiveData?.observe(this, Observer { val diffResult = DiffUtil .calculateDiff(DiffCallBack(adapter.getItems(), it)) - adapter.setItemsNoNotify(it) + adapter.setItems(it, false) diffResult.dispatchUpdatesTo(adapter) }) } From 2a53b9475429ee5ad6a293a8f839c61158c6a676 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 15 Oct 2019 13:33:12 +0800 Subject: [PATCH 1918/1997] up --- .../ui/main/bookshelf/BooksDiffCallBack.kt | 33 +++++++++++++++++++ .../app/ui/main/bookshelf/BooksFragment.kt | 4 +++ 2 files changed, 37 insertions(+) create mode 100644 app/src/main/java/io/legado/app/ui/main/bookshelf/BooksDiffCallBack.kt diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksDiffCallBack.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksDiffCallBack.kt new file mode 100644 index 000000000..c5b7d7c03 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksDiffCallBack.kt @@ -0,0 +1,33 @@ +package io.legado.app.ui.main.bookshelf + +import androidx.recyclerview.widget.DiffUtil +import io.legado.app.data.entities.Book + +class BooksDiffCallBack(private val oldItems: List, private val newItems: List) : + DiffUtil.Callback() { + + + override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { + return oldItems[oldItemPosition].bookUrl == newItems[newItemPosition].bookUrl + } + + override fun getOldListSize(): Int { + return oldItems.size + } + + override fun getNewListSize(): Int { + return newItems.size + } + + override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { + val oldItem = oldItems[oldItemPosition] + val newItem = newItems[newItemPosition] + return oldItem.name == newItem.name + && oldItem.durChapterTitle == newItem.durChapterTitle + && oldItem.latestChapterTitle == newItem.latestChapterTitle + && oldItem.getDisplayCover() == newItem.getDisplayCover() + && oldItem.getUnreadChapterNum() == newItem.getUnreadChapterNum() + && oldItem.lastCheckCount == newItem.lastCheckCount + } + +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt index 9c20f526b..f65337b52 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt @@ -5,6 +5,7 @@ import android.view.View import androidx.core.content.ContextCompat import androidx.lifecycle.LiveData import androidx.lifecycle.Observer +import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.App @@ -86,7 +87,10 @@ class BooksFragment : VMBaseFragment(R.layout.fragment_books), bookshelfLiveData?.observe( this, Observer { + val diffResult = + DiffUtil.calculateDiff(BooksDiffCallBack(booksAdapter.getItems(), it)) booksAdapter.setItems(it) + diffResult.dispatchUpdatesTo(booksAdapter) }) } From 1056b17076dbc9e52fad0350d2a8cd304fbb04b0 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 15 Oct 2019 13:34:54 +0800 Subject: [PATCH 1919/1997] up --- .../main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt index f65337b52..3a4657dbf 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BooksFragment.kt @@ -89,7 +89,7 @@ class BooksFragment : VMBaseFragment(R.layout.fragment_books), Observer { val diffResult = DiffUtil.calculateDiff(BooksDiffCallBack(booksAdapter.getItems(), it)) - booksAdapter.setItems(it) + booksAdapter.setItems(it, false) diffResult.dispatchUpdatesTo(booksAdapter) }) } From f94d9503d7bb741012276177c8b562ee015d0bff Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 15 Oct 2019 13:41:59 +0800 Subject: [PATCH 1920/1997] up --- .../java/io/legado/app/base/adapter/CommonRecyclerAdapter.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/base/adapter/CommonRecyclerAdapter.kt b/app/src/main/java/io/legado/app/base/adapter/CommonRecyclerAdapter.kt index 41c709057..a87416469 100644 --- a/app/src/main/java/io/legado/app/base/adapter/CommonRecyclerAdapter.kt +++ b/app/src/main/java/io/legado/app/base/adapter/CommonRecyclerAdapter.kt @@ -130,7 +130,9 @@ abstract class CommonRecyclerAdapter(protected val context: Context) : Rec if (items != null) { this.items.addAll(items) } - notifyDataSetChanged() + if (notify) { + notifyDataSetChanged() + } } } From fcac3946c8a4e95fbe4cf43a61cc2667dbddc6f3 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 15 Oct 2019 13:44:51 +0800 Subject: [PATCH 1921/1997] up --- app/src/main/java/io/legado/app/ui/main/MainViewModel.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt b/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt index 564939819..4c7bce35a 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt @@ -33,13 +33,17 @@ class MainViewModel(application: Application) : BaseViewModel(application) { } WebBook(bookSource).getChapterList(book) .onSuccess(IO) { + synchronized(this) { + updateList.remove(book.bookUrl) + postEvent(Bus.UP_BOOK, book.bookUrl) + } it?.let { App.db.bookDao().update(book) App.db.bookChapterDao().delByBook(book.bookUrl) App.db.bookChapterDao().insert(*it.toTypedArray()) } } - .onFinally { + .onError { synchronized(this) { updateList.remove(book.bookUrl) postEvent(Bus.UP_BOOK, book.bookUrl) From 9f8a98860e1008d6e1f718fb43f04b9311d59754 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 15 Oct 2019 13:46:51 +0800 Subject: [PATCH 1922/1997] up --- app/src/main/java/io/legado/app/ui/main/MainViewModel.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt b/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt index 4c7bce35a..d1146aae8 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt @@ -48,6 +48,7 @@ class MainViewModel(application: Application) : BaseViewModel(application) { updateList.remove(book.bookUrl) postEvent(Bus.UP_BOOK, book.bookUrl) } + it.printStackTrace() } } } From 08a2c5356afbddb14931a4248fcfc3abd7847e33 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 15 Oct 2019 13:55:30 +0800 Subject: [PATCH 1923/1997] up --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 22922cbbe..192a428ad 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -93,7 +93,7 @@ dependencies { implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0' implementation 'androidx.viewpager2:viewpager2:1.0.0-beta04' - implementation 'com.google.android.material:material:1.1.0-alpha10' + implementation 'com.google.android.material:material:1.1.0-beta01' implementation 'com.google.android:flexbox:1.1.0' //lifecycle From 8c957d586170caba6fd6d3c718955130242ea03c Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 15 Oct 2019 14:09:20 +0800 Subject: [PATCH 1924/1997] up --- .../recycler/RecyclerViewAtViewPager2.kt | 41 +++++++++++++++++++ app/src/main/res/layout/fragment_books.xml | 2 +- 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/io/legado/app/ui/widget/recycler/RecyclerViewAtViewPager2.kt diff --git a/app/src/main/java/io/legado/app/ui/widget/recycler/RecyclerViewAtViewPager2.kt b/app/src/main/java/io/legado/app/ui/widget/recycler/RecyclerViewAtViewPager2.kt new file mode 100644 index 000000000..79132f627 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/recycler/RecyclerViewAtViewPager2.kt @@ -0,0 +1,41 @@ +package io.legado.app.ui.widget.recycler + +import android.content.Context +import android.util.AttributeSet +import android.view.MotionEvent +import androidx.recyclerview.widget.RecyclerView +import kotlin.math.abs + +class RecyclerViewAtViewPager2(context: Context, attrs: AttributeSet?) : + RecyclerView(context, attrs) { + + private var startX: Int = 0 + private var startY: Int = 0 + + override fun dispatchTouchEvent(ev: MotionEvent): Boolean { + when (ev.action) { + MotionEvent.ACTION_DOWN -> { + startX = ev.x.toInt() + startY = ev.y.toInt() + parent.requestDisallowInterceptTouchEvent(true) + } + MotionEvent.ACTION_MOVE -> { + val endX = ev.x.toInt() + val endY = ev.y.toInt() + val disX = abs(endX - startX) + val disY = abs(endY - startY) + if (disX > disY) { + parent.requestDisallowInterceptTouchEvent(canScrollHorizontally(startX - endX)) + } else { + parent.requestDisallowInterceptTouchEvent(canScrollVertically(startY - endY)) + } + } + MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> parent.requestDisallowInterceptTouchEvent( + false + ) + } + return super.dispatchTouchEvent(ev) + } + + +} \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_books.xml b/app/src/main/res/layout/fragment_books.xml index 30f8ce74c..3eb83f71d 100644 --- a/app/src/main/res/layout/fragment_books.xml +++ b/app/src/main/res/layout/fragment_books.xml @@ -4,7 +4,7 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - From f75450e9f52ca4d4e3546052da9ce3be6f8601f8 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 15 Oct 2019 14:53:17 +0800 Subject: [PATCH 1925/1997] up --- app/src/main/assets/bg/中国红.png | Bin 49779 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 app/src/main/assets/bg/中国红.png diff --git a/app/src/main/assets/bg/中国红.png b/app/src/main/assets/bg/中国红.png deleted file mode 100644 index 32eedc092edbbb907b2516c4b40c87a3d80e8093..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49779 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±QnKRN0yS#3C`1vi|9B>j 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 From 9517a66c4fa10c1ae5ff4683403c622547dd1fa8 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 15 Oct 2019 15:26:38 +0800 Subject: [PATCH 1926/1997] up --- .../main/java/io/legado/app/ui/widget/page/curl/CurlView.kt | 5 +++++ .../app/ui/widget/page/delegate/SimulationPageDelegate.kt | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlView.kt b/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlView.kt index 086894434..a6089c4bc 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlView.kt @@ -1,6 +1,7 @@ package io.legado.app.ui.widget.page.curl import android.content.Context +import android.graphics.PixelFormat import android.graphics.PointF import android.opengl.GLSurfaceView import android.util.AttributeSet @@ -114,6 +115,10 @@ class CurlView : GLSurfaceView, View.OnTouchListener, CurlRenderer.Observer { * Initialize method. */ init { + setEGLConfigChooser(8, 8, 8, 8, 16, 0) + holder.setFormat(PixelFormat.TRANSLUCENT) + setZOrderOnTop(true) + setRenderer(mRenderer) renderMode = RENDERMODE_WHEN_DIRTY setOnTouchListener(this) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt index f3533de53..8468b3aef 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt @@ -15,7 +15,7 @@ class SimulationPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageVi pageView.addView(pageView.curlView) pageView.curlView?.mPageProvider = PageProvider() pageView.curlView?.setSizeChangedObserver(SizeChangedObserver()) - pageView.curlView?.currentIndex = 1 + pageView.curlView?.currentIndex = 0 } } @@ -54,7 +54,7 @@ class SimulationPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageVi // 定义书籍尺寸的变化监听器 private inner class SizeChangedObserver : CurlView.SizeChangedObserver { - override fun onSizeChanged(w: Int, h: Int) { + override fun onSizeChanged(width: Int, height: Int) { pageView.curlView?.setViewMode(CurlView.SHOW_ONE_PAGE) pageView.curlView?.setMargins(0f, 0f, 0f, 0f) } From 6f2f506bee1b9ff4576c0d81c9cbccc38c5d940f Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 15 Oct 2019 16:00:34 +0800 Subject: [PATCH 1927/1997] up --- .../java/io/legado/app/help/ReadBookConfig.kt | 50 ++++++++----------- 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index 8c0266c63..8c7d4ae18 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -20,36 +20,40 @@ import java.io.IOException */ object ReadBookConfig { const val readConfigFileName = "readConfig.json" - val configList: ArrayList = arrayListOf() - .apply { - upConfig(this) - } + val configList: ArrayList = arrayListOf() var styleSelect get() = App.INSTANCE.getPrefInt("readStyleSelect") set(value) = App.INSTANCE.putPrefInt("readStyleSelect", value) var bg: Drawable? = null + init { + upConfig() + } + + @Synchronized fun getConfig(index: Int = styleSelect): Config { + if (configList.size < 5) { + reset() + } return configList[index] } - fun upConfig(list: ArrayList = configList) { + fun upConfig() { val configFile = File(App.INSTANCE.filesDir.absolutePath + File.separator + readConfigFileName) val json = if (configFile.exists()) { - String(configFile.readBytes()) + configFile.readText() } else { String(App.INSTANCE.assets.open(readConfigFileName).readBytes()) } try { GSON.fromJsonArray(json)?.let { - list.clear() - list.addAll(it) - } + configList.clear() + configList.addAll(it) + } ?: reset() } catch (e: Exception) { - list.clear() - list.addAll(getOnError()) + reset() } } @@ -78,27 +82,13 @@ object ReadBookConfig { } } - fun reset() { - try { - val json = String(App.INSTANCE.assets.open(readConfigFileName).readBytes()) - GSON.fromJsonArray(json)?.let { - configList.clear() - configList.addAll(it) - } - } catch (e: Exception) { + private fun reset() { + val json = String(App.INSTANCE.assets.open(readConfigFileName).readBytes()) + GSON.fromJsonArray(json)?.let { configList.clear() - configList.addAll(getOnError()) + configList.addAll(it) } - } - - private fun getOnError(): ArrayList { - val list = arrayListOf() - list.add(Config()) - list.add(Config()) - list.add(Config()) - list.add(Config()) - list.add(Config()) - return list + save() } data class Config( From c8040a4278507b532de6688d45aeafb2a520b214 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 15 Oct 2019 16:07:13 +0800 Subject: [PATCH 1928/1997] up --- app/src/main/java/io/legado/app/help/ReadBookConfig.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt index 8c7d4ae18..328433c3c 100644 --- a/app/src/main/java/io/legado/app/help/ReadBookConfig.kt +++ b/app/src/main/java/io/legado/app/help/ReadBookConfig.kt @@ -20,6 +20,8 @@ import java.io.IOException */ object ReadBookConfig { const val readConfigFileName = "readConfig.json" + private val configFilePath = + App.INSTANCE.filesDir.absolutePath + File.separator + readConfigFileName val configList: ArrayList = arrayListOf() var styleSelect @@ -40,8 +42,7 @@ object ReadBookConfig { } fun upConfig() { - val configFile = - File(App.INSTANCE.filesDir.absolutePath + File.separator + readConfigFileName) + val configFile = File(configFilePath) val json = if (configFile.exists()) { configFile.readText() } else { @@ -68,8 +69,7 @@ object ReadBookConfig { fun save() { GlobalScope.launch(IO) { val json = GSON.toJson(configList) - val configFile = - File(App.INSTANCE.filesDir.absolutePath + File.separator + readConfigFileName) + val configFile = File(configFilePath) //获取流并存储 try { BufferedWriter(FileWriter(configFile)).use { writer -> From d53bdbd581d93ae055cda96716bac7840f882672 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 15 Oct 2019 17:38:32 +0800 Subject: [PATCH 1929/1997] up --- .../app/ui/widget/page/delegate/SimulationPageDelegate.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt index 8468b3aef..2a33d1615 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt @@ -9,6 +9,8 @@ import io.legado.app.utils.screenshot class SimulationPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageView) { + private var pageCount = 0 + init { pageView.curlView ?: let { pageView.curlView = CurlView(pageView.context) @@ -41,7 +43,7 @@ class SimulationPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageVi private inner class PageProvider : CurlView.PageProvider { override val pageCount: Int - get() = 3 + get() = this@SimulationPageDelegate.pageCount override fun updatePage(page: CurlPage, width: Int, height: Int, index: Int) { when (index) { From c90e50c99cfa5650f9ff936dd3dd0d146f7619a4 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 15 Oct 2019 19:55:09 +0800 Subject: [PATCH 1930/1997] up --- .../app/ui/widget/page/delegate/SimulationPageDelegate.kt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt index 2a33d1615..d7ee69211 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/SimulationPageDelegate.kt @@ -9,15 +9,13 @@ import io.legado.app.utils.screenshot class SimulationPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageView) { - private var pageCount = 0 - init { pageView.curlView ?: let { pageView.curlView = CurlView(pageView.context) pageView.addView(pageView.curlView) pageView.curlView?.mPageProvider = PageProvider() pageView.curlView?.setSizeChangedObserver(SizeChangedObserver()) - pageView.curlView?.currentIndex = 0 + pageView.curlView?.currentIndex = 1 } } @@ -43,7 +41,7 @@ class SimulationPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageVi private inner class PageProvider : CurlView.PageProvider { override val pageCount: Int - get() = this@SimulationPageDelegate.pageCount + get() = 3 override fun updatePage(page: CurlPage, width: Int, height: Int, index: Int) { when (index) { From da73619a28ae10f0c7c304bf0e34321b671e9739 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 15 Oct 2019 19:59:48 +0800 Subject: [PATCH 1931/1997] up --- .../app/ui/widget/page/curl/CurlMesh.java | 47 +++++++++---------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlMesh.java b/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlMesh.java index 3c733588c..f0e5a3fff 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlMesh.java +++ b/app/src/main/java/io/legado/app/ui/widget/page/curl/CurlMesh.java @@ -830,7 +830,7 @@ public class CurlMesh { private int mCapacity; private int mSize; - public Array(int capacity) { + Array(int capacity) { mCapacity = capacity; mArray = new Object[capacity]; } @@ -839,9 +839,7 @@ public class CurlMesh { if (index < 0 || index > mSize || mSize >= mCapacity) { throw new IndexOutOfBoundsException(); } - for (int i = mSize; i > index; --i) { - mArray[i] = mArray[i - 1]; - } + System.arraycopy(mArray, index, mArray, index + 1, mSize - index); mArray[index] = item; ++mSize; } @@ -880,9 +878,8 @@ public class CurlMesh { throw new IndexOutOfBoundsException(); } T item = (T) mArray[index]; - for (int i = index; i < mSize - 1; ++i) { - mArray[i] = mArray[i + 1]; - } + if (mSize - 1 - index >= 0) + System.arraycopy(mArray, index + 1, mArray, index, mSize - 1 - index); --mSize; return item; } @@ -897,34 +894,34 @@ public class CurlMesh { * Holder for shadow vertex information. */ private class ShadowVertex { - public double mPenumbraColor; - public double mPenumbraX; - public double mPenumbraY; - public double mPosX; - public double mPosY; - public double mPosZ; + double mPenumbraColor; + double mPenumbraX; + double mPenumbraY; + double mPosX; + double mPosY; + double mPosZ; } /** * Holder for vertex information. */ private class Vertex { - public int mColor; - public float mColorFactor; - public double mPenumbraX; - public double mPenumbraY; - public double mPosX; - public double mPosY; - public double mPosZ; - public double mTexX; - public double mTexY; - - public Vertex() { + int mColor; + float mColorFactor; + double mPenumbraX; + double mPenumbraY; + double mPosX; + double mPosY; + double mPosZ; + double mTexX; + double mTexY; + + Vertex() { mPosX = mPosY = mPosZ = mTexX = mTexY = 0; mColorFactor = 1.0f; } - public void rotateZ(double theta) { + void rotateZ(double theta) { double cos = Math.cos(theta); double sin = Math.sin(theta); double x = mPosX * cos + mPosY * sin; From f2c2046b75b5a371f4425ee41f12920dc33684a3 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 17 Oct 2019 14:41:38 +0800 Subject: [PATCH 1932/1997] up --- .../java/io/legado/app/utils/DateUtils.kt | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 app/src/main/java/io/legado/app/utils/DateUtils.kt diff --git a/app/src/main/java/io/legado/app/utils/DateUtils.kt b/app/src/main/java/io/legado/app/utils/DateUtils.kt new file mode 100644 index 000000000..dc1c81f62 --- /dev/null +++ b/app/src/main/java/io/legado/app/utils/DateUtils.kt @@ -0,0 +1,30 @@ +package io.legado.app.utils + +import android.annotation.SuppressLint +import java.text.ParseException +import java.text.SimpleDateFormat +import java.util.* + + +object DateUtils { + + /** + * @Description: 任意时间字符串转换成时间,无需指定解析模板 + * */ + @SuppressLint("SimpleDateFormat") + @Throws(ParseException::class) + fun parseStringToDate(date: String): Date { + val result: Date + var parse = date.replaceFirst("[0-9]{4}([^0-9]?)".toRegex(), "yyyy$1") + parse = parse.replaceFirst("^[0-9]{2}([^0-9]?)".toRegex(), "yy$1") + parse = parse.replaceFirst("([^0-9]?)[0-9]{1,2}([^0-9]?)".toRegex(), "$1MM$2") + parse = parse.replaceFirst("([^0-9]?)[0-9]{1,2}( ?)".toRegex(), "$1dd$2") + parse = parse.replaceFirst("( )[0-9]{1,2}([^0-9]?)".toRegex(), "$1HH$2") + parse = parse.replaceFirst("([^0-9]?)[0-9]{1,2}([^0-9]?)".toRegex(), "$1mm$2") + parse = parse.replaceFirst("([^0-9]?)[0-9]{1,2}([^0-9]?)".toRegex(), "$1ss$2") + val format = SimpleDateFormat(parse) + result = format.parse(date) + return result + } + +} \ No newline at end of file From 74ec2e08935c55a499115522f2bf37462f4edb59 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 18 Oct 2019 09:32:59 +0800 Subject: [PATCH 1933/1997] up --- app/build.gradle | 8 ++-- .../main/java/io/legado/app/help/BookHelp.kt | 7 ++-- .../java/io/legado/app/utils/DateUtils.kt | 30 --------------- .../io/legado/app/utils/StringExtensions.kt | 38 ------------------- 4 files changed, 9 insertions(+), 74 deletions(-) delete mode 100644 app/src/main/java/io/legado/app/utils/DateUtils.kt diff --git a/app/build.gradle b/app/build.gradle index 192a428ad..1bb42e0eb 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -86,13 +86,13 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" //androidX - implementation 'androidx.core:core-ktx:1.2.0-alpha04' + implementation 'androidx.core:core-ktx:1.2.0-beta01' implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'androidx.media:media:1.1.0' implementation 'androidx.preference:preference:1.1.0' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0' - implementation 'androidx.viewpager2:viewpager2:1.0.0-beta04' + implementation 'androidx.viewpager2:viewpager2:1.0.0-beta05' implementation 'com.google.android.material:material:1.1.0-beta01' implementation 'com.google.android:flexbox:1.1.0' @@ -102,7 +102,7 @@ dependencies { implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version" //room - def room_version = '2.1.0' + def room_version = '2.2.0' implementation "androidx.room:room-runtime:$room_version" kapt "androidx.room:room-compiler:$room_version" @@ -148,4 +148,6 @@ dependencies { //颜色选择 implementation 'com.jaredrummler:colorpicker:1.1.0' + implementation 'org.apache.commons:commons-lang3:3.9' + implementation 'org.apache.commons:commons-text:1.8' } diff --git a/app/src/main/java/io/legado/app/help/BookHelp.kt b/app/src/main/java/io/legado/app/help/BookHelp.kt index 6567dbb5b..ef1feedbe 100644 --- a/app/src/main/java/io/legado/app/help/BookHelp.kt +++ b/app/src/main/java/io/legado/app/help/BookHelp.kt @@ -6,7 +6,7 @@ import io.legado.app.data.entities.BookChapter import io.legado.app.data.entities.ReplaceRule import io.legado.app.utils.getPrefInt import io.legado.app.utils.getPrefString -import io.legado.app.utils.similarity +import org.apache.commons.text.similarity.JaccardSimilarity import java.io.File import kotlin.math.max import kotlin.math.min @@ -94,13 +94,14 @@ object BookHelp { if (chapters.size > index && title == chapters[index].title) { return index } - var similarity = 0F + var similarity = 0.0 var newIndex = index val start = max(index - 20, 0) val end = min(index + 20, chapters.lastIndex) + val jaccardSimilarity = JaccardSimilarity() if (start < end) { for (i in start..end) { - val s = title.similarity(chapters[i].title) + val s = jaccardSimilarity.apply(title, chapters[i].title) if (s > similarity) { similarity = s newIndex = i diff --git a/app/src/main/java/io/legado/app/utils/DateUtils.kt b/app/src/main/java/io/legado/app/utils/DateUtils.kt deleted file mode 100644 index dc1c81f62..000000000 --- a/app/src/main/java/io/legado/app/utils/DateUtils.kt +++ /dev/null @@ -1,30 +0,0 @@ -package io.legado.app.utils - -import android.annotation.SuppressLint -import java.text.ParseException -import java.text.SimpleDateFormat -import java.util.* - - -object DateUtils { - - /** - * @Description: 任意时间字符串转换成时间,无需指定解析模板 - * */ - @SuppressLint("SimpleDateFormat") - @Throws(ParseException::class) - fun parseStringToDate(date: String): Date { - val result: Date - var parse = date.replaceFirst("[0-9]{4}([^0-9]?)".toRegex(), "yyyy$1") - parse = parse.replaceFirst("^[0-9]{2}([^0-9]?)".toRegex(), "yy$1") - parse = parse.replaceFirst("([^0-9]?)[0-9]{1,2}([^0-9]?)".toRegex(), "$1MM$2") - parse = parse.replaceFirst("([^0-9]?)[0-9]{1,2}( ?)".toRegex(), "$1dd$2") - parse = parse.replaceFirst("( )[0-9]{1,2}([^0-9]?)".toRegex(), "$1HH$2") - parse = parse.replaceFirst("([^0-9]?)[0-9]{1,2}([^0-9]?)".toRegex(), "$1mm$2") - parse = parse.replaceFirst("([^0-9]?)[0-9]{1,2}([^0-9]?)".toRegex(), "$1ss$2") - val format = SimpleDateFormat(parse) - result = format.parse(date) - return result - } - -} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/utils/StringExtensions.kt b/app/src/main/java/io/legado/app/utils/StringExtensions.kt index f783373b3..987a0fce8 100644 --- a/app/src/main/java/io/legado/app/utils/StringExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/StringExtensions.kt @@ -1,7 +1,5 @@ package io.legado.app.utils -import kotlin.math.min - // import org.apache.commons.text.StringEscapeUtils fun String?.safeTrim() = if (this.isNullOrBlank()) null else this.trim() @@ -47,39 +45,3 @@ fun String.startWithIgnoreCase(start: String): Boolean { return if (this.isBlank()) false else startsWith(start, true) } -/** - * 计算相似度 - */ -fun String.similarity(target: String): Float { - //计算两个字符串的长度。 - val len1 = this.length - val len2 = target.length - //建立上面说的数组,比字符长度大一个空间 - val dif = Array(len1 + 1) { IntArray(len2 + 1) } - //赋初值,步骤B。 - for (a in 0..len1) { - dif[a][0] = a - } - for (a in 0..len2) { - dif[0][a] = a - } - //计算两个字符是否一样,计算左上的值 - var temp: Int - for (i in 1..len1) { - for (j in 1..len2) { - temp = if (this[i - 1] == target[j - 1]) { - 0 - } else { - 1 - } - //取三个值中最小的 - dif[i][j] = min( - min(dif[i - 1][j - 1] + temp, dif[i][j - 1] + 1), - dif[i - 1][j] + 1 - ) - } - } - //计算相似度 - return 1 - dif[len1][len2].toFloat() / Math.max(length, target.length) -} - From 03f888b8175a509b148a6f72b5e8ed3a2d2b1c1d Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 18 Oct 2019 10:04:58 +0800 Subject: [PATCH 1934/1997] up --- .../main/java/io/legado/app/help/BookHelp.kt | 41 ++++++++++++++----- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/BookHelp.kt b/app/src/main/java/io/legado/app/help/BookHelp.kt index ef1feedbe..608830baf 100644 --- a/app/src/main/java/io/legado/app/help/BookHelp.kt +++ b/app/src/main/java/io/legado/app/help/BookHelp.kt @@ -8,7 +8,6 @@ import io.legado.app.utils.getPrefInt import io.legado.app.utils.getPrefString import org.apache.commons.text.similarity.JaccardSimilarity import java.io.File -import kotlin.math.max import kotlin.math.min object BookHelp { @@ -94,17 +93,37 @@ object BookHelp { if (chapters.size > index && title == chapters[index].title) { return index } - var similarity = 0.0 - var newIndex = index - val start = max(index - 20, 0) - val end = min(index + 20, chapters.lastIndex) + + var newIndex = 0 val jaccardSimilarity = JaccardSimilarity() - if (start < end) { - for (i in start..end) { - val s = jaccardSimilarity.apply(title, chapters[i].title) - if (s > similarity) { - similarity = s - newIndex = i + var similarity = if (chapters.size > index) { + jaccardSimilarity.apply(title, chapters[index].title) + } else 0.0 + if (similarity == 1.0) { + return index + } else { + for (i in 1..50) { + if (index - 1 in chapters.indices) { + jaccardSimilarity.apply(title, chapters[index - i].title).let { + if (it > similarity) { + similarity = it + newIndex = index - i + if (similarity == 1.0) { + return newIndex + } + } + } + } + if (index + 1 in chapters.indices) { + jaccardSimilarity.apply(title, chapters[index + i].title).let { + if (it > similarity) { + similarity = it + newIndex = index + i + if (similarity == 1.0) { + return newIndex + } + } + } } } } From d91b2cd28a3e46d1d1e603d9dade904cd5566613 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 18 Oct 2019 10:06:52 +0800 Subject: [PATCH 1935/1997] up --- app/src/main/java/io/legado/app/help/BookHelp.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/BookHelp.kt b/app/src/main/java/io/legado/app/help/BookHelp.kt index 608830baf..e198a316f 100644 --- a/app/src/main/java/io/legado/app/help/BookHelp.kt +++ b/app/src/main/java/io/legado/app/help/BookHelp.kt @@ -103,7 +103,7 @@ object BookHelp { return index } else { for (i in 1..50) { - if (index - 1 in chapters.indices) { + if (index - i in chapters.indices) { jaccardSimilarity.apply(title, chapters[index - i].title).let { if (it > similarity) { similarity = it @@ -114,7 +114,7 @@ object BookHelp { } } } - if (index + 1 in chapters.indices) { + if (index + i in chapters.indices) { jaccardSimilarity.apply(title, chapters[index + i].title).let { if (it > similarity) { similarity = it From 15b364431271079940a2294ccc75bd225cf09709 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 18 Oct 2019 10:23:12 +0800 Subject: [PATCH 1936/1997] up --- app/src/main/java/io/legado/app/data/entities/RssSource.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/data/entities/RssSource.kt b/app/src/main/java/io/legado/app/data/entities/RssSource.kt index 3c2dd17b4..c295753b1 100644 --- a/app/src/main/java/io/legado/app/data/entities/RssSource.kt +++ b/app/src/main/java/io/legado/app/data/entities/RssSource.kt @@ -17,6 +17,7 @@ data class RssSource( var enabled: Boolean = true, //列表规则 var ruleArticles: String? = null, + var ruleNextPage: String? = null, var ruleTitle: String? = null, var rulePubDate: String? = null, //类别规则 From 8fbd6d36675de9a35742cceaf3acc5fa0b21c719 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 18 Oct 2019 14:22:48 +0800 Subject: [PATCH 1937/1997] up --- .../app/ui/rss/article/RssArticlesActivity.kt | 58 ++++++++++++++++++- .../ui/rss/article/RssArticlesViewModel.kt | 4 +- .../app/ui/widget/anima/RefreshProgressBar.kt | 8 +-- 3 files changed, 60 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt index 50d2676d3..61091613e 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt @@ -1,8 +1,11 @@ package io.legado.app.ui.rss.article +import android.annotation.SuppressLint import android.os.Bundle import android.view.Menu import android.view.MenuItem +import android.view.MotionEvent +import android.view.View import androidx.core.content.ContextCompat import androidx.lifecycle.LiveData import androidx.lifecycle.Observer @@ -29,13 +32,18 @@ class RssArticlesActivity : VMBaseActivity(R.layout.activi private val editSource = 12319 private var adapter: RssArticlesAdapter? = null private var rssArticlesData: LiveData>? = null + private var url: String? = null + + private var durTouchX = -1000000f + private var durTouchY = -1000000f override fun onActivityCreated(savedInstanceState: Bundle?) { initView() viewModel.titleLiveData.observe(this, Observer { title_bar.title = it }) - intent.getStringExtra("url")?.let { + url = intent.getStringExtra("url") + url?.let { initData(it) viewModel.loadContent(it) { refresh_progress_bar.isAutoLoading = false @@ -77,6 +85,54 @@ class RssArticlesActivity : VMBaseActivity(R.layout.activi adapter = RssArticlesAdapter(this, this) recycler_view.adapter = adapter refresh_progress_bar.isAutoLoading = true + recycler_view.setOnTouchListener(object : View.OnTouchListener { + @SuppressLint("ClickableViewAccessibility") + override fun onTouch(v: View?, event: MotionEvent?): Boolean { + when (event?.action) { + MotionEvent.ACTION_DOWN -> { + durTouchX = event.x + durTouchY = event.y + } + MotionEvent.ACTION_MOVE -> { + if (durTouchX == -1000000f) { + durTouchX = event.x + } + if (durTouchY == -1000000f) + durTouchY = event.y + + val dY = event.y - durTouchY //>0下拉 + durTouchY = event.y + if (!refresh_progress_bar.isAutoLoading && refresh_progress_bar.getSecondDurProgress() == refresh_progress_bar.secondFinalProgress) { + if (recycler_view.adapter!!.itemCount > 0) { + if (0 == (recycler_view.layoutManager as LinearLayoutManager).findFirstCompletelyVisibleItemPosition()) { + refresh_progress_bar.setSecondDurProgress((refresh_progress_bar.getSecondDurProgress() + dY / 2).toInt()) + } + } else { + refresh_progress_bar.setSecondDurProgress((refresh_progress_bar.getSecondDurProgress() + dY / 2).toInt()) + } + return refresh_progress_bar.getSecondDurProgress() > 0 + } + } + MotionEvent.ACTION_UP -> { + if (!refresh_progress_bar.isAutoLoading && refresh_progress_bar.secondMaxProgress > 0 && refresh_progress_bar.getSecondDurProgress() > 0) { + if (refresh_progress_bar.getSecondDurProgress() >= refresh_progress_bar.secondMaxProgress) { + refresh_progress_bar.isAutoLoading = true + url?.let { + viewModel.loadContent(it) { + refresh_progress_bar.isAutoLoading = false + } + } + } else { + refresh_progress_bar.setSecondDurProgressWithAnim(0) + } + } + durTouchX = -1000000f + durTouchY = -1000000f + } + } + return false + } + }) } private fun initData(origin: String) { diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt index 8fc44c1c9..1f16efee2 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt @@ -22,8 +22,8 @@ class RssArticlesViewModel(application: Application) : BaseViewModel(application } ?: let { rssSource = RssSource(sourceUrl = url) } - rssSource?.let { - Rss.getArticles(it, this) + rssSource?.let { rssSource -> + Rss.getArticles(rssSource, this) .onSuccess(IO) { it?.let { App.db.rssArticleDao().insert(*it.toTypedArray()) diff --git a/app/src/main/java/io/legado/app/ui/widget/anima/RefreshProgressBar.kt b/app/src/main/java/io/legado/app/ui/widget/anima/RefreshProgressBar.kt index 1095d5889..df123bfcd 100644 --- a/app/src/main/java/io/legado/app/ui/widget/anima/RefreshProgressBar.kt +++ b/app/src/main/java/io/legado/app/ui/widget/anima/RefreshProgressBar.kt @@ -34,11 +34,8 @@ class RefreshProgressBar @JvmOverloads constructor( var isAutoLoading: Boolean = false set(loading) { - if (loading && visibility != VISIBLE) { - visibility = VISIBLE - } field = loading - if (!this.isAutoLoading) { + if (!loading) { secondDurProgress = 0 secondFinalProgress = 0 } @@ -135,9 +132,6 @@ class RefreshProgressBar @JvmOverloads constructor( } this.invalidate() } - if (secondDurProgress == 0 && durProgress == 0 && secondFinalProgress == 0 && visibility == VISIBLE) { - visibility = INVISIBLE - } } } From c799f37dab075c483aa34e1c940697c2ecfc293b Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 18 Oct 2019 14:45:11 +0800 Subject: [PATCH 1938/1997] up --- .../legado/app/ui/rss/article/RssArticlesActivity.kt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt index 61091613e..a378740cb 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt @@ -103,12 +103,14 @@ class RssArticlesActivity : VMBaseActivity(R.layout.activi val dY = event.y - durTouchY //>0下拉 durTouchY = event.y if (!refresh_progress_bar.isAutoLoading && refresh_progress_bar.getSecondDurProgress() == refresh_progress_bar.secondFinalProgress) { - if (recycler_view.adapter!!.itemCount > 0) { - if (0 == (recycler_view.layoutManager as LinearLayoutManager).findFirstCompletelyVisibleItemPosition()) { + recycler_view.adapter?.let { + if (it.itemCount > 0) { + if (0 == (recycler_view.layoutManager as LinearLayoutManager).findFirstCompletelyVisibleItemPosition()) { + refresh_progress_bar.setSecondDurProgress((refresh_progress_bar.getSecondDurProgress() + dY / 2).toInt()) + } + } else { refresh_progress_bar.setSecondDurProgress((refresh_progress_bar.getSecondDurProgress() + dY / 2).toInt()) } - } else { - refresh_progress_bar.setSecondDurProgress((refresh_progress_bar.getSecondDurProgress() + dY / 2).toInt()) } return refresh_progress_bar.getSecondDurProgress() > 0 } From b9953c2e8760cfa647b30a4baae963d2e301886e Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 18 Oct 2019 15:21:25 +0800 Subject: [PATCH 1939/1997] up --- .../app/ui/rss/article/RssArticlesActivity.kt | 22 +++++++++++--- app/src/main/res/layout/view_load_more.xml | 29 +++++++++++++++++++ 2 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 app/src/main/res/layout/view_load_more.xml diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt index a378740cb..20353f4c8 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt @@ -2,15 +2,14 @@ package io.legado.app.ui.rss.article import android.annotation.SuppressLint import android.os.Bundle -import android.view.Menu -import android.view.MenuItem -import android.view.MotionEvent -import android.view.View +import android.util.Log +import android.view.* import androidx.core.content.ContextCompat import androidx.lifecycle.LiveData import androidx.lifecycle.Observer import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView import io.legado.app.App import io.legado.app.R import io.legado.app.base.VMBaseActivity @@ -73,6 +72,7 @@ class RssArticlesActivity : VMBaseActivity(R.layout.activi return super.onCompatOptionsItemSelected(item) } + @SuppressLint("InflateParams") private fun initView() { ATH.applyEdgeEffectColor(recycler_view) recycler_view.layoutManager = LinearLayoutManager(this) @@ -84,6 +84,8 @@ class RssArticlesActivity : VMBaseActivity(R.layout.activi }) adapter = RssArticlesAdapter(this, this) recycler_view.adapter = adapter + val loadMoreView = LayoutInflater.from(this).inflate(R.layout.view_load_more, null) + adapter?.addFooterView(loadMoreView) refresh_progress_bar.isAutoLoading = true recycler_view.setOnTouchListener(object : View.OnTouchListener { @SuppressLint("ClickableViewAccessibility") @@ -135,6 +137,14 @@ class RssArticlesActivity : VMBaseActivity(R.layout.activi return false } }) + recycler_view.addOnScrollListener(object : RecyclerView.OnScrollListener() { + override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { + super.onScrolled(recyclerView, dx, dy) + if (!recyclerView.canScrollVertically(1)) { + scrollToBottom() + } + } + }) } private fun initData(origin: String) { @@ -145,6 +155,10 @@ class RssArticlesActivity : VMBaseActivity(R.layout.activi }) } + private fun scrollToBottom() { + Log.d("xxxxxx", "scrollToBottom") + } + override fun readRss(rssArticle: RssArticle) { viewModel.read(rssArticle) startActivity( diff --git a/app/src/main/res/layout/view_load_more.xml b/app/src/main/res/layout/view_load_more.xml new file mode 100644 index 000000000..b8b37f64a --- /dev/null +++ b/app/src/main/res/layout/view_load_more.xml @@ -0,0 +1,29 @@ + + + + + + + + \ No newline at end of file From f3882b3c5f66b5edaccf5a9d05bb50d8ab7986ee Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 18 Oct 2019 16:36:21 +0800 Subject: [PATCH 1940/1997] up --- .../app/ui/rss/article/RssArticlesActivity.kt | 80 +++++-------------- .../ui/rss/article/RssArticlesViewModel.kt | 4 + .../ui/widget/recycler/RefreshRecyclerView.kt | 77 ++++++++++++++++++ .../main/res/layout/activity_rss_artivles.xml | 12 +-- app/src/main/res/layout/view_load_more.xml | 5 +- .../main/res/layout/view_refresh_recycler.xml | 16 ++++ 6 files changed, 122 insertions(+), 72 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/widget/recycler/RefreshRecyclerView.kt create mode 100644 app/src/main/res/layout/view_refresh_recycler.xml diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt index 20353f4c8..e2016e11b 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt @@ -1,9 +1,10 @@ package io.legado.app.ui.rss.article -import android.annotation.SuppressLint import android.os.Bundle -import android.util.Log -import android.view.* +import android.view.LayoutInflater +import android.view.Menu +import android.view.MenuItem +import android.view.View import androidx.core.content.ContextCompat import androidx.lifecycle.LiveData import androidx.lifecycle.Observer @@ -19,6 +20,8 @@ import io.legado.app.ui.rss.read.ReadRssActivity import io.legado.app.ui.rss.source.edit.RssSourceEditActivity import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_rss_artivles.* +import kotlinx.android.synthetic.main.view_load_more.view.* +import kotlinx.android.synthetic.main.view_refresh_recycler.* import org.jetbrains.anko.startActivity import org.jetbrains.anko.startActivityForResult @@ -32,9 +35,7 @@ class RssArticlesActivity : VMBaseActivity(R.layout.activi private var adapter: RssArticlesAdapter? = null private var rssArticlesData: LiveData>? = null private var url: String? = null - - private var durTouchX = -1000000f - private var durTouchY = -1000000f + private lateinit var loadMoreView: View override fun onActivityCreated(savedInstanceState: Bundle?) { initView() @@ -44,10 +45,8 @@ class RssArticlesActivity : VMBaseActivity(R.layout.activi url = intent.getStringExtra("url") url?.let { initData(it) - viewModel.loadContent(it) { - refresh_progress_bar.isAutoLoading = false - } } + refresh_recycler_view.startLoading() } override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { @@ -72,7 +71,6 @@ class RssArticlesActivity : VMBaseActivity(R.layout.activi return super.onCompatOptionsItemSelected(item) } - @SuppressLint("InflateParams") private fun initView() { ATH.applyEdgeEffectColor(recycler_view) recycler_view.layoutManager = LinearLayoutManager(this) @@ -84,59 +82,17 @@ class RssArticlesActivity : VMBaseActivity(R.layout.activi }) adapter = RssArticlesAdapter(this, this) recycler_view.adapter = adapter - val loadMoreView = LayoutInflater.from(this).inflate(R.layout.view_load_more, null) + loadMoreView = + LayoutInflater.from(this).inflate(R.layout.view_load_more, recycler_view, false) adapter?.addFooterView(loadMoreView) refresh_progress_bar.isAutoLoading = true - recycler_view.setOnTouchListener(object : View.OnTouchListener { - @SuppressLint("ClickableViewAccessibility") - override fun onTouch(v: View?, event: MotionEvent?): Boolean { - when (event?.action) { - MotionEvent.ACTION_DOWN -> { - durTouchX = event.x - durTouchY = event.y - } - MotionEvent.ACTION_MOVE -> { - if (durTouchX == -1000000f) { - durTouchX = event.x - } - if (durTouchY == -1000000f) - durTouchY = event.y - - val dY = event.y - durTouchY //>0下拉 - durTouchY = event.y - if (!refresh_progress_bar.isAutoLoading && refresh_progress_bar.getSecondDurProgress() == refresh_progress_bar.secondFinalProgress) { - recycler_view.adapter?.let { - if (it.itemCount > 0) { - if (0 == (recycler_view.layoutManager as LinearLayoutManager).findFirstCompletelyVisibleItemPosition()) { - refresh_progress_bar.setSecondDurProgress((refresh_progress_bar.getSecondDurProgress() + dY / 2).toInt()) - } - } else { - refresh_progress_bar.setSecondDurProgress((refresh_progress_bar.getSecondDurProgress() + dY / 2).toInt()) - } - } - return refresh_progress_bar.getSecondDurProgress() > 0 - } - } - MotionEvent.ACTION_UP -> { - if (!refresh_progress_bar.isAutoLoading && refresh_progress_bar.secondMaxProgress > 0 && refresh_progress_bar.getSecondDurProgress() > 0) { - if (refresh_progress_bar.getSecondDurProgress() >= refresh_progress_bar.secondMaxProgress) { - refresh_progress_bar.isAutoLoading = true - url?.let { - viewModel.loadContent(it) { - refresh_progress_bar.isAutoLoading = false - } - } - } else { - refresh_progress_bar.setSecondDurProgressWithAnim(0) - } - } - durTouchX = -1000000f - durTouchY = -1000000f - } + refresh_recycler_view.onRefreshStart = { + url?.let { + viewModel.loadContent(it) { + refresh_progress_bar.isAutoLoading = false } - return false } - }) + } recycler_view.addOnScrollListener(object : RecyclerView.OnScrollListener() { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { super.onScrolled(recyclerView, dx, dy) @@ -156,7 +112,11 @@ class RssArticlesActivity : VMBaseActivity(R.layout.activi } private fun scrollToBottom() { - Log.d("xxxxxx", "scrollToBottom") + adapter?.let { + if (it.getActualItemCount() > 0) { + loadMoreView.rotate_loading.show() + } + } } override fun readRss(rssArticle: RssArticle) { diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt index 1f16efee2..603a24148 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesViewModel.kt @@ -50,4 +50,8 @@ class RssArticlesViewModel(application: Application) : BaseViewModel(application loadContent(url, onFinally) } } + + fun loadMore() { + + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/recycler/RefreshRecyclerView.kt b/app/src/main/java/io/legado/app/ui/widget/recycler/RefreshRecyclerView.kt new file mode 100644 index 000000000..f3bb3feef --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/widget/recycler/RefreshRecyclerView.kt @@ -0,0 +1,77 @@ +package io.legado.app.ui.widget.recycler + +import android.annotation.SuppressLint +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.MotionEvent +import android.view.View +import android.widget.LinearLayout +import androidx.recyclerview.widget.LinearLayoutManager +import io.legado.app.R +import kotlinx.android.synthetic.main.view_refresh_recycler.view.* + + +class RefreshRecyclerView(context: Context?, attrs: AttributeSet?) : LinearLayout(context, attrs) { + + private var durTouchX = -1000000f + private var durTouchY = -1000000f + + var onRefreshStart: (() -> Unit)? = null + + init { + LayoutInflater.from(context).inflate(R.layout.view_refresh_recycler, this, true) + recycler_view.setOnTouchListener(object : View.OnTouchListener { + @SuppressLint("ClickableViewAccessibility") + override fun onTouch(v: View?, event: MotionEvent?): Boolean { + when (event?.action) { + MotionEvent.ACTION_DOWN -> { + durTouchX = event.x + durTouchY = event.y + } + MotionEvent.ACTION_MOVE -> { + if (durTouchX == -1000000f) { + durTouchX = event.x + } + if (durTouchY == -1000000f) + durTouchY = event.y + + val dY = event.y - durTouchY //>0下拉 + durTouchY = event.y + if (!refresh_progress_bar.isAutoLoading && refresh_progress_bar.getSecondDurProgress() == refresh_progress_bar.secondFinalProgress) { + recycler_view.adapter?.let { + if (it.itemCount > 0) { + if (0 == (recycler_view.layoutManager as LinearLayoutManager).findFirstCompletelyVisibleItemPosition()) { + refresh_progress_bar.setSecondDurProgress((refresh_progress_bar.getSecondDurProgress() + dY / 2).toInt()) + } + } else { + refresh_progress_bar.setSecondDurProgress((refresh_progress_bar.getSecondDurProgress() + dY / 2).toInt()) + } + } + return refresh_progress_bar.getSecondDurProgress() > 0 + } + } + MotionEvent.ACTION_UP -> { + if (!refresh_progress_bar.isAutoLoading && refresh_progress_bar.secondMaxProgress > 0 && refresh_progress_bar.getSecondDurProgress() > 0) { + if (refresh_progress_bar.getSecondDurProgress() >= refresh_progress_bar.secondMaxProgress) { + refresh_progress_bar.isAutoLoading = true + onRefreshStart?.invoke() + } else { + refresh_progress_bar.setSecondDurProgressWithAnim(0) + } + } + durTouchX = -1000000f + durTouchY = -1000000f + } + } + return false + } + }) + } + + fun startLoading() { + refresh_progress_bar.isAutoLoading = true + onRefreshStart?.invoke() + } + +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_rss_artivles.xml b/app/src/main/res/layout/activity_rss_artivles.xml index 5eceec843..39678114e 100644 --- a/app/src/main/res/layout/activity_rss_artivles.xml +++ b/app/src/main/res/layout/activity_rss_artivles.xml @@ -11,21 +11,15 @@ android:layout_height="wrap_content" app:layout_constraintTop_toTopOf="parent" /> - - + app:layout_constraintTop_toBottomOf="@id/title_bar"> - diff --git a/app/src/main/res/layout/view_load_more.xml b/app/src/main/res/layout/view_load_more.xml index b8b37f64a..a55372d30 100644 --- a/app/src/main/res/layout/view_load_more.xml +++ b/app/src/main/res/layout/view_load_more.xml @@ -2,7 +2,6 @@ @@ -11,16 +10,16 @@ android:layout_width="36dp" android:layout_height="36dp" android:layout_margin="6dp" - android:visibility="gone" + android:layout_gravity="center" app:loading_width="2dp" /> + + + + + + + \ No newline at end of file From 80338fd537ef64a71c22703afc0f15918594a376 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 18 Oct 2019 16:40:07 +0800 Subject: [PATCH 1941/1997] up --- .../io/legado/app/ui/widget/recycler/RefreshRecyclerView.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/recycler/RefreshRecyclerView.kt b/app/src/main/java/io/legado/app/ui/widget/recycler/RefreshRecyclerView.kt index f3bb3feef..35e165a26 100644 --- a/app/src/main/java/io/legado/app/ui/widget/recycler/RefreshRecyclerView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/recycler/RefreshRecyclerView.kt @@ -21,7 +21,7 @@ class RefreshRecyclerView(context: Context?, attrs: AttributeSet?) : LinearLayou init { LayoutInflater.from(context).inflate(R.layout.view_refresh_recycler, this, true) - recycler_view.setOnTouchListener(object : View.OnTouchListener { + recycler_view.setOnTouchListener(object : OnTouchListener { @SuppressLint("ClickableViewAccessibility") override fun onTouch(v: View?, event: MotionEvent?): Boolean { when (event?.action) { From d551568784299377f3ab8ac7dbe06f46941743c9 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 18 Oct 2019 16:41:45 +0800 Subject: [PATCH 1942/1997] up --- .../java/io/legado/app/ui/rss/article/RssArticlesActivity.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt index e2016e11b..6e3ac4318 100644 --- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesActivity.kt @@ -85,7 +85,6 @@ class RssArticlesActivity : VMBaseActivity(R.layout.activi loadMoreView = LayoutInflater.from(this).inflate(R.layout.view_load_more, recycler_view, false) adapter?.addFooterView(loadMoreView) - refresh_progress_bar.isAutoLoading = true refresh_recycler_view.onRefreshStart = { url?.let { viewModel.loadContent(it) { From 3b007ea8ac4a1b4894662f64514087ddad290d59 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 18 Oct 2019 16:46:39 +0800 Subject: [PATCH 1943/1997] up --- .../java/io/legado/app/ui/widget/recycler/RefreshRecyclerView.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/widget/recycler/RefreshRecyclerView.kt b/app/src/main/java/io/legado/app/ui/widget/recycler/RefreshRecyclerView.kt index 35e165a26..8fcc56d2c 100644 --- a/app/src/main/java/io/legado/app/ui/widget/recycler/RefreshRecyclerView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/recycler/RefreshRecyclerView.kt @@ -20,6 +20,7 @@ class RefreshRecyclerView(context: Context?, attrs: AttributeSet?) : LinearLayou var onRefreshStart: (() -> Unit)? = null init { + orientation = VERTICAL LayoutInflater.from(context).inflate(R.layout.view_refresh_recycler, this, true) recycler_view.setOnTouchListener(object : OnTouchListener { @SuppressLint("ClickableViewAccessibility") From 83756d26711bb99c4fc5ac1f668dc6da8785e09c Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 19 Oct 2019 10:57:51 +0800 Subject: [PATCH 1944/1997] up --- .../app/ui/book/search/SearchActivity.kt | 27 ++++++++++++++++--- .../menu/{search_book.xml => book_search.xml} | 8 +++++- 2 files changed, 30 insertions(+), 5 deletions(-) rename app/src/main/res/menu/{search_book.xml => book_search.xml} (63%) diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt index 03b6755b3..da00dd4ef 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt @@ -1,6 +1,8 @@ package io.legado.app.ui.book.search import android.os.Bundle +import android.view.Menu +import android.view.MenuItem import androidx.appcompat.widget.SearchView import androidx.lifecycle.LiveData import androidx.lifecycle.Observer @@ -17,10 +19,8 @@ import io.legado.app.data.entities.SearchShow import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.primaryTextColor import io.legado.app.ui.book.info.BookInfoActivity -import io.legado.app.utils.getViewModel -import io.legado.app.utils.gone -import io.legado.app.utils.invisible -import io.legado.app.utils.visible +import io.legado.app.ui.book.source.manage.BookSourceActivity +import io.legado.app.utils.* import kotlinx.android.synthetic.main.activity_book_search.* import kotlinx.android.synthetic.main.view_search.* import kotlinx.coroutines.Dispatchers.IO @@ -43,6 +43,7 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se private var searchBookData: LiveData>? = null private var historyData: LiveData>? = null private var bookData: LiveData>? = null + private var precisionSearchMenuItem: MenuItem? = null override fun onActivityCreated(savedInstanceState: Bundle?) { initRecyclerView() @@ -53,6 +54,24 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se upHistory() } + override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { + menuInflater.inflate(R.menu.book_search, menu) + precisionSearchMenuItem = menu.findItem(R.id.menu_precision_search) + precisionSearchMenuItem?.isChecked = getPrefBoolean("precisionSearch") + return super.onCompatCreateOptionsMenu(menu) + } + + override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.menu_precision_search -> { + putPrefBoolean("precisionSearch", !getPrefBoolean("precisionSearch")) + precisionSearchMenuItem?.isChecked = getPrefBoolean("precisionSearch") + } + R.id.menu_source_manage -> startActivity() + } + return super.onCompatOptionsItemSelected(item) + } + private fun initSearchView() { ATH.setTint(search_view, primaryTextColor) search_view.onActionViewExpanded() diff --git a/app/src/main/res/menu/search_book.xml b/app/src/main/res/menu/book_search.xml similarity index 63% rename from app/src/main/res/menu/search_book.xml rename to app/src/main/res/menu/book_search.xml index a55a3ed35..33e0b51f5 100644 --- a/app/src/main/res/menu/search_book.xml +++ b/app/src/main/res/menu/book_search.xml @@ -4,7 +4,13 @@ tools:context=".view.activity.MainActivity"> + + From 11275a4f1bfb726d0a685627673da7ce8ac10172 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 19 Oct 2019 11:34:39 +0800 Subject: [PATCH 1945/1997] up --- .../app/ui/book/search/SearchActivity.kt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt index da00dd4ef..ee9a13c52 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt @@ -43,7 +43,9 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se private var searchBookData: LiveData>? = null private var historyData: LiveData>? = null private var bookData: LiveData>? = null + private var menu: Menu? = null private var precisionSearchMenuItem: MenuItem? = null + private var groups = hashSetOf() override fun onActivityCreated(savedInstanceState: Bundle?) { initRecyclerView() @@ -58,6 +60,8 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se menuInflater.inflate(R.menu.book_search, menu) precisionSearchMenuItem = menu.findItem(R.id.menu_precision_search) precisionSearchMenuItem?.isChecked = getPrefBoolean("precisionSearch") + this.menu = menu + upGroupMenu() return super.onCompatCreateOptionsMenu(menu) } @@ -143,6 +147,13 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se ), 30 ).build() searchBookData?.observe(this, Observer { adapter.submitList(it) }) + App.db.bookSourceDao().liveGroup().observe(this, Observer { + groups.clear() + it.map { group -> + groups.addAll(group.splitNotBlank(",", ";")) + } + upGroupMenu() + }) } private fun initIntent() { @@ -151,6 +162,13 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se } } + private fun upGroupMenu() { + menu?.removeGroup(R.id.source_group) + groups.map { + menu?.add(R.id.source_group, Menu.NONE, Menu.NONE, it) + } + } + private fun upHistory(key: String? = null) { bookData?.removeObservers(this) if (key.isNullOrBlank()) { From 00a68d4765f24d9efe767b91c42ab21fbc41be82 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 19 Oct 2019 12:03:18 +0800 Subject: [PATCH 1946/1997] up --- .../java/io/legado/app/ui/book/search/SearchActivity.kt | 9 +++++++++ app/src/main/res/menu/book_search.xml | 4 +++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt index ee9a13c52..32667f476 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt @@ -72,6 +72,14 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se precisionSearchMenuItem?.isChecked = getPrefBoolean("precisionSearch") } R.id.menu_source_manage -> startActivity() + else -> if (item.groupId == R.id.source_group) { + item.isChecked = true + if (item.title.toString() == getString(R.string.all_source)) { + putPrefString("sourceGroup", "") + } else { + putPrefString("sourceGroup", item.title.toString()) + } + } } return super.onCompatOptionsItemSelected(item) } @@ -164,6 +172,7 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se private fun upGroupMenu() { menu?.removeGroup(R.id.source_group) + menu?.add(R.id.source_group, Menu.NONE, Menu.NONE, R.string.all_source) groups.map { menu?.add(R.id.source_group, Menu.NONE, Menu.NONE, it) } diff --git a/app/src/main/res/menu/book_search.xml b/app/src/main/res/menu/book_search.xml index 33e0b51f5..9c0b1762f 100644 --- a/app/src/main/res/menu/book_search.xml +++ b/app/src/main/res/menu/book_search.xml @@ -14,7 +14,9 @@ android:title="@string/book_source_manage" app:showAsAction="never" /> - + From fd6b475edfb3dce17b3cce543ba02cb4ac7952d5 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 19 Oct 2019 12:10:19 +0800 Subject: [PATCH 1947/1997] up --- .../io/legado/app/ui/book/search/SearchActivity.kt | 1 + app/src/main/res/menu/book_search.xml | 14 ++++---------- app/src/main/res/values/strings.xml | 1 + 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt index 32667f476..3e35e1a02 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt @@ -176,6 +176,7 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se groups.map { menu?.add(R.id.source_group, Menu.NONE, Menu.NONE, it) } + menu?.setGroupCheckable(R.id.source_group, true, true) } private fun upHistory(key: String? = null) { diff --git a/app/src/main/res/menu/book_search.xml b/app/src/main/res/menu/book_search.xml index 9c0b1762f..0a8ce4992 100644 --- a/app/src/main/res/menu/book_search.xml +++ b/app/src/main/res/menu/book_search.xml @@ -4,20 +4,14 @@ tools:context=".view.activity.MainActivity"> - - - - diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4347783a4..47d72c6a5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -533,5 +533,6 @@ 筛选 筛选发现 当前位置: + 精准搜索 From df2898a4f26595648474d0f5d73cdf473fca5caa Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 19 Oct 2019 12:41:24 +0800 Subject: [PATCH 1948/1997] up --- .../legado/app/ui/book/search/SearchActivity.kt | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt index 3e35e1a02..91010e820 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt @@ -75,9 +75,9 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se else -> if (item.groupId == R.id.source_group) { item.isChecked = true if (item.title.toString() == getString(R.string.all_source)) { - putPrefString("sourceGroup", "") + putPrefString("searchGroup", "") } else { - putPrefString("sourceGroup", item.title.toString()) + putPrefString("searchGroup", item.title.toString()) } } } @@ -171,10 +171,17 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se } private fun upGroupMenu() { + val selectedGroup = getPrefString("searchGroup") ?: "" menu?.removeGroup(R.id.source_group) - menu?.add(R.id.source_group, Menu.NONE, Menu.NONE, R.string.all_source) + var item = menu?.add(R.id.source_group, Menu.NONE, Menu.NONE, R.string.all_source) + if (selectedGroup == "") { + item?.isChecked = true + } groups.map { - menu?.add(R.id.source_group, Menu.NONE, Menu.NONE, it) + item = menu?.add(R.id.source_group, Menu.NONE, Menu.NONE, it) + if (it == selectedGroup) { + item?.isChecked = true + } } menu?.setGroupCheckable(R.id.source_group, true, true) } From e29bd6b3efba94b69c46dcf6a37205b7f5716c09 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 19 Oct 2019 12:52:47 +0800 Subject: [PATCH 1949/1997] up --- app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt | 3 +++ .../main/java/io/legado/app/ui/book/search/SearchActivity.kt | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt index e1864eb5b..2f3e1896b 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt @@ -23,6 +23,9 @@ interface BookSourceDao { @Query("select bookSourceGroup from book_sources where bookSourceGroup is not null and bookSourceGroup <> ''") fun liveGroup(): LiveData> + @Query("select bookSourceGroup from book_sources where enabled = 1 and bookSourceGroup is not null and bookSourceGroup <> ''") + fun liveGroupEnabled(): LiveData> + @Query("select distinct enabled from book_sources where bookSourceName like :searchKey or bookSourceGroup like :searchKey or bookSourceUrl like :searchKey") fun searchIsEnable(searchKey: String = ""): List diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt index 91010e820..197d1eddc 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt @@ -155,7 +155,7 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se ), 30 ).build() searchBookData?.observe(this, Observer { adapter.submitList(it) }) - App.db.bookSourceDao().liveGroup().observe(this, Observer { + App.db.bookSourceDao().liveGroupEnabled().observe(this, Observer { groups.clear() it.map { group -> groups.addAll(group.splitNotBlank(",", ";")) From cc31dfecd586dbf10565b06aae16517f268e4d24 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 19 Oct 2019 16:09:50 +0800 Subject: [PATCH 1950/1997] up --- .../main/java/io/legado/app/data/dao/BookSourceDao.kt | 3 +++ .../io/legado/app/ui/book/search/SearchViewModel.kt | 11 +++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt index 2f3e1896b..d2b48fa49 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt @@ -44,6 +44,9 @@ interface BookSourceDao { @Query("select * from book_sources where bookSourceGroup like '%' || :group || '%'") fun getByGroup(group: String): List + @Query("select * from book_sources where enabled = 1 and bookSourceGroup like '%' || :group || '%'") + fun getEnabledByGroup(group: String): List + @get:Query("select * from book_sources where bookSourceGroup is null or bookSourceGroup = ''") val noGroup: List diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt index 0c21d1820..88979461a 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt @@ -7,6 +7,7 @@ import io.legado.app.data.entities.SearchBook import io.legado.app.data.entities.SearchKeyword import io.legado.app.help.coroutine.Coroutine import io.legado.app.model.WebBook +import io.legado.app.utils.getPrefString import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.asCoroutineDispatcher import java.util.concurrent.Executors @@ -30,7 +31,12 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { start?.invoke() task = execute { //onCleared时自动取消 - val bookSourceList = App.db.bookSourceDao().allEnabled + val searchGroup = context.getPrefString("searchGroup") ?: "" + val bookSourceList = if (searchGroup.isBlank()) { + App.db.bookSourceDao().allEnabled + } else { + App.db.bookSourceDao().getEnabledByGroup(searchGroup) + } for (item in bookSourceList) { //task取消时自动取消 by (scope = this@execute) WebBook(item).searchBook( @@ -43,7 +49,8 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { .onSuccess(Dispatchers.IO) { it?.let { list -> list.map { searchBook -> - if (searchBook.name.contains(key) || searchBook.author.contains(key)) + if (searchBook.name.contains(key) || searchBook.author.contains(key)) { + } App.db.searchBookDao().insert(searchBook) } } From 884eba851bbf213cc6c2637a75cdefa2c7170aae Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 19 Oct 2019 16:23:55 +0800 Subject: [PATCH 1951/1997] up --- .../app/ui/book/search/SearchViewModel.kt | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt index 88979461a..184d8c782 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt @@ -7,6 +7,7 @@ import io.legado.app.data.entities.SearchBook import io.legado.app.data.entities.SearchKeyword import io.legado.app.help.coroutine.Coroutine import io.legado.app.model.WebBook +import io.legado.app.utils.getPrefBoolean import io.legado.app.utils.getPrefString import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.asCoroutineDispatcher @@ -48,11 +49,7 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { .timeout(30000L) .onSuccess(Dispatchers.IO) { it?.let { list -> - list.map { searchBook -> - if (searchBook.name.contains(key) || searchBook.author.contains(key)) { - } - App.db.searchBookDao().insert(searchBook) - } + searchSuccess(list) } } } @@ -63,6 +60,17 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { } } + private fun searchSuccess(searchBooks: List) { + searchBooks.forEach { searchBook -> + if (context.getPrefBoolean("precisionSearch")) { + if (searchBook.name.contains(searchKey) + || searchBook.author.contains(searchKey) + ) App.db.searchBookDao().insert(searchBook) + } else + App.db.searchBookDao().insert(searchBook) + } + } + fun stop() { task?.cancel() } From 08dfe25e2ff0951c26003adbcc8dac98374a2adb Mon Sep 17 00:00:00 2001 From: ca1e Date: Sat, 19 Oct 2019 18:24:58 +0800 Subject: [PATCH 1952/1997] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=95=8C=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/ui/widget/page/delegate/HorizontalPageDelegate.kt | 3 +++ app/src/main/res/drawable/ic_divider.xml | 2 +- app/src/main/res/layout/activity_main.xml | 1 + app/src/main/res/layout/fragment_my_config.xml | 2 +- app/src/main/res/layout/view_book_page.xml | 3 +++ app/src/main/res/layout/view_read_menu.xml | 5 +++-- 6 files changed, 12 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/HorizontalPageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/HorizontalPageDelegate.kt index 1f2b3fa42..1f0e377a2 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/HorizontalPageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/HorizontalPageDelegate.kt @@ -3,6 +3,7 @@ package io.legado.app.ui.widget.page.delegate import android.view.MotionEvent import io.legado.app.ui.widget.page.PageView import io.legado.app.utils.screenshot +import io.legado.app.utils.snackbar import kotlin.math.abs abstract class HorizontalPageDelegate(pageView: PageView) : PageDelegate(pageView) { @@ -22,6 +23,7 @@ abstract class HorizontalPageDelegate(pageView: PageView) : PageDelegate(pageVie //如果上一页不存在 if (!hasPrev()) { noNext = true + pageView.snackbar("没有上一页") return true } //上一页截图 @@ -30,6 +32,7 @@ abstract class HorizontalPageDelegate(pageView: PageView) : PageDelegate(pageVie //如果不存在表示没有下一页了 if (!hasNext()) { noNext = true + pageView.snackbar("没有下一页") return true } //下一页截图 diff --git a/app/src/main/res/drawable/ic_divider.xml b/app/src/main/res/drawable/ic_divider.xml index 1ecb2d6d8..21a88f21a 100644 --- a/app/src/main/res/drawable/ic_divider.xml +++ b/app/src/main/res/drawable/ic_divider.xml @@ -2,5 +2,5 @@ - + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 6b4eb4487..6795bf664 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -6,6 +6,7 @@ + app:title="@string/my" /> diff --git a/app/src/main/res/layout/view_read_menu.xml b/app/src/main/res/layout/view_read_menu.xml index 7ffd97ee2..9bba9e02d 100644 --- a/app/src/main/res/layout/view_read_menu.xml +++ b/app/src/main/res/layout/view_read_menu.xml @@ -148,7 +148,7 @@ + android:layout_height="120dp"> From 0c0da8a8931571ce19c89ea42e42f0ea417443a5 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 19 Oct 2019 18:37:32 +0800 Subject: [PATCH 1953/1997] up --- .../io/legado/app/ui/book/search/SearchViewModel.kt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt index 184d8c782..f43738c22 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchViewModel.kt @@ -25,9 +25,13 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { start: (() -> Unit)? = null, finally: (() -> Unit)? = null ) { - if (key.isEmpty()) return task?.cancel() - searchKey = key + if (key.isEmpty()) { + searchPage++ + } else { + searchKey = key + } + if (searchKey.isEmpty()) return startTime = System.currentTimeMillis() start?.invoke() task = execute { @@ -41,7 +45,7 @@ class SearchViewModel(application: Application) : BaseViewModel(application) { for (item in bookSourceList) { //task取消时自动取消 by (scope = this@execute) WebBook(item).searchBook( - key, + searchKey, searchPage, scope = this@execute, context = searchPool From 5f5ca3890429b22ed5f341c2ced2f34c7d87a107 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 20 Oct 2019 19:45:04 +0800 Subject: [PATCH 1954/1997] up --- app/src/main/res/layout/activity_main.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 6795bf664..23542ad52 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -6,7 +6,9 @@ Date: Sun, 20 Oct 2019 19:46:27 +0800 Subject: [PATCH 1955/1997] up --- app/src/main/res/layout/activity_main.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 23542ad52..a124291b5 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -6,7 +6,6 @@ Date: Sun, 20 Oct 2019 19:57:25 +0800 Subject: [PATCH 1956/1997] up --- .../main/java/io/legado/app/ui/book/search/SearchActivity.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt index 197d1eddc..7214418dd 100644 --- a/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/search/SearchActivity.kt @@ -53,7 +53,6 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se initOtherView() initData() initIntent() - upHistory() } override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { @@ -167,6 +166,8 @@ class SearchActivity : VMBaseActivity(R.layout.activity_book_se private fun initIntent() { intent.getStringExtra("key")?.let { search_view.setQuery(it, true) + } ?: let { + search_view.requestFocus() } } From eacaec35bc005aab27f013dbd4556661a8586f30 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 20 Oct 2019 20:08:16 +0800 Subject: [PATCH 1957/1997] up --- app/build.gradle | 2 ++ build.gradle | 1 + 2 files changed, 3 insertions(+) diff --git a/app/build.gradle b/app/build.gradle index 1bb42e0eb..a34132d84 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -151,3 +151,5 @@ dependencies { implementation 'org.apache.commons:commons-lang3:3.9' implementation 'org.apache.commons:commons-text:1.8' } + +apply plugin: 'com.google.gms.google-services' \ No newline at end of file diff --git a/build.gradle b/build.gradle index bfcb4cc7a..76fcc4b65 100644 --- a/build.gradle +++ b/build.gradle @@ -12,6 +12,7 @@ buildscript { classpath 'com.android.tools.build:gradle:3.5.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath 'de.timfreiheit.resourceplaceholders:placeholders:0.3' + classpath 'com.google.gms:google-services:4.3.2' } } From ee72ac32e637a73408bdf16b787bece6da2d20bf Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 20 Oct 2019 20:19:54 +0800 Subject: [PATCH 1958/1997] up --- app/build.gradle | 5 +++++ build.gradle | 1 + 2 files changed, 6 insertions(+) diff --git a/app/build.gradle b/app/build.gradle index a34132d84..c299deee3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -3,6 +3,7 @@ apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-kapt' apply plugin: "de.timfreiheit.resourceplaceholders" +apply plugin: 'io.fabric' androidExtensions { experimental = true @@ -85,6 +86,10 @@ dependencies { //kotlin implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" + //fireBase + implementation 'com.google.firebase:firebase-core:17.2.0' + implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1' + //androidX implementation 'androidx.core:core-ktx:1.2.0-beta01' implementation 'androidx.appcompat:appcompat:1.1.0' diff --git a/build.gradle b/build.gradle index 76fcc4b65..f880bb0e5 100644 --- a/build.gradle +++ b/build.gradle @@ -13,6 +13,7 @@ buildscript { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath 'de.timfreiheit.resourceplaceholders:placeholders:0.3' classpath 'com.google.gms:google-services:4.3.2' + classpath 'io.fabric.tools:gradle:1.31.0' } } From c23fdea6aa6551f1470747f97600ea610a41c0e1 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 20 Oct 2019 22:04:29 +0800 Subject: [PATCH 1959/1997] up --- .../io/legado/app/ui/main/MainActivity.kt | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt index bcd3fd017..81b7888f8 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt @@ -1,6 +1,7 @@ package io.legado.app.ui.main import android.os.Bundle +import android.view.KeyEvent import android.view.MenuItem import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager @@ -34,6 +35,8 @@ class MainActivity : VMBaseActivity(R.layout.activity_main), override val viewModel: MainViewModel get() = getViewModel(MainViewModel::class.java) + private var pagePosition = 0 + override fun onActivityCreated(savedInstanceState: Bundle?) { ATH.applyEdgeEffectColor(view_pager_main) ATH.applyBottomNavigationColor(bottom_navigation_view) @@ -80,9 +83,26 @@ class MainActivity : VMBaseActivity(R.layout.activity_main), } override fun onPageSelected(position: Int) { + pagePosition = position bottom_navigation_view.menu.getItem(position).isChecked = true } + override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean { + event?.let { + when (keyCode) { + KeyEvent.KEYCODE_BACK -> if ( + pagePosition != 0 + && event.isTracking + && !event.isCanceled + ) { + view_pager_main.currentItem = 0 + return true + } + } + } + return super.onKeyUp(keyCode, event) + } + private inner class TabFragmentPageAdapter internal constructor(fm: FragmentManager) : FragmentPagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { @@ -98,6 +118,7 @@ class MainActivity : VMBaseActivity(R.layout.activity_main), override fun getCount(): Int { return 4 } + } override fun observeLiveBus() { From 2544629aa64b1c7d860b09701de9c1bae2673932 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 20 Oct 2019 22:47:45 +0800 Subject: [PATCH 1960/1997] up --- .../main/java/io/legado/app/model/analyzeRule/AnalyzeByXPath.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByXPath.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByXPath.kt index 7cba03083..f2745ee69 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByXPath.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByXPath.kt @@ -121,7 +121,7 @@ class AnalyzeByXPath { if (rules.size == 1) { val jxNodes = jxNode?.sel(xPath) ?: jxDocument?.selN(xPath) jxNodes?.map { - result.add(jxNode.toString()) + result.add(it.asString()) } return result } else { From 3a01981e76986e6536272022f73451cdb72ef028 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 20 Oct 2019 23:17:10 +0800 Subject: [PATCH 1961/1997] up --- app/src/main/res/layout/view_read_menu.xml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/layout/view_read_menu.xml b/app/src/main/res/layout/view_read_menu.xml index 9bba9e02d..7ffd97ee2 100644 --- a/app/src/main/res/layout/view_read_menu.xml +++ b/app/src/main/res/layout/view_read_menu.xml @@ -148,7 +148,7 @@ + android:layout_height="100dp"> From 3415b48a6a78f919b4e18ac9f986920dffda16e7 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 20 Oct 2019 23:19:37 +0800 Subject: [PATCH 1962/1997] up --- app/src/main/res/layout/view_book_page.xml | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/src/main/res/layout/view_book_page.xml b/app/src/main/res/layout/view_book_page.xml index d4874fc79..eb27614ad 100644 --- a/app/src/main/res/layout/view_book_page.xml +++ b/app/src/main/res/layout/view_book_page.xml @@ -10,7 +10,6 @@ From 6038d2cb56c446ca276410399cc62434b3306b54 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 21 Oct 2019 09:35:25 +0800 Subject: [PATCH 1963/1997] up --- .../java/io/legado/app/ui/widget/page/TextPageFactory.kt | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt index 544049bdc..ee237dc02 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/TextPageFactory.kt @@ -69,35 +69,29 @@ class TextPageFactory(dataSource: DataSource) : PageFactory(dataSource getCurrentChapter()?.scrollPage() } else { getCurrentChapter()?.page(pageIndex) - } ?: TextPage(index = pageIndex, title = "index:${pageIndex}") + } } override fun nextPage(): TextPage? = with(dataSource) { if (isScrollDelegate) { return getNextChapter()?.scrollPage() - ?: TextPage(index = pageIndex + 1, title = "index:${pageIndex + 1}") } getCurrentChapter()?.let { if (pageIndex < it.pageSize() - 1) { return getCurrentChapter()?.page(pageIndex + 1)?.removePageAloudSpan() - ?: TextPage(index = pageIndex + 1, title = "index:${pageIndex + 1}") } } return getNextChapter()?.page(0)?.removePageAloudSpan() - ?: TextPage(index = pageIndex + 1, title = "index:${pageIndex + 1}") } override fun previousPage(): TextPage? = with(dataSource) { if (isScrollDelegate) { return getPreviousChapter()?.scrollPage() - ?: TextPage(index = pageIndex + 1, title = "index:${pageIndex + 1}") } if (pageIndex > 0) { return getCurrentChapter()?.page(pageIndex - 1)?.removePageAloudSpan() - ?: TextPage(index = pageIndex - 1, title = "index:${pageIndex - 1}") } return getPreviousChapter()?.lastPage()?.removePageAloudSpan() - ?: TextPage(index = pageIndex - 1, title = "index:${pageIndex - 1}") } From 0b7e210051da8dc2d0a95020b791cd7dfb9c3c4d Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 21 Oct 2019 10:13:55 +0800 Subject: [PATCH 1964/1997] up --- .../page/delegate/HorizontalPageDelegate.kt | 3 -- .../ui/widget/page/delegate/PageDelegate.kt | 32 +++++++++++++++++-- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/HorizontalPageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/HorizontalPageDelegate.kt index 1f0e377a2..1f2b3fa42 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/HorizontalPageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/HorizontalPageDelegate.kt @@ -3,7 +3,6 @@ package io.legado.app.ui.widget.page.delegate import android.view.MotionEvent import io.legado.app.ui.widget.page.PageView import io.legado.app.utils.screenshot -import io.legado.app.utils.snackbar import kotlin.math.abs abstract class HorizontalPageDelegate(pageView: PageView) : PageDelegate(pageView) { @@ -23,7 +22,6 @@ abstract class HorizontalPageDelegate(pageView: PageView) : PageDelegate(pageVie //如果上一页不存在 if (!hasPrev()) { noNext = true - pageView.snackbar("没有上一页") return true } //上一页截图 @@ -32,7 +30,6 @@ abstract class HorizontalPageDelegate(pageView: PageView) : PageDelegate(pageVie //如果不存在表示没有下一页了 if (!hasNext()) { noNext = true - pageView.snackbar("没有下一页") return true } //下一页截图 diff --git a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt index b70a1ac6d..d094e4a82 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/delegate/PageDelegate.kt @@ -8,9 +8,11 @@ import android.view.MotionEvent import android.widget.Scroller import androidx.annotation.CallSuper import androidx.interpolator.view.animation.FastOutLinearInInterpolator +import com.google.android.material.snackbar.Snackbar import io.legado.app.ui.widget.page.ContentView import io.legado.app.ui.widget.page.PageView import io.legado.app.utils.screenshot +import io.legado.app.utils.snackbar import kotlin.math.abs abstract class PageDelegate(protected val pageView: PageView) { @@ -42,6 +44,8 @@ abstract class PageDelegate(protected val pageView: PageView) { protected var atTop: Boolean = false protected var atBottom: Boolean = false + private var snackbar: Snackbar? = null + private val scroller: Scroller by lazy { Scroller( pageView.context, @@ -285,12 +289,36 @@ abstract class PageDelegate(protected val pageView: PageView) { fun hasPrev(): Boolean { //上一页的参数配置 direction = Direction.PREV - return pageView.pageFactory?.hasPrev() == true + val hasPrev = pageView.pageFactory?.hasPrev() == true + if (!hasPrev) { + snackbar ?: let { + snackbar = pageView.snackbar("没有上一页") + } + snackbar?.let { + if (!it.isShown) { + it.setText("没有上一页") + it.show() + } + } + } + return hasPrev } fun hasNext(): Boolean { //进行下一页的配置 direction = Direction.NEXT - return pageView.pageFactory?.hasNext() == true + val hasNext = pageView.pageFactory?.hasNext() == true + if (!hasNext) { + snackbar ?: let { + snackbar = pageView.snackbar("没有下一页") + } + snackbar?.let { + if (!it.isShown) { + it.setText("没有下一页") + it.show() + } + } + } + return hasNext } } \ No newline at end of file From 52e4d43191df951a4f6794f84cf068fa7450fc82 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 21 Oct 2019 10:55:19 +0800 Subject: [PATCH 1965/1997] up --- .../java/io/legado/app/data/entities/BookSource.kt | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/BookSource.kt b/app/src/main/java/io/legado/app/data/entities/BookSource.kt index 6a373bdef..8addf77db 100644 --- a/app/src/main/java/io/legado/app/data/entities/BookSource.kt +++ b/app/src/main/java/io/legado/app/data/entities/BookSource.kt @@ -70,8 +70,15 @@ data class BookSource( val headerMap = HashMap() headerMap["User-Agent"] = App.INSTANCE.getPrefString("user_agent") ?: userAgent header?.let { - GSON.fromJsonObject>(header)?.let { - headerMap.putAll(it) + val header1 = when { + it.startsWith("@js:", true) -> + AppConst.SCRIPT_ENGINE.eval(it.substring(4)).toString() + it.startsWith("", true) -> + AppConst.SCRIPT_ENGINE.eval(it.substring(4, it.lastIndexOf("<"))).toString() + else -> it + } + GSON.fromJsonObject>(header1)?.let { headers -> + headerMap.putAll(headers) } } return headerMap From 3be66e388add4afb2ee1441b8baac884c577b8c3 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 21 Oct 2019 11:00:58 +0800 Subject: [PATCH 1966/1997] up --- app/src/main/java/io/legado/app/data/entities/BookSource.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/data/entities/BookSource.kt b/app/src/main/java/io/legado/app/data/entities/BookSource.kt index 8addf77db..fc79db4c5 100644 --- a/app/src/main/java/io/legado/app/data/entities/BookSource.kt +++ b/app/src/main/java/io/legado/app/data/entities/BookSource.kt @@ -66,6 +66,7 @@ data class BookSource( @IgnoredOnParcel var contentRuleV: ContentRule? = null + @Throws(Exception::class) fun getHeaderMap(): Map { val headerMap = HashMap() headerMap["User-Agent"] = App.INSTANCE.getPrefString("user_agent") ?: userAgent @@ -84,7 +85,6 @@ data class BookSource( return headerMap } - fun getSearchRule(): SearchRule { searchRuleV ?: let { searchRuleV = GSON.fromJsonObject(ruleSearch) From 4bdbb4aadd4302657774a5e6e6740e8d07668ba9 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 21 Oct 2019 11:03:04 +0800 Subject: [PATCH 1967/1997] up --- .../java/io/legado/app/data/entities/BookSource.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/BookSource.kt b/app/src/main/java/io/legado/app/data/entities/BookSource.kt index fc79db4c5..fd5053f02 100644 --- a/app/src/main/java/io/legado/app/data/entities/BookSource.kt +++ b/app/src/main/java/io/legado/app/data/entities/BookSource.kt @@ -21,14 +21,14 @@ import javax.script.SimpleBindings @Parcelize @Entity( - tableName = "book_sources", - indices = [(Index(value = ["bookSourceUrl"], unique = false))] + tableName = "book_sources", + indices = [(Index(value = ["bookSourceUrl"], unique = false))] ) data class BookSource( var bookSourceName: String = "", // 名称 var bookSourceGroup: String? = null, // 分组 @PrimaryKey - var bookSourceUrl: String = "", // 地址,包括 http/https + var bookSourceUrl: String = "", // 地址,包括 http/https var bookSourceType: Int = 0, // 类型,0 文本,1 音频 var bookUrlPattern: String? = null, var customOrder: Int = 0, // 手动排序编号 @@ -78,8 +78,8 @@ data class BookSource( AppConst.SCRIPT_ENGINE.eval(it.substring(4, it.lastIndexOf("<"))).toString() else -> it } - GSON.fromJsonObject>(header1)?.let { headers -> - headerMap.putAll(headers) + GSON.fromJsonObject>(header1)?.let { map -> + headerMap.putAll(map) } } return headerMap From 36cd1a0ca71c704cdc6fab41d5550a56c60ebc09 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 21 Oct 2019 15:06:59 +0800 Subject: [PATCH 1968/1997] up --- .../io/legado/app/data/api/IHttpPostApi.kt | 8 +++ .../io/legado/app/help/http/ByteConverter.kt | 20 ++++++++ .../io/legado/app/help/http/HttpHelper.kt | 9 ++++ .../app/model/analyzeRule/AnalyzeRule.kt | 28 +++++----- .../app/model/analyzeRule/AnalyzeUrl.kt | 50 ++++++++---------- .../app/service/HttpReadAloudService.kt | 51 ++++++++++++++++--- .../java/io/legado/app/utils/NetworkUtils.kt | 8 +-- 7 files changed, 119 insertions(+), 55 deletions(-) create mode 100644 app/src/main/java/io/legado/app/help/http/ByteConverter.kt diff --git a/app/src/main/java/io/legado/app/data/api/IHttpPostApi.kt b/app/src/main/java/io/legado/app/data/api/IHttpPostApi.kt index 0aa3ef3db..92b5f1cf3 100644 --- a/app/src/main/java/io/legado/app/data/api/IHttpPostApi.kt +++ b/app/src/main/java/io/legado/app/data/api/IHttpPostApi.kt @@ -42,4 +42,12 @@ interface IHttpPostApi { @Body body: RequestBody, @HeaderMap headers: Map ): Call + + @FormUrlEncoded + @POST + fun postMapByte( + @Url url: String, + @FieldMap(encoded = true) fieldMap: Map, + @HeaderMap headers: Map + ): Call } diff --git a/app/src/main/java/io/legado/app/help/http/ByteConverter.kt b/app/src/main/java/io/legado/app/help/http/ByteConverter.kt new file mode 100644 index 000000000..0f1682274 --- /dev/null +++ b/app/src/main/java/io/legado/app/help/http/ByteConverter.kt @@ -0,0 +1,20 @@ +package io.legado.app.help.http + +import okhttp3.ResponseBody +import retrofit2.Converter +import retrofit2.Retrofit +import java.lang.reflect.Type + +class ByteConverter() : Converter.Factory() { + + override fun responseBodyConverter( + type: Type?, + annotations: Array?, + retrofit: Retrofit? + ): Converter? { + return Converter { value -> + value.bytes() + } + } + +} diff --git a/app/src/main/java/io/legado/app/help/http/HttpHelper.kt b/app/src/main/java/io/legado/app/help/http/HttpHelper.kt index 2945d2882..eeb54986e 100644 --- a/app/src/main/java/io/legado/app/help/http/HttpHelper.kt +++ b/app/src/main/java/io/legado/app/help/http/HttpHelper.kt @@ -51,6 +51,15 @@ object HttpHelper { .build() } + fun getByteRetrofit(baseUrl: String): Retrofit { + return Retrofit.Builder().baseUrl(baseUrl) + .addConverterFactory(ByteConverter()) + //增加返回值为Observable的支持 + .addCallAdapterFactory(CoroutinesCallAdapterFactory.create()) + .client(client) + .build() + } + private fun getHeaderInterceptor(): Interceptor { return Interceptor { chain -> val request = chain.request() diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt index efdb0397e..13dbfad04 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt @@ -42,7 +42,7 @@ class AnalyzeRule(private var book: BaseBook? = null) { if (content == null) throw AssertionError("Content cannot be null") isJSON = content.toString().isJson() this.content = content - this.baseUrl = baseUrl?.split("\n".toRegex(), 1)?.get(0) + this.baseUrl = baseUrl objectChangedXP = true objectChangedJS = true objectChangedJP = true @@ -150,19 +150,17 @@ class AnalyzeRule(private var book: BaseBook? = null) { if (result is String) { result = listOf((result as String).htmlFormat().split("\n")) } - baseUrl?.let { - if (isUrl && !TextUtils.isEmpty(it)) { - val urlList = ArrayList() - if (result is List<*>) { - for (url in result as List<*>) { - val absoluteURL = NetworkUtils.getAbsoluteURL(it, url.toString()) - if (!urlList.contains(absoluteURL)) { - urlList.add(absoluteURL) - } + if (isUrl) { + val urlList = ArrayList() + if (result is List<*>) { + for (url in result as List<*>) { + val absoluteURL = NetworkUtils.getAbsoluteURL(baseUrl, url.toString()) + if (!absoluteURL.isNullOrEmpty() && !urlList.contains(absoluteURL)) { + urlList.add(absoluteURL) } } - return urlList } + return urlList } @Suppress("UNCHECKED_CAST") return result as? List @@ -212,11 +210,9 @@ class AnalyzeRule(private var book: BaseBook? = null) { } } } - if (result == null) return "" - baseUrl?.let { - return if (isUrl) { - NetworkUtils.getAbsoluteURL(it, result.toString()) - } else result.toString() + if (result == null) result = "" + if (isUrl) { + return NetworkUtils.getAbsoluteURL(baseUrl, result.toString()) ?: "" } return result.toString() } diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt index 714b49418..8c9730fa8 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt @@ -255,23 +255,20 @@ class AnalyzeUrl( return when { method == Method.POST -> { if (fieldMap.isNotEmpty()) { - HttpHelper.getApiService( - baseUrl - ).postMap(url, fieldMap, headerMap) + HttpHelper + .getApiService(baseUrl) + .postMap(url, fieldMap, headerMap) } else { - HttpHelper.getApiService( - baseUrl - ).postBody( - url, - body, - headerMap - ) + HttpHelper + .getApiService(baseUrl) + .postBody(url, body, headerMap) } } - fieldMap.isEmpty() -> HttpHelper.getApiService( - baseUrl - ).get(url, headerMap) - else -> HttpHelper.getApiService(baseUrl) + fieldMap.isEmpty() -> HttpHelper + .getApiService(baseUrl) + .get(url, headerMap) + else -> HttpHelper + .getApiService(baseUrl) .getMap(url, fieldMap, headerMap) } } @@ -280,23 +277,20 @@ class AnalyzeUrl( return when { method == Method.POST -> { if (fieldMap.isNotEmpty()) { - HttpHelper.getApiService( - baseUrl - ).postMapAsync(url, fieldMap, headerMap) + HttpHelper + .getApiService(baseUrl) + .postMapAsync(url, fieldMap, headerMap) } else { - HttpHelper.getApiService( - baseUrl - ).postBodyAsync( - url, - body, - headerMap - ) + HttpHelper + .getApiService(baseUrl) + .postBodyAsync(url, body, headerMap) } } - fieldMap.isEmpty() -> HttpHelper.getApiService( - baseUrl - ).getAsync(url, headerMap) - else -> HttpHelper.getApiService(baseUrl) + fieldMap.isEmpty() -> HttpHelper + .getApiService(baseUrl) + .getAsync(url, headerMap) + else -> HttpHelper + .getApiService(baseUrl) .getMapAsync(url, fieldMap, headerMap) } } diff --git a/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt b/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt index 2dde06378..fb25b4e2d 100644 --- a/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/HttpReadAloudService.kt @@ -3,10 +3,20 @@ package io.legado.app.service import android.app.PendingIntent import android.media.MediaPlayer import io.legado.app.constant.Bus +import io.legado.app.data.api.IHttpPostApi +import io.legado.app.help.FileHelp import io.legado.app.help.IntentHelp +import io.legado.app.help.http.HttpHelper import io.legado.app.utils.getPrefInt import io.legado.app.utils.getPrefString import io.legado.app.utils.postEvent +import kotlinx.coroutines.Dispatchers.IO +import kotlinx.coroutines.Dispatchers.Main +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import org.jetbrains.anko.toast +import java.io.File +import java.io.FileInputStream class HttpReadAloudService : BaseReadAloudService(), MediaPlayer.OnPreparedListener, @@ -27,19 +37,46 @@ class HttpReadAloudService : BaseReadAloudService(), mediaPlayer.release() } - private fun getAudioPath(): String { - val audioText = contentList[nowSpeak] + private fun getAudioBody(): Map { val spd = (getPrefInt("ttsSpeechRate", 25) + 5) / 5 val per = getPrefString("ttsSpeechPer") ?: "0" - return "http://tts.baidu.com/text2audio?idx=1&tex=$audioText&cuid=baidu_speech_demo&cod=2&lan=zh&ctp=1&pdt=1&spd=$spd&per=$per&vol=5&pit=5&_res_tag_=audio" + return mapOf( + Pair("idx", "1"), + Pair("tex", contentList[nowSpeak]), + Pair("cuid", "baidu_speech_demo "), + Pair("cod", "2"), + Pair("lan", "zh"), + Pair("ctp", "1"), + Pair("pdt", "1"), + Pair("spd", spd.toString()), + Pair("per", per), + Pair("vol", "5"), + Pair("pit", "5"), + Pair("_res_tag_", "audio") + ) } override fun play() { if (contentList.isEmpty()) return - if (requestFocus()) { - mediaPlayer.reset() - mediaPlayer.setDataSource(getAudioPath()) - mediaPlayer.prepareAsync() + launch(IO) { + if (requestFocus()) { + val bytes = HttpHelper.getByteRetrofit("http://tts.baidu.com") + .create(IHttpPostApi::class.java) + .postMapByte("http://tts.baidu.com/text2audio", getAudioBody(), mapOf()) + .execute().body() + if (bytes == null) { + withContext(Main) { + toast("访问失败") + } + } else { + val file = + FileHelp.getFile(cacheDir.absolutePath + File.separator + "bdTts.mp3") + file.writeBytes(bytes) + mediaPlayer.reset() + mediaPlayer.setDataSource(FileInputStream(file).fd) + mediaPlayer.prepareAsync() + } + } } } diff --git a/app/src/main/java/io/legado/app/utils/NetworkUtils.kt b/app/src/main/java/io/legado/app/utils/NetworkUtils.kt index 7b1b23b32..3f42784f9 100644 --- a/app/src/main/java/io/legado/app/utils/NetworkUtils.kt +++ b/app/src/main/java/io/legado/app/utils/NetworkUtils.kt @@ -1,6 +1,5 @@ package io.legado.app.utils -import android.text.TextUtils import retrofit2.Response import java.net.URL import java.util.* @@ -71,11 +70,12 @@ object NetworkUtils { /** * 获取绝对地址 */ - fun getAbsoluteURL(baseURL: String, relativePath: String): String { + fun getAbsoluteURL(baseURL: String?, relativePath: String?): String? { + if (baseURL.isNullOrEmpty()) return relativePath + if (relativePath.isNullOrEmpty()) return baseURL var relativeUrl = relativePath - if (TextUtils.isEmpty(baseURL)) return relativePath try { - val absoluteUrl = URL(baseURL) + val absoluteUrl = URL(baseURL.substringBefore(",")) val parseUrl = URL(absoluteUrl, relativePath) relativeUrl = parseUrl.toString() return relativeUrl From deba599a0b925496fa898c8f9edc7eacff7dffc5 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 21 Oct 2019 15:31:17 +0800 Subject: [PATCH 1969/1997] up --- app/src/main/java/io/legado/app/constant/AppConst.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/constant/AppConst.kt b/app/src/main/java/io/legado/app/constant/AppConst.kt index 6503839bc..991da0859 100644 --- a/app/src/main/java/io/legado/app/constant/AppConst.kt +++ b/app/src/main/java/io/legado/app/constant/AppConst.kt @@ -19,8 +19,6 @@ object AppConst { const val channelIdReadAloud = "channel_read_aloud" const val channelIdWeb = "channel_web" - val NOT_AVAILABLE = App.INSTANCE.getString(R.string.not_available) - val userAgent: String by lazy { "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36" } From a0d6c9f842f7996afd228f00d21745a0b6deca86 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 21 Oct 2019 15:41:10 +0800 Subject: [PATCH 1970/1997] up --- .../app/ui/book/source/edit/BookSourceEditActivity.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt index 267890628..409b8701d 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt @@ -169,11 +169,11 @@ class BookSourceEditActivity : add(EditEntity("init", infoRule?.init, R.string.rule_book_info_init)) add(EditEntity("name", infoRule?.name, R.string.rule_book_name)) add(EditEntity("author", infoRule?.author, R.string.rule_book_author)) - add(EditEntity("coverUrl", infoRule?.coverUrl, R.string.rule_cover_url)) - add(EditEntity("intro", infoRule?.intro, R.string.rule_book_intro)) add(EditEntity("kind", infoRule?.kind, R.string.rule_book_kind)) add(EditEntity("wordCount", infoRule?.wordCount, R.string.rule_word_count)) add(EditEntity("lastChapter", infoRule?.lastChapter, R.string.rule_last_chapter)) + add(EditEntity("intro", infoRule?.intro, R.string.rule_book_intro)) + add(EditEntity("coverUrl", infoRule?.coverUrl, R.string.rule_cover_url)) add(EditEntity("tocUrl", infoRule?.tocUrl, R.string.rule_toc_url)) } } @@ -212,8 +212,8 @@ class BookSourceEditActivity : add(EditEntity("author", exploreRule?.author, R.string.rule_book_author)) add(EditEntity("kind", exploreRule?.kind, R.string.rule_book_kind)) add(EditEntity("wordCount", exploreRule?.wordCount, R.string.rule_word_count)) - add(EditEntity("intro", exploreRule?.intro, R.string.rule_book_intro)) add(EditEntity("lastChapter", exploreRule?.lastChapter, R.string.rule_last_chapter)) + add(EditEntity("intro", exploreRule?.intro, R.string.rule_book_intro)) add(EditEntity("coverUrl", exploreRule?.coverUrl, R.string.rule_cover_url)) add(EditEntity("bookUrl", exploreRule?.bookUrl, R.string.rule_book_url)) } From c0cc09822da92660cf97b3c5fb387dbf63df74d5 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 21 Oct 2019 17:26:43 +0800 Subject: [PATCH 1971/1997] up --- .../ui/book/source/edit/BookSourceEditViewModel.kt | 13 ++++++++----- .../ui/rss/source/edit/RssSourceEditViewModel.kt | 3 ++- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditViewModel.kt b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditViewModel.kt index 61cc49858..d50601117 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditViewModel.kt @@ -13,7 +13,7 @@ import io.legado.app.help.storage.OldRule class BookSourceEditViewModel(application: Application) : BaseViewModel(application) { val sourceLiveData: MutableLiveData = MutableLiveData() - var oldSourceUrl: String? = null + private var oldSourceUrl: String? = null fun initData(intent: Intent) { execute { @@ -33,7 +33,7 @@ class BookSourceEditViewModel(application: Application) : BaseViewModel(applicat } } - fun save(bookSource: BookSource, finally: (() -> Unit)? = null) { + fun save(bookSource: BookSource, success: (() -> Unit)? = null) { execute { oldSourceUrl?.let { if (oldSourceUrl != bookSource.bookSourceUrl) { @@ -42,9 +42,12 @@ class BookSourceEditViewModel(application: Application) : BaseViewModel(applicat } oldSourceUrl = bookSource.bookSourceUrl App.db.bookSourceDao().insert(bookSource) - }.onFinally { - finally?.let { it() } - } + }.onSuccess { + success?.invoke() + }.onError { + toast(it.localizedMessage) + it.printStackTrace() + } } fun pasteSource() { diff --git a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt index 8b0f2cd11..38fb18e98 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/edit/RssSourceEditViewModel.kt @@ -14,7 +14,7 @@ import io.legado.app.utils.fromJsonObject class RssSourceEditViewModel(application: Application) : BaseViewModel(application) { val sourceLiveData: MutableLiveData = MutableLiveData() - var oldSourceUrl: String? = null + private var oldSourceUrl: String? = null fun initData(intent: Intent) { execute { @@ -47,6 +47,7 @@ class RssSourceEditViewModel(application: Application) : BaseViewModel(applicati success() }.onError { toast(it.localizedMessage) + it.printStackTrace() } } From e70bf34472dadb8c22a1352e08250afedf9632f2 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 21 Oct 2019 20:08:07 +0800 Subject: [PATCH 1972/1997] up --- app/src/main/java/io/legado/app/model/webbook/BookInfo.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt b/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt index c80ce8c55..d7f1447ce 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt @@ -17,7 +17,7 @@ object BookInfo { bookSource: BookSource, analyzeUrl: AnalyzeUrl ) { - val baseUrl = analyzeUrl.url + val baseUrl = analyzeUrl.ruleUrl body ?: throw Exception( App.INSTANCE.getString( R.string.error_get_web_content, From f2fbdbec2d075faeccd08c84c5435dccd3a964bf Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 21 Oct 2019 21:16:18 +0800 Subject: [PATCH 1973/1997] up --- .../io/legado/app/data/entities/BaseBook.kt | 3 + .../java/io/legado/app/data/entities/Book.kt | 15 ++- .../io/legado/app/data/entities/SearchBook.kt | 14 ++- .../main/java/io/legado/app/model/WebBook.kt | 40 ++++---- .../app/model/webbook/BookChapterList.kt | 29 ++---- .../legado/app/model/webbook/BookContent.kt | 2 +- .../io/legado/app/model/webbook/BookInfo.kt | 44 +++++---- .../io/legado/app/model/webbook/BookList.kt | 94 ++++++++++--------- .../legado/app/model/webbook/SourceDebug.kt | 45 ++++----- 9 files changed, 156 insertions(+), 130 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/BaseBook.kt b/app/src/main/java/io/legado/app/data/entities/BaseBook.kt index 144f59ec4..bd5c28db3 100644 --- a/app/src/main/java/io/legado/app/data/entities/BaseBook.kt +++ b/app/src/main/java/io/legado/app/data/entities/BaseBook.kt @@ -7,6 +7,9 @@ interface BaseBook { var kind: String? var wordCount: String? + var infoHtml: String? + var tocHtml: String? + fun putVariable(key: String, value: String) fun getKindList(): List { diff --git a/app/src/main/java/io/legado/app/data/entities/Book.kt b/app/src/main/java/io/legado/app/data/entities/Book.kt index 15dd497a8..2b26dcf72 100644 --- a/app/src/main/java/io/legado/app/data/entities/Book.kt +++ b/app/src/main/java/io/legado/app/data/entities/Book.kt @@ -47,10 +47,18 @@ data class Book( var useReplaceRule: Boolean = true, // 正文使用净化替换规则 var variable: String? = null // 自定义书籍变量信息(用于书源规则检索书籍信息) ) : Parcelable, BaseBook { - @IgnoredOnParcel @Ignore + @IgnoredOnParcel override var variableMap: HashMap = GSON.fromJsonObject(variable) ?: HashMap() + @Ignore + @IgnoredOnParcel + override var infoHtml: String? = null + + @Ignore + @IgnoredOnParcel + override var tocHtml: String? = null + fun getUnreadChapterNum() = max(totalChapterNum - durChapterIndex - 1, 0) fun getDisplayCover() = if (customCoverUrl.isNullOrEmpty()) coverUrl else customCoverUrl @@ -77,6 +85,9 @@ data class Book( tocUrl = tocUrl, originOrder = originOrder, variable = variable - ) + ).apply { + this.infoHtml = this@Book.infoHtml + this.tocHtml = this@Book.tocHtml + } } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt index ec107ef77..7457c9b29 100644 --- a/app/src/main/java/io/legado/app/data/entities/SearchBook.kt +++ b/app/src/main/java/io/legado/app/data/entities/SearchBook.kt @@ -27,10 +27,17 @@ data class SearchBook( var tocUrl: String = "", // 目录页Url (toc=table of Contents) var time: Long = System.currentTimeMillis(), var variable: String? = null, - var bookInfoHtml: String? = null, var originOrder: Int = 0 ) : Parcelable, BaseBook, Comparable { + @Ignore + @IgnoredOnParcel + override var infoHtml: String? = null + + @Ignore + @IgnoredOnParcel + override var tocHtml: String? = null + override fun equals(other: Any?): Boolean { if (other is SearchBook) { if (other.bookUrl == bookUrl) { @@ -72,6 +79,9 @@ data class SearchBook( tocUrl = tocUrl, originOrder = originOrder, variable = variable - ) + ).apply { + this.infoHtml = this@SearchBook.infoHtml + this.tocUrl = this@SearchBook.tocUrl + } } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/model/WebBook.kt b/app/src/main/java/io/legado/app/model/WebBook.kt index 9201fd542..9a2371d00 100644 --- a/app/src/main/java/io/legado/app/model/WebBook.kt +++ b/app/src/main/java/io/legado/app/model/WebBook.kt @@ -73,14 +73,18 @@ class WebBook(val bookSource: BookSource) { context: CoroutineContext = Dispatchers.IO ): Coroutine { return Coroutine.async(scope, context) { - val analyzeUrl = AnalyzeUrl( - book = book, - ruleUrl = book.bookUrl, - baseUrl = sourceUrl, - headerMapF = bookSource.getHeaderMap() - ) - val response = analyzeUrl.getResponseAsync().await() - BookInfo.analyzeBookInfo(book, response.body(), bookSource, analyzeUrl) + val body = if (book.infoHtml.isNullOrEmpty()) { + val analyzeUrl = AnalyzeUrl( + book = book, + ruleUrl = book.bookUrl, + baseUrl = sourceUrl, + headerMapF = bookSource.getHeaderMap() + ) + analyzeUrl.getResponseAsync().await().body() + } else { + book.infoHtml + } + BookInfo.analyzeBookInfo(book, body, bookSource, book.bookUrl) book } } @@ -94,14 +98,18 @@ class WebBook(val bookSource: BookSource) { context: CoroutineContext = Dispatchers.IO ): Coroutine> { return Coroutine.async(scope, context) { - val analyzeUrl = AnalyzeUrl( - book = book, - ruleUrl = book.tocUrl, - baseUrl = book.bookUrl, - headerMapF = bookSource.getHeaderMap() - ) - val response = analyzeUrl.getResponseAsync().await() - BookChapterList.analyzeChapterList(this, book, response, bookSource, analyzeUrl) + val body = if (book.bookUrl == book.tocUrl && book.tocHtml.isNullOrEmpty()) { + val analyzeUrl = AnalyzeUrl( + book = book, + ruleUrl = book.tocUrl, + baseUrl = book.bookUrl, + headerMapF = bookSource.getHeaderMap() + ) + analyzeUrl.getResponseAsync().await().body() + } else { + book.tocUrl + } + BookChapterList.analyzeChapterList(this, book, body, bookSource, book.tocUrl) } } diff --git a/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt b/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt index 13c4ab54b..5207b9e43 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt @@ -9,30 +9,23 @@ import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.rule.TocRule import io.legado.app.model.analyzeRule.AnalyzeRule import io.legado.app.model.analyzeRule.AnalyzeUrl -import io.legado.app.utils.NetworkUtils import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.withContext -import retrofit2.Response object BookChapterList { suspend fun analyzeChapterList( coroutineScope: CoroutineScope, book: Book, - response: Response, + body: String?, bookSource: BookSource, - analyzeUrl: AnalyzeUrl + baseUrl: String ): List { var chapterList = arrayListOf() - val baseUrl: String = NetworkUtils.getUrl(response) - val body: String? = response.body() body ?: throw Exception( - App.INSTANCE.getString( - R.string.error_get_web_content, - analyzeUrl.ruleUrl - ) + App.INSTANCE.getString(R.string.error_get_web_content, baseUrl) ) - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取成功:${analyzeUrl.ruleUrl}") + SourceDebug.printLog(bookSource.bookSourceUrl, "获取成功:${baseUrl}") val tocRule = bookSource.getTocRule() val nextUrlList = arrayListOf(baseUrl) var reverse = false @@ -140,7 +133,7 @@ object BookChapterList { val analyzeRule = AnalyzeRule(book) analyzeRule.setContent(body, baseUrl) if (getNextUrl) { - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取目录下一页列表", printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, "获取目录下一页列表", print = printLog) analyzeRule.getStringList(tocRule.nextTocUrl ?: "", true)?.let { for (item in it) { if (item != baseUrl) { @@ -150,16 +143,15 @@ object BookChapterList { } SourceDebug.printLog( bookSource.bookSourceUrl, - 1, TextUtils.join(",", nextUrlList), - printLog + print = printLog ) } - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "解析目录列表", printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, "解析目录列表", print = printLog) val elements = analyzeRule.getElements(listRule) - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "目录数${elements.size}", printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, "目录数${elements.size}", print = printLog) if (elements.isNotEmpty()) { - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取目录", printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, "获取目录", print = printLog) val nameRule = analyzeRule.splitSourceRule(tocRule.chapterName ?: "") val urlRule = analyzeRule.splitSourceRule(tocRule.chapterUrl ?: "") for (item in elements) { @@ -175,9 +167,8 @@ object BookChapterList { } SourceDebug.printLog( bookSource.bookSourceUrl, - 1, "${chapterList[0].title}${chapterList[0].url}", - printLog + print = printLog ) } return ChapterData(chapterList, nextUrlList) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookContent.kt b/app/src/main/java/io/legado/app/model/webbook/BookContent.kt index fc5178104..65384aa77 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookContent.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookContent.kt @@ -34,7 +34,7 @@ object BookContent { analyzeUrl.ruleUrl ) ) - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取成功:${analyzeUrl.ruleUrl}") + SourceDebug.printLog(bookSource.bookSourceUrl, "获取成功:${analyzeUrl.ruleUrl}") val content = StringBuilder() val nextUrlList = arrayListOf(baseUrl) val contentRule = bookSource.getContentRule() diff --git a/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt b/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt index d7f1447ce..a3b1f29ba 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookInfo.kt @@ -5,7 +5,6 @@ import io.legado.app.R import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookSource import io.legado.app.model.analyzeRule.AnalyzeRule -import io.legado.app.model.analyzeRule.AnalyzeUrl import io.legado.app.utils.htmlFormat object BookInfo { @@ -15,59 +14,58 @@ object BookInfo { book: Book, body: String?, bookSource: BookSource, - analyzeUrl: AnalyzeUrl + baseUrl: String ) { - val baseUrl = analyzeUrl.ruleUrl body ?: throw Exception( - App.INSTANCE.getString( - R.string.error_get_web_content, - analyzeUrl.ruleUrl - ) + App.INSTANCE.getString(R.string.error_get_web_content, baseUrl) ) - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取成功:${analyzeUrl.ruleUrl}") + SourceDebug.printLog(bookSource.bookSourceUrl, "获取成功:${baseUrl}") val infoRule = bookSource.getBookInfoRule() val analyzeRule = AnalyzeRule(book) analyzeRule.setContent(body, baseUrl) infoRule.init?.let { if (it.isNotEmpty()) { - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "执行详情页初始化规则") + SourceDebug.printLog(bookSource.bookSourceUrl, "执行详情页初始化规则") analyzeRule.setContent(analyzeRule.getElement(it)) } } - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取书名") + SourceDebug.printLog(bookSource.bookSourceUrl, "获取书名") analyzeRule.getString(infoRule.name ?: "")?.let { if (it.isNotEmpty()) book.name = it } - SourceDebug.printLog(bookSource.bookSourceUrl, 1, book.name) - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取作者") + SourceDebug.printLog(bookSource.bookSourceUrl, book.name) + SourceDebug.printLog(bookSource.bookSourceUrl, "获取作者") analyzeRule.getString(infoRule.author ?: "")?.let { if (it.isNotEmpty()) book.author = it } - SourceDebug.printLog(bookSource.bookSourceUrl, 1, book.author) - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取分类") + SourceDebug.printLog(bookSource.bookSourceUrl, book.author) + SourceDebug.printLog(bookSource.bookSourceUrl, "获取分类") analyzeRule.getString(infoRule.kind ?: "")?.let { if (it.isNotEmpty()) book.kind = it } - SourceDebug.printLog(bookSource.bookSourceUrl, 1, book.kind ?: "") - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取简介") + SourceDebug.printLog(bookSource.bookSourceUrl, book.kind) + SourceDebug.printLog(bookSource.bookSourceUrl, "获取简介") analyzeRule.getString(infoRule.intro ?: "")?.let { if (it.isNotEmpty()) book.intro = it.htmlFormat() } - SourceDebug.printLog(bookSource.bookSourceUrl, 1, book.intro ?: "", isHtml = true) - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取字数") + SourceDebug.printLog(bookSource.bookSourceUrl, book.intro, isHtml = true) + SourceDebug.printLog(bookSource.bookSourceUrl, "获取字数") analyzeRule.getString(infoRule.wordCount ?: "")?.let { if (it.isNotEmpty()) book.wordCount = it } - SourceDebug.printLog(bookSource.bookSourceUrl, 1, book.wordCount ?: "") - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取最新章节") + SourceDebug.printLog(bookSource.bookSourceUrl, book.wordCount) + SourceDebug.printLog(bookSource.bookSourceUrl, "获取最新章节") analyzeRule.getString(infoRule.lastChapter ?: "")?.let { if (it.isNotEmpty()) book.latestChapterTitle = it } - SourceDebug.printLog(bookSource.bookSourceUrl, 1, book.latestChapterTitle ?: "") - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取目录Url") + SourceDebug.printLog(bookSource.bookSourceUrl, book.latestChapterTitle) + SourceDebug.printLog(bookSource.bookSourceUrl, "获取目录Url") book.tocUrl = analyzeRule.getString(infoRule.tocUrl ?: "", true) ?: baseUrl if (book.tocUrl.isEmpty()) book.tocUrl = baseUrl - SourceDebug.printLog(bookSource.bookSourceUrl, 1, book.tocUrl) + if (book.tocUrl == baseUrl) { + book.tocHtml = body + } + SourceDebug.printLog(bookSource.bookSourceUrl, book.tocUrl) } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/model/webbook/BookList.kt b/app/src/main/java/io/legado/app/model/webbook/BookList.kt index 8d953c342..65a3ded0f 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookList.kt @@ -28,14 +28,14 @@ object BookList { analyzeUrl.ruleUrl ) ) - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取成功:${analyzeUrl.ruleUrl}") + SourceDebug.printLog(bookSource.bookSourceUrl, "获取成功:${analyzeUrl.ruleUrl}") val analyzeRule = AnalyzeRule(null) analyzeRule.setContent(body, baseUrl) bookSource.bookUrlPattern?.let { if (baseUrl.matches(it.toRegex())) { - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "url为详情页") + SourceDebug.printLog(bookSource.bookSourceUrl, "url为详情页") getInfoItem(analyzeRule, bookSource, baseUrl)?.let { searchBook -> - searchBook.bookInfoHtml = body + searchBook.infoHtml = body bookList.add(searchBook) } return bookList @@ -56,12 +56,12 @@ object BookList { if (ruleList.startsWith("+")) { ruleList = ruleList.substring(1) } - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "解析书籍列表") + SourceDebug.printLog(bookSource.bookSourceUrl, "解析书籍列表") collections = analyzeRule.getElements(ruleList) if (collections.isEmpty() && bookSource.bookUrlPattern.isNullOrEmpty()) { - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "列表为空,按详情页解析") + SourceDebug.printLog(bookSource.bookSourceUrl, "列表为空,按详情页解析") getInfoItem(analyzeRule, bookSource, baseUrl)?.let { searchBook -> - searchBook.bookInfoHtml = body + searchBook.infoHtml = body bookList.add(searchBook) } } else { @@ -73,7 +73,7 @@ object BookList { val ruleKind = analyzeRule.splitSourceRule(bookListRule.kind ?: "") val ruleLastChapter = analyzeRule.splitSourceRule(bookListRule.lastChapter ?: "") val ruleWordCount = analyzeRule.splitSourceRule(bookListRule.wordCount ?: "") - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "列表数为${collections.size}") + SourceDebug.printLog(bookSource.bookSourceUrl, "列表数为${collections.size}") for ((index, item) in collections.withIndex()) { getSearchItem( item, @@ -91,7 +91,7 @@ object BookList { ruleWordCount = ruleWordCount )?.let { searchBook -> if (baseUrl == searchBook.bookUrl) { - searchBook.bookInfoHtml = body + searchBook.infoHtml = body } bookList.add(searchBook) } @@ -117,38 +117,36 @@ object BookList { with(bookSource.getBookInfoRule()) { init?.let { if (it.isNotEmpty()) { - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "执行详情页初始化规则") + SourceDebug.printLog(bookSource.bookSourceUrl, "执行详情页初始化规则") analyzeRule.setContent(analyzeRule.getElement(it)) } } - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取书名") + SourceDebug.printLog(bookSource.bookSourceUrl, "获取书名") searchBook.name = analyzeRule.getString(name ?: "") ?: "" - SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.name) + SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.name) if (searchBook.name.isNotEmpty()) { - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取作者") + SourceDebug.printLog(bookSource.bookSourceUrl, "获取作者") searchBook.author = BookHelp.formatAuthor(analyzeRule.getString(author ?: "")) - SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.author) - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取分类") + SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.author) + SourceDebug.printLog(bookSource.bookSourceUrl, "获取分类") searchBook.kind = analyzeRule.getString(kind ?: "") - SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.kind ?: "") - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取简介") + SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.kind) + SourceDebug.printLog(bookSource.bookSourceUrl, "获取简介") searchBook.intro = analyzeRule.getString(intro ?: "") SourceDebug.printLog( - bookSource.bookSourceUrl, 1, searchBook.intro - ?: "", isHtml = true + bookSource.bookSourceUrl, + msg = searchBook.intro, + isHtml = true ) - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取字数") + SourceDebug.printLog(bookSource.bookSourceUrl, "获取字数") searchBook.wordCount = analyzeRule.getString(wordCount ?: "") - SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.wordCount ?: "") - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取封面Url") + SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.wordCount) + SourceDebug.printLog(bookSource.bookSourceUrl, "获取封面Url") searchBook.coverUrl = analyzeRule.getString(coverUrl ?: "", true) - SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.coverUrl ?: "") - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取最新章节") + SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.coverUrl) + SourceDebug.printLog(bookSource.bookSourceUrl, "获取最新章节") searchBook.latestChapterTitle = analyzeRule.getString(lastChapter ?: "") - SourceDebug.printLog( - bookSource.bookSourceUrl, 1, searchBook.latestChapterTitle - ?: "" - ) + SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.latestChapterTitle) return searchBook } } @@ -176,36 +174,42 @@ object BookList { searchBook.originOrder = bookSource.customOrder analyzeRule.setBook(searchBook) analyzeRule.setContent(item) - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取书名", printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, "获取书名", print = printLog) searchBook.name = analyzeRule.getString(ruleName) - SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.name, printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.name, print = printLog) if (searchBook.name.isNotEmpty()) { - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取书籍Url", printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, "获取书籍Url", print = printLog) searchBook.bookUrl = analyzeRule.getString(ruleBookUrl, true) - SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.bookUrl, printLog) - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取作者", printLog) + if (searchBook.bookUrl.isEmpty()) { + searchBook.bookUrl = baseUrl + } + SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.bookUrl, print = printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, "获取作者", print = printLog) searchBook.author = BookHelp.formatAuthor(analyzeRule.getString(ruleAuthor)) - SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.author, printLog) - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取分类", printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.author, print = printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, "获取分类", print = printLog) searchBook.kind = analyzeRule.getString(ruleKind) - SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.kind ?: "", printLog) - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取简介", printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.kind, print = printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, "获取简介", print = printLog) searchBook.intro = analyzeRule.getString(ruleIntro) SourceDebug.printLog( - bookSource.bookSourceUrl, 1, searchBook.intro - ?: "", printLog, true + bookSource.bookSourceUrl, + searchBook.intro, + print = printLog, + isHtml = true ) - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取字数", printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, "获取字数", print = printLog) searchBook.wordCount = analyzeRule.getString(ruleWordCount) - SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.wordCount ?: "", printLog) - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取封面Url", printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.wordCount, print = printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, "获取封面Url", print = printLog) searchBook.coverUrl = analyzeRule.getString(ruleCoverUrl, true) - SourceDebug.printLog(bookSource.bookSourceUrl, 1, searchBook.coverUrl ?: "", printLog) - SourceDebug.printLog(bookSource.bookSourceUrl, 1, "获取最新章节", printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.coverUrl, print = printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, "获取最新章节", print = printLog) searchBook.latestChapterTitle = analyzeRule.getString(ruleLastChapter) SourceDebug.printLog( - bookSource.bookSourceUrl, 1, searchBook.latestChapterTitle - ?: "", printLog + bookSource.bookSourceUrl, + searchBook.latestChapterTitle, + print = printLog ) return searchBook } diff --git a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt index 97008b566..f6762c0f1 100644 --- a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt +++ b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt @@ -24,19 +24,20 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { @Synchronized fun printLog( sourceUrl: String?, - state: Int, - msg: String, + msg: String?, + state: Int = 1, print: Boolean = true, isHtml: Boolean = false, showTime: Boolean = true ) { if (debugSource != sourceUrl || callback == null || !print) return - var printMsg = msg + var printMsg = msg ?: "" if (isHtml) { printMsg = printMsg.htmlFormat() } if (showTime) { - printMsg = "${DEBUG_TIME_FORMAT.format(Date(System.currentTimeMillis() - startTime))} $printMsg" + printMsg = + "${DEBUG_TIME_FORMAT.format(Date(System.currentTimeMillis() - startTime))} $printMsg" } callback?.printLog(state, printMsg) } @@ -64,10 +65,10 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { val book = Book() book.origin = webBook.sourceUrl book.bookUrl = key - printLog(webBook.sourceUrl, 1, "开始访问$key") + printLog(webBook.sourceUrl, "开始访问$key") infoDebug(book) } else { - printLog(webBook.sourceUrl, 1, "开始搜索关键字$key") + printLog(webBook.sourceUrl, "开始搜索关键字$key") searchDebug(key) } } @@ -77,65 +78,65 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { .onSuccess { searchBooks -> searchBooks?.let { if (searchBooks.isNotEmpty()) { - printLog(debugSource, 1, "搜索完成") - printLog(debugSource, 1, "", showTime = false) + printLog(debugSource, "搜索完成") + printLog(debugSource, "", showTime = false) infoDebug(searchBooks[0].toBook()) } else { - printLog(debugSource, -1, "未获取到书籍") + printLog(debugSource, "未获取到书籍", -1) } } } .onError { - printLog(debugSource, -1, it.localizedMessage) + printLog(debugSource, it.localizedMessage, -1) } tasks.add(search) } private fun infoDebug(book: Book) { - printLog(debugSource, 1, "开始获取详情页") + printLog(debugSource, "开始获取详情页") val info = webBook.getBookInfo(book) .onSuccess { - printLog(debugSource, 1, "详情页完成") - printLog(debugSource, 1, "", showTime = false) + printLog(debugSource, "详情页完成") + printLog(debugSource, "", showTime = false) tocDebug(book) } .onError { - printLog(debugSource, -1, it.localizedMessage) + printLog(debugSource, it.localizedMessage, -1) } tasks.add(info) } private fun tocDebug(book: Book) { - printLog(debugSource, 1, "开始获取目录页") + printLog(debugSource, "开始获取目录页") val chapterList = webBook.getChapterList(book) .onSuccess { chapterList -> chapterList?.let { if (it.isNotEmpty()) { - printLog(debugSource, 1, "目录完成") - printLog(debugSource, 1, "", showTime = false) + printLog(debugSource, "目录完成") + printLog(debugSource, "", showTime = false) val nextChapterUrl = if (it.size > 1) it[1].url else null contentDebug(book, it[0], nextChapterUrl) } else { - printLog(debugSource, -1, "目录列表为空") + printLog(debugSource, "目录列表为空", -1) } } } .onError { - printLog(debugSource, -1, it.localizedMessage) + printLog(debugSource, it.localizedMessage, -1) } tasks.add(chapterList) } private fun contentDebug(book: Book, bookChapter: BookChapter, nextChapterUrl: String?) { - printLog(debugSource, 1, "开始获取内容") + printLog(debugSource, "开始获取内容") val content = webBook.getContent(book, bookChapter, nextChapterUrl) .onSuccess { content -> content?.let { - printLog(debugSource, 1000, it) + printLog(debugSource, it, 1000) } } .onError { - printLog(debugSource, -1, it.localizedMessage) + printLog(debugSource, it.localizedMessage, -1) } tasks.add(content) } From 66f17ba898926a2d88165d3ae5a0331eaa38d8f9 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 21 Oct 2019 22:12:24 +0800 Subject: [PATCH 1974/1997] up --- app/src/main/java/io/legado/app/model/WebBook.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/model/WebBook.kt b/app/src/main/java/io/legado/app/model/WebBook.kt index 9a2371d00..7dc90b751 100644 --- a/app/src/main/java/io/legado/app/model/WebBook.kt +++ b/app/src/main/java/io/legado/app/model/WebBook.kt @@ -107,7 +107,7 @@ class WebBook(val bookSource: BookSource) { ) analyzeUrl.getResponseAsync().await().body() } else { - book.tocUrl + book.tocHtml } BookChapterList.analyzeChapterList(this, book, body, bookSource, book.tocUrl) } From ca910982ebead4fbf0171d6e026b8fe977713caa Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 21 Oct 2019 22:21:24 +0800 Subject: [PATCH 1975/1997] up --- .../app/model/webbook/BookChapterList.kt | 12 ++--- .../io/legado/app/model/webbook/BookList.kt | 47 +++++++------------ .../legado/app/model/webbook/SourceDebug.kt | 18 +++---- 3 files changed, 32 insertions(+), 45 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt b/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt index 5207b9e43..67968f39f 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookChapterList.kt @@ -133,7 +133,7 @@ object BookChapterList { val analyzeRule = AnalyzeRule(book) analyzeRule.setContent(body, baseUrl) if (getNextUrl) { - SourceDebug.printLog(bookSource.bookSourceUrl, "获取目录下一页列表", print = printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, "获取目录下一页列表", printLog) analyzeRule.getStringList(tocRule.nextTocUrl ?: "", true)?.let { for (item in it) { if (item != baseUrl) { @@ -144,14 +144,14 @@ object BookChapterList { SourceDebug.printLog( bookSource.bookSourceUrl, TextUtils.join(",", nextUrlList), - print = printLog + printLog ) } - SourceDebug.printLog(bookSource.bookSourceUrl, "解析目录列表", print = printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, "解析目录列表", printLog) val elements = analyzeRule.getElements(listRule) - SourceDebug.printLog(bookSource.bookSourceUrl, "目录数${elements.size}", print = printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, "目录数${elements.size}", printLog) if (elements.isNotEmpty()) { - SourceDebug.printLog(bookSource.bookSourceUrl, "获取目录", print = printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, "获取目录", printLog) val nameRule = analyzeRule.splitSourceRule(tocRule.chapterName ?: "") val urlRule = analyzeRule.splitSourceRule(tocRule.chapterUrl ?: "") for (item in elements) { @@ -168,7 +168,7 @@ object BookChapterList { SourceDebug.printLog( bookSource.bookSourceUrl, "${chapterList[0].title}${chapterList[0].url}", - print = printLog + printLog ) } return ChapterData(chapterList, nextUrlList) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookList.kt b/app/src/main/java/io/legado/app/model/webbook/BookList.kt index 65a3ded0f..b61fdae35 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookList.kt @@ -133,11 +133,7 @@ object BookList { SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.kind) SourceDebug.printLog(bookSource.bookSourceUrl, "获取简介") searchBook.intro = analyzeRule.getString(intro ?: "") - SourceDebug.printLog( - bookSource.bookSourceUrl, - msg = searchBook.intro, - isHtml = true - ) + SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.intro, true) SourceDebug.printLog(bookSource.bookSourceUrl, "获取字数") searchBook.wordCount = analyzeRule.getString(wordCount ?: "") SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.wordCount) @@ -174,43 +170,34 @@ object BookList { searchBook.originOrder = bookSource.customOrder analyzeRule.setBook(searchBook) analyzeRule.setContent(item) - SourceDebug.printLog(bookSource.bookSourceUrl, "获取书名", print = printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, "获取书名", printLog) searchBook.name = analyzeRule.getString(ruleName) - SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.name, print = printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.name, printLog) if (searchBook.name.isNotEmpty()) { - SourceDebug.printLog(bookSource.bookSourceUrl, "获取书籍Url", print = printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, "获取书籍Url", printLog) searchBook.bookUrl = analyzeRule.getString(ruleBookUrl, true) if (searchBook.bookUrl.isEmpty()) { searchBook.bookUrl = baseUrl } - SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.bookUrl, print = printLog) - SourceDebug.printLog(bookSource.bookSourceUrl, "获取作者", print = printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.bookUrl, printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, "获取作者", printLog) searchBook.author = BookHelp.formatAuthor(analyzeRule.getString(ruleAuthor)) - SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.author, print = printLog) - SourceDebug.printLog(bookSource.bookSourceUrl, "获取分类", print = printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.author, printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, "获取分类", printLog) searchBook.kind = analyzeRule.getString(ruleKind) - SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.kind, print = printLog) - SourceDebug.printLog(bookSource.bookSourceUrl, "获取简介", print = printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.kind, printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, "获取简介", printLog) searchBook.intro = analyzeRule.getString(ruleIntro) - SourceDebug.printLog( - bookSource.bookSourceUrl, - searchBook.intro, - print = printLog, - isHtml = true - ) - SourceDebug.printLog(bookSource.bookSourceUrl, "获取字数", print = printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.intro, printLog, true) + SourceDebug.printLog(bookSource.bookSourceUrl, "获取字数", printLog) searchBook.wordCount = analyzeRule.getString(ruleWordCount) - SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.wordCount, print = printLog) - SourceDebug.printLog(bookSource.bookSourceUrl, "获取封面Url", print = printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.wordCount, printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, "获取封面Url", printLog) searchBook.coverUrl = analyzeRule.getString(ruleCoverUrl, true) - SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.coverUrl, print = printLog) - SourceDebug.printLog(bookSource.bookSourceUrl, "获取最新章节", print = printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.coverUrl, printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, "获取最新章节", printLog) searchBook.latestChapterTitle = analyzeRule.getString(ruleLastChapter) - SourceDebug.printLog( - bookSource.bookSourceUrl, - searchBook.latestChapterTitle, - print = printLog - ) + SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.latestChapterTitle, printLog) return searchBook } return null diff --git a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt index f6762c0f1..5348ea070 100644 --- a/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt +++ b/app/src/main/java/io/legado/app/model/webbook/SourceDebug.kt @@ -25,10 +25,10 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { fun printLog( sourceUrl: String?, msg: String?, - state: Int = 1, print: Boolean = true, isHtml: Boolean = false, - showTime: Boolean = true + showTime: Boolean = true, + state: Int = 1 ) { if (debugSource != sourceUrl || callback == null || !print) return var printMsg = msg ?: "" @@ -82,12 +82,12 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { printLog(debugSource, "", showTime = false) infoDebug(searchBooks[0].toBook()) } else { - printLog(debugSource, "未获取到书籍", -1) + printLog(debugSource, "未获取到书籍", state = -1) } } } .onError { - printLog(debugSource, it.localizedMessage, -1) + printLog(debugSource, it.localizedMessage, state = -1) } tasks.add(search) } @@ -101,7 +101,7 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { tocDebug(book) } .onError { - printLog(debugSource, it.localizedMessage, -1) + printLog(debugSource, it.localizedMessage, state = -1) } tasks.add(info) } @@ -117,12 +117,12 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { val nextChapterUrl = if (it.size > 1) it[1].url else null contentDebug(book, it[0], nextChapterUrl) } else { - printLog(debugSource, "目录列表为空", -1) + printLog(debugSource, "目录列表为空", state = -1) } } } .onError { - printLog(debugSource, it.localizedMessage, -1) + printLog(debugSource, it.localizedMessage, state = -1) } tasks.add(chapterList) } @@ -132,11 +132,11 @@ class SourceDebug(private val webBook: WebBook, callback: Callback) { val content = webBook.getContent(book, bookChapter, nextChapterUrl) .onSuccess { content -> content?.let { - printLog(debugSource, it, 1000) + printLog(debugSource, it, state = 1000) } } .onError { - printLog(debugSource, it.localizedMessage, -1) + printLog(debugSource, it.localizedMessage, state = -1) } tasks.add(content) } From 1f2fd8bd6442ca439b01bbdd231f534a017dac9b Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 22 Oct 2019 08:09:05 +0800 Subject: [PATCH 1976/1997] up --- .../java/io/legado/app/ui/book/read/ReadBookActivity.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt index fa79dd965..2eae91a6c 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt @@ -193,9 +193,6 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { when (keyCode) { - KeyEvent.KEYCODE_BACK -> { - event?.startTracking() - } KeyEvent.KEYCODE_VOLUME_UP -> { if (volumeKeyPage(PageDelegate.Direction.PREV)) { return true @@ -234,7 +231,10 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo } KeyEvent.KEYCODE_BACK -> { event?.let { - if ((event.flags and KeyEvent.FLAG_CANCELED_LONG_PRESS == 0)) { + if ((event.flags and KeyEvent.FLAG_CANCELED_LONG_PRESS == 0) + && event.isTracking + && !event.isCanceled + ) { if (readAloudStatus == Status.PLAY) { ReadAloud.pause(this) toast(R.string.read_aloud_pause) From 65ea5e4d3a0b902f03d3069b3b8cdde3515a0995 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 22 Oct 2019 08:16:28 +0800 Subject: [PATCH 1977/1997] up --- app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt index 2eae91a6c..4dc9d14b2 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt @@ -98,6 +98,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo super.onResume() upSystemUiVisibility() timeElectricityReceiver = TimeElectricityReceiver.register(this) + page_view.upTime() } override fun onPause() { From aa7e21bf2c1974527e951726564b81b57b1d0070 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 22 Oct 2019 08:43:27 +0800 Subject: [PATCH 1978/1997] up --- .../io/legado/app/ui/book/info/BookInfoViewModel.kt | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt b/app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt index dc96b4c0c..c1b992275 100644 --- a/app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt @@ -66,9 +66,13 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { loadChapter(it, changeDruChapterIndex) } }.onError { + isLoadingData.postValue(false) toast(R.string.error_get_book_info) } - } ?: toast(R.string.error_no_source) + } ?: let { + isLoadingData.postValue(false) + toast(R.string.error_no_source) + } } } @@ -94,13 +98,18 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) { changeDruChapterIndex(it) } } else { + isLoadingData.postValue(false) toast(R.string.chapter_list_empty) } } }.onError { + isLoadingData.postValue(false) toast(R.string.error_get_chapter_list) } - } ?: toast(R.string.error_no_source) + } ?: let { + isLoadingData.postValue(false) + toast(R.string.error_no_source) + } } } From 376f235f65e28f5ec5bb696903c5705b090f03a0 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 22 Oct 2019 09:01:15 +0800 Subject: [PATCH 1979/1997] up --- app/src/main/java/io/legado/app/model/WebBook.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/WebBook.kt b/app/src/main/java/io/legado/app/model/WebBook.kt index 7dc90b751..e290e555c 100644 --- a/app/src/main/java/io/legado/app/model/WebBook.kt +++ b/app/src/main/java/io/legado/app/model/WebBook.kt @@ -98,7 +98,9 @@ class WebBook(val bookSource: BookSource) { context: CoroutineContext = Dispatchers.IO ): Coroutine> { return Coroutine.async(scope, context) { - val body = if (book.bookUrl == book.tocUrl && book.tocHtml.isNullOrEmpty()) { + val body = if (book.bookUrl == book.tocUrl && !book.tocHtml.isNullOrEmpty()) { + book.tocHtml + } else { val analyzeUrl = AnalyzeUrl( book = book, ruleUrl = book.tocUrl, @@ -106,8 +108,6 @@ class WebBook(val bookSource: BookSource) { headerMapF = bookSource.getHeaderMap() ) analyzeUrl.getResponseAsync().await().body() - } else { - book.tocHtml } BookChapterList.analyzeChapterList(this, book, body, bookSource, book.tocUrl) } From 38e3c77fd97024eb7521da71ba554fc760898772 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 22 Oct 2019 16:33:47 +0800 Subject: [PATCH 1980/1997] up --- .../app/model/analyzeRule/AnalyzeByRegex.kt | 100 ----------------- .../app/model/analyzeRule/AnalyzeRule.kt | 101 +++++++++++------- 2 files changed, 62 insertions(+), 139 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByRegex.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByRegex.kt index 7518aa57d..28e022fb5 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByRegex.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByRegex.kt @@ -1,6 +1,5 @@ package io.legado.app.model.analyzeRule -import android.text.TextUtils import java.util.* import java.util.regex.Pattern @@ -57,103 +56,4 @@ object AnalyzeByRegex { return getElements(result.toString(), regs, ++vIndex) } } - - // 拆分正则表达式替换规则(如:$\d{1,2}或${name}) /*注意:千万别用正则表达式拆分字符串,效率太低了!*/ - fun splitRegexRule(str: String, ruleParam: MutableList, ruleType: MutableList) { - if (TextUtils.isEmpty(str)) { - ruleParam.add("") - ruleType.add(0) - return - } - var index = 0 - var start = 0 - val len = str.length - while (index < len) { - if (str[index] == '$') { - if (index + 1 >= len) { - break - } else if (str[index + 1] == '{') { - if (index > start) { - ruleParam.add(str.substring(start, index)) - ruleType.add(0) - start = index - } - index += 2 - while (index < len) { - if (str[index] == '}') { - ruleParam.add(str.substring(start + 2, index)) - ruleType.add(-1) - start = ++index - break - } else if (str[index] == '$' || str[index] == '@') { - break - } - index++ - } - } else if (str[index + 1] in '0'..'9') { - if (index > start) { - ruleParam.add(str.substring(start, index)) - ruleType.add(0) - start = index - } - if (index + 2 < len && str[index + 2] >= '0' && str[index + 2] <= '9') { - ruleParam.add(str.substring(start, index + 3)) - ruleType.add(string2Int(ruleParam[ruleParam.size - 1])) - index += 3 - start = index - } else { - ruleParam.add(str.substring(start, index + 2)) - ruleType.add(string2Int(ruleParam[ruleParam.size - 1])) - index += 2 - start = index - } - } else { - index++ - } - } else if (str[index] == '{') { - if (index + 1 >= len) { - break - } else if (str[index + 1] == '{') { - if (index > start) { - ruleParam.add(str.substring(start, index)) - ruleType.add(0) - start = index - } - while (index + 1 < len) { - if (str[index] == '}' && str[index + 1] == '}') { - ruleParam.add(str.substring(start + 2, index)) - ruleType.add(-11) - start = index + 2 - break - } - index++ - } - } else { - index++ - } - } else { - index++ - } - } - if (index > start) { - ruleParam.add(str.substring(start, index)) - ruleType.add(0) - } - } - - // String数字转int数字的高效方法(利用ASCII值判断) - private fun string2Int(s: String): Int { - var r = 0 - var n: Char - var i = 0 - val l = s.length - while (i < l) { - n = s[i] - if (n in '0'..'9') { - r = r * 10 + (n.toInt() - 0x30) //'0-9'的ASCII值为0x30-0x39 - } - i++ - } - return r - } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt index 13dbfad04..71d22bc3e 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt @@ -306,22 +306,6 @@ class AnalyzeRule(private var book: BaseBook? = null) { return vRuleStr } - /** - * 替换@get - */ - private fun replaceGet(ruleStr: String): String { - var vRuleStr = ruleStr - val getMatcher = getPattern.matcher(vRuleStr) - while (getMatcher.find()) { - var value = "" - book?.variableMap?.get(getMatcher.group(1))?.let { - value = it - } - vRuleStr = vRuleStr.replace(getMatcher.group(), value) - } - return vRuleStr - } - /** * 正则替换 */ @@ -454,11 +438,41 @@ class AnalyzeRule(private var book: BaseBook? = null) { } //分离put rule = splitPutRule(rule, putMap) - //get替换 - rule = replaceGet(rule) - // 拆分表达式替换规则 - if (mode != Mode.Js) { - AnalyzeByRegex.splitRegexRule(rule, ruleParam, ruleType) + //get,{{ }},$, 替换 + var start = 0 + var tmp: String + val evalMatcher = evalPattern.matcher(rule) + while (evalMatcher.find()) { + if (evalMatcher.start() > start) { + tmp = rule.substring(start, evalMatcher.start()) + ruleType.add(0) + ruleParam.add(tmp) + } + tmp = evalMatcher.group() + when { + tmp.startsWith("$") -> { + ruleType.add(tmp.substring(1).toInt()) + ruleParam.add(tmp) + } + tmp.startsWith("@get:", true) -> { + ruleType.add(-2) + ruleParam.add(tmp.substring(6, tmp.lastIndex)) + } + tmp.startsWith("{{") -> { + ruleType.add(-1) + ruleParam.add(tmp.substring(2, tmp.length - 2)) + } + else -> { + ruleType.add(0) + ruleParam.add(tmp) + } + } + start = evalMatcher.end() + } + if (rule.length > start) { + tmp = rule.substring(start) + ruleType.add(0) + ruleParam.add(tmp) } } @@ -468,25 +482,30 @@ class AnalyzeRule(private var book: BaseBook? = null) { var j = ruleParam.size while (j-- > 0) { val regType = ruleType[j] - if (regType > 0) { - @Suppress("UNCHECKED_CAST") - val resultList = result as List - if (resultList.size > regType) { - resultList[regType]?.let { - infoVal.insert(0, resultList[regType]) + when { + regType > 0 -> { + @Suppress("UNCHECKED_CAST") + val resultList = result as List + if (resultList.size > regType) { + resultList[regType]?.let { + infoVal.insert(0, resultList[regType]) + } + } + } + regType == -1 -> { + val jsEval: Any = evalJS(ruleParam[j], result) + if (jsEval is String) { + infoVal.insert(0, jsEval) + } else if (jsEval is Double && jsEval % 1.0 == 0.0) { + infoVal.insert(0, String.format("%.0f", jsEval)) + } else { + infoVal.insert(0, jsEval.toString()) } } - } else if (regType < 0) { - val jsEval: Any = evalJS(ruleParam[j], result) - if (jsEval is String) { - infoVal.insert(0, jsEval) - } else if (jsEval is Double && jsEval % 1.0 == 0.0) { - infoVal.insert(0, String.format("%.0f", jsEval)) - } else { - infoVal.insert(0, jsEval.toString()) + regType == -2 -> { + infoVal.insert(0, get(ruleParam[j])) } - } else { - infoVal.insert(0, ruleParam[j]) + else -> infoVal.insert(0, ruleParam[j]) } } rule = infoVal.toString() @@ -503,8 +522,8 @@ class AnalyzeRule(private var book: BaseBook? = null) { return value } - operator fun get(key: String): String? { - return book?.variableMap?.get(key) + operator fun get(key: String): String { + return book?.variableMap?.get(key) ?: "" } /** @@ -523,6 +542,10 @@ class AnalyzeRule(private var book: BaseBook? = null) { companion object { private val putPattern = Pattern.compile("@put:(\\{[^}]+?\\})", Pattern.CASE_INSENSITIVE) private val getPattern = Pattern.compile("@get:\\{([^}]+?)\\}", Pattern.CASE_INSENSITIVE) + private val evalPattern = Pattern.compile( + "@get:\\{[^}]+?\\}|\\{\\{[\\w\\W]*?\\}\\}|\\$\\d{1,2}", + Pattern.CASE_INSENSITIVE + ) } /** From 76ff4446756a8d5850f8edf1964e0da8b4d5f97b Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 22 Oct 2019 16:47:01 +0800 Subject: [PATCH 1981/1997] up --- .../app/model/analyzeRule/AnalyzeRule.kt | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt index 71d22bc3e..6a822e199 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt @@ -479,21 +479,25 @@ class AnalyzeRule(private var book: BaseBook? = null) { fun makeUpRule(result: Any?) { val infoVal = StringBuilder() if (ruleParam.isNotEmpty()) { - var j = ruleParam.size - while (j-- > 0) { - val regType = ruleType[j] + var index = ruleParam.size + while (index-- > 0) { + val regType = ruleType[index] when { regType > 0 -> { @Suppress("UNCHECKED_CAST") - val resultList = result as List - if (resultList.size > regType) { - resultList[regType]?.let { - infoVal.insert(0, resultList[regType]) + val resultList = result as? List + if (resultList != null) { + if (resultList.size > regType) { + resultList[regType]?.let { + infoVal.insert(0, resultList[regType]) + } } + } else { + infoVal.insert(0, ruleParam[index]) } } regType == -1 -> { - val jsEval: Any = evalJS(ruleParam[j], result) + val jsEval: Any = evalJS(ruleParam[index], result) if (jsEval is String) { infoVal.insert(0, jsEval) } else if (jsEval is Double && jsEval % 1.0 == 0.0) { @@ -503,9 +507,9 @@ class AnalyzeRule(private var book: BaseBook? = null) { } } regType == -2 -> { - infoVal.insert(0, get(ruleParam[j])) + infoVal.insert(0, get(ruleParam[index])) } - else -> infoVal.insert(0, ruleParam[j]) + else -> infoVal.insert(0, ruleParam[index]) } } rule = infoVal.toString() From 6dc231d1c71d89d1b1b165863d860ca68beb77b7 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 22 Oct 2019 19:11:44 +0800 Subject: [PATCH 1982/1997] up --- .../app/ui/widget/page/ContentTextView.kt | 54 +++++++------------ 1 file changed, 18 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt index 5434744db..ac444b4d6 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt @@ -30,7 +30,6 @@ class ContentTextView : AppCompatTextView { private val mViewFling: ViewFling by lazy { ViewFling() } private var velocityTracker: VelocityTracker? = null private var mScrollState = scrollStateIdle - private var mScrollPointerId = -1 private var mLastTouchY: Int = 0 private var mTouchSlop: Int = 0 private var mMinFlingVelocity: Int = 0 @@ -111,7 +110,6 @@ class ContentTextView : AppCompatTextView { override fun onTouchEvent(event: MotionEvent?): Boolean { event?.let { val action = event.action - val actionIndex = event.actionIndex val vtEvent = MotionEvent.obtain(event) if (velocityTracker == null) { @@ -121,51 +119,35 @@ class ContentTextView : AppCompatTextView { when (action) { MotionEvent.ACTION_DOWN -> { setScrollState(scrollStateIdle) - mScrollPointerId = event.getPointerId(0) mLastTouchY = (event.y + 0.5f).toInt() } - MotionEvent.ACTION_POINTER_DOWN -> { - mScrollPointerId = event.getPointerId(actionIndex) - mLastTouchY = (event.getY(actionIndex) + 0.5f).toInt() - } MotionEvent.ACTION_MOVE -> { - val index = event.findPointerIndex(mScrollPointerId) - if (index > 0) { - val y = (event.getY(index) + 0.5f).toInt() - var dy = mLastTouchY - y - - if (mScrollState != scrollStateDragging) { - var startScroll = false - - if (abs(dy) > mTouchSlop) { - if (dy > 0) { - dy -= mTouchSlop - } else { - dy += mTouchSlop - } - startScroll = true - } - if (startScroll) { - setScrollState(scrollStateDragging) + val y = (event.y + 0.5f).toInt() + var dy = mLastTouchY - y + + if (mScrollState != scrollStateDragging) { + var startScroll = false + + if (abs(dy) > mTouchSlop) { + if (dy > 0) { + dy -= mTouchSlop + } else { + dy += mTouchSlop } + startScroll = true } - - if (mScrollState == scrollStateDragging) { - mLastTouchY = y + if (startScroll) { + setScrollState(scrollStateDragging) } } - } - MotionEvent.ACTION_POINTER_UP -> { - if (event.getPointerId(actionIndex) == mScrollPointerId) { - // Pick a new pointer to pick up the slack. - val newIndex = if (actionIndex == 0) 1 else 0 - mScrollPointerId = event.getPointerId(newIndex) - mLastTouchY = (event.getY(newIndex) + 0.5f).toInt() + + if (mScrollState == scrollStateDragging) { + mLastTouchY = y } } MotionEvent.ACTION_UP -> { velocityTracker?.computeCurrentVelocity(1000, mMaxFlingVelocity.toFloat()) - val yVelocity = velocityTracker?.getYVelocity(mScrollPointerId) ?: 0f + val yVelocity = velocityTracker?.yVelocity ?: 0f if (abs(yVelocity) > mMinFlingVelocity) { mViewFling.fling(-yVelocity.toInt()) } else { From 0f264eb0ce5a556e9b5dc4d30ac36bff0497c012 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 22 Oct 2019 19:13:46 +0800 Subject: [PATCH 1983/1997] up --- .../java/io/legado/app/ui/widget/page/ContentTextView.kt | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt index ac444b4d6..df68b4cc5 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt @@ -109,14 +109,11 @@ class ContentTextView : AppCompatTextView { @SuppressLint("ClickableViewAccessibility") override fun onTouchEvent(event: MotionEvent?): Boolean { event?.let { - val action = event.action - val vtEvent = MotionEvent.obtain(event) - if (velocityTracker == null) { velocityTracker = VelocityTracker.obtain() } velocityTracker?.addMovement(it) - when (action) { + when (event.action) { MotionEvent.ACTION_DOWN -> { setScrollState(scrollStateIdle) mLastTouchY = (event.y + 0.5f).toInt() @@ -159,7 +156,6 @@ class ContentTextView : AppCompatTextView { resetTouch() } } - vtEvent.recycle() } return super.onTouchEvent(event) } From ec0ea267e9097485fa2bbbe3914551a9a339e7ce Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 22 Oct 2019 19:34:06 +0800 Subject: [PATCH 1984/1997] up --- .../main/java/io/legado/app/ui/widget/page/ContentTextView.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt b/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt index df68b4cc5..383425a7a 100644 --- a/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/page/ContentTextView.kt @@ -121,7 +121,6 @@ class ContentTextView : AppCompatTextView { MotionEvent.ACTION_MOVE -> { val y = (event.y + 0.5f).toInt() var dy = mLastTouchY - y - if (mScrollState != scrollStateDragging) { var startScroll = false @@ -137,7 +136,6 @@ class ContentTextView : AppCompatTextView { setScrollState(scrollStateDragging) } } - if (mScrollState == scrollStateDragging) { mLastTouchY = y } From 91e3c7c5bc7ff92c17d21e3ba77693bf2f10205a Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 23 Oct 2019 08:21:20 +0800 Subject: [PATCH 1985/1997] up --- .../main/java/io/legado/app/ui/main/explore/ExploreAdapter.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/main/explore/ExploreAdapter.kt b/app/src/main/java/io/legado/app/ui/main/explore/ExploreAdapter.kt index 15c4ecfdb..205cf4e2c 100644 --- a/app/src/main/java/io/legado/app/ui/main/explore/ExploreAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/explore/ExploreAdapter.kt @@ -24,7 +24,7 @@ import org.jetbrains.anko.sdk27.listeners.onLongClick class ExploreAdapter(context: Context, private val scope: CoroutineScope, val callBack: CallBack) : SimpleRecyclerAdapter(context, R.layout.item_find_book) { - var exIndex = 0 + private var exIndex = 0 override fun convert(holder: ItemViewHolder, item: BookSource, payloads: MutableList) { with(holder.itemView) { From 8ab80800cb33fa17307581cb055827795528734d Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 23 Oct 2019 09:29:32 +0800 Subject: [PATCH 1986/1997] up --- .../app/model/analyzeRule/AnalyzeRule.kt | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt index 6a822e199..2e1b854fc 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt @@ -438,7 +438,7 @@ class AnalyzeRule(private var book: BaseBook? = null) { } //分离put rule = splitPutRule(rule, putMap) - //get,{{ }},$, 替换 + //@get,{{ }},$1, 拆分 var start = 0 var tmp: String val evalMatcher = evalPattern.matcher(rule) @@ -476,6 +476,9 @@ class AnalyzeRule(private var book: BaseBook? = null) { } } + /** + * 替换@get,{{ }},$1, + */ fun makeUpRule(result: Any?) { val infoVal = StringBuilder() if (ruleParam.isNotEmpty()) { @@ -543,15 +546,6 @@ class AnalyzeRule(private var book: BaseBook? = null) { return SCRIPT_ENGINE.eval(jsStr, bindings) } - companion object { - private val putPattern = Pattern.compile("@put:(\\{[^}]+?\\})", Pattern.CASE_INSENSITIVE) - private val getPattern = Pattern.compile("@get:\\{([^}]+?)\\}", Pattern.CASE_INSENSITIVE) - private val evalPattern = Pattern.compile( - "@get:\\{[^}]+?\\}|\\{\\{[\\w\\W]*?\\}\\}|\\$\\d{1,2}", - Pattern.CASE_INSENSITIVE - ) - } - /** * js实现跨域访问,不能删 */ @@ -588,4 +582,14 @@ class AnalyzeRule(private var book: BaseBook? = null) { s } } + + companion object { + private val putPattern = Pattern.compile("@put:(\\{[^}]+?\\})", Pattern.CASE_INSENSITIVE) + private val getPattern = Pattern.compile("@get:\\{([^}]+?)\\}", Pattern.CASE_INSENSITIVE) + private val evalPattern = Pattern.compile( + "@get:\\{[^}]+?\\}|\\{\\{[\\w\\W]*?\\}\\}|\\$\\d{1,2}", + Pattern.CASE_INSENSITIVE + ) + } + } From ff5db43db4747dd838e5328146895017d0694037 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 23 Oct 2019 11:53:08 +0800 Subject: [PATCH 1987/1997] up --- .../io/legado/app/model/webbook/BookList.kt | 86 +++++++++++++++---- 1 file changed, 71 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/webbook/BookList.kt b/app/src/main/java/io/legado/app/model/webbook/BookList.kt index b61fdae35..b3f15f1e4 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookList.kt @@ -4,10 +4,12 @@ import io.legado.app.App import io.legado.app.R import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.SearchBook +import io.legado.app.data.entities.rule.BookListRule import io.legado.app.help.BookHelp import io.legado.app.model.analyzeRule.AnalyzeRule import io.legado.app.model.analyzeRule.AnalyzeUrl import io.legado.app.utils.NetworkUtils +import org.mozilla.javascript.NativeObject import retrofit2.Response object BookList { @@ -75,21 +77,31 @@ object BookList { val ruleWordCount = analyzeRule.splitSourceRule(bookListRule.wordCount ?: "") SourceDebug.printLog(bookSource.bookSourceUrl, "列表数为${collections.size}") for ((index, item) in collections.withIndex()) { - getSearchItem( - item, - analyzeRule, - bookSource, - baseUrl, - index == 0, - ruleName = ruleName, - ruleBookUrl = ruleBookUrl, - ruleAuthor = ruleAuthor, - ruleCoverUrl = ruleCoverUrl, - ruleIntro = ruleIntro, - ruleKind = ruleKind, - ruleLastChapter = ruleLastChapter, - ruleWordCount = ruleWordCount - )?.let { searchBook -> + if (item is NativeObject) { + getSearchItemAllInOne( + item, + bookSource, + bookListRule, + baseUrl, + index == 0 + ) + } else { + getSearchItem( + item, + analyzeRule, + bookSource, + baseUrl, + index == 0, + ruleName = ruleName, + ruleBookUrl = ruleBookUrl, + ruleAuthor = ruleAuthor, + ruleCoverUrl = ruleCoverUrl, + ruleIntro = ruleIntro, + ruleKind = ruleKind, + ruleLastChapter = ruleLastChapter, + ruleWordCount = ruleWordCount + ) + }?.let { searchBook -> if (baseUrl == searchBook.bookUrl) { searchBook.infoHtml = body } @@ -202,4 +214,48 @@ object BookList { } return null } + + private fun getSearchItemAllInOne( + item: NativeObject, + bookSource: BookSource, + bookListRule: BookListRule, + baseUrl: String, + printLog: Boolean + ): SearchBook? { + val searchBook = SearchBook() + searchBook.origin = bookSource.bookSourceUrl + searchBook.originName = bookSource.bookSourceName + searchBook.originOrder = bookSource.customOrder + SourceDebug.printLog(bookSource.bookSourceUrl, "获取书名", printLog) + searchBook.name = item[bookListRule.name]?.toString() ?: "" + SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.name, printLog) + if (searchBook.name.isNotEmpty()) { + SourceDebug.printLog(bookSource.bookSourceUrl, "获取书籍Url", printLog) + searchBook.bookUrl = item[bookListRule.bookUrl]?.toString() ?: "" + if (searchBook.bookUrl.isEmpty()) { + searchBook.bookUrl = baseUrl + } + SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.bookUrl, printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, "获取作者", printLog) + searchBook.author = BookHelp.formatAuthor(item[bookListRule.author]?.toString() ?: "") + SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.author, printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, "获取分类", printLog) + searchBook.kind = item[bookListRule.kind]?.toString() ?: "" + SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.kind, printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, "获取简介", printLog) + searchBook.intro = item[bookListRule.intro]?.toString() ?: "" + SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.intro, printLog, true) + SourceDebug.printLog(bookSource.bookSourceUrl, "获取字数", printLog) + searchBook.wordCount = item[bookListRule.wordCount]?.toString() ?: "" + SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.wordCount, printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, "获取封面Url", printLog) + searchBook.coverUrl = item[bookListRule.coverUrl]?.toString() ?: "" + SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.coverUrl, printLog) + SourceDebug.printLog(bookSource.bookSourceUrl, "获取最新章节", printLog) + searchBook.latestChapterTitle = item[bookListRule.lastChapter]?.toString() ?: "" + SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.latestChapterTitle, printLog) + return searchBook + } + return null + } } \ No newline at end of file From 213b3e772db16db08b29841631ec06b25f3f7122 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 23 Oct 2019 12:33:18 +0800 Subject: [PATCH 1988/1997] up --- .../app/model/analyzeRule/AnalyzeRule.kt | 79 +++++++++-------- .../io/legado/app/model/webbook/BookList.kt | 85 ++++--------------- 2 files changed, 59 insertions(+), 105 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt index 2e1b854fc..5a5cda401 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt @@ -6,6 +6,7 @@ import io.legado.app.constant.AppConst.SCRIPT_ENGINE import io.legado.app.constant.Pattern.JS_PATTERN import io.legado.app.data.entities.BaseBook import io.legado.app.utils.* +import org.mozilla.javascript.NativeObject import java.util.* import java.util.regex.Pattern import javax.script.SimpleBindings @@ -185,27 +186,32 @@ class AnalyzeRule(private var book: BaseBook? = null) { @JvmOverloads fun getString(ruleList: List, isUrl: Boolean = false): String { var result: Any? = null - content?.let { o -> - if (ruleList.isNotEmpty()) result = o - for (sourceRule in ruleList) { - putRule(sourceRule.putMap) - sourceRule.makeUpRule(result) - result?.let { - if (sourceRule.rule.isNotBlank()) { - result = when (sourceRule.mode) { - Mode.Js -> evalJS(sourceRule.rule, it) - Mode.Json -> getAnalyzeByJSonPath(it).getString(sourceRule.rule) - Mode.XPath -> getAnalyzeByXPath(it).getString(sourceRule.rule) - Mode.Default -> if (isUrl) { - getAnalyzeByJSoup(it).getString0(sourceRule.rule) - } else { - getAnalyzeByJSoup(it).getString(sourceRule.rule) + val content = this.content + if (content != null && ruleList.isNotEmpty()) { + result = content + if (content is NativeObject) { + result = content[ruleList[0].rule]?.toString() + } else { + for (sourceRule in ruleList) { + putRule(sourceRule.putMap) + sourceRule.makeUpRule(result) + result?.let { + if (sourceRule.rule.isNotBlank()) { + result = when (sourceRule.mode) { + Mode.Js -> evalJS(sourceRule.rule, it) + Mode.Json -> getAnalyzeByJSonPath(it).getString(sourceRule.rule) + Mode.XPath -> getAnalyzeByXPath(it).getString(sourceRule.rule) + Mode.Default -> if (isUrl) { + getAnalyzeByJSoup(it).getString0(sourceRule.rule) + } else { + getAnalyzeByJSoup(it).getString(sourceRule.rule) + } + else -> sourceRule.rule } - else -> sourceRule.rule } - } - if (sourceRule.replaceRegex.isNotEmpty()) { - result = replaceRegex(result.toString(), sourceRule) + if (sourceRule.replaceRegex.isNotEmpty()) { + result = replaceRegex(result.toString(), sourceRule) + } } } } @@ -231,7 +237,10 @@ class AnalyzeRule(private var book: BaseBook? = null) { putRule(sourceRule.putMap) result?.let { result = when (sourceRule.mode) { - Mode.Regex -> AnalyzeByRegex.getElement(result.toString(), sourceRule.rule.splitNotBlank("&&")) + Mode.Regex -> AnalyzeByRegex.getElement( + result.toString(), + sourceRule.rule.splitNotBlank("&&") + ) Mode.Js -> evalJS(sourceRule.rule, it) Mode.Json -> getAnalyzeByJSonPath(it).getObject(sourceRule.rule) Mode.XPath -> getAnalyzeByXPath(it).getElements(sourceRule.rule) @@ -260,7 +269,10 @@ class AnalyzeRule(private var book: BaseBook? = null) { putRule(sourceRule.putMap) result?.let { result = when (sourceRule.mode) { - Mode.Regex -> AnalyzeByRegex.getElements(result.toString(), sourceRule.rule.splitNotBlank("&&")) + Mode.Regex -> AnalyzeByRegex.getElements( + result.toString(), + sourceRule.rule.splitNotBlank("&&") + ) Mode.Js -> evalJS(sourceRule.rule, result) Mode.Json -> getAnalyzeByJSonPath(it).getList(sourceRule.rule) Mode.XPath -> getAnalyzeByXPath(it).getElements(sourceRule.rule) @@ -331,32 +343,28 @@ class AnalyzeRule(private var book: BaseBook? = null) { * 分解规则生成规则列表 */ @Throws(Exception::class) - fun splitSourceRule(ruleStr: String): List { + fun splitSourceRule(ruleStr: String, mode: Mode = Mode.Default): List { var vRuleStr = ruleStr val ruleList = ArrayList() if (TextUtils.isEmpty(vRuleStr)) return ruleList //检测Mode - val mode: Mode + var mMode: Mode = mode when { vRuleStr.startsWith("@XPath:", true) -> { - mode = Mode.XPath + mMode = Mode.XPath vRuleStr = vRuleStr.substring(7) } vRuleStr.startsWith("@Json:", true) -> { - mode = Mode.Json + mMode = Mode.Json vRuleStr = vRuleStr.substring(6) } vRuleStr.startsWith(":") -> { - mode = Mode.Regex + mMode = Mode.Regex isRegex = true vRuleStr = vRuleStr.substring(1) } - else -> mode = - when { - isRegex -> Mode.Regex - isJSON -> Mode.Json - else -> Mode.Default - } + isRegex -> mMode = Mode.Regex + isJSON -> mMode = Mode.Json } //拆分为规则列表 var start = 0 @@ -364,9 +372,10 @@ class AnalyzeRule(private var book: BaseBook? = null) { val jsMatcher = JS_PATTERN.matcher(vRuleStr) while (jsMatcher.find()) { if (jsMatcher.start() > start) { - tmp = vRuleStr.substring(start, jsMatcher.start()).replace("\n", "").trim { it <= ' ' } + tmp = vRuleStr.substring(start, jsMatcher.start()).replace("\n", "") + .trim { it <= ' ' } if (!TextUtils.isEmpty(tmp)) { - ruleList.add(SourceRule(tmp, mode)) + ruleList.add(SourceRule(tmp, mMode)) } } ruleList.add(SourceRule(jsMatcher.group(), Mode.Js)) @@ -375,7 +384,7 @@ class AnalyzeRule(private var book: BaseBook? = null) { if (vRuleStr.length > start) { tmp = vRuleStr.substring(start).replace("\n", "").trim { it <= ' ' } if (!TextUtils.isEmpty(tmp)) { - ruleList.add(SourceRule(tmp, mode)) + ruleList.add(SourceRule(tmp, mMode)) } } return ruleList diff --git a/app/src/main/java/io/legado/app/model/webbook/BookList.kt b/app/src/main/java/io/legado/app/model/webbook/BookList.kt index b3f15f1e4..a896aa3c0 100644 --- a/app/src/main/java/io/legado/app/model/webbook/BookList.kt +++ b/app/src/main/java/io/legado/app/model/webbook/BookList.kt @@ -4,12 +4,10 @@ import io.legado.app.App import io.legado.app.R import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.SearchBook -import io.legado.app.data.entities.rule.BookListRule import io.legado.app.help.BookHelp import io.legado.app.model.analyzeRule.AnalyzeRule import io.legado.app.model.analyzeRule.AnalyzeUrl import io.legado.app.utils.NetworkUtils -import org.mozilla.javascript.NativeObject import retrofit2.Response object BookList { @@ -77,31 +75,21 @@ object BookList { val ruleWordCount = analyzeRule.splitSourceRule(bookListRule.wordCount ?: "") SourceDebug.printLog(bookSource.bookSourceUrl, "列表数为${collections.size}") for ((index, item) in collections.withIndex()) { - if (item is NativeObject) { - getSearchItemAllInOne( - item, - bookSource, - bookListRule, - baseUrl, - index == 0 - ) - } else { - getSearchItem( - item, - analyzeRule, - bookSource, - baseUrl, - index == 0, - ruleName = ruleName, - ruleBookUrl = ruleBookUrl, - ruleAuthor = ruleAuthor, - ruleCoverUrl = ruleCoverUrl, - ruleIntro = ruleIntro, - ruleKind = ruleKind, - ruleLastChapter = ruleLastChapter, - ruleWordCount = ruleWordCount - ) - }?.let { searchBook -> + getSearchItem( + item, + analyzeRule, + bookSource, + baseUrl, + index == 0, + ruleName = ruleName, + ruleBookUrl = ruleBookUrl, + ruleAuthor = ruleAuthor, + ruleCoverUrl = ruleCoverUrl, + ruleIntro = ruleIntro, + ruleKind = ruleKind, + ruleLastChapter = ruleLastChapter, + ruleWordCount = ruleWordCount + )?.let { searchBook -> if (baseUrl == searchBook.bookUrl) { searchBook.infoHtml = body } @@ -215,47 +203,4 @@ object BookList { return null } - private fun getSearchItemAllInOne( - item: NativeObject, - bookSource: BookSource, - bookListRule: BookListRule, - baseUrl: String, - printLog: Boolean - ): SearchBook? { - val searchBook = SearchBook() - searchBook.origin = bookSource.bookSourceUrl - searchBook.originName = bookSource.bookSourceName - searchBook.originOrder = bookSource.customOrder - SourceDebug.printLog(bookSource.bookSourceUrl, "获取书名", printLog) - searchBook.name = item[bookListRule.name]?.toString() ?: "" - SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.name, printLog) - if (searchBook.name.isNotEmpty()) { - SourceDebug.printLog(bookSource.bookSourceUrl, "获取书籍Url", printLog) - searchBook.bookUrl = item[bookListRule.bookUrl]?.toString() ?: "" - if (searchBook.bookUrl.isEmpty()) { - searchBook.bookUrl = baseUrl - } - SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.bookUrl, printLog) - SourceDebug.printLog(bookSource.bookSourceUrl, "获取作者", printLog) - searchBook.author = BookHelp.formatAuthor(item[bookListRule.author]?.toString() ?: "") - SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.author, printLog) - SourceDebug.printLog(bookSource.bookSourceUrl, "获取分类", printLog) - searchBook.kind = item[bookListRule.kind]?.toString() ?: "" - SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.kind, printLog) - SourceDebug.printLog(bookSource.bookSourceUrl, "获取简介", printLog) - searchBook.intro = item[bookListRule.intro]?.toString() ?: "" - SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.intro, printLog, true) - SourceDebug.printLog(bookSource.bookSourceUrl, "获取字数", printLog) - searchBook.wordCount = item[bookListRule.wordCount]?.toString() ?: "" - SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.wordCount, printLog) - SourceDebug.printLog(bookSource.bookSourceUrl, "获取封面Url", printLog) - searchBook.coverUrl = item[bookListRule.coverUrl]?.toString() ?: "" - SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.coverUrl, printLog) - SourceDebug.printLog(bookSource.bookSourceUrl, "获取最新章节", printLog) - searchBook.latestChapterTitle = item[bookListRule.lastChapter]?.toString() ?: "" - SourceDebug.printLog(bookSource.bookSourceUrl, searchBook.latestChapterTitle, printLog) - return searchBook - } - return null - } } \ No newline at end of file From 9fafda85dc28f561707b62bf218ef4a3620db746 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 23 Oct 2019 14:03:30 +0800 Subject: [PATCH 1989/1997] up --- .../java/io/legado/app/help/JsExtensions.kt | 9 ++++ .../app/model/analyzeRule/AnalyzeRule.kt | 8 ++++ .../java/io/legado/app/utils/MD5Utils.java | 44 +++++++++++++++++++ 3 files changed, 61 insertions(+) create mode 100644 app/src/main/java/io/legado/app/utils/MD5Utils.java diff --git a/app/src/main/java/io/legado/app/help/JsExtensions.kt b/app/src/main/java/io/legado/app/help/JsExtensions.kt index d449d553c..f317c52b5 100644 --- a/app/src/main/java/io/legado/app/help/JsExtensions.kt +++ b/app/src/main/java/io/legado/app/help/JsExtensions.kt @@ -2,6 +2,7 @@ package io.legado.app.help import io.legado.app.model.analyzeRule.AnalyzeUrl import io.legado.app.utils.EncoderUtils +import io.legado.app.utils.MD5Utils import io.legado.app.utils.StringUtils import java.util.regex.Pattern @@ -46,4 +47,12 @@ class JsExtensions { } } + fun strToMd5By32(str: String?): String? { + return MD5Utils.strToMd5By32(str) + } + + fun strToMd5By16(str: String?): String? { + return MD5Utils.strToMd5By16(str) + } + } diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt index 5a5cda401..cba7bc0f1 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt @@ -592,6 +592,14 @@ class AnalyzeRule(private var book: BaseBook? = null) { } } + fun strToMd5By32(str: String?): String? { + return MD5Utils.strToMd5By32(str) + } + + fun strToMd5By16(str: String?): String? { + return MD5Utils.strToMd5By16(str) + } + companion object { private val putPattern = Pattern.compile("@put:(\\{[^}]+?\\})", Pattern.CASE_INSENSITIVE) private val getPattern = Pattern.compile("@get:\\{([^}]+?)\\}", Pattern.CASE_INSENSITIVE) diff --git a/app/src/main/java/io/legado/app/utils/MD5Utils.java b/app/src/main/java/io/legado/app/utils/MD5Utils.java new file mode 100644 index 000000000..8b955b922 --- /dev/null +++ b/app/src/main/java/io/legado/app/utils/MD5Utils.java @@ -0,0 +1,44 @@ +package io.legado.app.utils; + +/** + * Created by newbiechen on 2018/1/1. + */ + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * 将字符串转化为MD5 + */ + +public class MD5Utils { + + public static String strToMd5By32(String str) { + if (str == null) return null; + String reStr = null; + try { + MessageDigest md5 = MessageDigest.getInstance("MD5"); + byte[] bytes = md5.digest(str.getBytes()); + StringBuilder stringBuffer = new StringBuilder(); + for (byte b : bytes) { + int bt = b & 0xff; + if (bt < 16) { + stringBuffer.append(0); + } + stringBuffer.append(Integer.toHexString(bt)); + } + reStr = stringBuffer.toString(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + return reStr; + } + + public static String strToMd5By16(String str) { + String reStr = strToMd5By32(str); + if (reStr != null) { + reStr = reStr.substring(8, 24); + } + return reStr; + } +} From a8dca31be293fded1ea0a7dc8d36803e4adcdba4 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 23 Oct 2019 14:07:29 +0800 Subject: [PATCH 1990/1997] up --- app/src/main/java/io/legado/app/data/entities/BookSource.kt | 2 +- app/src/main/java/io/legado/app/help/JsExtensions.kt | 2 +- .../main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/BookSource.kt b/app/src/main/java/io/legado/app/data/entities/BookSource.kt index fd5053f02..373c31de5 100644 --- a/app/src/main/java/io/legado/app/data/entities/BookSource.kt +++ b/app/src/main/java/io/legado/app/data/entities/BookSource.kt @@ -137,7 +137,7 @@ data class BookSource( if (a.isBlank()) { val bindings = SimpleBindings() bindings["baseUrl"] = bookSourceUrl - bindings["java"] = JsExtensions() + bindings["java"] = JsExtensions a = AppConst.SCRIPT_ENGINE.eval( it.substring(4, it.lastIndexOf("<")), bindings diff --git a/app/src/main/java/io/legado/app/help/JsExtensions.kt b/app/src/main/java/io/legado/app/help/JsExtensions.kt index f317c52b5..ad4024379 100644 --- a/app/src/main/java/io/legado/app/help/JsExtensions.kt +++ b/app/src/main/java/io/legado/app/help/JsExtensions.kt @@ -8,7 +8,7 @@ import java.util.regex.Pattern @Suppress("unused") -class JsExtensions { +object JsExtensions { /** * js实现跨域访问,不能删 diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt index 8c9730fa8..8e6ded010 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt @@ -9,6 +9,7 @@ import io.legado.app.constant.Pattern.JS_PATTERN import io.legado.app.data.api.IHttpGetApi import io.legado.app.data.api.IHttpPostApi import io.legado.app.data.entities.BaseBook +import io.legado.app.help.JsExtensions import io.legado.app.help.http.HttpHelper import io.legado.app.utils.* import kotlinx.coroutines.Deferred @@ -139,6 +140,7 @@ class AnalyzeUrl( var jsEval: Any val sb = StringBuffer(ruleUrl.length) val simpleBindings = SimpleBindings() + simpleBindings["java"] = JsExtensions simpleBindings["baseUrl"] = baseUrl simpleBindings["page"] = page simpleBindings["key"] = key @@ -238,7 +240,7 @@ class AnalyzeUrl( book: BaseBook? ): Any { val bindings = SimpleBindings() - bindings["java"] = this + bindings["java"] = JsExtensions bindings["page"] = page bindings["key"] = key bindings["book"] = book From 810f9362e5e468b6473f018f97ebeb205ef516fa Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 23 Oct 2019 14:14:39 +0800 Subject: [PATCH 1991/1997] up --- .../java/io/legado/app/help/JsExtensions.kt | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/JsExtensions.kt b/app/src/main/java/io/legado/app/help/JsExtensions.kt index ad4024379..1db26a4fe 100644 --- a/app/src/main/java/io/legado/app/help/JsExtensions.kt +++ b/app/src/main/java/io/legado/app/help/JsExtensions.kt @@ -3,8 +3,6 @@ package io.legado.app.help import io.legado.app.model.analyzeRule.AnalyzeUrl import io.legado.app.utils.EncoderUtils import io.legado.app.utils.MD5Utils -import io.legado.app.utils.StringUtils -import java.util.regex.Pattern @Suppress("unused") @@ -31,22 +29,6 @@ object JsExtensions { return EncoderUtils.base64Decoder(str) } - /** - * 章节数转数字 - */ - fun toNumChapter(s: String?): String? { - if (s == null) { - return null - } - val pattern = Pattern.compile("(第)(.+?)(章)") - val matcher = pattern.matcher(s) - return if (matcher.find()) { - matcher.group(1) + StringUtils.stringToInt(matcher.group(2)) + matcher.group(3) - } else { - s - } - } - fun strToMd5By32(str: String?): String? { return MD5Utils.strToMd5By32(str) } From 4e94e0e279f893dad852d79775099e65c03a31ff Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 23 Oct 2019 14:32:42 +0800 Subject: [PATCH 1992/1997] up --- .../java/io/legado/app/help/JsExtensions.kt | 4 ++++ .../app/model/analyzeRule/AnalyzeRule.kt | 20 +++++++++++-------- .../java/io/legado/app/utils/EncoderUtils.kt | 4 ++++ 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/JsExtensions.kt b/app/src/main/java/io/legado/app/help/JsExtensions.kt index 1db26a4fe..4e9bf6c41 100644 --- a/app/src/main/java/io/legado/app/help/JsExtensions.kt +++ b/app/src/main/java/io/legado/app/help/JsExtensions.kt @@ -29,6 +29,10 @@ object JsExtensions { return EncoderUtils.base64Decoder(str) } + fun base64Encoder(str: String): ByteArray? { + return EncoderUtils.base64Encoder(str) + } + fun strToMd5By32(str: String?): String? { return MD5Utils.strToMd5By32(str) } diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt index cba7bc0f1..287774a77 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt @@ -576,6 +576,18 @@ class AnalyzeRule(private var book: BaseBook? = null) { return EncoderUtils.base64Decoder(str) } + fun base64Encoder(str: String): ByteArray? { + return EncoderUtils.base64Encoder(str) + } + + fun strToMd5By32(str: String?): String? { + return MD5Utils.strToMd5By32(str) + } + + fun strToMd5By16(str: String?): String? { + return MD5Utils.strToMd5By16(str) + } + /** * 章节数转数字 */ @@ -592,14 +604,6 @@ class AnalyzeRule(private var book: BaseBook? = null) { } } - fun strToMd5By32(str: String?): String? { - return MD5Utils.strToMd5By32(str) - } - - fun strToMd5By16(str: String?): String? { - return MD5Utils.strToMd5By16(str) - } - companion object { private val putPattern = Pattern.compile("@put:(\\{[^}]+?\\})", Pattern.CASE_INSENSITIVE) private val getPattern = Pattern.compile("@get:\\{([^}]+?)\\}", Pattern.CASE_INSENSITIVE) diff --git a/app/src/main/java/io/legado/app/utils/EncoderUtils.kt b/app/src/main/java/io/legado/app/utils/EncoderUtils.kt index 112ac65f9..3798bfa9c 100644 --- a/app/src/main/java/io/legado/app/utils/EncoderUtils.kt +++ b/app/src/main/java/io/legado/app/utils/EncoderUtils.kt @@ -32,4 +32,8 @@ object EncoderUtils { String(bytes) } } + + fun base64Encoder(str: String): ByteArray? { + return Base64.encode(str.toByteArray(), Base64.DEFAULT) + } } \ No newline at end of file From 7f78c38fb1b256c44812bc5369eb6a35814b2bac Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 23 Oct 2019 14:33:58 +0800 Subject: [PATCH 1993/1997] up --- app/src/main/java/io/legado/app/utils/MD5Utils.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/utils/MD5Utils.java b/app/src/main/java/io/legado/app/utils/MD5Utils.java index 8b955b922..d4f0d8a12 100644 --- a/app/src/main/java/io/legado/app/utils/MD5Utils.java +++ b/app/src/main/java/io/legado/app/utils/MD5Utils.java @@ -1,9 +1,5 @@ package io.legado.app.utils; -/** - * Created by newbiechen on 2018/1/1. - */ - import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; From 8ae0ec73fa0d021689240e597aaf7255bab923af Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 23 Oct 2019 15:00:13 +0800 Subject: [PATCH 1994/1997] up --- app/src/main/java/io/legado/app/help/JsExtensions.kt | 2 +- .../main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt | 2 +- app/src/main/java/io/legado/app/utils/EncoderUtils.kt | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/JsExtensions.kt b/app/src/main/java/io/legado/app/help/JsExtensions.kt index 4e9bf6c41..6a0a87109 100644 --- a/app/src/main/java/io/legado/app/help/JsExtensions.kt +++ b/app/src/main/java/io/legado/app/help/JsExtensions.kt @@ -29,7 +29,7 @@ object JsExtensions { return EncoderUtils.base64Decoder(str) } - fun base64Encoder(str: String): ByteArray? { + fun base64Encoder(str: String): String? { return EncoderUtils.base64Encoder(str) } diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt index 287774a77..501e00777 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt @@ -576,7 +576,7 @@ class AnalyzeRule(private var book: BaseBook? = null) { return EncoderUtils.base64Decoder(str) } - fun base64Encoder(str: String): ByteArray? { + fun base64Encoder(str: String): String? { return EncoderUtils.base64Encoder(str) } diff --git a/app/src/main/java/io/legado/app/utils/EncoderUtils.kt b/app/src/main/java/io/legado/app/utils/EncoderUtils.kt index 3798bfa9c..9e98b35db 100644 --- a/app/src/main/java/io/legado/app/utils/EncoderUtils.kt +++ b/app/src/main/java/io/legado/app/utils/EncoderUtils.kt @@ -33,7 +33,7 @@ object EncoderUtils { } } - fun base64Encoder(str: String): ByteArray? { - return Base64.encode(str.toByteArray(), Base64.DEFAULT) + fun base64Encoder(str: String): String? { + return Base64.encodeToString(str.toByteArray(), Base64.DEFAULT) } } \ No newline at end of file From a0fc5fe58811ac2c5032372258a6b19785e36b9e Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 23 Oct 2019 15:27:43 +0800 Subject: [PATCH 1995/1997] up --- app/src/main/java/io/legado/app/help/JsExtensions.kt | 8 ++++---- .../java/io/legado/app/model/analyzeRule/AnalyzeRule.kt | 8 ++++---- app/src/main/java/io/legado/app/utils/EncoderUtils.kt | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/JsExtensions.kt b/app/src/main/java/io/legado/app/help/JsExtensions.kt index 6a0a87109..8d54ac21c 100644 --- a/app/src/main/java/io/legado/app/help/JsExtensions.kt +++ b/app/src/main/java/io/legado/app/help/JsExtensions.kt @@ -25,12 +25,12 @@ object JsExtensions { /** * js实现解码,不能删 */ - fun base64Decoder(str: String): String { - return EncoderUtils.base64Decoder(str) + fun base64Decode(str: String): String { + return EncoderUtils.base64Decode(str) } - fun base64Encoder(str: String): String? { - return EncoderUtils.base64Encoder(str) + fun base64Encode(str: String): String? { + return EncoderUtils.base64Encode(str) } fun strToMd5By32(str: String?): String? { diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt index 501e00777..831714667 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt @@ -572,12 +572,12 @@ class AnalyzeRule(private var book: BaseBook? = null) { /** * js实现解码,不能删 */ - fun base64Decoder(str: String): String { - return EncoderUtils.base64Decoder(str) + fun base64Decode(str: String): String { + return EncoderUtils.base64Decode(str) } - fun base64Encoder(str: String): String? { - return EncoderUtils.base64Encoder(str) + fun base64Encode(str: String): String? { + return EncoderUtils.base64Encode(str) } fun strToMd5By32(str: String?): String? { diff --git a/app/src/main/java/io/legado/app/utils/EncoderUtils.kt b/app/src/main/java/io/legado/app/utils/EncoderUtils.kt index 9e98b35db..8e5c03522 100644 --- a/app/src/main/java/io/legado/app/utils/EncoderUtils.kt +++ b/app/src/main/java/io/legado/app/utils/EncoderUtils.kt @@ -24,7 +24,7 @@ object EncoderUtils { return tmp.toString() } - fun base64Decoder(str: String): String { + fun base64Decode(str: String): String { val bytes = Base64.decode(str, Base64.DEFAULT) return try { String(bytes, StandardCharsets.UTF_8) @@ -33,7 +33,7 @@ object EncoderUtils { } } - fun base64Encoder(str: String): String? { + fun base64Encode(str: String): String? { return Base64.encodeToString(str.toByteArray(), Base64.DEFAULT) } } \ No newline at end of file From 75792ac8c4d3dd4478d2f0a3b9cce78f3eca452f Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 23 Oct 2019 15:34:17 +0800 Subject: [PATCH 1996/1997] up --- app/src/main/java/io/legado/app/help/JsExtensions.kt | 4 ++-- .../main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/JsExtensions.kt b/app/src/main/java/io/legado/app/help/JsExtensions.kt index 8d54ac21c..d321f57fb 100644 --- a/app/src/main/java/io/legado/app/help/JsExtensions.kt +++ b/app/src/main/java/io/legado/app/help/JsExtensions.kt @@ -33,11 +33,11 @@ object JsExtensions { return EncoderUtils.base64Encode(str) } - fun strToMd5By32(str: String?): String? { + fun strToMd5By32(str: String): String? { return MD5Utils.strToMd5By32(str) } - fun strToMd5By16(str: String?): String? { + fun strToMd5By16(str: String): String? { return MD5Utils.strToMd5By16(str) } diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt index 831714667..b4bb0276e 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt @@ -580,11 +580,11 @@ class AnalyzeRule(private var book: BaseBook? = null) { return EncoderUtils.base64Encode(str) } - fun strToMd5By32(str: String?): String? { + fun strToMd5By32(str: String): String? { return MD5Utils.strToMd5By32(str) } - fun strToMd5By16(str: String?): String? { + fun strToMd5By16(str: String): String? { return MD5Utils.strToMd5By16(str) } From 6446c13de6f6e5ae2c51fc9915f6102727c432a1 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 23 Oct 2019 15:37:28 +0800 Subject: [PATCH 1997/1997] up --- .../java/io/legado/app/data/entities/BookSource.kt | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/entities/BookSource.kt b/app/src/main/java/io/legado/app/data/entities/BookSource.kt index 373c31de5..3236d5796 100644 --- a/app/src/main/java/io/legado/app/data/entities/BookSource.kt +++ b/app/src/main/java/io/legado/app/data/entities/BookSource.kt @@ -73,9 +73,9 @@ data class BookSource( header?.let { val header1 = when { it.startsWith("@js:", true) -> - AppConst.SCRIPT_ENGINE.eval(it.substring(4)).toString() + evalJS(it.substring(4)).toString() it.startsWith("", true) -> - AppConst.SCRIPT_ENGINE.eval(it.substring(4, it.lastIndexOf("<"))).toString() + evalJS(it.substring(4, it.lastIndexOf("<"))).toString() else -> it } GSON.fromJsonObject>(header1)?.let { map -> @@ -159,6 +159,16 @@ data class BookSource( return exploreKinds } + /** + * 执行JS + */ + @Throws(Exception::class) + private fun evalJS(jsStr: String): Any { + val bindings = SimpleBindings() + bindings["java"] = JsExtensions + return AppConst.SCRIPT_ENGINE.eval(jsStr, bindings) + } + data class ExploreKind( var title: String, var url: String? = null

    -i;Ez#sl3ooWh((_oH-=1>RKys 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