Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pull] master from gedoor:master #172

Merged
merged 2 commits into from
Dec 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions app/src/main/java/io/legado/app/data/dao/RssArticleDao.kt
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,10 @@ interface RssArticleDao {
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insertRecord(vararg rssReadRecord: RssReadRecord)

@get:Query("select count(1) from rssReadRecords")
val countRead: Int

@Query("delete from rssReadRecords")
fun deleteRecord()

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import androidx.lifecycle.LifecycleRegistry
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.snackbar.Snackbar
import io.legado.app.R
import io.legado.app.base.VMBaseActivity
Expand Down Expand Up @@ -49,6 +50,7 @@ import io.legado.app.ui.widget.recycler.DragSelectTouchHelper
import io.legado.app.ui.widget.recycler.ItemTouchCallback
import io.legado.app.ui.widget.recycler.VerticalDivider
import io.legado.app.utils.ACache
import io.legado.app.utils.NetworkUtils
import io.legado.app.utils.applyTint
import io.legado.app.utils.cnCompare
import io.legado.app.utils.dpToPx
Expand Down Expand Up @@ -103,6 +105,11 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
override var sortAscending = true
private set
private var snackBar: Snackbar? = null
private var showDuplicationSource = false
private val bookSourceDecoration by lazy {
BookSourceDecoration(adapter)
}
private val hostMap = hashMapOf<String, String>()
private val qrResult = registerForActivityResult(QrCodeResult()) {
it ?: return@registerForActivityResult
showDialogFragment(ImportBookSourceDialog(it))
Expand Down Expand Up @@ -265,6 +272,11 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
searchView.setQuery(getString(R.string.disabled_explore), true)
}

R.id.menu_show_same_source -> {
item.isChecked = !item.isChecked
toggleDuplicationSourceView(item.isChecked)
}

R.id.menu_help -> showHelp("SourceMBookHelp")
}
if (item.groupId == R.id.source_group) {
Expand Down Expand Up @@ -335,7 +347,12 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
appDb.bookSourceDao.flowSearch(searchKey)
}
}.map { data ->
if (sortAscending) {
hostMap.clear()
if (showDuplicationSource) {
data.sortedWith(
compareBy<BookSourcePart> { getSourceHost(it.bookSourceUrl) == "#" }
.thenBy { getSourceHost(it.bookSourceUrl) })
} else if (sortAscending) {
when (sort) {
BookSourceSort.Weight -> data.sortedBy { it.weight }
BookSourceSort.Name -> data.sortedWith { o1, o2 ->
Expand Down Expand Up @@ -383,7 +400,8 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
AppLog.put("书源界面更新书源出错", it)
}.flowOn(IO).conflate().collect { data ->
adapter.setItems(data, adapter.diffItemCallback, !Debug.isChecking)
itemTouchCallback.isCanDrag = sort == BookSourceSort.Default
itemTouchCallback.isCanDrag =
sort == BookSourceSort.Default && !showDuplicationSource
delay(500)
}
}
Expand Down Expand Up @@ -667,6 +685,21 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
}
}

private fun toggleDuplicationSourceView(enable: Boolean) {
showDuplicationSource = enable
adapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
override fun onChanged() {
if (enable) {
binding.recyclerView.addItemDecoration(bookSourceDecoration)
} else {
binding.recyclerView.removeItemDecoration(bookSourceDecoration)
}
adapter.unregisterAdapterDataObserver(this)
}
})
upBookSource(searchView.query?.toString())
}

/**
* 保持亮屏
*/
Expand All @@ -686,6 +719,12 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
.upCountView(adapter.selection.size, adapter.itemCount)
}

override fun getSourceHost(origin: String): String {
return hostMap.getOrPut(origin) {
NetworkUtils.getSubDomainOrNull(origin) ?: "#"
}
}

