diff --git a/app/build.gradle b/app/build.gradle
index 2e4307723..01d15e189 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -81,7 +81,7 @@ dependencies {
//androidX
implementation 'androidx.core:core-ktx:1.2.0-alpha01'
implementation 'androidx.appcompat:appcompat:1.1.0-beta01'
- implementation 'androidx.preference:preference:1.1.0-alpha05'
+ implementation 'androidx.preference:preference:1.1.0-beta01'
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta1'
implementation 'com.google.android.material:material:1.1.0-alpha07'
@@ -119,6 +119,9 @@ dependencies {
implementation 'net.minidev:json-smart:2.3'
// implementation 'com.jayway.jsonpath:json-path:2.4.0'
+ //JS
+ 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'
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 91282f69e..f3aa77c93 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -27,24 +27,32 @@
android:theme="@style/AppTheme.Light"
tools:ignore="AllowBackup,GoogleAppIndexingWarning,UnusedAttribute">
+ android:name=".ui.welcome.WelcomeActivity"
+ android:label="@string/app_name">
-
+
-
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/ic_launcher-web.png b/app/src/main/ic_launcher-web.png
index 9fafc3aa3..7e2060a9c 100644
Binary files a/app/src/main/ic_launcher-web.png and b/app/src/main/ic_launcher-web.png differ
diff --git a/app/src/main/java/io/legado/app/App.kt b/app/src/main/java/io/legado/app/App.kt
index e5d088125..563183807 100644
--- a/app/src/main/java/io/legado/app/App.kt
+++ b/app/src/main/java/io/legado/app/App.kt
@@ -4,9 +4,6 @@ import android.app.Application
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
-import android.content.pm.PackageManager
-import android.graphics.PorterDuff
-import android.graphics.drawable.Drawable
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatDelegate
@@ -17,7 +14,6 @@ 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.getCompatDrawable
import io.legado.app.utils.getPrefBoolean
import io.legado.app.utils.getPrefInt
import java.util.*
@@ -35,29 +31,25 @@ class App : Application() {
private set
}
- private var versionCode = 0
+ var versionCode = 0
+ var versionName = ""
override fun onCreate() {
super.onCreate()
INSTANCE = this
db = AppDatabase.createDatabase(INSTANCE)
- versionCode = try {
- packageManager.getPackageInfo(packageName, 0).versionCode
- } catch (e: PackageManager.NameNotFoundException) {
- 0
+ packageManager.getPackageInfo(packageName, 0)?.let {
+ versionCode = it.versionCode
+ versionName = it.versionName
}
-
if (!ThemeStore.isConfigured(this, versionCode)) upThemeStore()
initNightTheme()
-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) createChannelId()
-
LiveEventBus.get()
.config()
.supportBroadcast(this)
.lifecycleObserverAlwaysActive(true)
.autoClear(false)
-
}
fun initNightTheme() {
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 6b1c46817..eb3855e49 100644
--- a/app/src/main/java/io/legado/app/data/AppDatabase.kt
+++ b/app/src/main/java/io/legado/app/data/AppDatabase.kt
@@ -6,15 +6,12 @@ import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
-import io.legado.app.data.dao.BookDao
-import io.legado.app.data.dao.BookGroupDao
-import io.legado.app.data.dao.BookSourceDao
-import io.legado.app.data.dao.ReplaceRuleDao
+import io.legado.app.data.dao.*
import io.legado.app.data.entities.*
@Database(
- entities = [Book::class, BookGroup::class, BookSource::class, Chapter::class, ReplaceRule::class],
+ entities = [Book::class, BookGroup::class, BookSource::class, Chapter::class, ReplaceRule::class, SearchBook::class, SearchKeyword::class],
version = 1,
exportSchema = true
)
@@ -35,7 +32,11 @@ abstract class AppDatabase : RoomDatabase() {
}
fun createDatabase(context: Context): AppDatabase {
- return Room.databaseBuilder(context.applicationContext, AppDatabase::class.java, DATABASE_NAME)
+ return Room.databaseBuilder(
+ context.applicationContext,
+ AppDatabase::class.java,
+ DATABASE_NAME
+ )
// .addMigrations(MIGRATION_1_2)
// .addMigrations(MIGRATION_2_3)
// .addMigrations(MIGRATION_3_4)
@@ -50,5 +51,6 @@ abstract class AppDatabase : RoomDatabase() {
abstract fun bookGroupDao(): BookGroupDao
abstract fun bookSourceDao(): BookSourceDao
abstract fun replaceRuleDao(): ReplaceRuleDao
-
+ abstract fun searchBookDao(): SearchBookDao
+ abstract fun searchKeywordDao(): SearchKeywordDao
}
\ No newline at end of file
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 3fabd852e..cd7b359d1 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
@@ -11,6 +11,9 @@ import io.legado.app.data.entities.Book
@Dao
interface BookDao {
+ @Query("SELECT * FROM books")
+ fun observeAll(): DataSource.Factory
+
@Query("SELECT * FROM books WHERE `group` = :group")
fun observeByGroup(group: Int): DataSource.Factory
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
new file mode 100644
index 000000000..ff36e8afb
--- /dev/null
+++ b/app/src/main/java/io/legado/app/data/dao/SearchBookDao.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.SearchBook
+
+@Dao
+interface SearchBookDao {
+
+ @Query("SELECT * FROM searchBooks")
+ fun observeAll(): DataSource.Factory
+
+ @Query("SELECT * FROM searchBooks where time >= :time")
+ fun observeNew(time: Long): DataSource.Factory
+
+
+}
\ 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 6c7a2e4b3..129135a9b 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
@@ -15,40 +15,44 @@ import kotlinx.android.parcel.Parcelize
@Parcelize
@Entity(tableName = "books", indices = [(Index(value = ["descUrl"], unique = true))])
data class Book(
- @PrimaryKey
- var descUrl: String = "", // 详情页Url(本地书源存储完整文件路径)
- var tocUrl: String = "", // 目录页Url (toc=table of Contents)
- var sourceId: Int = -1, // 书源规则id(默认-1,表示本地书籍)
- var name: String? = null, // 书籍名称(书源获取)
- var customName: String? = null, // 书籍名称(用户修改)
- var author: String? = null, // 作者名称(书源获取)
- var customAuthor: String? = null, // 作者名称(用户修改)
- var tag: String? = null, // 分类信息(书源获取)
- var customTag: String? = null, // 分类信息(用户修改)
- var coverUrl: String? = null, // 封面Url(书源获取)
- var customCoverUrl: String? = null, // 封面Url(用户修改)
- var description: String? = null, // 简介内容(书源获取)
- var customDescription: String? = null, // 简介内容(用户修改)
- var charset: String? = null, // 自定义字符集名称(仅适用于本地书籍)
- var type: Int = 0, // 0: 文本读物, 1: 有声读物
- var group: Int = 0, // 自定义分组索引号
- var latestChapterTitle: String? = null, // 最新章节标题
- var latestChapterTime: Long = 0, // 最新章节标题更新时间
- var lastCheckTime: Long = 0, // 最近一次更新书籍信息的时间
- 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 canUpdate: Boolean = true, // 刷新书架时更新书籍信息
- var order: Int = 0, // 手动排序
- var useReplaceRule: Boolean = true, // 正文使用净化替换规则
- var variable: String? = null // 自定义书籍变量信息(用于书源规则检索书籍信息)
+ @PrimaryKey
+ var descUrl: String = "", // 详情页Url(本地书源存储完整文件路径)
+ var tocUrl: String = "", // 目录页Url (toc=table of Contents)
+ var origin: String = "", // 书源规则id(默认-1,表示本地书籍)
+ var name: String? = null, // 书籍名称(书源获取)
+ var customName: String? = null, // 书籍名称(用户修改)
+ var author: String? = null, // 作者名称(书源获取)
+ var customAuthor: String? = null, // 作者名称(用户修改)
+ var tag: String? = null, // 分类信息(书源获取)
+ var customTag: String? = null, // 分类信息(用户修改)
+ var coverUrl: String? = null, // 封面Url(书源获取)
+ var customCoverUrl: String? = null, // 封面Url(用户修改)
+ var description: String? = null, // 简介内容(书源获取)
+ var customDescription: String? = null, // 简介内容(用户修改)
+ var charset: String? = null, // 自定义字符集名称(仅适用于本地书籍)
+ var type: Int = 0, // 0: 文本读物, 1: 有声读物
+ var group: Int = 0, // 自定义分组索引号
+ var latestChapterTitle: String? = null, // 最新章节标题
+ var latestChapterTime: Long = 0, // 最新章节标题更新时间
+ var lastCheckTime: Long = 0, // 最近一次更新书籍信息的时间
+ 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 canUpdate: Boolean = true, // 刷新书架时更新书籍信息
+ var order: Int = 0, // 手动排序
+ var useReplaceRule: Boolean = true, // 正文使用净化替换规则
+ var variable: String? = null // 自定义书籍变量信息(用于书源规则检索书籍信息)
) : Parcelable, BaseBook {
@IgnoredOnParcel
@Ignore
override var variableMap: HashMap? = null
+ get() = run {
+ initVariableMap()
+ return field
+ }
fun getUnreadChapterNum() = Math.max(totalChapterNum - durChapterIndex - 1, 0)
@@ -72,5 +76,7 @@ data class Book(
override fun putVariable(key: String, value: String) {
initVariableMap()
+ variableMap?.put(key, value)
+ variable = Gson().toJson(variableMap)
}
}
\ 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 8994f14bd..97a504b3c 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,3 +1,53 @@
package io.legado.app.data.entities
-class SearchBook
\ No newline at end of file
+import android.os.Parcelable
+import android.text.TextUtils
+import androidx.room.Entity
+import androidx.room.Ignore
+import androidx.room.Index
+import androidx.room.PrimaryKey
+import com.google.gson.Gson
+import io.legado.app.utils.fromJson
+import kotlinx.android.parcel.IgnoredOnParcel
+import kotlinx.android.parcel.Parcelize
+
+@Parcelize
+@Entity(tableName = "searchBooks", indices = [(Index(value = ["descUrl"], unique = true))])
+data class SearchBook(
+ @PrimaryKey
+ var descUrl: String = "",
+ var origin: String = "", // 书源规则id(默认-1,表示本地书籍)
+ var name: String? = null,
+ var author: String? = null,
+ var tag: String? = null,
+ var coverUrl: String? = null,
+ var description: String? = null,
+ var latestChapterTitle: String? = null,
+ var time: Long = 0L,
+ var variable: String? = null
+) : Parcelable, BaseBook {
+
+ @IgnoredOnParcel
+ @Ignore
+ override var variableMap: HashMap? = null
+ get() = run {
+ initVariableMap()
+ return field
+ }
+
+ private fun initVariableMap() {
+ if (variableMap == null) {
+ variableMap = if (TextUtils.isEmpty(variable)) {
+ HashMap()
+ } else {
+ Gson().fromJson>(variable!!)
+ }
+ }
+ }
+
+ override fun putVariable(key: String, value: String) {
+ initVariableMap()
+ variableMap?.put(key, value)
+ variable = Gson().toJson(variableMap)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/analyzeJsoup.kt b/app/src/main/java/io/legado/app/model/analyzeRule/analyzeJsoup.kt
new file mode 100644
index 000000000..c65049d4e
--- /dev/null
+++ b/app/src/main/java/io/legado/app/model/analyzeRule/analyzeJsoup.kt
@@ -0,0 +1,2 @@
+package io.legado.app.model.analyzeRule
+
diff --git a/app/src/main/java/io/legado/app/model/content/BookList.kt b/app/src/main/java/io/legado/app/model/content/BookList.kt
new file mode 100644
index 000000000..e70ece772
--- /dev/null
+++ b/app/src/main/java/io/legado/app/model/content/BookList.kt
@@ -0,0 +1,2 @@
+package io.legado.app.model.content
+
diff --git a/app/src/main/java/io/legado/app/service/CheckSourceService.kt b/app/src/main/java/io/legado/app/service/CheckSourceService.kt
new file mode 100644
index 000000000..060e89f19
--- /dev/null
+++ b/app/src/main/java/io/legado/app/service/CheckSourceService.kt
@@ -0,0 +1,12 @@
+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
+ }
+
+}
\ 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
new file mode 100644
index 000000000..58baf3188
--- /dev/null
+++ b/app/src/main/java/io/legado/app/service/DownloadService.kt
@@ -0,0 +1,12 @@
+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
+ }
+
+}
\ 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
new file mode 100644
index 000000000..2735e54be
--- /dev/null
+++ b/app/src/main/java/io/legado/app/service/ReadAloudService.kt
@@ -0,0 +1,12 @@
+package io.legado.app.service
+
+import android.app.Service
+import android.content.Intent
+import android.os.IBinder
+
+class ReadAloudService : Service() {
+ override fun onBind(intent: Intent?): IBinder? {
+ return null
+ }
+
+}
\ 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
new file mode 100644
index 000000000..0abfb5db9
--- /dev/null
+++ b/app/src/main/java/io/legado/app/service/ShareService.kt
@@ -0,0 +1,12 @@
+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
+ }
+
+}
\ 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
new file mode 100644
index 000000000..266d0a5bd
--- /dev/null
+++ b/app/src/main/java/io/legado/app/service/UpdateService.kt
@@ -0,0 +1,12 @@
+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
+ }
+
+}
\ 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
new file mode 100644
index 000000000..366a48ede
--- /dev/null
+++ b/app/src/main/java/io/legado/app/service/WebService.kt
@@ -0,0 +1,12 @@
+package io.legado.app.service
+
+import android.app.Service
+import android.content.Intent
+import android.os.IBinder
+
+class WebService : Service() {
+ override fun onBind(intent: Intent?): IBinder? {
+ return null
+ }
+
+}
\ No newline at end of file
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 fff5b7433..c50e14a46 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
@@ -1,10 +1,15 @@
package io.legado.app.ui.about
+import android.content.Intent
+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.utils.getViewModel
+import org.jetbrains.anko.toast
class AboutActivity : BaseActivity() {
override val viewModel: AndroidViewModel
@@ -13,7 +18,35 @@ class AboutActivity : BaseActivity() {
get() = R.layout.activity_about
override fun onViewModelCreated(viewModel: AndroidViewModel, savedInstanceState: Bundle?) {
+ val fTag = "aboutFragment"
+ var aboutFragment = supportFragmentManager.findFragmentByTag(fTag)
+ if (aboutFragment == null) aboutFragment = AboutFragment()
+ supportFragmentManager.beginTransaction()
+ .replace(R.id.fl_fragment, aboutFragment, fTag)
+ .commit()
+ }
+
+ override fun onCompatCreateOptionsMenu(menu: Menu): Boolean {
+ menuInflater.inflate(R.menu.about, menu)
+ return super.onCompatCreateOptionsMenu(menu)
+ }
+ override fun onCompatOptionsItemSelected(item: MenuItem): Boolean {
+ when (item.itemId) {
+ R.id.menu_scoring -> {
+ openIntent(Intent.ACTION_VIEW, "market://details?id=$packageName")
+ }
+ }
+ return super.onCompatOptionsItemSelected(item)
}
+ private fun openIntent(intentName: String, address: String) {
+ try {
+ val intent = Intent(intentName)
+ intent.data = Uri.parse(address)
+ startActivity(intent)
+ } catch (e: Exception) {
+ toast(R.string.can_not_open)
+ }
+ }
}
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
new file mode 100644
index 000000000..db9285137
--- /dev/null
+++ b/app/src/main/java/io/legado/app/ui/about/AboutFragment.kt
@@ -0,0 +1,35 @@
+package io.legado.app.ui.about
+
+import android.content.Intent
+import android.net.Uri
+import android.os.Bundle
+import androidx.preference.Preference
+import androidx.preference.PreferenceFragmentCompat
+import io.legado.app.App
+import io.legado.app.R
+import io.legado.app.utils.toast
+
+class AboutFragment : PreferenceFragmentCompat() {
+ override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
+ addPreferencesFromResource(R.xml.about)
+ findPreference("version")?.summary = App.INSTANCE.versionName
+ }
+
+ override fun onPreferenceTreeClick(preference: Preference?): Boolean {
+ when (preference?.key) {
+
+ }
+ return super.onPreferenceTreeClick(preference)
+ }
+
+ private fun openIntent(intentName: String, address: String) {
+ try {
+ val intent = Intent(intentName)
+ intent.data = Uri.parse(address)
+ startActivity(intent)
+ } catch (e: Exception) {
+ toast(R.string.can_not_open)
+ }
+
+ }
+}
\ No newline at end of file
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
new file mode 100644
index 000000000..432e99a58
--- /dev/null
+++ b/app/src/main/java/io/legado/app/ui/about/DonateActivity.kt
@@ -0,0 +1,95 @@
+package io.legado.app.ui.about
+
+
+import android.content.ClipData
+import android.content.ClipboardManager
+import android.content.Context
+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.utils.getViewModel
+import kotlinx.android.synthetic.main.activity_donate.*
+import kotlinx.android.synthetic.main.view_title_bar.*
+import org.jetbrains.anko.toast
+import java.net.URLEncoder
+
+/**
+ * Created by GKF on 2018/1/13.
+ * 捐赠页面
+ */
+
+class DonateActivity : BaseActivity() {
+
+ override val viewModel: AndroidViewModel
+ get() = getViewModel(AndroidViewModel::class.java)
+
+ override val layoutID: Int
+ get() = R.layout.activity_donate
+
+ override fun onViewModelCreated(viewModel: AndroidViewModel, savedInstanceState: Bundle?) {
+ setSupportActionBar(toolbar)
+ vw_zfb_tz.setOnClickListener { aliDonate(this) }
+ cv_wx_gzh.setOnClickListener {
+ val clipboard = this.getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager
+ val clipData = ClipData.newPlainText(null, "开源阅读软件")
+ clipboard?.let {
+ clipboard.primaryClip = clipData
+ toast(R.string.copy_complete)
+ }
+ }
+ vw_zfb_hb.setOnClickListener { openActionViewIntent("https://gedoor.github.io/MyBookshelf/zfbhbrwm.png") }
+ vw_zfb_rwm.setOnClickListener { openActionViewIntent("https://gedoor.github.io/MyBookshelf/zfbskrwm.jpg") }
+ vw_wx_rwm.setOnClickListener { openActionViewIntent("https://gedoor.github.io/MyBookshelf/wxskrwm.jpg") }
+ vw_qq_rwm.setOnClickListener { openActionViewIntent("https://gedoor.github.io/MyBookshelf/qqskrwm.jpg") }
+ vw_zfb_hb_ssm.setOnClickListener { getZfbHb(this) }
+ }
+
+ private fun getZfbHb(context: Context) {
+ val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager
+ val clipData = ClipData.newPlainText(null, "537954522")
+ clipboard?.let {
+ clipboard.primaryClip = clipData
+ Toast.makeText(context, "高级功能已开启\n红包码已复制\n支付宝首页搜索“537954522” 立即领红包", Toast.LENGTH_LONG)
+ .show()
+ }
+ try {
+ val packageManager = context.applicationContext.packageManager
+ val intent = packageManager.getLaunchIntentForPackage("com.eg.android.AlipayGphone")!!
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ context.startActivity(intent)
+ } catch (e: Exception) {
+ e.printStackTrace()
+ } finally {
+
+ }
+ }
+
+ private fun openActionViewIntent(address: String) {
+ try {
+ val intent = Intent(Intent.ACTION_VIEW)
+ intent.data = Uri.parse(address)
+ startActivity(intent)
+ } catch (e: Exception) {
+ e.printStackTrace()
+ Toast.makeText(this, R.string.can_not_open, Toast.LENGTH_SHORT).show()
+ }
+
+ }
+
+ 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 intent = Intent(Intent.ACTION_VIEW, Uri.parse(aliPayQr))
+ context.startActivity(intent)
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+
+ }
+}
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
new file mode 100644
index 000000000..083fb8823
--- /dev/null
+++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoActivity.kt
@@ -0,0 +1,19 @@
+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
+
+ override fun onViewModelCreated(viewModel: BookInfoViewModel, savedInstanceState: Bundle?) {
+
+ }
+
+
+}
\ 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/BookInfoEditActivity.kt
new file mode 100644
index 000000000..4572b425d
--- /dev/null
+++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoEditActivity.kt
@@ -0,0 +1,18 @@
+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 BookInfoEditActivity : BaseActivity() {
+ override val viewModel: BookInfoViewModel
+ get() = getViewModel(BookInfoViewModel::class.java)
+ override val layoutID: Int
+ get() = R.layout.activity_book_info_edit
+
+ override fun onViewModelCreated(viewModel: BookInfoViewModel, savedInstanceState: Bundle?) {
+
+ }
+
+}
\ 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
new file mode 100644
index 000000000..cf943895d
--- /dev/null
+++ b/app/src/main/java/io/legado/app/ui/bookinfo/BookInfoViewModel.kt
@@ -0,0 +1,8 @@
+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
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 445abca97..f0af48ac7 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
@@ -1,8 +1,17 @@
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.BaseActivity
+import io.legado.app.data.entities.Book
import io.legado.app.utils.getViewModel
import kotlinx.android.synthetic.main.activity_bookshelf.*
@@ -12,6 +21,9 @@ class BookshelfActivity : BaseActivity() {
override val layoutID: Int
get() = R.layout.activity_bookshelf
+ private lateinit var bookshelfAdapter: BookshelfAdapter
+ private var bookshelfLiveData: LiveData>? = null
+
override fun onViewModelCreated(viewModel: BookshelfViewModel, savedInstanceState: Bundle?) {
if (viewModel.bookGroup == null) {
viewModel.bookGroup = intent.getParcelableExtra("data")
@@ -19,6 +31,33 @@ class BookshelfActivity : BaseActivity() {
viewModel.bookGroup?.let {
title_bar.title = it.groupName
}
+ initRecyclerView()
+ upRecyclerData()
+ }
+
+ private fun initRecyclerView() {
+ rv_bookshelf.layoutManager = LinearLayoutManager(this)
+ rv_bookshelf.addItemDecoration(DividerItemDecoration(this, LinearLayout.VERTICAL))
+ bookshelfAdapter = BookshelfAdapter()
+ rv_bookshelf.adapter = bookshelfAdapter
+ }
+
+ private fun upRecyclerData() {
+ viewModel.bookGroup?.let {
+ when (it.groupId) {
+ -1 -> {
+ bookshelfLiveData?.removeObservers(this)
+ bookshelfLiveData =
+ LivePagedListBuilder(App.db.bookDao().observeAll(), 10).build()
+ bookshelfLiveData?.observe(
+ this,
+ Observer { pageList -> bookshelfAdapter.submitList(pageList) })
+ }
+ else -> {
+
+ }
+ }
+ }
}
}
\ 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
new file mode 100644
index 000000000..b7fdf7b8d
--- /dev/null
+++ b/app/src/main/java/io/legado/app/ui/bookshelf/BookshelfAdapter.kt
@@ -0,0 +1,87 @@
+package io.legado.app.ui.bookshelf
+
+import android.text.TextUtils.isEmpty
+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 com.bumptech.glide.Glide
+import com.bumptech.glide.load.engine.DiskCacheStrategy
+import io.legado.app.R
+import io.legado.app.data.entities.Book
+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 java.io.File
+
+class BookshelfAdapter : PagedListAdapter(DIFF_CALLBACK) {
+
+ companion object {
+ @JvmField
+ val DIFF_CALLBACK = object : DiffUtil.ItemCallback() {
+ override fun areItemsTheSame(oldItem: Book, newItem: Book): Boolean =
+ oldItem.descUrl == newItem.descUrl
+
+ override fun areContentsTheSame(oldItem: Book, newItem: Book): Boolean =
+ oldItem.descUrl == newItem.descUrl
+ && oldItem.durChapterTitle == newItem.durChapterTitle
+ && oldItem.latestChapterTitle == newItem.latestChapterTitle
+ }
+ }
+
+ var callBack: CallBack? = null
+
+ 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) {
+ tv_name.text = book.name
+ tv_author.text = book.author
+ tv_read.text = book.durChapterTitle
+ tv_last.text = book.latestChapterTitle
+ val cover = if (isEmpty(book.customCoverUrl)) book.coverUrl else book.customCoverUrl
+ cover?.let {
+ if (it.startsWith("http")) {
+ Glide.with(itemView).load(it)
+ .placeholder(R.drawable.img_cover_default)
+ .centerCrop()
+ .diskCacheStrategy(DiskCacheStrategy.RESOURCE)
+ .into(iv_cover)
+ } else {
+ Glide.with(itemView).load(File(it))
+ .placeholder(R.drawable.img_cover_default)
+ .centerCrop()
+ .diskCacheStrategy(DiskCacheStrategy.RESOURCE)
+ .into(iv_cover)
+ }
+ }
+ itemView.setOnClickListener { callBack?.open(book) }
+ }
+ }
+
+ interface CallBack {
+ fun open(book: Book)
+ fun search()
+ }
+}
\ No newline at end of file
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 c2a1b2f77..55020c1db 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,12 +9,12 @@ import androidx.lifecycle.Observer
import androidx.viewpager.widget.ViewPager
import com.google.android.material.bottomnavigation.BottomNavigationView
import com.jeremyliao.liveeventbus.LiveEventBus
+import io.legado.app.App
import io.legado.app.R
import io.legado.app.base.BaseActivity
import io.legado.app.constant.Bus
import io.legado.app.help.permission.Permissions
import io.legado.app.help.permission.PermissionsCompat
-import io.legado.app.help.storage.Restore
import io.legado.app.lib.theme.Selector
import io.legado.app.lib.theme.ThemeStore
import io.legado.app.ui.main.bookshelf.BookshelfFragment
@@ -24,6 +24,9 @@ import io.legado.app.ui.main.myconfig.MyConfigFragment
import io.legado.app.utils.getCompatColor
import io.legado.app.utils.getViewModel
import kotlinx.android.synthetic.main.activity_main.*
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.launch
class MainActivity : BaseActivity(), BottomNavigationView.OnNavigationItemSelectedListener,
ViewPager.OnPageChangeListener {
@@ -45,6 +48,7 @@ class MainActivity : BaseActivity(), BottomNavigationView.OnNavig
view_pager_main.adapter = TabFragmentPageAdapter(supportFragmentManager)
view_pager_main.addOnPageChangeListener(this)
bottom_navigation_view.setOnNavigationItemSelectedListener(this)
+ importYueDu()
}
override fun onNavigationItemSelected(item: MenuItem): Boolean {
@@ -58,10 +62,17 @@ class MainActivity : BaseActivity(), BottomNavigationView.OnNavig
}
private fun importYueDu() {
- PermissionsCompat.Builder(this)
- .addPermissions(*Permissions.Group.STORAGE)
- .rationale(R.string.tip_perm_request_storage)
- .onGranted { Restore.importYueDuData(this) }.request()
+ GlobalScope.launch {
+ if (App.db.bookDao().allBookCount == 0) {
+ GlobalScope.launch(Dispatchers.Main) {
+ PermissionsCompat.Builder(this@MainActivity)
+ .addPermissions(*Permissions.Group.STORAGE)
+ .rationale(R.string.tip_perm_request_storage)
+ .onGranted { viewModel.restore() }
+ .request()
+ }
+ }
+ }
}
override fun onPageScrollStateChanged(state: Int) {
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 cf2f8f600..4285ae62c 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,22 +1,16 @@
package io.legado.app.ui.main
import android.app.Application
-import io.legado.app.App
-import io.legado.app.base.BaseViewModel
-import kotlinx.coroutines.async
-import org.jetbrains.anko.toast
+import androidx.lifecycle.AndroidViewModel
+import io.legado.app.help.storage.Restore
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.launch
-class MainViewModel(application: Application) : BaseViewModel(application) {
+class MainViewModel(application: Application) : AndroidViewModel(application) {
- fun test() {
- launchOnUI({
-
- val result = async {
- "结果"
- }
-
-// App.INSTANCE.toast("result: $result")
- })
+ fun restore() {
+ GlobalScope.launch {
+ Restore.importYueDuData(getApplication())
+ }
}
-
}
\ 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 eae2f0aec..87bcaf63b 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
@@ -16,7 +16,7 @@ import kotlinx.android.synthetic.main.item_bookshelf_list.view.*
import kotlinx.android.synthetic.main.item_relace_rule.view.tv_name
import java.io.File
-class BookshelfAdapter : PagedListAdapter(DIFF_CALLBACK) {
+class BookshelfAdapter : PagedListAdapter(DIFF_CALLBACK) {
companion object {
@JvmField
@@ -33,43 +33,15 @@ class BookshelfAdapter : PagedListAdapter(DIFF_CA
var callBack: CallBack? = null
- override fun getItemViewType(position: Int): Int {
- if (position == itemCount - 1) {
- return 1
- }
- return super.getItemViewType(position)
- }
-
- override fun getItemCount(): Int {
- return super.getItemCount() + 1
- }
-
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
- if (viewType == 1) {
- return AddViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_bookshelf_list_add, parent, false))
- }
+ 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: RecyclerView.ViewHolder, position: Int) {
- when (holder) {
- is MyViewHolder -> {
- currentList?.get(position)?.let {
- holder.bind(it, callBack)
- }
- }
- is AddViewHolder -> holder.bind(callBack)
- }
-
- }
-
- class AddViewHolder(view: View) : RecyclerView.ViewHolder(view) {
-
- fun bind(callBack: CallBack?) = with(itemView) {
- setOnClickListener { callBack?.search() }
+ override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
+ currentList?.get(position)?.let {
+ holder.bind(it, callBack)
}
}
-
class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) {
init {
diff --git a/app/src/main/java/io/legado/app/ui/main/booksource/BookSourceFragment.kt b/app/src/main/java/io/legado/app/ui/main/booksource/BookSourceFragment.kt
index ea182f6dc..90b75c4d4 100644
--- a/app/src/main/java/io/legado/app/ui/main/booksource/BookSourceFragment.kt
+++ b/app/src/main/java/io/legado/app/ui/main/booksource/BookSourceFragment.kt
@@ -55,7 +55,12 @@ class BookSourceFragment : BaseFragment(R.layout.fragment_book_source), BookSour
private fun initRecyclerView() {
recycler_view.layoutManager = LinearLayoutManager(context)
- recycler_view.addItemDecoration(DividerItemDecoration(context, LinearLayoutManager.VERTICAL))
+ recycler_view.addItemDecoration(
+ DividerItemDecoration(
+ context,
+ LinearLayoutManager.VERTICAL
+ )
+ )
adapter = BookSourceAdapter()
adapter.callBack = this
recycler_view.adapter = adapter
@@ -76,9 +81,10 @@ class BookSourceFragment : BaseFragment(R.layout.fragment_book_source), BookSour
private fun initDataObserve(searchKey: String = "") {
bookSourceLiveDate?.removeObservers(viewLifecycleOwner)
val dataFactory =
- if (searchKey.isEmpty()) App.db.bookSourceDao().observeAll() else App.db.bookSourceDao().observeSearch(
- searchKey
- )
+ if (searchKey.isEmpty())
+ App.db.bookSourceDao().observeAll()
+ else
+ App.db.bookSourceDao().observeSearch(searchKey)
bookSourceLiveDate = LivePagedListBuilder(dataFactory, 30).build()
bookSourceLiveDate?.observe(viewLifecycleOwner, Observer { adapter.submitList(it) })
}
diff --git a/app/src/main/java/io/legado/app/ui/main/myconfig/PreferenceFragment.kt b/app/src/main/java/io/legado/app/ui/main/myconfig/PreferenceFragment.kt
index d3f862d20..98b399c1c 100644
--- a/app/src/main/java/io/legado/app/ui/main/myconfig/PreferenceFragment.kt
+++ b/app/src/main/java/io/legado/app/ui/main/myconfig/PreferenceFragment.kt
@@ -7,11 +7,13 @@ import androidx.preference.PreferenceFragmentCompat
import io.legado.app.App
import io.legado.app.R
import io.legado.app.ui.about.AboutActivity
+import io.legado.app.ui.about.DonateActivity
import io.legado.app.ui.config.ConfigActivity
import io.legado.app.ui.config.ConfigViewModel
import org.jetbrains.anko.startActivity
-class PreferenceFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedPreferenceChangeListener {
+class PreferenceFragment : PreferenceFragmentCompat(),
+ SharedPreferences.OnSharedPreferenceChangeListener {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.pref_main)
@@ -38,22 +40,18 @@ class PreferenceFragment : PreferenceFragmentCompat(), SharedPreferences.OnShare
override fun onPreferenceTreeClick(preference: Preference?): Boolean {
preference?.let {
when (preference.key) {
- "setting" -> {
- requireContext().startActivity(
- Pair("configType", ConfigViewModel.TYPE_CONFIG)
- )
- }
- "web_dav_setting" -> {
- requireContext().startActivity(
- Pair("configType", ConfigViewModel.TYPE_WEB_DAV_CONFIG)
- )
- }
- "theme_setting" -> {
- requireContext().startActivity(
- Pair("configType", ConfigViewModel.TYPE_THEME_CONFIG)
- )
- }
- "about" -> requireContext().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)
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 ad9019228..9d84fffea 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
@@ -5,6 +5,7 @@ import android.content.Intent
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
@@ -66,7 +67,7 @@ class QrCodeActivity : BaseActivity(), QRCodeView.Delegate {
.addPermissions(*Permissions.Group.CAMERA)
.rationale(R.string.qr_per)
.onGranted {
- zxingview.startCamera() // 打开后置摄像头开始预览,但是并未开始识别
+ zxingview.visibility = View.VISIBLE
zxingview.startSpotAndShowRect() // 显示扫描框,并开始识别
}.request()
}
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
new file mode 100644
index 000000000..587794914
--- /dev/null
+++ b/app/src/main/java/io/legado/app/ui/welcome/WelcomeActivity.kt
@@ -0,0 +1,50 @@
+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
+
+ override fun onViewModelCreated(viewModel: AndroidViewModel, savedInstanceState: Bundle?) {
+ iv_bg.setColorFilter(ThemeStore.accentColor(this))
+ val welAnimator = ValueAnimator.ofFloat(1f, 0f).setDuration(800)
+ welAnimator.startDelay = 100
+ welAnimator.addUpdateListener { animation ->
+ val alpha = animation.animatedValue as Float
+ iv_bg.alpha = alpha
+ }
+ welAnimator.addListener(object : Animator.AnimatorListener {
+ override fun onAnimationStart(animation: Animator) {
+ startActivity()
+ finish()
+ }
+
+ override fun onAnimationEnd(animation: Animator) {
+
+ }
+
+ override fun onAnimationCancel(animation: Animator) {
+
+ }
+
+ override fun onAnimationRepeat(animation: Animator) {
+
+ }
+ })
+ welAnimator.start()
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/legado/app/ui/widget/RotateLoading.kt b/app/src/main/java/io/legado/app/ui/widget/anima/RotateLoading.kt
similarity index 100%
rename from app/src/main/java/io/legado/app/ui/widget/RotateLoading.kt
rename to app/src/main/java/io/legado/app/ui/widget/anima/RotateLoading.kt
diff --git a/app/src/main/java/io/legado/app/ui/widget/anima/explosion_field/ExplosionAnimator.kt b/app/src/main/java/io/legado/app/ui/widget/anima/explosion_field/ExplosionAnimator.kt
new file mode 100644
index 000000000..28bb1602a
--- /dev/null
+++ b/app/src/main/java/io/legado/app/ui/widget/anima/explosion_field/ExplosionAnimator.kt
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2015 tyrantgit
+ *
+ * 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.ui.widget.anima.explosion_field
+
+import android.animation.ValueAnimator
+import android.graphics.*
+import android.view.View
+import android.view.animation.AccelerateInterpolator
+import java.util.*
+
+class ExplosionAnimator(private val mContainer: View, bitmap: Bitmap, bound: Rect) :
+ ValueAnimator() {
+ private val mPaint: Paint
+ private val mParticles: Array
+ private val mBound: Rect
+
+ init {
+ mPaint = Paint()
+ mBound = Rect(bound)
+ val partLen = 15
+ mParticles = arrayOfNulls(partLen * partLen)
+ val random = Random(System.currentTimeMillis())
+ val w = bitmap.width / (partLen + 2)
+ val h = bitmap.height / (partLen + 2)
+ for (i in 0 until partLen) {
+ for (j in 0 until partLen) {
+ mParticles[i * partLen + j] =
+ generateParticle(bitmap.getPixel((j + 1) * w, (i + 1) * h), random)
+ }
+ }
+ setFloatValues(0f, END_VALUE)
+ interpolator = DEFAULT_INTERPOLATOR
+ duration = DEFAULT_DURATION
+ }
+
+ private fun generateParticle(color: Int, random: Random): Particle {
+ val particle = Particle()
+ particle.color = color
+ particle.radius = V
+ if (random.nextFloat() < 0.2f) {
+ particle.baseRadius = V + (X - V) * random.nextFloat()
+ } else {
+ particle.baseRadius = W + (V - W) * random.nextFloat()
+ }
+ val nextFloat = random.nextFloat()
+ particle.top = mBound.height() * (0.18f * random.nextFloat() + 0.2f)
+ particle.top =
+ if (nextFloat < 0.2f) particle.top else particle.top + particle.top * 0.2f * random.nextFloat()
+ particle.bottom = mBound.height() * (random.nextFloat() - 0.5f) * 1.8f
+ var f =
+ if (nextFloat < 0.2f) particle.bottom else if (nextFloat < 0.8f) particle.bottom * 0.6f else particle.bottom * 0.3f
+ particle.bottom = f
+ particle.mag = 4.0f * particle.top / particle.bottom
+ particle.neg = -particle.mag / particle.bottom
+ f = mBound.centerX() + Y * (random.nextFloat() - 0.5f)
+ particle.baseCx = f
+ particle.cx = f
+ f = mBound.centerY() + Y * (random.nextFloat() - 0.5f)
+ particle.baseCy = f
+ particle.cy = f
+ particle.life = END_VALUE / 10 * random.nextFloat()
+ particle.overflow = 0.4f * random.nextFloat()
+ particle.alpha = 1f
+ return particle
+ }
+
+ fun draw(canvas: Canvas): Boolean {
+ if (!isStarted) {
+ return false
+ }
+ for (particle in mParticles) {
+ particle?.let {
+ particle.advance(animatedValue as Float)
+ if (particle.alpha > 0f) {
+ mPaint.color = particle.color
+ mPaint.alpha = (Color.alpha(particle.color) * particle.alpha).toInt()
+ canvas.drawCircle(particle.cx, particle.cy, particle.radius, mPaint)
+ }
+ }
+ }
+ mContainer.invalidate()
+ return true
+ }
+
+ override fun start() {
+ super.start()
+ mContainer.invalidate(mBound)
+ }
+
+ private inner class Particle {
+ internal var alpha: Float = 0.toFloat()
+ internal var color: Int = 0
+ internal var cx: Float = 0.toFloat()
+ internal var cy: Float = 0.toFloat()
+ internal var radius: Float = 0.toFloat()
+ internal var baseCx: Float = 0.toFloat()
+ internal var baseCy: Float = 0.toFloat()
+ internal var baseRadius: Float = 0.toFloat()
+ internal var top: Float = 0.toFloat()
+ internal var bottom: Float = 0.toFloat()
+ internal var mag: Float = 0.toFloat()
+ internal var neg: Float = 0.toFloat()
+ internal var life: Float = 0.toFloat()
+ internal var overflow: Float = 0.toFloat()
+
+
+ fun advance(factor: Float) {
+ var f = 0f
+ var normalization = factor / END_VALUE
+ if (normalization < life || normalization > 1f - overflow) {
+ alpha = 0f
+ return
+ }
+ normalization = (normalization - life) / (1f - life - overflow)
+ val f2 = normalization * END_VALUE
+ if (normalization >= 0.7f) {
+ f = (normalization - 0.7f) / 0.3f
+ }
+ alpha = 1f - f
+ f = bottom * f2
+ cx = baseCx + f
+ cy = (baseCy - this.neg * Math.pow(f.toDouble(), 2.0)).toFloat() - f * mag
+ radius = V + (baseRadius - V) * f2
+ }
+ }
+
+ companion object {
+
+ internal var DEFAULT_DURATION: Long = 0x400
+ private val DEFAULT_INTERPOLATOR = AccelerateInterpolator(0.6f)
+ private val END_VALUE = 1.4f
+ private val X = Utils.dp2Px(5).toFloat()
+ private val Y = Utils.dp2Px(20).toFloat()
+ private val V = Utils.dp2Px(2).toFloat()
+ private val W = Utils.dp2Px(1).toFloat()
+ }
+}
diff --git a/app/src/main/java/io/legado/app/ui/widget/anima/explosion_field/ExplosionField.kt b/app/src/main/java/io/legado/app/ui/widget/anima/explosion_field/ExplosionField.kt
new file mode 100644
index 000000000..1332a3969
--- /dev/null
+++ b/app/src/main/java/io/legado/app/ui/widget/anima/explosion_field/ExplosionField.kt
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2015 tyrantgit
+ *
+ * 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.ui.widget.anima.explosion_field
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.ValueAnimator
+import android.app.Activity
+import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import android.graphics.Rect
+import android.media.MediaPlayer
+import android.util.AttributeSet
+import android.util.Log
+import android.view.View
+import android.view.ViewGroup
+import android.view.Window
+import java.util.*
+
+
+class ExplosionField : View {
+
+ private var customDuration = ExplosionAnimator.DEFAULT_DURATION
+ private var idPlayAnimationEffect = 0
+ private var mZAnimatorListener: OnAnimatorListener? = null
+ private var mOnClickListener: View.OnClickListener? = null
+
+ private val mExplosions = ArrayList()
+ private val mExpandInset = IntArray(2)
+
+ constructor(context: Context) : super(context) {
+ init()
+ }
+
+ constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
+ init()
+ }
+
+ constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(
+ context,
+ attrs,
+ defStyleAttr
+ ) {
+ init()
+ }
+
+ private fun init() {
+
+ Arrays.fill(mExpandInset, Utils.dp2Px(32))
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ super.onDraw(canvas)
+ for (explosion in mExplosions) {
+ explosion.draw(canvas)
+ }
+ }
+
+ fun playSoundAnimationEffect(id: Int) {
+ this.idPlayAnimationEffect = id
+ }
+
+ fun setCustomDuration(customDuration: Long) {
+ this.customDuration = customDuration
+ }
+
+ fun addActionEvent(ievents: OnAnimatorListener) {
+ this.mZAnimatorListener = ievents
+ }
+
+
+ fun expandExplosionBound(dx: Int, dy: Int) {
+ mExpandInset[0] = dx
+ mExpandInset[1] = dy
+ }
+
+ @JvmOverloads
+ fun explode(bitmap: Bitmap?, bound: Rect, startDelay: Long, view: View? = null) {
+ val currentDuration = customDuration
+ val explosion = ExplosionAnimator(this, bitmap!!, bound)
+ explosion.addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator) {
+ mExplosions.remove(animation)
+ if (view != null) {
+ view.scaleX = 1f
+ view.scaleY = 1f
+ view.alpha = 1f
+ view.setOnClickListener(mOnClickListener)//set event
+
+ }
+ }
+ })
+ explosion.startDelay = startDelay
+ explosion.duration = currentDuration
+ mExplosions.add(explosion)
+ explosion.start()
+ }
+
+ @JvmOverloads
+ fun explode(view: View, restartState: Boolean? = false) {
+
+ val r = Rect()
+ view.getGlobalVisibleRect(r)
+ val location = IntArray(2)
+ getLocationOnScreen(location)
+ // getLocationInWindow(location);
+ // view.getLocationInWindow(location);
+ r.offset(-location[0], -location[1])
+ r.inset(-mExpandInset[0], -mExpandInset[1])
+ val startDelay = 100
+ val animator = ValueAnimator.ofFloat(0f, 1f).setDuration(150)
+ animator.addUpdateListener(object : ValueAnimator.AnimatorUpdateListener {
+
+ internal var random = Random()
+
+ override fun onAnimationUpdate(animation: ValueAnimator) {
+ view.translationX = (random.nextFloat() - 0.5f) * view.width.toFloat() * 0.05f
+ view.translationY = (random.nextFloat() - 0.5f) * view.height.toFloat() * 0.05f
+ }
+ })
+
+ animator.addListener(object : Animator.AnimatorListener {
+ override fun onAnimationStart(animator: Animator) {
+ if (idPlayAnimationEffect != 0)
+ MediaPlayer.create(context, idPlayAnimationEffect).start()
+ }
+
+ override fun onAnimationEnd(animator: Animator) {
+ if (mZAnimatorListener != null) {
+ mZAnimatorListener!!.onAnimationEnd(animator, this@ExplosionField)
+ }
+ }
+
+ override fun onAnimationCancel(animator: Animator) {
+ Log.i("PRUEBA", "CANCEL")
+ }
+
+ override fun onAnimationRepeat(animator: Animator) {
+ Log.i("PRUEBA", "REPEAT")
+ }
+ })
+
+ animator.start()
+ view.animate().setDuration(150).setStartDelay(startDelay.toLong()).scaleX(0f).scaleY(0f)
+ .alpha(0f).start()
+ if (restartState!!)
+ explode(Utils.createBitmapFromView(view), r, startDelay.toLong(), view)
+ else
+ explode(Utils.createBitmapFromView(view), r, startDelay.toLong())
+
+ }
+
+ fun clear() {
+ mExplosions.clear()
+ invalidate()
+ }
+
+ override fun setOnClickListener(mOnClickListener: View.OnClickListener?) {
+ this.mOnClickListener = mOnClickListener
+ }
+
+ companion object {
+
+ fun attach2Window(activity: Activity): ExplosionField {
+ val rootView = activity.findViewById(Window.ID_ANDROID_CONTENT) as ViewGroup
+ val explosionField = ExplosionField(activity)
+ rootView.addView(
+ explosionField, ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT
+ )
+ )
+ return explosionField
+ }
+ }
+
+
+}
diff --git a/app/src/main/java/io/legado/app/ui/widget/anima/explosion_field/OnAnimatorListener.kt b/app/src/main/java/io/legado/app/ui/widget/anima/explosion_field/OnAnimatorListener.kt
new file mode 100644
index 000000000..13a04c670
--- /dev/null
+++ b/app/src/main/java/io/legado/app/ui/widget/anima/explosion_field/OnAnimatorListener.kt
@@ -0,0 +1,8 @@
+package io.legado.app.ui.widget.anima.explosion_field
+
+import android.animation.Animator
+import android.view.View
+
+interface OnAnimatorListener {
+ fun onAnimationEnd(animator: Animator, view: View)
+}
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
new file mode 100644
index 000000000..2f99191d2
--- /dev/null
+++ b/app/src/main/java/io/legado/app/ui/widget/anima/explosion_field/Utils.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2015 tyrantgit
+ *
+ * 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.ui.widget.anima.explosion_field
+
+
+import android.content.res.Resources
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import android.graphics.drawable.BitmapDrawable
+import android.view.View
+import android.widget.ImageView
+
+object Utils {
+
+ private val DENSITY = Resources.getSystem().displayMetrics.density
+ private val sCanvas = Canvas()
+
+ fun dp2Px(dp: Int): Int {
+ return Math.round(dp * DENSITY)
+ }
+
+ fun createBitmapFromView(view: View): Bitmap? {
+ if (view is ImageView) {
+ val drawable = view.drawable
+ if (drawable != null && drawable is BitmapDrawable) {
+ return drawable.bitmap
+ }
+ }
+ view.clearFocus()
+ val bitmap = createBitmapSafely(
+ view.width,
+ view.height, Bitmap.Config.ARGB_8888, 1
+ )
+ if (bitmap != null) {
+ synchronized(sCanvas) {
+ val canvas = sCanvas
+ canvas.setBitmap(bitmap)
+ view.draw(canvas)
+ canvas.setBitmap(null)
+ }
+ }
+ return bitmap
+ }
+
+ fun createBitmapSafely(
+ width: Int,
+ height: Int,
+ config: Bitmap.Config,
+ retryCount: Int
+ ): Bitmap? {
+ try {
+ return Bitmap.createBitmap(width, height, config)
+ } catch (e: OutOfMemoryError) {
+ e.printStackTrace()
+ if (retryCount > 0) {
+ System.gc()
+ return createBitmapSafely(width, height, config, retryCount - 1)
+ }
+ return null
+ }
+
+ }
+}
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 7a5b315c9..f539d7738 100644
--- a/app/src/main/java/io/legado/app/utils/GsonExtensions.kt
+++ b/app/src/main/java/io/legado/app/utils/GsonExtensions.kt
@@ -1,5 +1,34 @@
package io.legado.app.utils
+import android.text.TextUtils
import com.google.gson.Gson
+import com.google.gson.GsonBuilder
+import com.google.gson.JsonParser
-inline fun Gson.fromJson(json: String) = fromJson(json, T::class.java)
\ No newline at end of file
+inline fun Gson.fromJson(json: String): T = fromJson(json, T::class.java)
+
+inline fun Gson.arrayFromJson(json: String): ArrayList? = kotlin.run {
+ var result: ArrayList? = null
+ if (!TextUtils.isEmpty(json)) {
+ val gson = GsonBuilder().create()
+ try {
+ val parser = JsonParser()
+ val jArray = parser.parse(json).asJsonArray
+ jArray?.let {
+ result = java.util.ArrayList()
+ for (obj in it) {
+ try {
+ val cse = gson.fromJson(obj, T::class.java)
+ result?.add(cse)
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ }
+ }
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+
+ }
+ return result
+}
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_about.xml b/app/src/main/res/layout/activity_about.xml
index 30f83b7ce..65bacf179 100644
--- a/app/src/main/res/layout/activity_about.xml
+++ b/app/src/main/res/layout/activity_about.xml
@@ -1,14 +1,49 @@
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ tools:context="io.legado.app.ui.about.AboutActivity">
+
+
+
+
+ android:orientation="vertical"
+ android:padding="10dp">
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_book_info.xml b/app/src/main/res/layout/activity_book_info.xml
new file mode 100644
index 000000000..d829e291c
--- /dev/null
+++ b/app/src/main/res/layout/activity_book_info.xml
@@ -0,0 +1,7 @@
+
+
+
+
\ 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
new file mode 100644
index 000000000..d829e291c
--- /dev/null
+++ b/app/src/main/res/layout/activity_book_info_edit.xml
@@ -0,0 +1,7 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_bookshelf.xml b/app/src/main/res/layout/activity_bookshelf.xml
index 49c8c9d5d..a18920e81 100644
--- a/app/src/main/res/layout/activity_bookshelf.xml
+++ b/app/src/main/res/layout/activity_bookshelf.xml
@@ -9,4 +9,9 @@
android:layout_width="match_parent"
android:layout_height="wrap_content" />
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_donate.xml b/app/src/main/res/layout/activity_donate.xml
new file mode 100644
index 000000000..e485130be
--- /dev/null
+++ b/app/src/main/res/layout/activity_donate.xml
@@ -0,0 +1,234 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_qrcode_capture.xml b/app/src/main/res/layout/activity_qrcode_capture.xml
index 0bdc89c35..62337c255 100644
--- a/app/src/main/res/layout/activity_qrcode_capture.xml
+++ b/app/src/main/res/layout/activity_qrcode_capture.xml
@@ -8,6 +8,7 @@
android:id="@+id/zxingview"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:visibility="gone"
app:qrcv_animTime="1000"
app:qrcv_barCodeTipText="将条码放入框内,即可自动扫描"
app:qrcv_barcodeRectHeight="120dp"
diff --git a/app/src/main/res/layout/activity_welcome.xml b/app/src/main/res/layout/activity_welcome.xml
new file mode 100644
index 000000000..e8e320279
--- /dev/null
+++ b/app/src/main/res/layout/activity_welcome.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
\ 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 722707e63..d5f6c6819 100644
--- a/app/src/main/res/layout/fragment_bookshelf.xml
+++ b/app/src/main/res/layout/fragment_bookshelf.xml
@@ -1,41 +1,42 @@
+ 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:attachToActivity="false"
+ app:title="@string/bookshelf" />
+ android:id="@+id/rv_book_group"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+ android:id="@+id/tv_recent_reading"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@color/background"
+ android:elevation="3dp"
+ android:focusable="true"
+ android:padding="5dp"
+ android:text="@string/recent_reading" />
+ android:id="@+id/refresh_layout"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1">
+ android:id="@+id/rv_bookshelf"
+ 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_bookshelf_list.xml b/app/src/main/res/layout/item_bookshelf_list.xml
index 03845fa18..aaed990db 100644
--- a/app/src/main/res/layout/item_bookshelf_list.xml
+++ b/app/src/main/res/layout/item_bookshelf_list.xml
@@ -40,7 +40,7 @@
android:includeFontPadding="false"
tools:ignore="RtlHardcoded" />
-
\ No newline at end of file
diff --git a/app/src/main/res/menu/about.xml b/app/src/main/res/menu/about.xml
new file mode 100644
index 000000000..7dd8f1e86
--- /dev/null
+++ b/app/src/main/res/menu/about.xml
@@ -0,0 +1,9 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
index 3a032189d..80723f59b 100644
Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
index 476310a94..3395b0f61 100644
Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png and b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
index 11b4303f9..9e96002d2 100644
Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
index 81b37de25..40accb5f5 100644
Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
index 5ffaa876b..2acbeea1c 100644
Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png and b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
index 0232c0eda..e27af4a03 100644
Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
index 09e9ac96e..afdcc42eb 100644
Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
index 84423e50d..bbcfb61a3 100644
Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png and b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
index 6199be922..9d6a0e1ac 100644
Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
index 0e972a090..3e9fdc29a 100644
Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
index 2cb1c71f0..9a126a90a 100644
Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
index d503e83e6..eac246932 100644
Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
index b30fd3f50..a51e958cf 100644
Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
index 630cd5669..ba2513cc6 100644
Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
index cad94acbb..6fe033b04 100644
Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/values/ic_launcher_background.xml b/app/src/main/res/values/ic_launcher_background.xml
index f4e297174..08f52ee5c 100644
--- a/app/src/main/res/values/ic_launcher_background.xml
+++ b/app/src/main/res/values/ic_launcher_background.xml
@@ -1,4 +1,4 @@
- #EAE7EE
+ #EC5436
\ 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 d6ba1a7ff..9af81ad1c 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -55,7 +55,7 @@
退出
还未保存,是否继续编辑
阅读样式设置
-
+ 版本
本地
搜索
没有网络
diff --git a/app/src/main/res/xml/about.xml b/app/src/main/res/xml/about.xml
new file mode 100644
index 000000000..620859558
--- /dev/null
+++ b/app/src/main/res/xml/about.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/xml/pref_config_theme.xml b/app/src/main/res/xml/pref_config_theme.xml
index f5013bd7b..04f68f5e9 100644
--- a/app/src/main/res/xml/pref_config_theme.xml
+++ b/app/src/main/res/xml/pref_config_theme.xml
@@ -6,8 +6,7 @@
-
-