书架更新时显示剩余更新数量,在书架布局里配置
This commit is contained in:
@@ -127,6 +127,7 @@ object PreferKey {
|
|||||||
const val audioPlayWakeLock = "audioPlayWakeLock"
|
const val audioPlayWakeLock = "audioPlayWakeLock"
|
||||||
const val readAloudWakeLock = "readAloudWakeLock"
|
const val readAloudWakeLock = "readAloudWakeLock"
|
||||||
const val showLastUpdateTime = "showLastUpdateTime"
|
const val showLastUpdateTime = "showLastUpdateTime"
|
||||||
|
const val showWaitUpCount = "showWaitUpCount"
|
||||||
const val clearWebViewData = "clearWebViewData"
|
const val clearWebViewData = "clearWebViewData"
|
||||||
const val onlyLatestBackup = "onlyLatestBackup"
|
const val onlyLatestBackup = "onlyLatestBackup"
|
||||||
const val brightnessVwPos = "brightnessVwPos"
|
const val brightnessVwPos = "brightnessVwPos"
|
||||||
|
|||||||
@@ -88,6 +88,12 @@ object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
|
|||||||
appCtx.putPrefBoolean(PreferKey.showLastUpdateTime, value)
|
appCtx.putPrefBoolean(PreferKey.showLastUpdateTime, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var showWaitUpCount: Boolean
|
||||||
|
get() = appCtx.getPrefBoolean(PreferKey.showWaitUpCount, false)
|
||||||
|
set(value) {
|
||||||
|
appCtx.putPrefBoolean(PreferKey.showWaitUpCount, value)
|
||||||
|
}
|
||||||
|
|
||||||
var readBrightness: Int
|
var readBrightness: Int
|
||||||
get() = if (isNightTheme) {
|
get() = if (isNightTheme) {
|
||||||
appCtx.getPrefInt(PreferKey.nightBrightness, 100)
|
appCtx.getPrefInt(PreferKey.nightBrightness, 100)
|
||||||
|
|||||||
@@ -2,11 +2,16 @@ package io.legado.app.lib.theme.view
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import com.google.android.material.bottomnavigation.BottomNavigationItemView
|
||||||
|
import com.google.android.material.bottomnavigation.BottomNavigationMenuView
|
||||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||||
|
import io.legado.app.databinding.ViewNavigationBadgeBinding
|
||||||
import io.legado.app.lib.theme.Selector
|
import io.legado.app.lib.theme.Selector
|
||||||
import io.legado.app.lib.theme.ThemeStore
|
import io.legado.app.lib.theme.ThemeStore
|
||||||
import io.legado.app.lib.theme.bottomBackground
|
import io.legado.app.lib.theme.bottomBackground
|
||||||
import io.legado.app.lib.theme.getSecondaryTextColor
|
import io.legado.app.lib.theme.getSecondaryTextColor
|
||||||
|
import io.legado.app.ui.widget.text.BadgeView
|
||||||
import io.legado.app.utils.ColorUtils
|
import io.legado.app.utils.ColorUtils
|
||||||
|
|
||||||
class ThemeBottomNavigationVIew(context: Context, attrs: AttributeSet) :
|
class ThemeBottomNavigationVIew(context: Context, attrs: AttributeSet) :
|
||||||
@@ -24,4 +29,14 @@ class ThemeBottomNavigationVIew(context: Context, attrs: AttributeSet) :
|
|||||||
itemTextColor = colorStateList
|
itemTextColor = colorStateList
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun addBadgeView(index: Int): BadgeView {
|
||||||
|
//获取底部菜单view
|
||||||
|
val menuView = getChildAt(0) as BottomNavigationMenuView
|
||||||
|
//获取第index个itemView
|
||||||
|
val itemView = menuView.getChildAt(index) as BottomNavigationItemView
|
||||||
|
val badgeBinding = ViewNavigationBadgeBinding.inflate(LayoutInflater.from(context))
|
||||||
|
itemView.addView(badgeBinding.root)
|
||||||
|
return badgeBinding.viewBadge
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -74,6 +74,9 @@ class MainActivity : VMBaseActivity<ActivityMainBinding, MainViewModel>(),
|
|||||||
private val adapter by lazy {
|
private val adapter by lazy {
|
||||||
TabFragmentPageAdapter(supportFragmentManager)
|
TabFragmentPageAdapter(supportFragmentManager)
|
||||||
}
|
}
|
||||||
|
private val onUpBooksBadgeView by lazy {
|
||||||
|
binding.bottomNavigationView.addBadgeView(0)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
upBottomMenu()
|
upBottomMenu()
|
||||||
@@ -128,10 +131,13 @@ class MainActivity : VMBaseActivity<ActivityMainBinding, MainViewModel>(),
|
|||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
R.id.menu_bookshelf ->
|
R.id.menu_bookshelf ->
|
||||||
viewPagerMain.setCurrentItem(0, false)
|
viewPagerMain.setCurrentItem(0, false)
|
||||||
|
|
||||||
R.id.menu_discovery ->
|
R.id.menu_discovery ->
|
||||||
viewPagerMain.setCurrentItem(realPositions.indexOf(idExplore), false)
|
viewPagerMain.setCurrentItem(realPositions.indexOf(idExplore), false)
|
||||||
|
|
||||||
R.id.menu_rss ->
|
R.id.menu_rss ->
|
||||||
viewPagerMain.setCurrentItem(realPositions.indexOf(idRss), false)
|
viewPagerMain.setCurrentItem(realPositions.indexOf(idRss), false)
|
||||||
|
|
||||||
R.id.menu_my_config ->
|
R.id.menu_my_config ->
|
||||||
viewPagerMain.setCurrentItem(realPositions.indexOf(idMy), false)
|
viewPagerMain.setCurrentItem(realPositions.indexOf(idMy), false)
|
||||||
}
|
}
|
||||||
@@ -147,6 +153,7 @@ class MainActivity : VMBaseActivity<ActivityMainBinding, MainViewModel>(),
|
|||||||
(fragmentMap[getFragmentId(0)] as? BaseBookshelfFragment)?.gotoTop()
|
(fragmentMap[getFragmentId(0)] as? BaseBookshelfFragment)?.gotoTop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.menu_discovery -> {
|
R.id.menu_discovery -> {
|
||||||
if (System.currentTimeMillis() - exploreReselected > 300) {
|
if (System.currentTimeMillis() - exploreReselected > 300) {
|
||||||
exploreReselected = System.currentTimeMillis()
|
exploreReselected = System.currentTimeMillis()
|
||||||
@@ -304,6 +311,9 @@ class MainActivity : VMBaseActivity<ActivityMainBinding, MainViewModel>(),
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun observeLiveBus() {
|
override fun observeLiveBus() {
|
||||||
|
viewModel.onUpBooksLiveData.observe(this) {
|
||||||
|
onUpBooksBadgeView.setBadgeCount(it)
|
||||||
|
}
|
||||||
observeEvent<String>(EventBus.RECREATE) {
|
observeEvent<String>(EventBus.RECREATE) {
|
||||||
recreate()
|
recreate()
|
||||||
}
|
}
|
||||||
@@ -400,9 +410,11 @@ class MainActivity : VMBaseActivity<ActivityMainBinding, MainViewModel>(),
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Callback {
|
interface Callback {
|
||||||
|
|
||||||
fun onActive()
|
fun onActive()
|
||||||
|
|
||||||
fun onInactive()
|
fun onInactive()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package io.legado.app.ui.main
|
package io.legado.app.ui.main
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import io.legado.app.base.BaseViewModel
|
import io.legado.app.base.BaseViewModel
|
||||||
import io.legado.app.constant.AppConst
|
import io.legado.app.constant.AppConst
|
||||||
@@ -12,15 +13,25 @@ import io.legado.app.data.entities.Book
|
|||||||
import io.legado.app.data.entities.BookSource
|
import io.legado.app.data.entities.BookSource
|
||||||
import io.legado.app.help.AppWebDav
|
import io.legado.app.help.AppWebDav
|
||||||
import io.legado.app.help.DefaultData
|
import io.legado.app.help.DefaultData
|
||||||
import io.legado.app.help.book.*
|
import io.legado.app.help.book.BookHelp
|
||||||
|
import io.legado.app.help.book.addType
|
||||||
|
import io.legado.app.help.book.isLocal
|
||||||
|
import io.legado.app.help.book.isSameNameAuthor
|
||||||
|
import io.legado.app.help.book.isUpError
|
||||||
|
import io.legado.app.help.book.removeType
|
||||||
|
import io.legado.app.help.book.sync
|
||||||
import io.legado.app.help.config.AppConfig
|
import io.legado.app.help.config.AppConfig
|
||||||
import io.legado.app.model.CacheBook
|
import io.legado.app.model.CacheBook
|
||||||
import io.legado.app.model.ReadBook
|
import io.legado.app.model.ReadBook
|
||||||
import io.legado.app.model.webBook.WebBook
|
import io.legado.app.model.webBook.WebBook
|
||||||
import io.legado.app.service.CacheBookService
|
import io.legado.app.service.CacheBookService
|
||||||
import io.legado.app.utils.postEvent
|
import io.legado.app.utils.postEvent
|
||||||
import kotlinx.coroutines.*
|
|
||||||
import kotlinx.coroutines.Dispatchers.IO
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.asCoroutineDispatcher
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.isActive
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import java.util.concurrent.CopyOnWriteArraySet
|
import java.util.concurrent.CopyOnWriteArraySet
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
@@ -31,6 +42,7 @@ class MainViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
Executors.newFixedThreadPool(min(threadCount, AppConst.MAX_THREAD)).asCoroutineDispatcher()
|
Executors.newFixedThreadPool(min(threadCount, AppConst.MAX_THREAD)).asCoroutineDispatcher()
|
||||||
private val waitUpTocBooks = arrayListOf<String>()
|
private val waitUpTocBooks = arrayListOf<String>()
|
||||||
private val onUpTocBooks = CopyOnWriteArraySet<String>()
|
private val onUpTocBooks = CopyOnWriteArraySet<String>()
|
||||||
|
val onUpBooksLiveData = MutableLiveData<Int>()
|
||||||
private var upTocJob: Job? = null
|
private var upTocJob: Job? = null
|
||||||
private var cacheBookJob: Job? = null
|
private var cacheBookJob: Job? = null
|
||||||
|
|
||||||
@@ -79,6 +91,7 @@ class MainViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun startUpTocJob() {
|
private fun startUpTocJob() {
|
||||||
|
postUpBooksLiveData()
|
||||||
upTocJob = viewModelScope.launch(upTocPool) {
|
upTocJob = viewModelScope.launch(upTocPool) {
|
||||||
while (isActive) {
|
while (isActive) {
|
||||||
when {
|
when {
|
||||||
@@ -104,11 +117,13 @@ class MainViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
val bookUrl = waitUpTocBooks.firstOrNull() ?: return
|
val bookUrl = waitUpTocBooks.firstOrNull() ?: return
|
||||||
if (onUpTocBooks.contains(bookUrl)) {
|
if (onUpTocBooks.contains(bookUrl)) {
|
||||||
waitUpTocBooks.remove(bookUrl)
|
waitUpTocBooks.remove(bookUrl)
|
||||||
|
postUpBooksLiveData()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val book = appDb.bookDao.getBook(bookUrl)
|
val book = appDb.bookDao.getBook(bookUrl)
|
||||||
if (book == null) {
|
if (book == null) {
|
||||||
waitUpTocBooks.remove(bookUrl)
|
waitUpTocBooks.remove(bookUrl)
|
||||||
|
postUpBooksLiveData()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val source = appDb.bookSourceDao.getBookSource(book.origin)
|
val source = appDb.bookSourceDao.getBookSource(book.origin)
|
||||||
@@ -118,6 +133,7 @@ class MainViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
appDb.bookDao.update(book)
|
appDb.bookDao.update(book)
|
||||||
}
|
}
|
||||||
waitUpTocBooks.remove(book.bookUrl)
|
waitUpTocBooks.remove(book.bookUrl)
|
||||||
|
postUpBooksLiveData()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
waitUpTocBooks.remove(bookUrl)
|
waitUpTocBooks.remove(bookUrl)
|
||||||
@@ -160,6 +176,15 @@ class MainViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
}.onFinally(upTocPool) {
|
}.onFinally(upTocPool) {
|
||||||
upTocFinally(bookUrl)
|
upTocFinally(bookUrl)
|
||||||
upTocFinally(book.bookUrl)
|
upTocFinally(book.bookUrl)
|
||||||
|
postUpBooksLiveData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun postUpBooksLiveData() {
|
||||||
|
if (AppConfig.showWaitUpCount) {
|
||||||
|
onUpBooksLiveData.postValue(waitUpTocBooks.size + onUpTocBooks.size)
|
||||||
|
} else {
|
||||||
|
onUpBooksLiveData.postValue(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -135,6 +135,7 @@ abstract class BaseBookshelfFragment(layoutId: Int) : VMBaseFragment<BookshelfVi
|
|||||||
spGroupStyle.setSelection(AppConfig.bookGroupStyle)
|
spGroupStyle.setSelection(AppConfig.bookGroupStyle)
|
||||||
swShowUnread.isChecked = AppConfig.showUnread
|
swShowUnread.isChecked = AppConfig.showUnread
|
||||||
swShowLastUpdateTime.isChecked = AppConfig.showLastUpdateTime
|
swShowLastUpdateTime.isChecked = AppConfig.showLastUpdateTime
|
||||||
|
swShowWaitUpBooks.isChecked = AppConfig.showWaitUpCount
|
||||||
rgLayout.checkByIndex(bookshelfLayout)
|
rgLayout.checkByIndex(bookshelfLayout)
|
||||||
rgSort.checkByIndex(bookshelfSort)
|
rgSort.checkByIndex(bookshelfSort)
|
||||||
}
|
}
|
||||||
@@ -153,6 +154,10 @@ abstract class BaseBookshelfFragment(layoutId: Int) : VMBaseFragment<BookshelfVi
|
|||||||
AppConfig.showLastUpdateTime = swShowLastUpdateTime.isChecked
|
AppConfig.showLastUpdateTime = swShowLastUpdateTime.isChecked
|
||||||
postEvent(EventBus.BOOKSHELF_REFRESH, "")
|
postEvent(EventBus.BOOKSHELF_REFRESH, "")
|
||||||
}
|
}
|
||||||
|
if (AppConfig.showWaitUpCount != swShowWaitUpBooks.isChecked) {
|
||||||
|
AppConfig.showWaitUpCount = swShowWaitUpBooks.isChecked
|
||||||
|
activityViewModel.postUpBooksLiveData()
|
||||||
|
}
|
||||||
var changed = false
|
var changed = false
|
||||||
if (bookshelfLayout != rgLayout.getCheckedIndex()) {
|
if (bookshelfLayout != rgLayout.getCheckedIndex()) {
|
||||||
putPrefInt(PreferKey.bookshelfLayout, rgLayout.getCheckedIndex())
|
putPrefInt(PreferKey.bookshelfLayout, rgLayout.getCheckedIndex())
|
||||||
|
|||||||
@@ -49,13 +49,22 @@
|
|||||||
app:layout_constraintTop_toBottomOf="@+id/sw_show_unread"
|
app:layout_constraintTop_toBottomOf="@+id/sw_show_unread"
|
||||||
tools:ignore="TouchTargetSizeCheck" />
|
tools:ignore="TouchTargetSizeCheck" />
|
||||||
|
|
||||||
|
<io.legado.app.lib.theme.view.ThemeSwitch
|
||||||
|
android:id="@+id/sw_show_wait_up_books"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="6dp"
|
||||||
|
android:text="@string/show_wait_up_count"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/sw_show_last_update_time"
|
||||||
|
tools:ignore="TouchTargetSizeCheck" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/ll_layout"
|
android:id="@+id/ll_layout"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
app:layout_constraintRight_toLeftOf="@+id/ll_sort"
|
app:layout_constraintRight_toLeftOf="@+id/ll_sort"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/sw_show_last_update_time"
|
app:layout_constraintTop_toBottomOf="@+id/sw_show_wait_up_books"
|
||||||
app:layout_constraintLeft_toLeftOf="parent">
|
app:layout_constraintLeft_toLeftOf="parent">
|
||||||
|
|
||||||
<io.legado.app.ui.widget.text.AccentTextView
|
<io.legado.app.ui.widget.text.AccentTextView
|
||||||
@@ -110,7 +119,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
app:layout_constraintLeft_toRightOf="@+id/ll_layout"
|
app:layout_constraintLeft_toRightOf="@+id/ll_layout"
|
||||||
app:layout_constraintTop_toBottomOf="@id/sw_show_last_update_time"
|
app:layout_constraintTop_toBottomOf="@id/sw_show_wait_up_books"
|
||||||
app:layout_constraintRight_toRightOf="parent">
|
app:layout_constraintRight_toRightOf="parent">
|
||||||
|
|
||||||
<io.legado.app.ui.widget.text.AccentTextView
|
<io.legado.app.ui.widget.text.AccentTextView
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<io.legado.app.ui.widget.text.BadgeView
|
||||||
|
android:id="@+id/view_badge"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="18dp"
|
||||||
|
android:layout_marginLeft="12dp"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
tools:ignore="RtlHardcoded" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
@@ -1115,4 +1115,5 @@
|
|||||||
<string name="is_compress">是否压缩</string>
|
<string name="is_compress">是否压缩</string>
|
||||||
<string name="sort_desc">反序</string>
|
<string name="sort_desc">反序</string>
|
||||||
<string name="test">测试</string>
|
<string name="test">测试</string>
|
||||||
|
<string name="show_wait_up_count">显示等待更新数量</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1118,4 +1118,5 @@
|
|||||||
<string name="is_compress">是否压缩</string>
|
<string name="is_compress">是否压缩</string>
|
||||||
<string name="sort_desc">反序</string>
|
<string name="sort_desc">反序</string>
|
||||||
<string name="test">测试</string>
|
<string name="test">测试</string>
|
||||||
|
<string name="show_wait_up_count">显示等待更新数量</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1118,4 +1118,5 @@
|
|||||||
<string name="is_compress">是否压缩</string>
|
<string name="is_compress">是否压缩</string>
|
||||||
<string name="sort_desc">反序</string>
|
<string name="sort_desc">反序</string>
|
||||||
<string name="test">测试</string>
|
<string name="test">测试</string>
|
||||||
|
<string name="show_wait_up_count">显示等待更新数量</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1115,4 +1115,5 @@
|
|||||||
<string name="is_compress">是否压缩</string>
|
<string name="is_compress">是否压缩</string>
|
||||||
<string name="sort_desc">反序</string>
|
<string name="sort_desc">反序</string>
|
||||||
<string name="test">测试</string>
|
<string name="test">测试</string>
|
||||||
|
<string name="show_wait_up_count">显示等待更新数量</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1117,4 +1117,5 @@
|
|||||||
<string name="is_compress">是否压缩</string>
|
<string name="is_compress">是否压缩</string>
|
||||||
<string name="sort_desc">反序</string>
|
<string name="sort_desc">反序</string>
|
||||||
<string name="test">测试</string>
|
<string name="test">测试</string>
|
||||||
|
<string name="show_wait_up_count">显示等待更新数量</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1117,4 +1117,5 @@
|
|||||||
<string name="is_compress">是否压缩</string>
|
<string name="is_compress">是否压缩</string>
|
||||||
<string name="sort_desc">反序</string>
|
<string name="sort_desc">反序</string>
|
||||||
<string name="test">测试</string>
|
<string name="test">测试</string>
|
||||||
|
<string name="show_wait_up_count">显示等待更新数量</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1118,4 +1118,5 @@
|
|||||||
<string name="is_compress">是否压缩</string>
|
<string name="is_compress">是否压缩</string>
|
||||||
<string name="sort_desc">反序</string>
|
<string name="sort_desc">反序</string>
|
||||||
<string name="test">测试</string>
|
<string name="test">测试</string>
|
||||||
|
<string name="show_wait_up_count">显示等待更新数量</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user