Update sources manage screen
This commit is contained in:
@@ -39,6 +39,7 @@ class CaptchaNotifier(
|
|||||||
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
|
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
|
||||||
.setDefaults(NotificationCompat.DEFAULT_SOUND)
|
.setDefaults(NotificationCompat.DEFAULT_SOUND)
|
||||||
.setSmallIcon(android.R.drawable.stat_notify_error)
|
.setSmallIcon(android.R.drawable.stat_notify_error)
|
||||||
|
.setAutoCancel(true)
|
||||||
.setVisibility(
|
.setVisibility(
|
||||||
if (exception.source?.contentType == ContentType.HENTAI) {
|
if (exception.source?.contentType == ContentType.HENTAI) {
|
||||||
NotificationCompat.VISIBILITY_SECRET
|
NotificationCompat.VISIBILITY_SECRET
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ open class BaseListAdapter<T : ListModel>(
|
|||||||
.setBackgroundThreadExecutor(Dispatchers.Default.limitedParallelism(2).asExecutor())
|
.setBackgroundThreadExecutor(Dispatchers.Default.limitedParallelism(2).asExecutor())
|
||||||
.build(),
|
.build(),
|
||||||
*delegates,
|
*delegates,
|
||||||
), FlowCollector<List<T>> {
|
), FlowCollector<List<T>?> {
|
||||||
|
|
||||||
override suspend fun emit(value: List<T>) = suspendCoroutine { cont ->
|
override suspend fun emit(value: List<T>?) = suspendCoroutine { cont ->
|
||||||
setItems(value, ContinuationResumeRunnable(cont))
|
setItems(value.orEmpty(), ContinuationResumeRunnable(cont))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addDelegate(type: ListItemType, delegate: AdapterDelegate<List<T>>): BaseListAdapter<T> {
|
fun addDelegate(type: ListItemType, delegate: AdapterDelegate<List<T>>): BaseListAdapter<T> {
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import org.koitharu.kotatsu.main.ui.owners.AppBarOwner
|
|||||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||||
import org.koitharu.kotatsu.settings.about.AboutSettingsFragment
|
import org.koitharu.kotatsu.settings.about.AboutSettingsFragment
|
||||||
import org.koitharu.kotatsu.settings.sources.SourceSettingsFragment
|
import org.koitharu.kotatsu.settings.sources.SourceSettingsFragment
|
||||||
import org.koitharu.kotatsu.settings.sources.SourcesListFragment
|
import org.koitharu.kotatsu.settings.sources.SourcesManageFragment
|
||||||
import org.koitharu.kotatsu.settings.tracker.TrackerSettingsFragment
|
import org.koitharu.kotatsu.settings.tracker.TrackerSettingsFragment
|
||||||
import org.koitharu.kotatsu.settings.userdata.UserDataSettingsFragment
|
import org.koitharu.kotatsu.settings.userdata.UserDataSettingsFragment
|
||||||
|
|
||||||
@@ -155,7 +155,7 @@ class SettingsActivity :
|
|||||||
intent.getSerializableExtraCompat(EXTRA_SOURCE) as? MangaSource ?: MangaSource.LOCAL,
|
intent.getSerializableExtraCompat(EXTRA_SOURCE) as? MangaSource ?: MangaSource.LOCAL,
|
||||||
)
|
)
|
||||||
|
|
||||||
ACTION_MANAGE_SOURCES -> SourcesListFragment()
|
ACTION_MANAGE_SOURCES -> SourcesManageFragment()
|
||||||
Intent.ACTION_VIEW -> {
|
Intent.ACTION_VIEW -> {
|
||||||
when (intent.data?.host) {
|
when (intent.data?.host) {
|
||||||
HOST_ABOUT -> AboutSettingsFragment()
|
HOST_ABOUT -> AboutSettingsFragment()
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import android.content.DialogInterface
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.view.isVisible
|
||||||
import androidx.fragment.app.FragmentManager
|
import androidx.fragment.app.FragmentManager
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
@@ -45,9 +46,7 @@ class OnboardDialogFragment :
|
|||||||
if (isWelcome) {
|
if (isWelcome) {
|
||||||
builder.setTitle(R.string.welcome)
|
builder.setTitle(R.string.welcome)
|
||||||
} else {
|
} else {
|
||||||
builder
|
builder.setTitle(R.string.remote_sources)
|
||||||
.setTitle(R.string.remote_sources)
|
|
||||||
.setNegativeButton(android.R.string.cancel, this)
|
|
||||||
}
|
}
|
||||||
return builder
|
return builder
|
||||||
}
|
}
|
||||||
@@ -56,10 +55,12 @@ class OnboardDialogFragment :
|
|||||||
super.onViewBindingCreated(binding, savedInstanceState)
|
super.onViewBindingCreated(binding, savedInstanceState)
|
||||||
val adapter = SourceLocalesAdapter(this)
|
val adapter = SourceLocalesAdapter(this)
|
||||||
binding.recyclerView.adapter = adapter
|
binding.recyclerView.adapter = adapter
|
||||||
binding.textViewTitle.setText(R.string.onboard_text)
|
if (isWelcome) {
|
||||||
viewModel.list.observe(viewLifecycleOwner) {
|
binding.textViewTitle.setText(R.string.onboard_text)
|
||||||
adapter.items = it.orEmpty()
|
} else {
|
||||||
|
binding.textViewTitle.isVisible = false
|
||||||
}
|
}
|
||||||
|
viewModel.list.observe(viewLifecycleOwner, adapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onItemCheckedChanged(item: SourceLocale, isChecked: Boolean) {
|
override fun onItemCheckedChanged(item: SourceLocale, isChecked: Boolean) {
|
||||||
|
|||||||
@@ -26,13 +26,14 @@ import org.koitharu.kotatsu.core.util.ext.observeEvent
|
|||||||
import org.koitharu.kotatsu.databinding.FragmentSettingsSourcesBinding
|
import org.koitharu.kotatsu.databinding.FragmentSettingsSourcesBinding
|
||||||
import org.koitharu.kotatsu.main.ui.owners.AppBarOwner
|
import org.koitharu.kotatsu.main.ui.owners.AppBarOwner
|
||||||
import org.koitharu.kotatsu.settings.SettingsActivity
|
import org.koitharu.kotatsu.settings.SettingsActivity
|
||||||
|
import org.koitharu.kotatsu.settings.onboard.OnboardDialogFragment
|
||||||
import org.koitharu.kotatsu.settings.sources.adapter.SourceConfigAdapter
|
import org.koitharu.kotatsu.settings.sources.adapter.SourceConfigAdapter
|
||||||
import org.koitharu.kotatsu.settings.sources.adapter.SourceConfigListener
|
import org.koitharu.kotatsu.settings.sources.adapter.SourceConfigListener
|
||||||
import org.koitharu.kotatsu.settings.sources.model.SourceConfigItem
|
import org.koitharu.kotatsu.settings.sources.model.SourceConfigItem
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class SourcesListFragment :
|
class SourcesManageFragment :
|
||||||
BaseFragment<FragmentSettingsSourcesBinding>(),
|
BaseFragment<FragmentSettingsSourcesBinding>(),
|
||||||
SourceConfigListener,
|
SourceConfigListener,
|
||||||
RecyclerViewOwner {
|
RecyclerViewOwner {
|
||||||
@@ -41,7 +42,7 @@ class SourcesListFragment :
|
|||||||
lateinit var coil: ImageLoader
|
lateinit var coil: ImageLoader
|
||||||
|
|
||||||
private var reorderHelper: ItemTouchHelper? = null
|
private var reorderHelper: ItemTouchHelper? = null
|
||||||
private val viewModel by viewModels<SourcesListViewModel>()
|
private val viewModel by viewModels<SourcesManageViewModel>()
|
||||||
|
|
||||||
override val recyclerView: RecyclerView
|
override val recyclerView: RecyclerView
|
||||||
get() = requireViewBinding().recyclerView
|
get() = requireViewBinding().recyclerView
|
||||||
@@ -61,9 +62,7 @@ class SourcesListFragment :
|
|||||||
it.attachToRecyclerView(this)
|
it.attachToRecyclerView(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
viewModel.items.observe(viewLifecycleOwner) {
|
viewModel.content.observe(viewLifecycleOwner, sourcesAdapter)
|
||||||
sourcesAdapter.items = it
|
|
||||||
}
|
|
||||||
viewModel.onActionDone.observeEvent(viewLifecycleOwner, ReversibleActionObserver(binding.recyclerView))
|
viewModel.onActionDone.observeEvent(viewLifecycleOwner, ReversibleActionObserver(binding.recyclerView))
|
||||||
addMenuProvider(SourcesMenuProvider())
|
addMenuProvider(SourcesMenuProvider())
|
||||||
}
|
}
|
||||||
@@ -124,6 +123,11 @@ class SourcesListFragment :
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
R.id.action_locales -> {
|
||||||
|
OnboardDialogFragment.show(childFragmentManager)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,17 +1,24 @@
|
|||||||
package org.koitharu.kotatsu.settings.sources
|
package org.koitharu.kotatsu.settings.sources
|
||||||
|
|
||||||
|
import androidx.annotation.CheckResult
|
||||||
import androidx.core.os.LocaleListCompat
|
import androidx.core.os.LocaleListCompat
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.CoroutineStart
|
import kotlinx.coroutines.CoroutineStart
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
|
import kotlinx.coroutines.flow.combine
|
||||||
|
import kotlinx.coroutines.flow.stateIn
|
||||||
|
import kotlinx.coroutines.plus
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
import org.koitharu.kotatsu.core.model.getLocaleTitle
|
import org.koitharu.kotatsu.core.model.getLocaleTitle
|
||||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||||
|
import org.koitharu.kotatsu.core.prefs.observeAsFlow
|
||||||
import org.koitharu.kotatsu.core.ui.BaseViewModel
|
import org.koitharu.kotatsu.core.ui.BaseViewModel
|
||||||
import org.koitharu.kotatsu.core.ui.util.ReversibleAction
|
import org.koitharu.kotatsu.core.ui.util.ReversibleAction
|
||||||
import org.koitharu.kotatsu.core.util.AlphanumComparator
|
import org.koitharu.kotatsu.core.util.AlphanumComparator
|
||||||
@@ -23,7 +30,6 @@ import org.koitharu.kotatsu.explore.data.MangaSourcesRepository
|
|||||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||||
import org.koitharu.kotatsu.parsers.util.toTitleCase
|
import org.koitharu.kotatsu.parsers.util.toTitleCase
|
||||||
import org.koitharu.kotatsu.settings.sources.model.SourceConfigItem
|
import org.koitharu.kotatsu.settings.sources.model.SourceConfigItem
|
||||||
import java.util.EnumSet
|
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import java.util.TreeMap
|
import java.util.TreeMap
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@@ -34,26 +40,28 @@ private const val KEY_ENABLED = "!"
|
|||||||
private const val TIP_REORDER = "src_reorder"
|
private const val TIP_REORDER = "src_reorder"
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class SourcesListViewModel @Inject constructor(
|
class SourcesManageViewModel @Inject constructor(
|
||||||
private val settings: AppSettings,
|
private val settings: AppSettings,
|
||||||
private val repository: MangaSourcesRepository,
|
private val repository: MangaSourcesRepository,
|
||||||
) : BaseViewModel() {
|
) : BaseViewModel() {
|
||||||
|
|
||||||
val items = MutableStateFlow<List<SourceConfigItem>>(emptyList())
|
private val expandedGroups = MutableStateFlow(emptySet<String?>())
|
||||||
val onActionDone = MutableEventFlow<ReversibleAction>()
|
private var searchQuery = MutableStateFlow<String?>(null)
|
||||||
private val mutex = Mutex()
|
private val mutex = Mutex()
|
||||||
|
|
||||||
private val expandedGroups = HashSet<String?>()
|
val content = combine(
|
||||||
private var searchQuery: String? = null
|
repository.observeEnabledSources(),
|
||||||
|
expandedGroups,
|
||||||
|
searchQuery,
|
||||||
|
observeTip(),
|
||||||
|
) { sources, groups, query, tip ->
|
||||||
|
buildList(sources, groups, query, tip)
|
||||||
|
}.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, emptyList())
|
||||||
|
|
||||||
init {
|
val onActionDone = MutableEventFlow<ReversibleAction>()
|
||||||
launchAtomicJob(Dispatchers.Default) {
|
|
||||||
buildList()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun reorderSources(oldPos: Int, newPos: Int): Boolean {
|
fun reorderSources(oldPos: Int, newPos: Int): Boolean {
|
||||||
val snapshot = items.value.toMutableList()
|
val snapshot = content.value
|
||||||
val item = (snapshot[oldPos] as? SourceConfigItem.SourceItem) ?: return false
|
val item = (snapshot[oldPos] as? SourceConfigItem.SourceItem) ?: return false
|
||||||
if ((snapshot[newPos] as? SourceConfigItem.SourceItem)?.isDraggable != true) return false
|
if ((snapshot[newPos] as? SourceConfigItem.SourceItem)?.isDraggable != true) return false
|
||||||
launchAtomicJob(Dispatchers.Default) {
|
launchAtomicJob(Dispatchers.Default) {
|
||||||
@@ -67,13 +75,12 @@ class SourcesListViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
repository.setPosition(item.source, targetPosition)
|
repository.setPosition(item.source, targetPosition)
|
||||||
buildList()
|
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun canReorder(oldPos: Int, newPos: Int): Boolean {
|
fun canReorder(oldPos: Int, newPos: Int): Boolean {
|
||||||
val snapshot = items.value.toMutableList()
|
val snapshot = content.value
|
||||||
if ((snapshot[oldPos] as? SourceConfigItem.SourceItem)?.isEnabled != true) return false
|
if ((snapshot[oldPos] as? SourceConfigItem.SourceItem)?.isEnabled != true) return false
|
||||||
return (snapshot[newPos] as? SourceConfigItem.SourceItem)?.isEnabled == true
|
return (snapshot[newPos] as? SourceConfigItem.SourceItem)?.isEnabled == true
|
||||||
}
|
}
|
||||||
@@ -84,49 +91,45 @@ class SourcesListViewModel @Inject constructor(
|
|||||||
if (!isEnabled) {
|
if (!isEnabled) {
|
||||||
onActionDone.call(ReversibleAction(R.string.source_disabled, rollback))
|
onActionDone.call(ReversibleAction(R.string.source_disabled, rollback))
|
||||||
}
|
}
|
||||||
buildList()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun disableAll() {
|
fun disableAll() {
|
||||||
launchAtomicJob(Dispatchers.Default) {
|
launchAtomicJob(Dispatchers.Default) {
|
||||||
repository.disableAllSources()
|
repository.disableAllSources()
|
||||||
buildList()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun expandOrCollapse(headerId: String?) {
|
fun expandOrCollapse(headerId: String?) {
|
||||||
launchAtomicJob {
|
val expanded = expandedGroups.value
|
||||||
if (headerId in expandedGroups) {
|
expandedGroups.value = if (headerId in expanded) {
|
||||||
expandedGroups.remove(headerId)
|
expanded - headerId
|
||||||
} else {
|
} else {
|
||||||
expandedGroups.add(headerId)
|
expanded + headerId
|
||||||
}
|
|
||||||
buildList()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun performSearch(query: String?) {
|
fun performSearch(query: String?) {
|
||||||
launchAtomicJob {
|
searchQuery.value = query?.trim()
|
||||||
searchQuery = query?.trim()
|
|
||||||
buildList()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onTipClosed(item: SourceConfigItem.Tip) {
|
fun onTipClosed(item: SourceConfigItem.Tip) {
|
||||||
launchAtomicJob(Dispatchers.Default) {
|
launchAtomicJob(Dispatchers.Default) {
|
||||||
settings.closeTip(item.key)
|
settings.closeTip(item.key)
|
||||||
buildList()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun buildList() = withContext(Dispatchers.Default) {
|
@CheckResult
|
||||||
|
private fun buildList(
|
||||||
|
enabledSources: List<MangaSource>,
|
||||||
|
expanded: Set<String?>,
|
||||||
|
query: String?,
|
||||||
|
withTip: Boolean,
|
||||||
|
): List<SourceConfigItem> {
|
||||||
val allSources = repository.allMangaSources
|
val allSources = repository.allMangaSources
|
||||||
val enabledSources = repository.getEnabledSources()
|
|
||||||
val enabledSet = enabledSources.toEnumSet()
|
val enabledSet = enabledSources.toEnumSet()
|
||||||
val query = searchQuery
|
|
||||||
if (!query.isNullOrEmpty()) {
|
if (!query.isNullOrEmpty()) {
|
||||||
items.value = allSources.mapNotNull {
|
return allSources.mapNotNull {
|
||||||
if (!it.title.contains(query, ignoreCase = true)) {
|
if (!it.title.contains(query, ignoreCase = true)) {
|
||||||
return@mapNotNull null
|
return@mapNotNull null
|
||||||
}
|
}
|
||||||
@@ -139,7 +142,6 @@ class SourcesListViewModel @Inject constructor(
|
|||||||
}.ifEmpty {
|
}.ifEmpty {
|
||||||
listOf(SourceConfigItem.EmptySearchResult)
|
listOf(SourceConfigItem.EmptySearchResult)
|
||||||
}
|
}
|
||||||
return@withContext
|
|
||||||
}
|
}
|
||||||
val map = allSources.groupByTo(TreeMap(LocaleKeyComparator())) {
|
val map = allSources.groupByTo(TreeMap(LocaleKeyComparator())) {
|
||||||
if (it in enabledSet) {
|
if (it in enabledSet) {
|
||||||
@@ -152,7 +154,7 @@ class SourcesListViewModel @Inject constructor(
|
|||||||
val result = ArrayList<SourceConfigItem>(allSources.size + map.size + 2)
|
val result = ArrayList<SourceConfigItem>(allSources.size + map.size + 2)
|
||||||
if (enabledSources.isNotEmpty()) {
|
if (enabledSources.isNotEmpty()) {
|
||||||
result += SourceConfigItem.Header(R.string.enabled_sources)
|
result += SourceConfigItem.Header(R.string.enabled_sources)
|
||||||
if (settings.isTipEnabled(TIP_REORDER)) {
|
if (withTip) {
|
||||||
result += SourceConfigItem.Tip(TIP_REORDER, R.drawable.ic_tap_reorder, R.string.sources_reorder_tip)
|
result += SourceConfigItem.Tip(TIP_REORDER, R.drawable.ic_tap_reorder, R.string.sources_reorder_tip)
|
||||||
}
|
}
|
||||||
enabledSources.mapTo(result) {
|
enabledSources.mapTo(result) {
|
||||||
@@ -169,7 +171,7 @@ class SourcesListViewModel @Inject constructor(
|
|||||||
val comparator = compareBy<MangaSource, String>(AlphanumComparator()) { it.name }
|
val comparator = compareBy<MangaSource, String>(AlphanumComparator()) { it.name }
|
||||||
for ((key, list) in map) {
|
for ((key, list) in map) {
|
||||||
list.sortWith(comparator)
|
list.sortWith(comparator)
|
||||||
val isExpanded = key in expandedGroups
|
val isExpanded = key in expanded
|
||||||
result += SourceConfigItem.LocaleGroup(
|
result += SourceConfigItem.LocaleGroup(
|
||||||
localeId = key,
|
localeId = key,
|
||||||
title = getLocaleTitle(key),
|
title = getLocaleTitle(key),
|
||||||
@@ -187,7 +189,7 @@ class SourcesListViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
items.value = result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getLocaleTitle(localeKey: String?): String? {
|
private fun getLocaleTitle(localeKey: String?): String? {
|
||||||
@@ -204,6 +206,10 @@ class SourcesListViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun observeTip() = settings.observeAsFlow(AppSettings.KEY_TIPS_CLOSED) {
|
||||||
|
isTipEnabled(TIP_REORDER)
|
||||||
|
}
|
||||||
|
|
||||||
private class LocaleKeyComparator : Comparator<String?> {
|
private class LocaleKeyComparator : Comparator<String?> {
|
||||||
|
|
||||||
private val deviceLocales = LocaleListCompat.getAdjustedDefault()
|
private val deviceLocales = LocaleListCompat.getAdjustedDefault()
|
||||||
@@ -10,9 +10,14 @@
|
|||||||
app:actionViewClass="androidx.appcompat.widget.SearchView"
|
app:actionViewClass="androidx.appcompat.widget.SearchView"
|
||||||
app:showAsAction="ifRoom|collapseActionView" />
|
app:showAsAction="ifRoom|collapseActionView" />
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_locales"
|
||||||
|
android:title="@string/languages"
|
||||||
|
app:showAsAction="never" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_disable_all"
|
android:id="@+id/action_disable_all"
|
||||||
android:title="@string/disable_all"
|
android:title="@string/disable_all"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="never" />
|
||||||
|
|
||||||
</menu>
|
</menu>
|
||||||
|
|||||||
@@ -469,4 +469,5 @@
|
|||||||
<string name="view_list">View list</string>
|
<string name="view_list">View list</string>
|
||||||
<string name="show">Show</string>
|
<string name="show">Show</string>
|
||||||
<string name="captcha_required_summary">%s requires a captcha to be resolved to work properly</string>
|
<string name="captcha_required_summary">%s requires a captcha to be resolved to work properly</string>
|
||||||
|
<string name="languages">Languages</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
android:title="@string/appearance" />
|
android:title="@string/appearance" />
|
||||||
|
|
||||||
<PreferenceScreen
|
<PreferenceScreen
|
||||||
android:fragment="org.koitharu.kotatsu.settings.sources.SourcesListFragment"
|
android:fragment="org.koitharu.kotatsu.settings.sources.SourcesManageFragment"
|
||||||
android:icon="@drawable/ic_manga_source"
|
android:icon="@drawable/ic_manga_source"
|
||||||
android:key="remote_sources"
|
android:key="remote_sources"
|
||||||
android:title="@string/remote_sources" />
|
android:title="@string/remote_sources" />
|
||||||
|
|||||||
Reference in New Issue
Block a user