diff --git a/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt b/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt index df0bf605c..b4018f803 100644 --- a/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/RssSourceDao.kt @@ -31,21 +31,12 @@ interface RssSourceDao { @Query("select sourceGroup from rssSources where sourceGroup is not null and sourceGroup <> ''") fun liveGroup(): LiveData> - @Query("update rssSources set enabled = 1 where sourceUrl in (:sourceUrls)") - fun enableSection(vararg sourceUrls: String) - - @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 diff --git a/app/src/main/java/io/legado/app/data/entities/RssSource.kt b/app/src/main/java/io/legado/app/data/entities/RssSource.kt index 261611caf..999b12523 100644 --- a/app/src/main/java/io/legado/app/data/entities/RssSource.kt +++ b/app/src/main/java/io/legado/app/data/entities/RssSource.kt @@ -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 { val headerMap = HashMap() diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt index d579b7529..233ea5486 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceActivity.kt @@ -128,9 +128,6 @@ class BookSourceActivity : VMBaseActivity(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(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() diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt index ae491e14c..0176433c8 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceActivity.kt @@ -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(R.layout.activity_rss_source), + PopupMenu.OnMenuItemClickListener, FileChooserDialog.CallBack, RssSourceAdapter.CallBack { @@ -54,12 +57,14 @@ class RssSourceActivity : VMBaseActivity(R.layout.activity_r private var sourceLiveData: LiveData>? = null private var groups = hashSetOf() 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(R.layout.activity_r override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { R.id.menu_add -> startActivity() - R.id.menu_select_all -> adapter.selectAll() - R.id.menu_revert_selection -> adapter.revertSelection() - R.id.menu_enable_selection -> viewModel.enableSelection(adapter.getSelectionIds()) - R.id.menu_disable_selection -> viewModel.disableSelection(adapter.getSelectionIds()) - R.id.menu_del_selection -> viewModel.delSelection(adapter.getSelectionIds()) - 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(qrRequestCode) @@ -94,6 +93,18 @@ class RssSourceActivity : VMBaseActivity(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(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(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) diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceAdapter.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceAdapter.kt index 1ec7d8bbd..324a683c0 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceAdapter.kt @@ -18,31 +18,33 @@ class RssSourceAdapter(context: Context, val callBack: CallBack) : SimpleRecyclerAdapter(context, R.layout.item_rss_source), ItemTouchCallback.OnItemTouchCallbackListener { - private val selectedIds = linkedSetOf() + private val selected = linkedSetOf() 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 { - val selection = linkedSetOf() + fun getSelection(): LinkedHashSet { + val selection = linkedSetOf() 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() } } diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt index bed9a6e62..bb9e5f219 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt @@ -41,32 +41,38 @@ class RssSourceViewModel(application: Application) : BaseViewModel(application) } } - fun enableSelection(ids: LinkedHashSet) { + fun enableSelection(sources: LinkedHashSet) { execute { - App.db.rssSourceDao().enableSection(*ids.toTypedArray()) + val list = arrayListOf() + sources.forEach { + list.add(it.copy(enabled = true)) + } + App.db.rssSourceDao().update(*list.toTypedArray()) } } - fun disableSelection(ids: LinkedHashSet) { + fun disableSelection(sources: LinkedHashSet) { execute { - App.db.rssSourceDao().disableSection(*ids.toTypedArray()) + val list = arrayListOf() + sources.forEach { + list.add(it.copy(enabled = false)) + } + App.db.rssSourceDao().update(*list.toTypedArray()) } } - fun delSelection(ids: LinkedHashSet) { + fun delSelection(sources: LinkedHashSet) { execute { - App.db.rssSourceDao().delSection(*ids.toTypedArray()) + App.db.rssSourceDao().delete(*sources.toTypedArray()) } } - fun exportSelection(ids: LinkedHashSet) { + fun exportSelection(sources: LinkedHashSet) { 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 json = GSON.toJson(sources) + val file = + FileUtils.createFileIfNotExist(Backup.exportPath + File.separator + "exportRssSource.json") + file.writeText(json) }.onSuccess { context.toast("成功导出至\n${Backup.exportPath}") }.onError { diff --git a/app/src/main/res/layout/activity_rss_source.xml b/app/src/main/res/layout/activity_rss_source.xml index e3c5bd53e..65f0b5722 100644 --- a/app/src/main/res/layout/activity_rss_source.xml +++ b/app/src/main/res/layout/activity_rss_source.xml @@ -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"> + android:layout_height="0dp" + android:layout_weight="1"> + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/rss_source_sel.xml b/app/src/main/res/menu/rss_source_sel.xml new file mode 100644 index 000000000..e1a5c9e2d --- /dev/null +++ b/app/src/main/res/menu/rss_source_sel.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + +