@@ -18,7 +18,7 @@ import org.koitharu.kotatsu.explore.data.SourcesSortOrder
|
||||
@Dao
|
||||
abstract class MangaSourcesDao {
|
||||
|
||||
@Query("SELECT * FROM sources ORDER BY sort_key")
|
||||
@Query("SELECT * FROM sources ORDER BY pinned DESC, sort_key")
|
||||
abstract suspend fun findAll(): List<MangaSourceEntity>
|
||||
|
||||
@Query("SELECT source FROM sources WHERE enabled = 1")
|
||||
@@ -27,7 +27,7 @@ abstract class MangaSourcesDao {
|
||||
@Query("SELECT * FROM sources WHERE added_in >= :version")
|
||||
abstract suspend fun findAllFromVersion(version: Int): List<MangaSourceEntity>
|
||||
|
||||
@Query("SELECT * FROM sources ORDER BY sort_key")
|
||||
@Query("SELECT * FROM sources ORDER BY pinned DESC, sort_key")
|
||||
abstract fun observeAll(): Flow<List<MangaSourceEntity>>
|
||||
|
||||
@Query("SELECT enabled FROM sources WHERE source = :source")
|
||||
@@ -55,6 +55,9 @@ abstract class MangaSourcesDao {
|
||||
@Upsert
|
||||
abstract suspend fun upsert(entry: MangaSourceEntity)
|
||||
|
||||
@Query("SELECT * FROM sources WHERE pinned = 1")
|
||||
abstract suspend fun findAllPinned(): List<MangaSourceEntity>
|
||||
|
||||
fun observeEnabled(order: SourcesSortOrder): Flow<List<MangaSourceEntity>> {
|
||||
val orderBy = getOrderBy(order)
|
||||
|
||||
@@ -67,7 +70,7 @@ abstract class MangaSourcesDao {
|
||||
val orderBy = getOrderBy(order)
|
||||
|
||||
@Language("RoomSql")
|
||||
val query = SimpleSQLiteQuery("SELECT * FROM sources WHERE enabled = 1 ORDER BY $orderBy")
|
||||
val query = SimpleSQLiteQuery("SELECT * FROM sources WHERE enabled = 1 ORDER BY pinned DESC, $orderBy")
|
||||
return findAllImpl(query)
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,14 @@ class MangaSourcesRepository @Inject constructor(
|
||||
return dao.findAllEnabled(order).toSources(settings.isNsfwContentDisabled, order)
|
||||
}
|
||||
|
||||
suspend fun getPinnedSources(): Set<MangaSource> {
|
||||
assimilateNewSources()
|
||||
val skipNsfw = settings.isNsfwContentDisabled
|
||||
return dao.findAllPinned().mapNotNullTo(EnumSet.noneOf(MangaSource::class.java)) {
|
||||
it.source.toMangaSourceOrNull()?.takeUnless { x -> skipNsfw && x.isNsfw() }
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getDisabledSources(): Set<MangaSource> {
|
||||
assimilateNewSources()
|
||||
val result = EnumSet.copyOf(remoteSources)
|
||||
@@ -226,8 +234,11 @@ class MangaSourcesRepository @Inject constructor(
|
||||
return settings.sourcesVersion == 0 && dao.findAllEnabledNames().isEmpty()
|
||||
}
|
||||
|
||||
suspend fun setIsPinned(source: MangaSource, isPinned: Boolean) {
|
||||
dao.setPinned(source.name, isPinned)
|
||||
suspend fun setIsPinned(sources: Collection<MangaSource>, isPinned: Boolean): ReversibleHandle {
|
||||
setSourcesPinnedImpl(sources, isPinned)
|
||||
return ReversibleHandle {
|
||||
setSourcesEnabledImpl(sources, !isPinned)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun trackUsage(source: MangaSource) {
|
||||
@@ -246,6 +257,18 @@ class MangaSourcesRepository @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun setSourcesPinnedImpl(sources: Collection<MangaSource>, isPinned: Boolean) {
|
||||
if (sources.size == 1) { // fast path
|
||||
dao.setPinned(sources.first().name, isPinned)
|
||||
return
|
||||
}
|
||||
db.withTransaction {
|
||||
for (source in sources) {
|
||||
dao.setPinned(source.name, isPinned)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getNewSources(): MutableSet<MangaSource> {
|
||||
val entities = dao.findAll()
|
||||
val result = EnumSet.copyOf(remoteSources)
|
||||
@@ -260,6 +283,7 @@ class MangaSourcesRepository @Inject constructor(
|
||||
sortOrder: SourcesSortOrder?,
|
||||
): MutableList<MangaSource> {
|
||||
val result = ArrayList<MangaSource>(size)
|
||||
val pinned = EnumSet.noneOf(MangaSource::class.java)
|
||||
for (entity in this) {
|
||||
val source = entity.source.toMangaSourceOrNull() ?: continue
|
||||
if (skipNsfwSources && source.isNsfw()) {
|
||||
@@ -267,10 +291,13 @@ class MangaSourcesRepository @Inject constructor(
|
||||
}
|
||||
if (source in remoteSources) {
|
||||
result.add(source)
|
||||
if (entity.isPinned) {
|
||||
pinned.add(source)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sortOrder == SourcesSortOrder.ALPHABETIC) {
|
||||
result.sortBy { it.title }
|
||||
result.sortWith(compareBy<MangaSource> { it in pinned }.thenBy { it.title })
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -196,6 +196,16 @@ class ExploreFragment :
|
||||
mode.finish()
|
||||
}
|
||||
|
||||
R.id.action_pin -> {
|
||||
viewModel.setSourcesPinned(selectedSources, isPinned = true)
|
||||
mode.finish()
|
||||
}
|
||||
|
||||
R.id.action_unpin -> {
|
||||
viewModel.setSourcesPinned(selectedSources, isPinned = false)
|
||||
mode.finish()
|
||||
}
|
||||
|
||||
else -> return false
|
||||
}
|
||||
return true
|
||||
|
||||
@@ -108,6 +108,18 @@ class ExploreViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun setSourcesPinned(sources: Set<MangaSource>, isPinned: Boolean) {
|
||||
launchJob(Dispatchers.Default) {
|
||||
sourcesRepository.setIsPinned(sources, isPinned)
|
||||
val message = if (sources.size == 1) {
|
||||
if (isPinned) R.string.source_pinned else R.string.source_unpinned
|
||||
} else {
|
||||
if (isPinned) R.string.sources_pinned else R.string.sources_unpinned
|
||||
}
|
||||
onActionDone.call(ReversibleAction(message, null))
|
||||
}
|
||||
}
|
||||
|
||||
fun respondSuggestionTip(isAccepted: Boolean) {
|
||||
settings.isSuggestionsEnabled = isAccepted
|
||||
settings.closeTip(TIP_SUGGESTIONS)
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.koitharu.kotatsu.settings.sources.adapter
|
||||
|
||||
import android.view.View
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.pm.ShortcutManagerCompat
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
@@ -16,49 +17,14 @@ import org.koitharu.kotatsu.core.parser.favicon.faviconUri
|
||||
import org.koitharu.kotatsu.core.ui.image.FaviconDrawable
|
||||
import org.koitharu.kotatsu.core.ui.list.OnTipCloseListener
|
||||
import org.koitharu.kotatsu.core.util.ext.crossfade
|
||||
import org.koitharu.kotatsu.core.util.ext.drawableStart
|
||||
import org.koitharu.kotatsu.core.util.ext.enqueueWith
|
||||
import org.koitharu.kotatsu.core.util.ext.newImageRequest
|
||||
import org.koitharu.kotatsu.core.util.ext.source
|
||||
import org.koitharu.kotatsu.databinding.ItemSourceConfigBinding
|
||||
import org.koitharu.kotatsu.databinding.ItemSourceConfigCheckableBinding
|
||||
import org.koitharu.kotatsu.databinding.ItemTipBinding
|
||||
import org.koitharu.kotatsu.settings.sources.model.SourceConfigItem
|
||||
|
||||
fun sourceConfigItemCheckableDelegate(
|
||||
listener: SourceConfigListener,
|
||||
coil: ImageLoader,
|
||||
lifecycleOwner: LifecycleOwner,
|
||||
) = adapterDelegateViewBinding<SourceConfigItem.SourceItem, SourceConfigItem, ItemSourceConfigCheckableBinding>(
|
||||
{ layoutInflater, parent ->
|
||||
ItemSourceConfigCheckableBinding.inflate(
|
||||
layoutInflater,
|
||||
parent,
|
||||
false,
|
||||
)
|
||||
},
|
||||
) {
|
||||
|
||||
binding.switchToggle.setOnCheckedChangeListener { _, isChecked ->
|
||||
listener.onItemEnabledChanged(item, isChecked)
|
||||
}
|
||||
|
||||
bind {
|
||||
binding.textViewTitle.text = item.source.getTitle(context)
|
||||
binding.switchToggle.isChecked = item.isEnabled
|
||||
binding.switchToggle.isEnabled = item.isAvailable
|
||||
binding.textViewDescription.text = item.source.getSummary(context)
|
||||
val fallbackIcon = FaviconDrawable(context, R.style.FaviconDrawable_Small, item.source.name)
|
||||
binding.imageViewIcon.newImageRequest(lifecycleOwner, item.source.faviconUri())?.run {
|
||||
crossfade(context)
|
||||
error(fallbackIcon)
|
||||
placeholder(fallbackIcon)
|
||||
fallback(fallbackIcon)
|
||||
source(item.source)
|
||||
enqueueWith(coil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun sourceConfigItemDelegate2(
|
||||
listener: SourceConfigListener,
|
||||
coil: ImageLoader,
|
||||
@@ -73,6 +39,7 @@ fun sourceConfigItemDelegate2(
|
||||
},
|
||||
) {
|
||||
|
||||
val iconPinned = ContextCompat.getDrawable(context, R.drawable.ic_pin_small)
|
||||
val eventListener = View.OnClickListener { v ->
|
||||
when (v.id) {
|
||||
R.id.imageView_add -> listener.onItemEnabledChanged(item, true)
|
||||
@@ -89,6 +56,7 @@ fun sourceConfigItemDelegate2(
|
||||
binding.imageViewAdd.isGone = item.isEnabled || !item.isAvailable
|
||||
binding.imageViewRemove.isVisible = item.isEnabled
|
||||
binding.imageViewMenu.isVisible = item.isEnabled
|
||||
binding.textViewTitle.drawableStart = if (item.isPinned) iconPinned else null
|
||||
binding.textViewDescription.text = item.source.getSummary(context)
|
||||
val fallbackIcon = FaviconDrawable(context, R.style.FaviconDrawable_Small, item.source.name)
|
||||
binding.imageViewIcon.newImageRequest(lifecycleOwner, item.source.faviconUri())?.run {
|
||||
@@ -132,12 +100,15 @@ private fun showSourceMenu(
|
||||
menu.inflate(R.menu.popup_source_config)
|
||||
menu.menu.findItem(R.id.action_shortcut)
|
||||
?.isVisible = ShortcutManagerCompat.isRequestPinShortcutSupported(anchor.context)
|
||||
menu.menu.findItem(R.id.action_pin)?.isVisible = item.isEnabled
|
||||
menu.menu.findItem(R.id.action_pin)?.isChecked = item.isPinned
|
||||
menu.menu.findItem(R.id.action_lift)?.isVisible = item.isDraggable
|
||||
menu.setOnMenuItemClickListener {
|
||||
when (it.itemId) {
|
||||
R.id.action_settings -> listener.onItemSettingsClick(item)
|
||||
R.id.action_lift -> listener.onItemLiftClick(item)
|
||||
R.id.action_shortcut -> listener.onItemShortcutClick(item)
|
||||
R.id.action_pin -> listener.onItemPinClick(item)
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
@@ -11,5 +11,7 @@ interface SourceConfigListener : OnTipCloseListener<SourceConfigItem.Tip> {
|
||||
|
||||
fun onItemShortcutClick(item: SourceConfigItem.SourceItem)
|
||||
|
||||
fun onItemPinClick(item: SourceConfigItem.SourceItem)
|
||||
|
||||
fun onItemEnabledChanged(item: SourceConfigItem.SourceItem, isEnabled: Boolean)
|
||||
}
|
||||
|
||||
@@ -61,6 +61,7 @@ class SourcesListProducer @Inject constructor(
|
||||
|
||||
private suspend fun buildList(): List<SourceConfigItem> {
|
||||
val enabledSources = repository.getEnabledSources()
|
||||
val pinned = repository.getPinnedSources()
|
||||
val isNsfwDisabled = settings.isNsfwContentDisabled
|
||||
val isReorderAvailable = settings.sourcesSortOrder == SourcesSortOrder.MANUAL
|
||||
val withTip = isReorderAvailable && settings.isTipEnabled(TIP_REORDER)
|
||||
@@ -75,6 +76,7 @@ class SourcesListProducer @Inject constructor(
|
||||
isEnabled = it in enabledSet,
|
||||
isDraggable = false,
|
||||
isAvailable = !isNsfwDisabled || !it.isNsfw(),
|
||||
isPinned = it in pinned,
|
||||
)
|
||||
}.ifEmpty {
|
||||
listOf(SourceConfigItem.EmptySearchResult)
|
||||
@@ -95,6 +97,7 @@ class SourcesListProducer @Inject constructor(
|
||||
isEnabled = true,
|
||||
isDraggable = isReorderAvailable,
|
||||
isAvailable = false,
|
||||
isPinned = it in pinned,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,6 +120,10 @@ class SourcesManageFragment :
|
||||
}
|
||||
}
|
||||
|
||||
override fun onItemPinClick(item: SourceConfigItem.SourceItem) {
|
||||
viewModel.setPinned(item.source, !item.isPinned)
|
||||
}
|
||||
|
||||
override fun onItemEnabledChanged(item: SourceConfigItem.SourceItem, isEnabled: Boolean) {
|
||||
viewModel.setEnabled(item.source, isEnabled)
|
||||
}
|
||||
|
||||
@@ -58,8 +58,9 @@ class SourcesManageViewModel @Inject constructor(
|
||||
|
||||
fun canReorder(oldPos: Int, newPos: Int): Boolean {
|
||||
val snapshot = content.value
|
||||
if ((snapshot[oldPos] as? SourceConfigItem.SourceItem)?.isEnabled != true) return false
|
||||
return (snapshot[newPos] as? SourceConfigItem.SourceItem)?.isEnabled == true
|
||||
val oldPosItem = snapshot.getOrNull(oldPos) as? SourceConfigItem.SourceItem ?: return false
|
||||
val newPosItem = snapshot.getOrNull(newPos) as? SourceConfigItem.SourceItem ?: return false
|
||||
return oldPosItem.isEnabled && newPosItem.isEnabled && oldPosItem.isPinned == newPosItem.isPinned
|
||||
}
|
||||
|
||||
fun setEnabled(source: MangaSource, isEnabled: Boolean) {
|
||||
@@ -71,6 +72,14 @@ class SourcesManageViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun setPinned(source: MangaSource, isPinned: Boolean) {
|
||||
launchJob(Dispatchers.Default) {
|
||||
val rollback = repository.setIsPinned(setOf(source), isPinned)
|
||||
val message = if (isPinned) R.string.source_pinned else R.string.source_unpinned
|
||||
onActionDone.call(ReversibleAction(message, rollback))
|
||||
}
|
||||
}
|
||||
|
||||
fun bringToTop(source: MangaSource) {
|
||||
val snapshot = content.value
|
||||
launchJob(Dispatchers.Default) {
|
||||
|
||||
@@ -13,6 +13,7 @@ sealed interface SourceConfigItem : ListModel {
|
||||
val isEnabled: Boolean,
|
||||
val isDraggable: Boolean,
|
||||
val isAvailable: Boolean,
|
||||
val isPinned: Boolean,
|
||||
) : SourceConfigItem {
|
||||
|
||||
val isNsfw: Boolean
|
||||
|
||||
12
app/src/main/res/drawable/ic_pin_small.xml
Normal file
12
app/src/main/res/drawable/ic_pin_small.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="14dp"
|
||||
android:height="14dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M16,12V4H17V2H7V4H8V12L6,14V16H11.2V22H12.8V16H18V14L16,12Z" />
|
||||
</vector>
|
||||
@@ -6,6 +6,6 @@
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M19.43 12.98c0.04-0.32 0.07-0.64 0.07-0.98 0-0.34-0.03-0.66-0.07-0.98l2.11-1.65c0.19-0.15 0.24-0.42 0.12-0.64l-2-3.46c-0.09-0.16-0.26-0.25-0.44-0.25-0.06 0-0.12 0.01-0.17 0.03l-2.49 1c-0.52-0.4-1.08-0.73-1.69-0.98l-0.38-2.65C14.46 2.18 14.25 2 14 2h-4C9.75 2 9.54 2.18 9.51 2.42L9.13 5.07C8.52 5.32 7.96 5.66 7.44 6.05l-2.49-1C4.89 5.03 4.83 5.02 4.77 5.02c-0.17 0-0.34 0.09-0.43 0.25l-2 3.46C2.21 8.95 2.27 9.22 2.46 9.37l2.11 1.65C4.53 11.34 4.5 11.67 4.5 12c0 0.33 0.03 0.66 0.07 0.98l-2.11 1.65c-0.19 0.15-0.24 0.42-0.12 0.64l2 3.46c0.09 0.16 0.26 0.25 0.44 0.25 0.06 0 0.12-0.01 0.17-0.03l2.49-1c0.52 0.4 1.08 0.73 1.69 0.98l0.38 2.65C9.54 21.82 9.75 22 10 22h4c0.25 0 0.46-0.18 0.49-0.42l0.38-2.65c0.61-0.25 1.17-0.59 1.69-0.98l2.49 1c0.06 0.02 0.12 0.03 0.18 0.03 0.17 0 0.34-0.09 0.43-0.25l2-3.46c0.12-0.22 0.07-0.49-0.12-0.64l-2.11-1.65zm-1.98-1.71c0.04 0.31 0.05 0.52 0.05 0.73 0 0.21-0.02 0.43-0.05 0.73l-0.14 1.13 0.89 0.7 1.08 0.84-0.7 1.21-1.27-0.51-1.04-0.42-0.9 0.68c-0.43 0.32-0.84 0.56-1.25 0.73l-1.06 0.43-0.16 1.13L12.7 20h-1.4l-0.19-1.35-0.16-1.13-1.06-0.43c-0.43-0.18-0.83-0.41-1.23-0.71l-0.91-0.7-1.06 0.43-1.27 0.51-0.7-1.21 1.08-0.84 0.89-0.7-0.14-1.13C6.52 12.43 6.5 12.2 6.5 12s0.02-0.43 0.05-0.73l0.14-1.13-0.89-0.7L4.72 8.6l0.7-1.21L6.69 7.9l1.04 0.42 0.9-0.68c0.43-0.32 0.84-0.56 1.25-0.73l1.06-0.43 0.16-1.13L11.3 4h1.39l0.19 1.35 0.16 1.13 1.06 0.43c0.43 0.18 0.83 0.41 1.23 0.71l0.91 0.7 1.06-0.43 1.27-0.51 0.7 1.21-1.07 0.85-0.89 0.7 0.14 1.13zM12 8c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm0 6c-1.1 0-2-0.9-2-2s0.9-2 2-2 2 0.9 2 2-0.9 2-2 2z" />
|
||||
</vector>
|
||||
|
||||
12
app/src/main/res/drawable/ic_shortcut.xml
Normal file
12
app/src/main/res/drawable/ic_shortcut.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="M14,14.5V12H10V15H8V11A1,1 0 0,1 9,10H14V7.5L17.5,11M21.71,11.29L12.71,2.29H12.7C12.31,1.9 11.68,1.9 11.29,2.29L2.29,11.29C1.9,11.68 1.9,12.32 2.29,12.71L11.29,21.71C11.68,22.09 12.31,22.1 12.71,21.71L21.71,12.71C22.1,12.32 22.1,11.68 21.71,11.29Z" />
|
||||
</vector>
|
||||
12
app/src/main/res/drawable/ic_unpin.xml
Normal file
12
app/src/main/res/drawable/ic_unpin.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="M8,6.2V4H7V2H17V4H16V12L18,14V16H17.8L14,12.2V4H10V8.2L8,6.2M20,20.7L18.7,22L12.8,16.1V22H11.2V16H6V14L8,12V11.3L2,5.3L3.3,4L20,20.7M8.8,14H10.6L9.7,13.1L8.8,14Z" />
|
||||
</vector>
|
||||
@@ -35,9 +35,11 @@
|
||||
android:id="@+id/textView_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawablePadding="4dp"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="?attr/textAppearanceTitleSmall"
|
||||
tools:drawableStart="@drawable/ic_pin_small"
|
||||
tools:text="@tools:sample/lorem[15]" />
|
||||
|
||||
<TextView
|
||||
|
||||
@@ -11,10 +11,22 @@
|
||||
|
||||
<item
|
||||
android:id="@+id/action_shortcut"
|
||||
android:icon="@drawable/ic_pin"
|
||||
android:icon="@drawable/ic_shortcut"
|
||||
android:title="@string/create_shortcut"
|
||||
app:showAsAction="ifRoom|withText" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_pin"
|
||||
android:icon="@drawable/ic_pin"
|
||||
android:title="@string/pin"
|
||||
app:showAsAction="ifRoom|withText" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_unpin"
|
||||
android:icon="@drawable/ic_unpin"
|
||||
android:title="@string/unpin"
|
||||
app:showAsAction="ifRoom|withText" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_settings"
|
||||
android:icon="@drawable/ic_settings"
|
||||
|
||||
@@ -6,6 +6,11 @@
|
||||
android:id="@+id/action_lift"
|
||||
android:title="@string/to_top" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_pin"
|
||||
android:checkable="true"
|
||||
android:title="@string/pin" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_shortcut"
|
||||
android:title="@string/create_shortcut" />
|
||||
|
||||
@@ -657,4 +657,10 @@
|
||||
<string name="image_server">Preferred image server</string>
|
||||
<string name="inline_preference_pattern" translatable="false">%1$s: %2$s</string>
|
||||
<string name="crop_pages">Crop pages</string>
|
||||
<string name="pin">Pin</string>
|
||||
<string name="unpin">Unpin</string>
|
||||
<string name="source_pinned">Source pinned</string>
|
||||
<string name="source_unpinned">Source unpinned</string>
|
||||
<string name="sources_unpinned">Sources unpinned</string>
|
||||
<string name="sources_pinned">Sources pinned</string>
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user