Multiple sources selection
This commit is contained in:
@@ -18,6 +18,7 @@ import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.db.TABLE_HISTORY
|
||||
import org.koitharu.kotatsu.core.parser.MangaDataRepository
|
||||
@@ -150,7 +151,7 @@ class AppShortcutManager @Inject constructor(
|
||||
.build()
|
||||
}
|
||||
|
||||
private suspend fun buildShortcutInfo(source: MangaSource): ShortcutInfoCompat {
|
||||
private suspend fun buildShortcutInfo(source: MangaSource): ShortcutInfoCompat = withContext(Dispatchers.Default) {
|
||||
val icon = runCatchingCancellable {
|
||||
coil.execute(
|
||||
ImageRequest.Builder(context)
|
||||
@@ -163,7 +164,7 @@ class AppShortcutManager @Inject constructor(
|
||||
onSuccess = { IconCompat.createWithAdaptiveBitmap(it) },
|
||||
onFailure = { IconCompat.createWithResource(context, R.drawable.ic_shortcut_default) },
|
||||
)
|
||||
return ShortcutInfoCompat.Builder(context, source.name)
|
||||
ShortcutInfoCompat.Builder(context, source.name)
|
||||
.setShortLabel(source.title)
|
||||
.setLongLabel(source.title)
|
||||
.setIcon(icon)
|
||||
|
||||
@@ -7,6 +7,7 @@ import android.graphics.Paint
|
||||
import android.graphics.RectF
|
||||
import android.view.View
|
||||
import androidx.cardview.widget.CardView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.graphics.ColorUtils
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import org.koitharu.kotatsu.R
|
||||
@@ -19,7 +20,10 @@ import com.google.android.material.R as materialR
|
||||
class ChaptersSelectionDecoration(context: Context) : AbstractSelectionItemDecoration() {
|
||||
|
||||
private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
|
||||
private val defaultRadius = context.resources.getDimension(materialR.dimen.abc_control_corner_material)
|
||||
private val radius = context.resources.getDimension(materialR.dimen.abc_control_corner_material)
|
||||
private val checkIcon = ContextCompat.getDrawable(context, materialR.drawable.ic_mtrl_checked_circle)
|
||||
private val iconOffset = context.resources.getDimensionPixelOffset(R.dimen.chapter_check_offset)
|
||||
private val iconSize = context.resources.getDimensionPixelOffset(R.dimen.chapter_check_size)
|
||||
private val strokeColor = context.getThemeColor(materialR.attr.colorPrimary, Color.RED)
|
||||
private val fillColor = ColorUtils.setAlphaComponent(
|
||||
ColorUtils.blendARGB(strokeColor, context.getThemeColor(materialR.attr.colorSurface), 0.8f),
|
||||
@@ -32,11 +36,12 @@ class ChaptersSelectionDecoration(context: Context) : AbstractSelectionItemDecor
|
||||
98,
|
||||
)
|
||||
paint.style = Paint.Style.FILL
|
||||
hasBackground = false
|
||||
hasBackground = true
|
||||
hasForeground = true
|
||||
isIncludeDecorAndMargins = false
|
||||
|
||||
paint.strokeWidth = context.resources.getDimension(R.dimen.selection_stroke_width)
|
||||
checkIcon?.setTint(strokeColor)
|
||||
}
|
||||
|
||||
override fun getItemId(parent: RecyclerView, child: View): Long {
|
||||
@@ -45,6 +50,19 @@ class ChaptersSelectionDecoration(context: Context) : AbstractSelectionItemDecor
|
||||
return item.chapter.id
|
||||
}
|
||||
|
||||
override fun onDrawBackground(
|
||||
canvas: Canvas,
|
||||
parent: RecyclerView,
|
||||
child: View,
|
||||
bounds: RectF,
|
||||
state: RecyclerView.State,
|
||||
) {
|
||||
if (child is CardView) {
|
||||
return
|
||||
}
|
||||
canvas.drawRoundRect(bounds, radius, radius, paint)
|
||||
}
|
||||
|
||||
override fun onDrawForeground(
|
||||
canvas: Canvas,
|
||||
parent: RecyclerView,
|
||||
@@ -52,16 +70,24 @@ class ChaptersSelectionDecoration(context: Context) : AbstractSelectionItemDecor
|
||||
bounds: RectF,
|
||||
state: RecyclerView.State
|
||||
) {
|
||||
val radius = if (child is CardView) {
|
||||
child.radius
|
||||
} else {
|
||||
defaultRadius
|
||||
if (child !is CardView) {
|
||||
return
|
||||
}
|
||||
val radius = child.radius
|
||||
paint.color = fillColor
|
||||
paint.style = Paint.Style.FILL
|
||||
canvas.drawRoundRect(bounds, radius, radius, paint)
|
||||
paint.color = strokeColor
|
||||
paint.style = Paint.Style.STROKE
|
||||
canvas.drawRoundRect(bounds, radius, radius, paint)
|
||||
checkIcon?.run {
|
||||
setBounds(
|
||||
(bounds.right - iconSize - iconOffset).toInt(),
|
||||
(bounds.top + iconOffset).toInt(),
|
||||
(bounds.right - iconOffset).toInt(),
|
||||
(bounds.top + iconOffset + iconSize).toInt(),
|
||||
)
|
||||
draw(canvas)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,10 +97,10 @@ class MangaSourcesRepository @Inject constructor(
|
||||
result
|
||||
}
|
||||
|
||||
suspend fun setSourceEnabled(source: MangaSource, isEnabled: Boolean): ReversibleHandle {
|
||||
dao.setEnabled(source.name, isEnabled)
|
||||
suspend fun setSourcesEnabled(sources: Collection<MangaSource>, isEnabled: Boolean): ReversibleHandle {
|
||||
setSourcesEnabledImpl(sources, isEnabled)
|
||||
return ReversibleHandle {
|
||||
dao.setEnabled(source.name, !isEnabled)
|
||||
setSourcesEnabledImpl(sources, !isEnabled)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,6 +171,18 @@ class MangaSourcesRepository @Inject constructor(
|
||||
return dao.findAll().isEmpty()
|
||||
}
|
||||
|
||||
private suspend fun setSourcesEnabledImpl(sources: Collection<MangaSource>, isEnabled: Boolean) {
|
||||
if (sources.size == 1) { // fast path
|
||||
dao.setEnabled(sources.first().name, isEnabled)
|
||||
return
|
||||
}
|
||||
db.withTransaction {
|
||||
for (source in sources) {
|
||||
dao.setEnabled(source.name, isEnabled)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getNewSources(): MutableSet<MangaSource> {
|
||||
val entities = dao.findAll()
|
||||
val result = EnumSet.copyOf(remoteSources)
|
||||
|
||||
@@ -4,11 +4,11 @@ import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.core.content.pm.ShortcutManagerCompat
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.core.graphics.Insets
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.fragment.app.viewModels
|
||||
@@ -24,12 +24,14 @@ import org.koitharu.kotatsu.core.exceptions.resolve.SnackbarErrorObserver
|
||||
import org.koitharu.kotatsu.core.os.AppShortcutManager
|
||||
import org.koitharu.kotatsu.core.ui.BaseFragment
|
||||
import org.koitharu.kotatsu.core.ui.dialog.TwoButtonsAlertDialog
|
||||
import org.koitharu.kotatsu.core.ui.list.ListSelectionController
|
||||
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
|
||||
import org.koitharu.kotatsu.core.ui.util.RecyclerViewOwner
|
||||
import org.koitharu.kotatsu.core.ui.util.ReversibleActionObserver
|
||||
import org.koitharu.kotatsu.core.ui.util.SpanSizeResolver
|
||||
import org.koitharu.kotatsu.core.ui.widgets.TipView
|
||||
import org.koitharu.kotatsu.core.util.ext.addMenuProvider
|
||||
import org.koitharu.kotatsu.core.util.ext.findAppCompatDelegate
|
||||
import org.koitharu.kotatsu.core.util.ext.observe
|
||||
import org.koitharu.kotatsu.core.util.ext.observeEvent
|
||||
import org.koitharu.kotatsu.core.util.ext.viewLifecycleScope
|
||||
@@ -44,6 +46,7 @@ import org.koitharu.kotatsu.list.ui.model.ListHeader
|
||||
import org.koitharu.kotatsu.list.ui.model.TipModel
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.parsers.util.mapNotNullToSet
|
||||
import org.koitharu.kotatsu.search.ui.MangaListActivity
|
||||
import org.koitharu.kotatsu.settings.SettingsActivity
|
||||
import org.koitharu.kotatsu.settings.newsources.NewSourcesDialogFragment
|
||||
@@ -56,7 +59,7 @@ class ExploreFragment :
|
||||
BaseFragment<FragmentExploreBinding>(),
|
||||
RecyclerViewOwner,
|
||||
ExploreListEventListener,
|
||||
OnListItemClickListener<MangaSourceItem>, TipView.OnButtonClickListener {
|
||||
OnListItemClickListener<MangaSourceItem>, TipView.OnButtonClickListener, ListSelectionController.Callback2 {
|
||||
|
||||
@Inject
|
||||
lateinit var coil: ImageLoader
|
||||
@@ -66,6 +69,7 @@ class ExploreFragment :
|
||||
|
||||
private val viewModel by viewModels<ExploreViewModel>()
|
||||
private var exploreAdapter: ExploreAdapter? = null
|
||||
private var sourceSelectionController: ListSelectionController? = null
|
||||
|
||||
override val recyclerView: RecyclerView
|
||||
get() = requireViewBinding().recyclerView
|
||||
@@ -79,11 +83,18 @@ class ExploreFragment :
|
||||
exploreAdapter = ExploreAdapter(coil, viewLifecycleOwner, this, this, this) { manga, view ->
|
||||
startActivity(DetailsActivity.newIntent(view.context, manga))
|
||||
}
|
||||
sourceSelectionController = ListSelectionController(
|
||||
appCompatDelegate = checkNotNull(findAppCompatDelegate()),
|
||||
decoration = SourceSelectionDecoration(binding.root.context),
|
||||
registryOwner = this,
|
||||
callback = this,
|
||||
)
|
||||
with(binding.recyclerView) {
|
||||
adapter = exploreAdapter
|
||||
setHasFixedSize(true)
|
||||
SpanSizeResolver(this, resources.getDimensionPixelSize(R.dimen.explore_grid_width)).attach()
|
||||
addItemDecoration(TypedListSpacingDecoration(context, false))
|
||||
checkNotNull(sourceSelectionController).attachToRecyclerView(this)
|
||||
}
|
||||
addMenuProvider(ExploreMenuProvider(binding.root.context))
|
||||
viewModel.content.observe(viewLifecycleOwner) {
|
||||
@@ -100,6 +111,7 @@ class ExploreFragment :
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
sourceSelectionController = null
|
||||
exploreAdapter = null
|
||||
}
|
||||
|
||||
@@ -147,18 +159,15 @@ class ExploreFragment :
|
||||
}
|
||||
|
||||
override fun onItemClick(item: MangaSourceItem, view: View) {
|
||||
if (sourceSelectionController?.onItemClick(item.id) == true) {
|
||||
return
|
||||
}
|
||||
val intent = MangaListActivity.newIntent(view.context, item.source)
|
||||
startActivity(intent)
|
||||
}
|
||||
|
||||
override fun onItemLongClick(item: MangaSourceItem, view: View): Boolean {
|
||||
val menu = PopupMenu(view.context, view)
|
||||
menu.inflate(R.menu.popup_source)
|
||||
menu.menu.findItem(R.id.action_shortcut)
|
||||
?.isVisible = ShortcutManagerCompat.isRequestPinShortcutSupported(view.context)
|
||||
menu.setOnMenuItemClickListener(SourceMenuListener(item))
|
||||
menu.show()
|
||||
return true
|
||||
return sourceSelectionController?.onItemLongClick(item.id) ?: false
|
||||
}
|
||||
|
||||
override fun onRetryClick(error: Throwable) = Unit
|
||||
@@ -167,6 +176,54 @@ class ExploreFragment :
|
||||
startActivity(Intent(context ?: return, SourcesCatalogActivity::class.java))
|
||||
}
|
||||
|
||||
override fun onSelectionChanged(controller: ListSelectionController, count: Int) {
|
||||
viewBinding?.recyclerView?.invalidateItemDecorations()
|
||||
}
|
||||
|
||||
override fun onCreateActionMode(controller: ListSelectionController, mode: ActionMode, menu: Menu): Boolean {
|
||||
mode.menuInflater.inflate(R.menu.mode_source, menu)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onPrepareActionMode(controller: ListSelectionController, mode: ActionMode, menu: Menu): Boolean {
|
||||
val isSingleSelection = controller.count == 1
|
||||
menu.findItem(R.id.action_settings).isVisible = isSingleSelection
|
||||
menu.findItem(R.id.action_shortcut).isVisible = isSingleSelection
|
||||
return super.onPrepareActionMode(controller, mode, menu)
|
||||
}
|
||||
|
||||
override fun onActionItemClicked(controller: ListSelectionController, mode: ActionMode, item: MenuItem): Boolean {
|
||||
val selectedSources = controller.peekCheckedIds().mapNotNullToSet { id ->
|
||||
MangaSource.entries.getOrNull(id.toInt())
|
||||
}
|
||||
if (selectedSources.isEmpty()) {
|
||||
return false
|
||||
}
|
||||
when (item.itemId) {
|
||||
R.id.action_settings -> {
|
||||
val source = selectedSources.singleOrNull() ?: return false
|
||||
startActivity(SettingsActivity.newSourceSettingsIntent(requireContext(), source))
|
||||
mode.finish()
|
||||
}
|
||||
|
||||
R.id.action_disable -> {
|
||||
viewModel.disableSources(selectedSources)
|
||||
mode.finish()
|
||||
}
|
||||
|
||||
R.id.action_shortcut -> {
|
||||
val source = selectedSources.singleOrNull() ?: return false
|
||||
viewLifecycleScope.launch {
|
||||
shortcutManager.requestPinShortcut(source)
|
||||
}
|
||||
mode.finish()
|
||||
}
|
||||
|
||||
else -> return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun onOpenManga(manga: Manga) {
|
||||
val intent = DetailsActivity.newIntent(context ?: return, manga)
|
||||
startActivity(intent)
|
||||
@@ -194,30 +251,4 @@ class ExploreFragment :
|
||||
.create()
|
||||
.show()
|
||||
}
|
||||
|
||||
private inner class SourceMenuListener(
|
||||
private val sourceItem: MangaSourceItem,
|
||||
) : PopupMenu.OnMenuItemClickListener {
|
||||
|
||||
override fun onMenuItemClick(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
R.id.action_settings -> {
|
||||
startActivity(SettingsActivity.newSourceSettingsIntent(requireContext(), sourceItem.source))
|
||||
}
|
||||
|
||||
R.id.action_disable -> {
|
||||
viewModel.disableSource(sourceItem.source)
|
||||
}
|
||||
|
||||
R.id.action_shortcut -> {
|
||||
viewLifecycleScope.launch {
|
||||
shortcutManager.requestPinShortcut(sourceItem.source)
|
||||
}
|
||||
}
|
||||
|
||||
else -> return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,10 +92,11 @@ class ExploreViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun disableSource(source: MangaSource) {
|
||||
fun disableSources(sources: Collection<MangaSource>) {
|
||||
launchJob(Dispatchers.Default) {
|
||||
val rollback = sourcesRepository.setSourceEnabled(source, isEnabled = false)
|
||||
onActionDone.call(ReversibleAction(R.string.source_disabled, rollback))
|
||||
val rollback = sourcesRepository.setSourcesEnabled(sources, isEnabled = false)
|
||||
val message = if (sources.size == 1) R.string.source_disabled else R.string.sources_disabled
|
||||
onActionDone.call(ReversibleAction(message, rollback))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
package org.koitharu.kotatsu.explore.ui
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Color
|
||||
import android.graphics.Paint
|
||||
import android.graphics.RectF
|
||||
import android.view.View
|
||||
import androidx.core.graphics.ColorUtils
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.RecyclerView.NO_ID
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.ui.list.decor.AbstractSelectionItemDecoration
|
||||
import org.koitharu.kotatsu.core.util.ext.getItem
|
||||
import org.koitharu.kotatsu.core.util.ext.getThemeColor
|
||||
import org.koitharu.kotatsu.explore.ui.model.MangaSourceItem
|
||||
import com.google.android.material.R as materialR
|
||||
|
||||
class SourceSelectionDecoration(context: Context) : AbstractSelectionItemDecoration() {
|
||||
|
||||
private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
|
||||
private val strokeColor = context.getThemeColor(materialR.attr.colorPrimary, Color.RED)
|
||||
private val fillColor = ColorUtils.setAlphaComponent(
|
||||
ColorUtils.blendARGB(strokeColor, context.getThemeColor(materialR.attr.colorSurface), 0.8f),
|
||||
0x74,
|
||||
)
|
||||
private val defaultRadius = context.resources.getDimension(R.dimen.list_selector_corner)
|
||||
|
||||
init {
|
||||
hasBackground = false
|
||||
hasForeground = true
|
||||
isIncludeDecorAndMargins = false
|
||||
paint.strokeWidth = context.resources.getDimension(R.dimen.selection_stroke_width)
|
||||
}
|
||||
|
||||
override fun getItemId(parent: RecyclerView, child: View): Long {
|
||||
val holder = parent.getChildViewHolder(child) ?: return NO_ID
|
||||
val item = holder.getItem(MangaSourceItem::class.java) ?: return NO_ID
|
||||
return item.id
|
||||
}
|
||||
|
||||
override fun onDrawForeground(
|
||||
canvas: Canvas,
|
||||
parent: RecyclerView,
|
||||
child: View,
|
||||
bounds: RectF,
|
||||
state: RecyclerView.State,
|
||||
) {
|
||||
paint.color = fillColor
|
||||
paint.style = Paint.Style.FILL
|
||||
canvas.drawRoundRect(bounds, defaultRadius, defaultRadius, paint)
|
||||
paint.color = strokeColor
|
||||
paint.style = Paint.Style.STROKE
|
||||
canvas.drawRoundRect(bounds, defaultRadius, defaultRadius, paint)
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,9 @@ data class MangaSourceItem(
|
||||
val isGrid: Boolean,
|
||||
) : ListModel {
|
||||
|
||||
val id: Long
|
||||
get() = source.ordinal.toLong()
|
||||
|
||||
override fun areItemsTheSame(other: ListModel): Boolean {
|
||||
return other is MangaSourceItem && other.source == source
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ class SearchSuggestionViewModel @Inject constructor(
|
||||
|
||||
fun onSourceToggle(source: MangaSource, isEnabled: Boolean) {
|
||||
launchJob(Dispatchers.Default) {
|
||||
sourcesRepository.setSourceEnabled(source, isEnabled)
|
||||
sourcesRepository.setSourcesEnabled(setOf(source), isEnabled)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ class NewSourcesViewModel @Inject constructor(
|
||||
|
||||
fun onItemEnabledChanged(item: SourceConfigItem.SourceItem, isEnabled: Boolean) {
|
||||
launchJob(Dispatchers.Default) {
|
||||
repository.setSourceEnabled(item.source, isEnabled)
|
||||
repository.setSourcesEnabled(setOf(item.source), isEnabled)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ import org.koitharu.kotatsu.core.util.ext.MutableEventFlow
|
||||
import org.koitharu.kotatsu.core.util.ext.call
|
||||
import org.koitharu.kotatsu.core.util.ext.require
|
||||
import org.koitharu.kotatsu.explore.data.MangaSourcesRepository
|
||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||
import org.koitharu.kotatsu.parsers.exception.AuthRequiredException
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import javax.inject.Inject
|
||||
@@ -75,7 +74,7 @@ class SourceSettingsViewModel @Inject constructor(
|
||||
|
||||
fun setEnabled(value: Boolean) {
|
||||
launchJob(Dispatchers.Default) {
|
||||
mangaSourcesRepository.setSourceEnabled(source, value)
|
||||
mangaSourcesRepository.setSourcesEnabled(setOf(source), value)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ class SourcesCatalogViewModel @Inject constructor(
|
||||
|
||||
fun addSource(source: MangaSource) {
|
||||
launchJob(Dispatchers.Default) {
|
||||
val rollback = repository.setSourceEnabled(source, true)
|
||||
val rollback = repository.setSourcesEnabled(setOf(source), true)
|
||||
onActionDone.call(ReversibleAction(R.string.source_enabled, rollback))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ class SourcesManageViewModel @Inject constructor(
|
||||
|
||||
fun setEnabled(source: MangaSource, isEnabled: Boolean) {
|
||||
launchJob(Dispatchers.Default) {
|
||||
val rollback = repository.setSourceEnabled(source, isEnabled)
|
||||
val rollback = repository.setSourcesEnabled(setOf(source), isEnabled)
|
||||
if (!isEnabled) {
|
||||
onActionDone.call(ReversibleAction(R.string.source_disabled, rollback))
|
||||
}
|
||||
|
||||
12
app/src/main/res/drawable/ic_pin.xml
Normal file
12
app/src/main/res/drawable/ic_pin.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M16,12V4H17V2H7V4H8V12L6,14V16H11.2V22H12.8V16H18V14L16,12M8.8,14L10,12.8V4H14V12.8L15.2,14H8.8Z" />
|
||||
</vector>
|
||||
23
app/src/main/res/menu/mode_source.xml
Normal file
23
app/src/main/res/menu/mode_source.xml
Normal file
@@ -0,0 +1,23 @@
|
||||
<?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/action_disable"
|
||||
android:icon="@drawable/ic_eye_off"
|
||||
android:title="@string/disable"
|
||||
app:showAsAction="ifRoom|withText" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_shortcut"
|
||||
android:icon="@drawable/ic_pin"
|
||||
android:title="@string/create_shortcut"
|
||||
app:showAsAction="ifRoom|withText" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_settings"
|
||||
android:icon="@drawable/ic_settings"
|
||||
android:title="@string/settings"
|
||||
app:showAsAction="ifRoom|withText" />
|
||||
</menu>
|
||||
@@ -1,17 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item
|
||||
android:id="@+id/action_settings"
|
||||
android:title="@string/settings" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_shortcut"
|
||||
android:title="@string/create_shortcut" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_disable"
|
||||
android:title="@string/disable" />
|
||||
|
||||
</menu>
|
||||
@@ -642,4 +642,5 @@
|
||||
<string name="authors">Authors</string>
|
||||
<string name="blocked_by_server_message">You are blocked by the server. Try to use a different network connection (VPN, Proxy, etc.)</string>
|
||||
<string name="disable">Disable</string>
|
||||
<string name="sources_disabled">Sources disabled</string>
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user