Merge pull request #370 from h11128/h11128pull

书源排序,分享,注释优化
pull/374/head
kunfei 4 years ago committed by GitHub
commit 3b978193ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      app/src/main/java/io/legado/app/constant/AppPattern.kt
  2. 2
      app/src/main/java/io/legado/app/data/dao/BookSourceDao.kt
  3. 4
      app/src/main/java/io/legado/app/data/entities/BookSource.kt
  4. 6
      app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt
  5. 68
      app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt
  6. 17
      app/src/main/java/io/legado/app/utils/FileUtils.kt
  7. 13
      app/src/main/res/drawable/ic_share.xml
  8. 11
      app/src/main/res/menu/book_source.xml
  9. 2
      app/src/main/res/values-zh-rHK/strings.xml
  10. 2
      app/src/main/res/values-zh-rTW/strings.xml
  11. 2
      app/src/main/res/values-zh/strings.xml
  12. 5
      app/src/main/res/values/strings.xml
  13. 15
      app/src/main/res/xml/file_paths.xml

@ -12,5 +12,5 @@ object AppPattern {
val nameRegex = Regex("\\s+作\\s*者.*") val nameRegex = Regex("\\s+作\\s*者.*")
val authorRegex = Regex(".*?作\\s*?者[::]") val authorRegex = Regex(".*?作\\s*?者[::]")
val fileNameRegex = Regex("[\\\\/:*?\"<>|.]") val fileNameRegex = Regex("[\\\\/:*?\"<>|.]")
val splitGroupRegex = Regex("[,;]") val splitGroupRegex = Regex("[,;,;]")
} }