override fun onQueryTextChange(newText: String?): Boolean {
newText?.let {
upBookSource(it)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,18 @@ class BookSourceAdapter(context: Context, val callBack: CallBack) :
callBack.upCountView()
}

fun getHeaderText(position: Int): String {
val source = getItem(position)!!
return callBack.getSourceHost(source.bookSourceUrl)
}

fun isItemHeader(position: Int): Boolean {
if (position == 0) return true
val lastHost = getHeaderText(position - 1)
val curHost = getHeaderText(position)
return lastHost != curHost
}

override fun swap(srcPosition: Int, targetPosition: Int): Boolean {
val srcItem = getItem(srcPosition)
val targetItem = getItem(targetPosition)
Expand Down Expand Up @@ -344,5 +356,6 @@ class BookSourceAdapter(context: Context, val callBack: CallBack) :
fun enable(enable: Boolean, bookSource: BookSourcePart)
fun enableExplore(enable: Boolean, bookSource: BookSourcePart)
fun upCountView()
fun getSourceHost(origin: String): String
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package io.legado.app.ui.book.source.manage

import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Rect
import android.text.TextPaint
import android.view.View
import androidx.recyclerview.widget.RecyclerView
import io.legado.app.lib.theme.accentColor
import io.legado.app.lib.theme.backgroundColor
import io.legado.app.utils.dpToPx
import io.legado.app.utils.spToPx
import splitties.init.appCtx

class BookSourceDecoration(val adapter: BookSourceAdapter): RecyclerView.ItemDecoration() {

private val headerLeft = 16f.dpToPx()
private val headerHeight = 32f.dpToPx()

private val headerPaint = Paint().apply {
color = appCtx.backgroundColor
}
private val textPaint = TextPaint().apply {
textSize = 16f.spToPx()
color = appCtx.accentColor
isAntiAlias = true
}
private val textRect = Rect()

override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
val count = parent.childCount
for (i in 0 until count) {
val view = parent.getChildAt(i)
val position = parent.getChildLayoutPosition(view)
val isHeader = adapter.isItemHeader(position)
if (isHeader) {
c.drawRect(
0f,
view.top - headerHeight,
parent.width.toFloat(),
view.top.toFloat(),
headerPaint
)
val headerText = adapter.getHeaderText(position)
textPaint.getTextBounds(headerText, 0, headerText.length, textRect)
c.drawText(
headerText,
headerLeft,
(view.top - headerHeight) + headerHeight / 2 + textRect.height() / 2,
textPaint
)
}
}
}

override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
val position = parent.getChildLayoutPosition(view)
val isHeader = adapter.isItemHeader(position)
if (isHeader) {
outRect.top = headerHeight.toInt()
}
}

}
16 changes: 16 additions & 0 deletions app/src/main/java/io/legado/app/ui/rss/article/RssSortActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import io.legado.app.R
import io.legado.app.base.VMBaseActivity
import io.legado.app.databinding.ActivityRssArtivlesBinding
import io.legado.app.help.source.sortUrls
import io.legado.app.lib.dialogs.alert
import io.legado.app.lib.theme.accentColor
import io.legado.app.ui.login.SourceLoginActivity
import io.legado.app.ui.rss.source.edit.RssSourceEditActivity
Expand Down Expand Up @@ -90,6 +91,10 @@ class RssSortActivity : VMBaseActivity<ActivityRssArtivlesBinding, RssSortViewMo
viewModel.switchLayout()
upFragments()
}

R.id.menu_del_read_record -> {
delReadRecord()
}
}
return super.onCompatOptionsItemSelected(item)
}
Expand All @@ -109,6 +114,17 @@ class RssSortActivity : VMBaseActivity<ActivityRssArtivlesBinding, RssSortViewMo
}
}

private fun delReadRecord() {
alert(R.string.draw) {
val countRead = viewModel.countRead()
setMessage(getString(R.string.sure_del) + "\n" + countRead + " " + getString(R.string.read_record))
noButton()
yesButton(){
viewModel.delReadRecord()
}
}
}

