This commit is contained in:
kunfei 2020-02-08 15:24:03 +08:00
parent e5d8441c54
commit 1c0e9731b8
8 changed files with 213 additions and 59 deletions

View File

@ -31,21 +31,12 @@ interface RssSourceDao {
@Query("select sourceGroup from rssSources where sourceGroup is not null and sourceGroup <> ''")
fun liveGroup(): LiveData<List<String>>
@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)
@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)
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(vararg rssSource: RssSource)
@ -55,9 +46,6 @@ interface RssSourceDao {
@Delete
fun delete(vararg rssSource: RssSource)
@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<RssSource>

View File

@ -39,6 +39,17 @@ data class RssSource(
var customOrder: Int = 0
) : Parcelable, JsExtensions {
override fun equals(other: Any?): Boolean {
if (other is RssSource) {
return other.sourceUrl == sourceUrl
}
return false
}
override fun hashCode(): Int {
return sourceUrl.hashCode()
}
@Throws(Exception::class)
fun getHeaderMap(): Map<String, String> {
val headerMap = HashMap<String, String>()

View File

@ -128,9 +128,6 @@ class BookSourceActivity : VMBaseActivity<BookSourceViewModel>(R.layout.activity
search_view.queryHint = getString(R.string.search_book_source)
search_view.clearFocus()
search_view.setOnQueryTextListener(this)
selMenu = PopupMenu(this, iv_menu_more)
selMenu.inflate(R.menu.book_source_sel)
selMenu.setOnMenuItemClickListener(this)
}
private fun initLiveDataBookSource(searchKey: String? = null) {
@ -160,6 +157,9 @@ class BookSourceActivity : VMBaseActivity<BookSourceViewModel>(R.layout.activity
}
private fun initViewEvent() {
selMenu = PopupMenu(this, iv_menu_more)
selMenu.inflate(R.menu.book_source_sel)
selMenu.setOnMenuItemClickListener(this)
cb_selected_all.onClick {
if (adapter.getSelection().size == adapter.getActualItemCount()) {
adapter.revertSelection()

View File

@ -7,6 +7,7 @@ import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.view.SubMenu
import android.widget.PopupMenu
import androidx.appcompat.widget.SearchView
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
@ -35,6 +36,7 @@ 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 org.jetbrains.anko.sdk27.listeners.onClick
import org.jetbrains.anko.startActivity
import org.jetbrains.anko.startActivityForResult
import org.jetbrains.anko.toast
@ -42,6 +44,7 @@ import java.io.FileNotFoundException
class RssSourceActivity : VMBaseActivity<RssSourceViewModel>(R.layout.activity_rss_source),
PopupMenu.OnMenuItemClickListener,
FileChooserDialog.CallBack,
RssSourceAdapter.CallBack {
@ -54,12 +57,14 @@ class RssSourceActivity : VMBaseActivity<RssSourceViewModel>(R.layout.activity_r
private var sourceLiveData: LiveData<List<RssSource>>? = null
private var groups = hashSetOf<String>()
private var groupMenu: SubMenu? = null
private lateinit var selMenu: PopupMenu
override fun onActivityCreated(savedInstanceState: Bundle?) {
initRecyclerView()
initSearchView()
initLiveDataGroup()
initLiveDataSource()
initViewEvent()
}
override fun onCompatCreateOptionsMenu(menu: Menu): Boolean {
@ -76,12 +81,6 @@ class RssSourceActivity : VMBaseActivity<RssSourceViewModel>(R.layout.activity_r
override fun onCompatOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.menu_add -> startActivity<RssSourceEditActivity>()
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_export_selection -> viewModel.exportSelection(adapter.getSelectionIds())
R.id.menu_import_source_local -> selectFileSys()
R.id.menu_import_source_onLine -> showImportDialog()
R.id.menu_import_source_qr -> startActivityForResult<QrCodeActivity>(qrRequestCode)
@ -94,6 +93,18 @@ class RssSourceActivity : VMBaseActivity<RssSourceViewModel>(R.layout.activity_r
return super.onCompatOptionsItemSelected(item)
}
override fun onMenuItemClick(item: MenuItem?): Boolean {
when (item?.itemId) {
R.id.menu_select_all -> adapter.selectAll()
R.id.menu_revert_selection -> adapter.revertSelection()
R.id.menu_enable_selection -> viewModel.enableSelection(adapter.getSelection())
R.id.menu_disable_selection -> viewModel.disableSelection(adapter.getSelection())
R.id.menu_del_selection -> viewModel.delSelection(adapter.getSelection())
R.id.menu_export_selection -> viewModel.exportSelection(adapter.getSelection())
}
return true
}
private fun initRecyclerView() {
ATH.applyEdgeEffectColor(recycler_view)
recycler_view.layoutManager = LinearLayoutManager(this)
@ -133,6 +144,25 @@ class RssSourceActivity : VMBaseActivity<RssSourceViewModel>(R.layout.activity_r
})
}
private fun initViewEvent() {
selMenu = PopupMenu(this, iv_menu_more)
selMenu.inflate(R.menu.rss_source_sel)
selMenu.setOnMenuItemClickListener(this)
cb_selected_all.onClick {
if (adapter.getSelection().size == adapter.getActualItemCount()) {
adapter.revertSelection()
} else {
adapter.selectAll()
}
}
btn_revert_selection.onClick {
adapter.revertSelection()
}
iv_menu_more.onClick {
selMenu.show()
}
}
private fun upGroupMenu() {
groupMenu?.removeGroup(R.id.source_group)
groups.map {
@ -153,9 +183,44 @@ class RssSourceActivity : VMBaseActivity<RssSourceViewModel>(R.layout.activity_r
.calculateDiff(DiffCallBack(adapter.getItems(), it))
adapter.setItems(it, false)
diffResult.dispatchUpdatesTo(adapter)
upCountView()
})
}
override fun upCountView() {
val selectCount = adapter.getSelection().size
if (selectCount == 0) {
cb_selected_all.isChecked = false
} else {
cb_selected_all.isChecked = selectCount >= adapter.getActualItemCount()
}
//重置全选的文字
if (cb_selected_all.isChecked) {
cb_selected_all.text = getString(
R.string.select_cancel_count,
selectCount,
adapter.getActualItemCount()
)
} else {
cb_selected_all.text = getString(
R.string.select_all_count,
selectCount,
adapter.getActualItemCount()
)
}
setMenuClickable(selectCount > 0)
}
private fun setMenuClickable(isClickable: Boolean) {
//设置是否可删除
btn_delete.isEnabled = isClickable
btn_delete.isClickable = isClickable
//设置是否可添加书籍
btn_revert_selection.isEnabled = isClickable
btn_revert_selection.isClickable = isClickable
}
@SuppressLint("InflateParams")
private fun showImportDialog() {
val aCache = ACache.get(this, cacheDir = false)

View File

@ -18,31 +18,33 @@ class RssSourceAdapter(context: Context, val callBack: CallBack) :
SimpleRecyclerAdapter<RssSource>(context, R.layout.item_rss_source),
ItemTouchCallback.OnItemTouchCallbackListener {
private val selectedIds = linkedSetOf<String>()
private val selected = linkedSetOf<RssSource>()
fun selectAll() {
getItems().forEach {
selectedIds.add(it.sourceUrl)
selected.add(it)
}
notifyItemRangeChanged(0, itemCount, 1)
callBack.upCountView()
}
fun revertSelection() {
getItems().forEach {
if (selectedIds.contains(it.sourceUrl)) {
selectedIds.remove(it.sourceUrl)
if (selected.contains(it)) {
selected.remove(it)
} else {
selectedIds.add(it.sourceUrl)
selected.add(it)
}
}
notifyItemRangeChanged(0, itemCount, 1)
callBack.upCountView()
}
fun getSelectionIds(): LinkedHashSet<String> {
val selection = linkedSetOf<String>()
fun getSelection(): LinkedHashSet<RssSource> {
val selection = linkedSetOf<RssSource>()
getItems().forEach {
if (selectedIds.contains(it.sourceUrl)) {
selection.add(it.sourceUrl)
if (selected.contains(it)) {
selection.add(it)
}
}
return selection
@ -63,13 +65,14 @@ class RssSourceAdapter(context: Context, val callBack: CallBack) :
item.enabled = swt_enabled.isChecked
callBack.update(item)
}
cb_source.isChecked = selectedIds.contains(item.sourceUrl)
cb_source.isChecked = selected.contains(item)
cb_source.setOnClickListener {
if (cb_source.isChecked) {
selectedIds.add(item.sourceUrl)
selected.add(item)
} else {
selectedIds.remove(item.sourceUrl)
selected.remove(item)
}
callBack.upCountView()
}
iv_edit.onClick { callBack.edit(item) }
iv_menu_more.onClick {
@ -87,7 +90,7 @@ class RssSourceAdapter(context: Context, val callBack: CallBack) :
}
} else {
when (payloads[0]) {
1 -> cb_source.isChecked = selectedIds.contains(item.sourceUrl)
1 -> cb_source.isChecked = selected.contains(item)
2 -> swt_enabled.isChecked = item.enabled
}
}
@ -128,5 +131,6 @@ class RssSourceAdapter(context: Context, val callBack: CallBack) :
fun update(vararg source: RssSource)
fun toTop(source: RssSource)
fun upOrder()
fun upCountView()
}
}

View File

@ -41,32 +41,38 @@ class RssSourceViewModel(application: Application) : BaseViewModel(application)
}
}
fun enableSelection(ids: LinkedHashSet<String>) {
fun enableSelection(sources: LinkedHashSet<RssSource>) {
execute {
App.db.rssSourceDao().enableSection(*ids.toTypedArray())
}
}
fun disableSelection(ids: LinkedHashSet<String>) {
execute {
App.db.rssSourceDao().disableSection(*ids.toTypedArray())
}
}
fun delSelection(ids: LinkedHashSet<String>) {
execute {
App.db.rssSourceDao().delSection(*ids.toTypedArray())
}
}
fun exportSelection(ids: LinkedHashSet<String>) {
execute {
App.db.rssSourceDao().getRssSources(*ids.toTypedArray()).let {
val json = GSON.toJson(it)
val file =
FileUtils.createFileIfNotExist(Backup.exportPath + File.separator + "exportRssSource.json")
file.writeText(json)
val list = arrayListOf<RssSource>()
sources.forEach {
list.add(it.copy(enabled = true))
}
App.db.rssSourceDao().update(*list.toTypedArray())
}
}
fun disableSelection(sources: LinkedHashSet<RssSource>) {
execute {
val list = arrayListOf<RssSource>()
sources.forEach {
list.add(it.copy(enabled = false))
}
App.db.rssSourceDao().update(*list.toTypedArray())
}
}
fun delSelection(sources: LinkedHashSet<RssSource>) {
execute {
App.db.rssSourceDao().delete(*sources.toTypedArray())
}
}
fun exportSelection(sources: LinkedHashSet<RssSource>) {
execute {
val json = GSON.toJson(sources)
val file =
FileUtils.createFileIfNotExist(Backup.exportPath + File.separator + "exportRssSource.json")
file.writeText(json)
}.onSuccess {
context.toast("成功导出至\n${Backup.exportPath}")
}.onError {

View File

@ -3,6 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical">
<io.legado.app.ui.widget.TitleBar
@ -16,7 +17,8 @@
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="0dp"
android:layout_weight="1">
<io.legado.app.ui.widget.recycler.scroller.FastScrollRecyclerView
android:id="@+id/recycler_view"
@ -25,4 +27,57 @@
</FrameLayout>
<!--文件点击按钮-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/background"
android:gravity="center_vertical"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="6dp"
android:paddingBottom="6dp"
android:elevation="2dp">
<io.legado.app.lib.theme.view.ATECheckBox
android:id="@+id/cb_selected_all"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:padding="5dp"
android:text="@string/select_all_count"
android:textColor="@color/tv_text_default" />
<io.legado.app.lib.theme.view.ATEAccentStrokeTextView
android:id="@+id/btn_revert_selection"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:padding="5dp"
android:gravity="center"
android:minWidth="80dp"
android:text="@string/revert_selection" />
<io.legado.app.lib.theme.view.ATEAccentStrokeTextView
android:id="@+id/btn_delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:padding="5dp"
android:minWidth="80dp"
android:gravity="center"
android:text="@string/delete" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_menu_more"
android:layout_width="36dp"
android:layout_height="36dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:padding="6dp"
android:src="@drawable/ic_more_vert"
android:tint="@color/tv_text_default"
tools:ignore="RtlHardcoded" />
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_enable_selection"
android:title="@string/enable_selection"
app:showAsAction="never" />
<item
android:id="@+id/menu_disable_selection"
android:title="@string/disable_selection"
app:showAsAction="never" />
<item
android:id="@+id/menu_del_selection"
android:title="@string/del_select"
app:showAsAction="never" />
<item
android:id="@+id/menu_export_selection"
android:title="@string/export_selection"
app:showAsAction="never" />
</menu>