mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-11-20 04:29:18 +01:00
Change sorting order of installed extensions
Default is Name Other options are Recently updated, Recently installed, and Language
This commit is contained in:
parent
fa80fa94a0
commit
7e812f9530
@ -152,6 +152,8 @@ object PreferenceKeys {
|
||||
|
||||
const val automaticExtUpdates = "automatic_ext_updates"
|
||||
|
||||
const val installedExtensionsOrder = "installed_extensions_order"
|
||||
|
||||
const val autoHideHopper = "autohide_hopper"
|
||||
|
||||
const val hopperLongPress = "hopper_long_press"
|
||||
|
@ -14,6 +14,7 @@ import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.track.TrackService
|
||||
import eu.kanade.tachiyomi.data.updater.AutoUpdaterJob
|
||||
import eu.kanade.tachiyomi.extension.model.InstalledExtensionsOrder
|
||||
import eu.kanade.tachiyomi.ui.library.filter.FilterBottomSheet
|
||||
import eu.kanade.tachiyomi.ui.reader.settings.OrientationType
|
||||
import eu.kanade.tachiyomi.ui.reader.settings.PageLayout
|
||||
@ -297,6 +298,8 @@ class PreferencesHelper(val context: Context) {
|
||||
|
||||
fun automaticExtUpdates() = flowPrefs.getBoolean(Keys.automaticExtUpdates, true)
|
||||
|
||||
fun installedExtensionsOrder() = flowPrefs.getInt(Keys.installedExtensionsOrder, InstalledExtensionsOrder.Name.value)
|
||||
|
||||
fun collapsedCategories() = rxPrefs.getStringSet("collapsed_categories", mutableSetOf())
|
||||
|
||||
fun collapsedDynamicCategories() = flowPrefs.getStringSet("collapsed_dynamic_categories", mutableSetOf())
|
||||
|
@ -0,0 +1,18 @@
|
||||
package eu.kanade.tachiyomi.extension.model
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
|
||||
enum class InstalledExtensionsOrder(val value: Int, @StringRes val nameRes: Int) {
|
||||
Name(0, R.string.name),
|
||||
RecentlyUpdated(1, R.string.recently_updated),
|
||||
RecentlyInstalled(2, R.string.recently_installed),
|
||||
Language(3, R.string.language),
|
||||
;
|
||||
|
||||
companion object {
|
||||
fun fromValue(preference: Int) = values().find { it.value == preference } ?: Name
|
||||
fun fromPreference(pref: PreferencesHelper) = fromValue(pref.installedExtensionsOrder().get())
|
||||
}
|
||||
}
|
@ -1,8 +1,11 @@
|
||||
package eu.kanade.tachiyomi.ui.extension
|
||||
|
||||
import android.widget.TextView
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.IFlexible
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.ui.extension.ExtensionAdapter.OnButtonClickListener
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
/**
|
||||
* Adapter that holds the catalogue cards.
|
||||
@ -12,6 +15,10 @@ import eu.kanade.tachiyomi.ui.extension.ExtensionAdapter.OnButtonClickListener
|
||||
class ExtensionAdapter(val listener: OnButtonClickListener) :
|
||||
FlexibleAdapter<IFlexible<*>>(null, listener, true) {
|
||||
|
||||
val preferences: PreferencesHelper by injectLazy()
|
||||
|
||||
var installedSortOrder = preferences.installedExtensionsOrder().get()
|
||||
|
||||
init {
|
||||
setDisplayHeadersAtStartUp(true)
|
||||
}
|
||||
@ -25,5 +32,6 @@ class ExtensionAdapter(val listener: OnButtonClickListener) :
|
||||
fun onButtonClick(position: Int)
|
||||
fun onCancelClick(position: Int)
|
||||
fun onUpdateAllClicked(position: Int)
|
||||
fun onExtSortClicked(view: TextView, position: Int)
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import eu.kanade.tachiyomi.extension.ExtensionManager
|
||||
import eu.kanade.tachiyomi.extension.ExtensionsChangedListener
|
||||
import eu.kanade.tachiyomi.extension.model.Extension
|
||||
import eu.kanade.tachiyomi.extension.model.InstallStep
|
||||
import eu.kanade.tachiyomi.extension.model.InstalledExtensionsOrder
|
||||
import eu.kanade.tachiyomi.source.LocalSource
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
@ -24,7 +25,6 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
@ -181,11 +181,25 @@ class ExtensionBottomPresenter(
|
||||
|
||||
val items = mutableListOf<ExtensionItem>()
|
||||
|
||||
val updatesSorted = installed.filter { it.hasUpdate && (showNsfwExtensions || !it.isNsfw) }.sortedBy { it.pkgName }
|
||||
val updatesSorted = installed.filter { it.hasUpdate && (showNsfwExtensions || !it.isNsfw) }.sortedBy { it.name }
|
||||
val sortOrder = InstalledExtensionsOrder.fromPreference(preferences)
|
||||
val installedSorted = installed
|
||||
.filter { !it.hasUpdate && (showNsfwExtensions || !it.isNsfw) }
|
||||
.sortedWith(compareBy({ !it.isObsolete }, { it.pkgName }))
|
||||
val untrustedSorted = untrusted.sortedBy { it.pkgName }
|
||||
.sortedWith(
|
||||
compareBy(
|
||||
{ !it.isObsolete },
|
||||
{
|
||||
when (sortOrder) {
|
||||
InstalledExtensionsOrder.Name -> it.name
|
||||
InstalledExtensionsOrder.RecentlyUpdated -> Long.MAX_VALUE - extensionUpdateDate(it.pkgName)
|
||||
InstalledExtensionsOrder.RecentlyInstalled -> Long.MAX_VALUE - extensionInstallDate(it.pkgName)
|
||||
InstalledExtensionsOrder.Language -> it.lang
|
||||
}
|
||||
},
|
||||
{ it.name }
|
||||
)
|
||||
)
|
||||
val untrustedSorted = untrusted.sortedBy { it.name }
|
||||
val availableSorted = available
|
||||
// Filter out already installed extensions and disabled languages
|
||||
.filter { avail ->
|
||||
@ -194,7 +208,7 @@ class ExtensionBottomPresenter(
|
||||
(avail.lang in activeLangs || avail.lang == "all") &&
|
||||
(showNsfwExtensions || !avail.isNsfw)
|
||||
}
|
||||
.sortedBy { it.pkgName }
|
||||
.sortedBy { it.name }
|
||||
|
||||
if (updatesSorted.isNotEmpty()) {
|
||||
val header = ExtensionGroupItem(
|
||||
@ -211,7 +225,7 @@ class ExtensionBottomPresenter(
|
||||
}
|
||||
}
|
||||
if (installedSorted.isNotEmpty() || untrustedSorted.isNotEmpty()) {
|
||||
val header = ExtensionGroupItem(context.getString(R.string.installed), installedSorted.size + untrustedSorted.size)
|
||||
val header = ExtensionGroupItem(context.getString(R.string.installed), installedSorted.size + untrustedSorted.size, installedSorting = preferences.installedExtensionsOrder().get())
|
||||
items += installedSorted.map { extension ->
|
||||
ExtensionItem(extension, header, currentDownloads[extension.pkgName])
|
||||
}
|
||||
@ -237,8 +251,25 @@ class ExtensionBottomPresenter(
|
||||
return items
|
||||
}
|
||||
|
||||
private fun extensionInstallDate(pkgName: String): Long {
|
||||
val context = bottomSheet.context
|
||||
return try {
|
||||
context.packageManager.getPackageInfo(pkgName, 0).firstInstallTime
|
||||
} catch (e: java.lang.Exception) {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
private fun extensionUpdateDate(pkgName: String): Long {
|
||||
val context = bottomSheet.context
|
||||
return try {
|
||||
context.packageManager.getPackageInfo(pkgName, 0).lastUpdateTime
|
||||
} catch (e: java.lang.Exception) {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
fun getExtensionUpdateCount(): Int = preferences.extensionUpdatesCount().getOrDefault()
|
||||
fun getAutoCheckPref() = preferences.automaticExtUpdates()
|
||||
|
||||
@Synchronized
|
||||
private fun updateInstallStep(
|
||||
|
@ -6,6 +6,7 @@ import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
@ -18,6 +19,7 @@ import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||
import eu.kanade.tachiyomi.databinding.ExtensionsBottomSheetBinding
|
||||
import eu.kanade.tachiyomi.databinding.RecyclerWithScrollerBinding
|
||||
import eu.kanade.tachiyomi.extension.model.Extension
|
||||
import eu.kanade.tachiyomi.extension.model.InstalledExtensionsOrder
|
||||
import eu.kanade.tachiyomi.ui.extension.details.ExtensionDetailsController
|
||||
import eu.kanade.tachiyomi.ui.migration.MangaAdapter
|
||||
import eu.kanade.tachiyomi.ui.migration.MangaItem
|
||||
@ -30,6 +32,7 @@ import eu.kanade.tachiyomi.util.view.collapse
|
||||
import eu.kanade.tachiyomi.util.view.doOnApplyWindowInsets
|
||||
import eu.kanade.tachiyomi.util.view.expand
|
||||
import eu.kanade.tachiyomi.util.view.isExpanded
|
||||
import eu.kanade.tachiyomi.util.view.popupMenu
|
||||
import eu.kanade.tachiyomi.util.view.smoothScrollToTop
|
||||
import eu.kanade.tachiyomi.util.view.updatePaddingRelative
|
||||
import eu.kanade.tachiyomi.util.view.withFadeTransaction
|
||||
@ -217,6 +220,18 @@ class ExtensionBottomSheet @JvmOverloads constructor(context: Context, attrs: At
|
||||
}
|
||||
}
|
||||
|
||||
override fun onExtSortClicked(view: TextView, position: Int) {
|
||||
view.popupMenu(
|
||||
InstalledExtensionsOrder.values().map { it.value to it.nameRes },
|
||||
presenter.preferences.installedExtensionsOrder().get()
|
||||
) {
|
||||
presenter.preferences.installedExtensionsOrder().set(itemId)
|
||||
extAdapter?.installedSortOrder = itemId
|
||||
view.setText(InstalledExtensionsOrder.fromValue(itemId).nameRes)
|
||||
presenter.refreshExtensions()
|
||||
}
|
||||
}
|
||||
|
||||
fun updateAllExtensions(position: Int) {
|
||||
val header = (extAdapter?.getSectionHeader(position)) as? ExtensionGroupItem ?: return
|
||||
val items = extAdapter?.getSectionItemPositions(header)
|
||||
|
@ -8,6 +8,7 @@ import androidx.recyclerview.widget.RecyclerView
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.IFlexible
|
||||
import eu.kanade.tachiyomi.databinding.ExtensionCardHeaderBinding
|
||||
import eu.kanade.tachiyomi.extension.model.InstalledExtensionsOrder
|
||||
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
|
||||
|
||||
class ExtensionGroupHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>) :
|
||||
@ -19,6 +20,9 @@ class ExtensionGroupHolder(view: View, adapter: FlexibleAdapter<IFlexible<Recycl
|
||||
binding.extButton.setOnClickListener {
|
||||
(adapter as? ExtensionAdapter)?.listener?.onUpdateAllClicked(bindingAdapterPosition)
|
||||
}
|
||||
binding.extSort.setOnClickListener {
|
||||
(adapter as? ExtensionAdapter)?.listener?.onExtSortClicked(binding.extSort, bindingAdapterPosition)
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
@ -26,5 +30,9 @@ class ExtensionGroupHolder(view: View, adapter: FlexibleAdapter<IFlexible<Recycl
|
||||
binding.title.text = item.name
|
||||
binding.extButton.isVisible = item.canUpdate != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
|
||||
binding.extButton.isEnabled = item.canUpdate == true
|
||||
binding.extSort.isVisible = item.installedSorting != null
|
||||
binding.extSort.setText(InstalledExtensionsOrder.fromValue(item.installedSorting ?: 0).nameRes)
|
||||
binding.extSort.post {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ import eu.kanade.tachiyomi.R
|
||||
* @param name The header name.
|
||||
* @param size The number of items in the group.
|
||||
*/
|
||||
data class ExtensionGroupItem(val name: String, val size: Int, var canUpdate: Boolean? = null) : AbstractHeaderItem<ExtensionGroupHolder>() {
|
||||
data class ExtensionGroupItem(val name: String, val size: Int, var canUpdate: Boolean? = null, var installedSorting: Int? = null) : AbstractHeaderItem<ExtensionGroupHolder>() {
|
||||
|
||||
/**
|
||||
* Returns the layout resource of this item.
|
||||
|
@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.ui.extension
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Color
|
||||
import android.view.View
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import coil.clear
|
||||
import coil.load
|
||||
@ -14,6 +15,8 @@ import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||
import eu.kanade.tachiyomi.data.image.coil.CoverViewTarget
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.databinding.ExtensionCardItemBinding
|
||||
import eu.kanade.tachiyomi.extension.model.InstalledExtensionsOrder
|
||||
import eu.kanade.tachiyomi.util.system.timeSpanFromNow
|
||||
import eu.kanade.tachiyomi.util.view.resetStrokeColor
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
@ -41,7 +44,34 @@ class ExtensionHolder(view: View, val adapter: ExtensionAdapter) :
|
||||
|
||||
// Set source name
|
||||
binding.extTitle.text = extension.name
|
||||
binding.version.text = extension.versionName
|
||||
|
||||
val infoText = mutableListOf(extension.versionName)
|
||||
if (extension is Extension.Installed) {
|
||||
when (InstalledExtensionsOrder.fromValue(adapter.installedSortOrder)) {
|
||||
InstalledExtensionsOrder.RecentlyUpdated -> {
|
||||
binding.date.isVisible = true
|
||||
binding.date.text = itemView.context.getString(
|
||||
R.string.updated_,
|
||||
extensionUpdateDate(extension.pkgName).timeSpanFromNow
|
||||
)
|
||||
infoText.add("")
|
||||
}
|
||||
InstalledExtensionsOrder.RecentlyInstalled -> {
|
||||
binding.date.isVisible = true
|
||||
binding.date.text = itemView.context.getString(
|
||||
R.string.installed_,
|
||||
extensionInstallDate(extension.pkgName).timeSpanFromNow
|
||||
)
|
||||
infoText.add("")
|
||||
}
|
||||
else -> binding.date.isVisible = false
|
||||
}
|
||||
} else {
|
||||
binding.date.isVisible = false
|
||||
}
|
||||
binding.lang.isVisible = binding.date.isGone
|
||||
|
||||
binding.version.text = infoText.joinToString(" • ")
|
||||
binding.lang.text = LocaleHelper.getDisplayName(extension.lang)
|
||||
binding.warning.text = when {
|
||||
extension is Extension.Untrusted -> itemView.context.getString(R.string.untrusted)
|
||||
@ -113,4 +143,22 @@ class ExtensionHolder(view: View, val adapter: ExtensionAdapter) :
|
||||
setText(R.string.install)
|
||||
}
|
||||
}
|
||||
|
||||
private fun extensionInstallDate(pkgName: String): Long {
|
||||
val context = itemView.context
|
||||
return try {
|
||||
context.packageManager.getPackageInfo(pkgName, 0).firstInstallTime
|
||||
} catch (e: java.lang.Exception) {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
private fun extensionUpdateDate(pkgName: String): Long {
|
||||
val context = itemView.context
|
||||
return try {
|
||||
context.packageManager.getPackageInfo(pkgName, 0).lastUpdateTime
|
||||
} catch (e: java.lang.Exception) {
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,7 @@
|
||||
android:textAllCaps="false"
|
||||
android:textColor="@color/accent_text_btn_color_selector"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"
|
||||
tools:visibility="gone"
|
||||
app:layout_constraintBaseline_toBaselineOf="@id/title"
|
||||
app:layout_constraintBottom_toBottomOf="@id/title"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
@ -43,6 +43,34 @@
|
||||
app:rippleColor="@color/fullRippleColor"
|
||||
android:text="@string/update_all" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/ext_sort"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:background="@drawable/square_ripple"
|
||||
android:clickable="true"
|
||||
android:drawablePadding="6dp"
|
||||
app:drawableTint="?android:textColorPrimary"
|
||||
android:ellipsize="start"
|
||||
android:focusable="true"
|
||||
android:gravity="center|end"
|
||||
android:maxLines="2"
|
||||
android:padding="6dp"
|
||||
android:textAlignment="textEnd"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Body2"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="normal"
|
||||
app:layout_constraintBaseline_toBaselineOf="@id/title"
|
||||
app:layout_constraintBottom_toBottomOf="@id/title"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="1.0"
|
||||
app:layout_constraintStart_toEndOf="@id/title"
|
||||
app:layout_constraintTop_toTopOf="@id/title"
|
||||
tools:text="Recently Updated"
|
||||
app:drawableEndCompat="@drawable/ic_sort_24dp" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</FrameLayout>
|
||||
|
@ -49,7 +49,7 @@
|
||||
android:maxLines="1"
|
||||
android:textAppearance="@style/TextAppearance.Regular.SubHeading"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintBottom_toTopOf="@id/lang"
|
||||
app:layout_constraintBottom_toTopOf="@id/version"
|
||||
app:layout_constraintEnd_toStartOf="@id/button_layout"
|
||||
app:layout_constraintStart_toEndOf="@id/source_image"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
@ -63,8 +63,13 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="1"
|
||||
android:textSize="12sp"
|
||||
android:layout_marginEnd="4dp"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintVertical_bias="0.0"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/source_image"
|
||||
app:layout_constraintEnd_toStartOf="@id/version"
|
||||
app:layout_constraintTop_toBottomOf="@+id/ext_title"
|
||||
tools:text="English"
|
||||
tools:visibility="visible" />
|
||||
@ -74,13 +79,28 @@
|
||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="middle"
|
||||
android:textSize="12sp"
|
||||
app:layout_constraintBaseline_toBaselineOf="@id/lang"
|
||||
app:layout_constraintTop_toBottomOf="@+id/ext_title"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/lang"
|
||||
tools:text="Version" />
|
||||
app:layout_constraintEnd_toStartOf="@id/date"
|
||||
tools:text="Version • " />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/date"
|
||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="start"
|
||||
app:layout_constrainedWidth="true"
|
||||
android:textSize="12sp"
|
||||
app:layout_constraintTop_toBottomOf="@+id/ext_title"
|
||||
app:layout_constraintStart_toEndOf="@id/version"
|
||||
app:layout_constraintEnd_toStartOf="@id/warning"
|
||||
tools:text="Updated 5 days ago" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/warning"
|
||||
@ -91,8 +111,11 @@
|
||||
android:maxLines="1"
|
||||
android:textColor="?attr/colorError"
|
||||
android:textSize="12sp"
|
||||
app:layout_constraintStart_toEndOf="@id/version"
|
||||
android:layout_marginEnd="6dp"
|
||||
app:layout_constraintEnd_toStartOf="@id/button_layout"
|
||||
app:layout_constraintTop_toBottomOf="@+id/ext_title"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toEndOf="@id/date"
|
||||
tools:text="Warning" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
|
@ -312,6 +312,7 @@
|
||||
<string name="version_">Version: %1$s</string>
|
||||
<string name="language_">Language: %1$s</string>
|
||||
<string name="nsfw_short">18+</string>
|
||||
<string name="installed_">Installed %1$s</string>
|
||||
<string name="unofficial">Unofficial</string>
|
||||
<string name="extensions_miui_warning">MIUI Optimization must be disabled to install extensions.</string>
|
||||
<string name="may_contain_nsfw">May contain NSFW (18+) content</string>
|
||||
@ -963,6 +964,9 @@
|
||||
<string name="move_to_top">Move to top</string>
|
||||
<string name="move_to_">Move to %1$s</string>
|
||||
<string name="moved_to_">Moved to %1$s</string>
|
||||
<string name="name">Name</string>
|
||||
<string name="recently_updated">Recently updated</string>
|
||||
<string name="recently_installed">Recently installed</string>
|
||||
<string name="never">Never</string>
|
||||
<string name="newest">Newest</string>
|
||||
<string name="next">Next</string>
|
||||
|
Loading…
Reference in New Issue
Block a user