private fun setSourceVariable() {
lifecycleScope.launch {
val source = viewModel.rssSource
Expand Down
10 changes: 10 additions & 0 deletions app/src/main/java/io/legado/app/ui/rss/article/RssSortViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,14 @@ class RssSortViewModel(application: Application) : BaseViewModel(application) {
}
}

fun countRead() : Int{
return appDb.rssArticleDao.countRead
}

fun delReadRecord() {
execute {
appDb.rssArticleDao.deleteRecord()
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import android.view.SubMenu
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentStatePagerAdapter
import androidx.lifecycle.lifecycleScope
import androidx.viewpager.widget.ViewPager
import io.legado.app.R
import io.legado.app.base.BaseActivity
import io.legado.app.constant.AppLog
Expand All @@ -35,7 +34,6 @@ class RssFavoritesActivity : BaseActivity<ActivityRssFavoritesBinding>() {
private val adapter by lazy { TabFragmentPageAdapter() }
private var groupList = mutableListOf<String>()
private var groupsMenu: SubMenu? = null
private var currentGroup = ""

override fun onActivityCreated(savedInstanceState: Bundle?) {
initView()
Expand All @@ -44,21 +42,6 @@ class RssFavoritesActivity : BaseActivity<ActivityRssFavoritesBinding>() {

private fun initView() {
binding.viewPager.adapter = adapter
binding.viewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
override fun onPageScrolled(
position: Int,
positionOffset: Float,
positionOffsetPixels: Int
) {
}

override fun onPageSelected(position: Int) {
currentGroup = groupList[position]
}

override fun onPageScrollStateChanged(state: Int) {}

})
binding.tabLayout.setupWithViewPager(binding.viewPager)
binding.tabLayout.setSelectedTabIndicatorColor(accentColor)
}
Expand Down Expand Up @@ -105,12 +88,6 @@ class RssFavoritesActivity : BaseActivity<ActivityRssFavoritesBinding>() {
upGroupsMenu()
}
adapter.notifyDataSetChanged()
val item = groupList.indexOf(currentGroup)
if (item > -1) {
binding.viewPager.setCurrentItem(item)
} else if (groupList.isNotEmpty()) {
currentGroup = groupList[binding.viewPager.currentItem]
}
}
}
}
Expand All @@ -119,7 +96,7 @@ class RssFavoritesActivity : BaseActivity<ActivityRssFavoritesBinding>() {
alert(R.string.draw) {
val item = binding.viewPager.currentItem
val group = groupList[item]
setMessage(getString(R.string.sure_del) + "\n" + group + " 分组的收藏")
setMessage(getString(R.string.sure_del) + "\n<" + group + ">" + getString(R.string.group))
noButton()
yesButton {
appDb.rssStarDao.deleteByGroup(group)
Expand All @@ -129,7 +106,7 @@ class RssFavoritesActivity : BaseActivity<ActivityRssFavoritesBinding>() {

private fun deleteAll() {
alert(R.string.draw) {
setMessage(getString(R.string.sure_del) + "\n" + "所有收藏")
setMessage(getString(R.string.sure_del) + "\n<" + getString(R.string.all) + ">" + getString(R.string.favorite))
noButton()
yesButton {
appDb.rssStarDao.deleteAll()
Expand Down
20 changes: 18 additions & 2 deletions app/src/main/java/io/legado/app/utils/NetworkUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,19 @@ object NetworkUtils {
}.getOrDefault(baseUrl)
}

fun getSubDomainOrNull(url: String): String? {
val baseUrl = getBaseUrl(url) ?: return null
return kotlin.runCatching {
val mURL = URL(baseUrl)
val host: String = mURL.host
//mURL.scheme https/http
//判断是否为ip
if (isIPAddress(host)) return host
//PublicSuffixDatabase处理域名
PublicSuffixDatabase.get().getEffectiveTldPlusOne(host) ?: host
}.getOrDefault(null)
}

fun getDomain(url: String): String {
val baseUrl = getBaseUrl(url) ?: return url
return kotlin.runCatching {
Expand Down Expand Up @@ -219,14 +232,17 @@ object NetworkUtils {
* @return True if the input parameter is a valid IPv4 address.
*/
fun isIPv4Address(input: String?): Boolean {
return input != null && Validator.isIpv4(input)
return input != null && input.isNotEmpty()
&& input[0] in '1'..'9'
&& input.count { it == '.' } == 3
&& Validator.isIpv4(input)
}

/**
* Check if valid IPV6 address.
*/
fun isIPv6Address(input: String?): Boolean {
return input != null && Validator.isIpv6(input)
return input != null && input.contains(":") && Validator.isIpv6(input)
}

/**
Expand Down
6 changes: 6 additions & 0 deletions app/src/main/res/menu/book_source.xml
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,12 @@
android:title="@string/import_by_qr_code"
app:showAsAction="never" />

<item
android:id="@+id/menu_show_same_source"
android:checkable="true"
android:title="@string/show_same_source"
app:showAsAction="never" />

<item
android:id="@+id/menu_help"
android:icon="@drawable/ic_help"
Expand Down
5 changes: 5 additions & 0 deletions app/src/main/res/menu/rss_articles.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,9 @@
android:title="@string/clear"
app:showAsAction="never" />

<item
android:id="@+id/menu_del_read_record"
android:title="@string/del_read_record"
app:showAsAction="never" />

</menu>
Loading
Loading