@ -11,7 +11,7 @@ interface BookSourceDao {
@Query("select * from book_sources order by customOrder asc") @Query("select * from book_sources order by customOrder asc")
fun liveDataAll(): LiveData<List<BookSource>> fun liveDataAll(): LiveData<List<BookSource>>
@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 or bookSourceComment like :searchKey order by customOrder asc")
fun liveDataSearch(searchKey: String = ""): LiveData<List<BookSource>> fun liveDataSearch(searchKey: String = ""): LiveData<List<BookSource>>
@Query("select * from book_sources where enabled = 1 order by customOrder asc") @Query("select * from book_sources where enabled = 1 order by customOrder asc")

@ -135,7 +135,7 @@ data class BookSource(
bindings["java"] = this bindings["java"] = this
return AppConst.SCRIPT_ENGINE.eval(jsStr, bindings) return AppConst.SCRIPT_ENGINE.eval(jsStr, bindings)
} }
fun equal(source: BookSource) = fun equal(source: BookSource) =
equal(bookSourceName, source.bookSourceName) equal(bookSourceName, source.bookSourceName)
&& equal(bookSourceUrl, source.bookSourceUrl) && equal(bookSourceUrl, source.bookSourceUrl)
@ -156,7 +156,7 @@ data class BookSource(
&& getContentRule() == source.getContentRule() && getContentRule() == source.getContentRule()
private fun equal(a: String?, b: String?) = a == b || (a.isNullOrEmpty() && b.isNullOrEmpty()) private fun equal(a: String?, b: String?) = a == b || (a.isNullOrEmpty() && b.isNullOrEmpty())
data class ExploreKind( data class ExploreKind(
var title: String, var title: String,
var url: String? = null var url: String? = null

@ -63,6 +63,9 @@ class BookSourceEditActivity :
override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { override fun onCompatOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) { when (item.itemId) {
R.id.menu_save -> getSource().let { source -> R.id.menu_save -> getSource().let { source ->
if (!source.equal(viewModel.bookSource ?: BookSource())){
source.lastUpdateTime = System.currentTimeMillis()
}
if (checkSource(source)) { if (checkSource(source)) {
viewModel.save(source) { setResult(Activity.RESULT_OK); finish() } viewModel.save(source) { setResult(Activity.RESULT_OK); finish() }
} }
@ -170,10 +173,11 @@ class BookSourceEditActivity :
add(EditEntity("bookSourceUrl", source?.bookSourceUrl, R.string.source_url)) add(EditEntity("bookSourceUrl", source?.bookSourceUrl, R.string.source_url))
add(EditEntity("bookSourceName", source?.bookSourceName, R.string.source_name)) add(EditEntity("bookSourceName", source?.bookSourceName, R.string.source_name))
add(EditEntity("bookSourceGroup", source?.bookSourceGroup, R.string.source_group)) add(EditEntity("bookSourceGroup", source?.bookSourceGroup, R.string.source_group))
add(EditEntity("bookSourceComment", source?.bookSourceComment, R.string.comment))
add(EditEntity("loginUrl", source?.loginUrl, R.string.login_url)) add(EditEntity("loginUrl", source?.loginUrl, R.string.login_url))
add(EditEntity("bookUrlPattern", source?.bookUrlPattern, R.string.book_url_pattern)) add(EditEntity("bookUrlPattern", source?.bookUrlPattern, R.string.book_url_pattern))
add(EditEntity("header", source?.header, R.string.source_http_header)) add(EditEntity("header", source?.header, R.string.source_http_header))
add(EditEntity("bookSourceComment", source?.bookSourceComment, R.string.comment))
} }
//搜索 //搜索
val sr = source?.getSearchRule() val sr = source?.getSearchRule()

@ -2,6 +2,7 @@ package io.legado.app.ui.book.source.manage
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Activity import android.app.Activity
import android.content.ActivityNotFoundException
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.Menu import android.view.Menu
@ -9,18 +10,23 @@ import android.view.MenuItem
import android.view.SubMenu import android.view.SubMenu
import androidx.appcompat.widget.PopupMenu import androidx.appcompat.widget.PopupMenu
import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SearchView
import androidx.core.content.FileProvider
import androidx.documentfile.provider.DocumentFile import androidx.documentfile.provider.DocumentFile
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import io.legado.app.App import io.legado.app.App
import io.legado.app.BuildConfig
import io.legado.app.R import io.legado.app.R
import io.legado.app.base.VMBaseActivity import io.legado.app.base.VMBaseActivity
import io.legado.app.constant.AppPattern import io.legado.app.constant.AppPattern
import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.BookSource
import io.legado.app.help.IntentDataHelp import io.legado.app.help.IntentDataHelp
import io.legado.app.lib.dialogs.* import io.legado.app.lib.dialogs.*
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.lib.theme.ATH import io.legado.app.lib.theme.ATH
import io.legado.app.lib.theme.primaryTextColor import io.legado.app.lib.theme.primaryTextColor
import io.legado.app.service.help.CheckSource import io.legado.app.service.help.CheckSource
@ -41,6 +47,7 @@ import kotlinx.android.synthetic.main.view_search.*
import org.jetbrains.anko.startActivity import org.jetbrains.anko.startActivity
import org.jetbrains.anko.startActivityForResult import org.jetbrains.anko.startActivityForResult
import org.jetbrains.anko.toast import org.jetbrains.anko.toast
import java.io.File import java.io.File
import java.text.Collator import java.text.Collator
@ -60,6 +67,7 @@ class BookSourceActivity : VMBaseActivity<BookSourceViewModel>(R.layout.activity
private var groups = linkedSetOf<String>() private var groups = linkedSetOf<String>()
private var groupMenu: SubMenu? = null private var groupMenu: SubMenu? = null
private var sort = 0 private var sort = 0
private var sortAscending = 0
override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
initRecyclerView() initRecyclerView()
@ -86,6 +94,21 @@ class BookSourceActivity : VMBaseActivity<BookSourceViewModel>(R.layout.activity
when (item.itemId) { when (item.itemId) {
R.id.menu_add_book_source -> startActivity<BookSourceEditActivity>() R.id.menu_add_book_source -> startActivity<BookSourceEditActivity>()
R.id.menu_import_source_qr -> startActivityForResult<QrCodeActivity>(qrRequestCode) R.id.menu_import_source_qr -> startActivityForResult<QrCodeActivity>(qrRequestCode)
R.id.menu_share_source -> {
try {
val json = GSON.toJson(adapter.getSelection())
val intent = Intent(Intent.ACTION_SEND)
val file = FileUtils.createFileWithReplace("$filesDir/shareBookSource.json")
file.writeText(json)
val fileUri = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".fileProvider", file)
intent.type = "text/*"
intent.putExtra(Intent.EXTRA_STREAM, fileUri)
intent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
startActivity(Intent.createChooser(intent, getString(R.string.share_selected_source)))
} catch (e: ActivityNotFoundException) {
e.printStackTrace()
}
}
R.id.menu_group_manage -> R.id.menu_group_manage ->
GroupManageDialog().show(supportFragmentManager, "groupManage") GroupManageDialog().show(supportFragmentManager, "groupManage")
R.id.menu_import_source_local -> FilePicker R.id.menu_import_source_local -> FilePicker
@ -93,22 +116,27 @@ class BookSourceActivity : VMBaseActivity<BookSourceViewModel>(R.layout.activity
R.id.menu_import_source_onLine -> showImportDialog() R.id.menu_import_source_onLine -> showImportDialog()
R.id.menu_sort_manual -> { R.id.menu_sort_manual -> {
item.isChecked = true item.isChecked = true
sort = 0 sortCheck(0)
initLiveDataBookSource(search_view.query?.toString()) initLiveDataBookSource(search_view.query?.toString())
} }
R.id.menu_sort_auto -> { R.id.menu_sort_auto -> {
item.isChecked = true item.isChecked = true
sort = 2 sortCheck(1)
initLiveDataBookSource(search_view.query?.toString()) initLiveDataBookSource(search_view.query?.toString())
} }
R.id.menu_sort_pin_yin -> { R.id.menu_sort_pin_yin -> {
item.isChecked = true item.isChecked = true
sort = 3 sortCheck(2)
initLiveDataBookSource(search_view.query?.toString()) initLiveDataBookSource(search_view.query?.toString())
} }
R.id.menu_sort_url -> { R.id.menu_sort_url -> {
item.isChecked = true item.isChecked = true
sort = 4 sortCheck(3)
initLiveDataBookSource(search_view.query?.toString())
}
R.id.menu_sort_time -> {
item.isChecked = true
sortCheck(4)
initLiveDataBookSource(search_view.query?.toString()) initLiveDataBookSource(search_view.query?.toString())
} }
R.id.menu_enabled_group -> { R.id.menu_enabled_group -> {
@ -168,18 +196,38 @@ class BookSourceActivity : VMBaseActivity<BookSourceViewModel>(R.layout.activity
} }
} }
bookSourceLiveDate?.observe(this, { data -> bookSourceLiveDate?.observe(this, { data ->
val sourceList = when (sort) { val sourceList = when (sortAscending % 2){
1 -> data.sortedBy { it.weight } 0 -> when (sort) {
2 -> data.sortedBy { it.bookSourceName } 1 -> data.sortedBy { it.weight }
3 -> data.sortedBy { it.bookSourceUrl } 2 -> data.sortedBy { it.bookSourceName }
else -> data 3 -> data.sortedBy { it.bookSourceUrl }
4 -> data.sortedByDescending { it.lastUpdateTime}
else -> data
}
else -> when (sort) {
1 -> data.sortedByDescending { it.weight }
2 -> data.sortedByDescending { it.bookSourceName }
3 -> data.sortedByDescending { it.bookSourceUrl }
4 -> data.sortedBy { it.lastUpdateTime}
else -> data.reversed()
}
} }
recycler_view.scrollToPosition(0)
val diffResult = DiffUtil val diffResult = DiffUtil
.calculateDiff(DiffCallBack(ArrayList(adapter.getItems()), sourceList)) .calculateDiff(DiffCallBack(ArrayList(adapter.getItems()), sourceList))
adapter.setItems(sourceList, diffResult) adapter.setItems(sourceList, diffResult)
upCountView() upCountView()
}) })
} }
private fun sortCheck (sortId: Int){
if (sort == sortId){
sortAscending +=1
}
else{
sortAscending = 0
sort = sortId
}
}
private fun initLiveDataGroup() { private fun initLiveDataGroup() {
App.db.bookSourceDao().liveGroup().observe(this, { App.db.bookSourceDao().liveGroup().observe(this, {
@ -226,12 +274,12 @@ class BookSourceActivity : VMBaseActivity<BookSourceViewModel>(R.layout.activity
R.id.menu_disable_selection -> viewModel.disableSelection(adapter.getSelection()) R.id.menu_disable_selection -> viewModel.disableSelection(adapter.getSelection())
R.id.menu_enable_explore -> viewModel.enableSelectExplore(adapter.getSelection()) R.id.menu_enable_explore -> viewModel.enableSelectExplore(adapter.getSelection())
R.id.menu_disable_explore -> viewModel.disableSelectExplore(adapter.getSelection()) R.id.menu_disable_explore -> viewModel.disableSelectExplore(adapter.getSelection())
R.id.menu_export_selection -> FilePicker.selectFolder(this, exportRequestCode)
R.id.menu_check_source -> checkSource() R.id.menu_check_source -> checkSource()
R.id.menu_top_sel -> viewModel.topSource(*adapter.getSelection().toTypedArray()) R.id.menu_top_sel -> viewModel.topSource(*adapter.getSelection().toTypedArray())
R.id.menu_bottom_sel -> viewModel.bottomSource(*adapter.getSelection().toTypedArray()) R.id.menu_bottom_sel -> viewModel.bottomSource(*adapter.getSelection().toTypedArray())
R.id.menu_add_group -> selectionAddToGroups() R.id.menu_add_group -> selectionAddToGroups()
R.id.menu_remove_group -> selectionRemoveFromGroups() R.id.menu_remove_group -> selectionRemoveFromGroups()
R.id.menu_export_selection -> FilePicker.selectFolder(this, exportRequestCode)
} }
return true return true
} }

@ -55,6 +55,23 @@ object FileUtils {
return file return file
} }
fun createFileWithReplace(filePath: String) : File{
val file = File(filePath)
if (!file.exists()) {
//创建父类文件夹
file.parent?.let {
createFolderIfNotExist(it)
}
//创建文件
file.createNewFile()
}
else{
file.delete()
file.createNewFile()
}
return file
}
fun getFile(root: File, vararg subDirFiles: String): File { fun getFile(root: File, vararg subDirFiles: String): File {
val filePath = getPath(root, *subDirFiles) val filePath = getPath(root, *subDirFiles)
return File(filePath) return File(filePath)

@ -1,14 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:width="24dp"
android:height="24dp" android:height="24dp"
android:viewportWidth="24" android:viewportWidth="24"
android:viewportHeight="24"> android:viewportHeight="24">
<path
<path android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z"
android:fillColor="#FFFFFF" android:fillColor="#000000"/>
android:pathData="M9.866,9.9c-1.158,0-2.1,0.941-2.1,2.1s0.941,2.1,2.1,2.1s2.1-0.941,2.1-2.1S11.024,9.9,9.866,9.9z M9.866,13.1c-0.606,0-1.1-0.493-1.1-1.1s0.493-1.1,1.1-1.1s1.1,0.493,1.1,1.1S10.473,13.1,9.866,13.1z" /> </vector>
<path
android:fillColor="#FFFFFF"
android:pathData="M16.267,16c-0.37,0-0.716,0.091-1.029,0.241l-1.656-1.657c0.513-0.734,0.817-1.623,0.817-2.584 s-0.305-1.85-0.817-2.584l1.656-1.657C15.551,7.909,15.896,8,16.267,8c1.323,0,2.399-1.077,2.399-2.4S17.59,3.2,16.267,3.2 s-2.4,1.076-2.4,2.399c0,0.369,0.091,0.715,0.241,1.028L12.45,8.285c-0.733-0.513-1.622-0.818-2.584-0.818 c-2.5,0-4.533,2.033-4.533,4.533s2.033,4.533,4.533,4.533c0.962,0,1.851-0.306,2.584-0.818l1.657,1.657 c-0.15,0.313-0.241,0.659-0.241,1.028c0,1.323,1.077,2.399,2.4,2.399s2.399-1.076,2.399-2.399S17.59,16,16.267,16z M16.267,4.8 c0.44,0,0.8,0.359,0.8,0.8c0,0.441-0.359,0.801-0.8,0.801c-0.441,0-0.801-0.359-0.801-0.801C15.466,5.159,15.825,4.8,16.267,4.8z M9.866,14.934c-1.617,0-2.934-1.316-2.934-2.934s1.316-2.934,2.934-2.934s2.933,1.316,2.933,2.934S11.483,14.934,9.866,14.934z M16.267,19.2c-0.441,0-0.801-0.359-0.801-0.8c0-0.441,0.359-0.801,0.801-0.801c0.44,0,0.8,0.359,0.8,0.801 C17.066,18.841,16.707,19.2,16.267,19.2z" />
</vector>

@ -46,6 +46,10 @@
android:checkable="true" android:checkable="true"
android:title="@string/sort_by_url" /> android:title="@string/sort_by_url" />
<item
android:id="@+id/menu_sort_time"
android:checkable="true"
android:title="@string/sort_by_lastUppdateTime" />
</group> </group>
</menu> </menu>
@ -92,4 +96,11 @@
android:title="@string/import_by_qr_code" android:title="@string/import_by_qr_code"
app:showAsAction="never" /> app:showAsAction="never" />
<item
android:id="@+id/menu_share_source"
android:icon="@drawable/ic_share"
android:title="@string/share_selected_source"
app:showAsAction="never" />
</menu> </menu>

@ -759,5 +759,7 @@
<string name="theme_list">主题列表</string> <string name="theme_list">主题列表</string>
<string name="theme_list_summary">使用保存主题,导入,分享主题</string> <string name="theme_list_summary">使用保存主题,导入,分享主题</string>
<string name="select_theme">切換默認主題</string> <string name="select_theme">切換默認主題</string>
<string name="share_selected_source">分享選中書源</string>
<string name="sort_by_lastUppdateTime">時間排序</string>
</resources> </resources>

@ -759,6 +759,8 @@
<string name="theme_list">主题列表</string> <string name="theme_list">主题列表</string>
<string name="theme_list_summary">使用保存主题,导入,分享主题</string> <string name="theme_list_summary">使用保存主题,导入,分享主题</string>
<string name="select_theme">切換默認主題</string> <string name="select_theme">切換默認主題</string>
<string name="share_selected_source">分享選中書源</string>
<string name="sort_by_lastUppdateTime">時間排序</string>
</resources> </resources>

@ -444,6 +444,7 @@
<string name="source_http_header">请求头(header)</string> <string name="source_http_header">请求头(header)</string>
<string name="debug_source">调试源</string> <string name="debug_source">调试源</string>
<string name="import_by_qr_code">二维码导入</string> <string name="import_by_qr_code">二维码导入</string>
<string name="share_selected_source">分享选中书源</string>
<string name="scan_qr_code">扫描二维码</string> <string name="scan_qr_code">扫描二维码</string>
<string name="click_on_selected_show_menu">选中时点击可弹出菜单</string> <string name="click_on_selected_show_menu">选中时点击可弹出菜单</string>
<string name="theme">主题</string> <string name="theme">主题</string>
@ -759,5 +760,6 @@
<string name="theme_list">主题列表</string> <string name="theme_list">主题列表</string>
<string name="theme_list_summary">使用保存主题,导入,分享主题</string> <string name="theme_list_summary">使用保存主题,导入,分享主题</string>
<string name="select_theme">切换默认主题</string> <string name="select_theme">切换默认主题</string>
<string name="sort_by_lastUppdateTime">时间排序</string>
</resources> </resources>

@ -388,6 +388,7 @@
<string name="sort_url">分类Url</string> <string name="sort_url">分类Url</string>
<string name="login_url">登录URL(loginUrl)</string> <string name="login_url">登录URL(loginUrl)</string>
<string name="comment">源注释(sourceComment)</string> <string name="comment">源注释(sourceComment)</string>
<string name="source_http_header">请求头(header)</string>
<string name="r_search_url">搜索地址(url)</string> <string name="r_search_url">搜索地址(url)</string>
<string name="r_find_url">发现地址规则(url)</string> <string name="r_find_url">发现地址规则(url)</string>
<string name="r_book_list">书籍列表规则(bookList)</string> <string name="r_book_list">书籍列表规则(bookList)</string>
@ -444,7 +445,7 @@
<string name="net_error_10003">Data parsing failed</string> <string name="net_error_10003">Data parsing failed</string>
<!--error string end--> <!--error string end-->
<string name="source_http_header">Source http header</string>
<string name="debug_source">Debug source</string> <string name="debug_source">Debug source</string>
<string name="import_by_qr_code">Import from QR code</string> <string name="import_by_qr_code">Import from QR code</string>
<string name="scan_qr_code">Scan QR code</string> <string name="scan_qr_code">Scan QR code</string>
@ -761,5 +762,7 @@
<string name="save_night_theme_summary">Save night theme config</string> <string name="save_night_theme_summary">Save night theme config</string>
<string name="theme_list">Theme list</string> <string name="theme_list">Theme list</string>
<string name="theme_list_summary">Save, Import, Share theme</string> <string name="theme_list_summary">Save, Import, Share theme</string>
<string name="share_selected_source">Share selected sources</string>
<string name="sort_by_lastUppdateTime">Sort by update time</string>
</resources> </resources>

@ -6,4 +6,19 @@
<external-path <external-path
name="external_storage_root" name="external_storage_root"
path="." /> path="." />
<files-path
name="share"
path="." />
<external-files-path
name="external_files"
path="." />
<cache-path
name="cache"
path="." />
<external-cache-path
name="external_cache"
path="." />
<files-path
name="files"
path="." />
</paths> </paths>
Loading…
Cancel
Save