Compare commits
17 Commits
2310ed06c1
...
36a74f32df
| Author | SHA1 | Date | |
|---|---|---|---|
|
36a74f32df
|
|||
|
0e4ef32642
|
|||
|
3125cac4c8
|
|||
|
5d9016d1bc
|
|||
| c5eeb89d10 | |||
|
|
4f8f43cab1 | ||
|
|
4cbff308ce | ||
|
|
d786ab7deb | ||
|
|
c823d402ff | ||
|
|
12e68db41f | ||
|
|
96717321d2 | ||
|
|
044b5590ef | ||
|
|
00112ebb44 | ||
|
00dde80fdf
|
|||
|
f1dfc4ebd6
|
|||
|
5426edd83a
|
|||
|
2a500eb2cb
|
@@ -16,8 +16,8 @@ android {
|
||||
applicationId 'org.koitharu.kotatsu'
|
||||
minSdk = 21
|
||||
targetSdk = 34
|
||||
versionCode = 621
|
||||
versionName = '6.7-b1'
|
||||
versionCode = 622
|
||||
versionName = '6.7'
|
||||
generatedDensities = []
|
||||
testInstrumentationRunner 'org.koitharu.kotatsu.HiltTestRunner'
|
||||
ksp {
|
||||
@@ -82,7 +82,7 @@ afterEvaluate {
|
||||
}
|
||||
dependencies {
|
||||
//noinspection GradleDependency
|
||||
implementation('com.github.KotatsuApp:kotatsu-parsers:4a8c7fa36a') {
|
||||
implementation('com.github.KotatsuApp:kotatsu-parsers:014ea5ef49') {
|
||||
exclude group: 'org.json', module: 'json'
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ dependencies {
|
||||
|
||||
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
|
||||
implementation 'com.squareup.okhttp3:okhttp-dnsoverhttps:4.12.0'
|
||||
implementation 'com.squareup.okio:okio:3.7.0'
|
||||
implementation 'com.squareup.okio:okio:3.8.0'
|
||||
|
||||
implementation 'com.hannesdorfmann:adapterdelegates4-kotlin-dsl:4.3.2'
|
||||
implementation 'com.hannesdorfmann:adapterdelegates4-kotlin-dsl-viewbinding:4.3.2'
|
||||
|
||||
@@ -403,6 +403,9 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) {
|
||||
get() = prefs.getString(KEY_BACKUP_PERIODICAL_OUTPUT, null)?.toUriOrNull()
|
||||
set(value) = prefs.edit { putString(KEY_BACKUP_PERIODICAL_OUTPUT, value?.toString()) }
|
||||
|
||||
val isReadingTimeEstimationEnabled: Boolean
|
||||
get() = prefs.getBoolean(KEY_READING_TIME, true)
|
||||
|
||||
fun isTipEnabled(tip: String): Boolean {
|
||||
return prefs.getStringSet(KEY_TIPS_CLOSED, emptySet())?.contains(tip) != true
|
||||
}
|
||||
@@ -579,6 +582,7 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) {
|
||||
const val KEY_CF_GRAYSCALE = "cf_grayscale"
|
||||
const val KEY_IGNORE_DOZE = "ignore_dose"
|
||||
const val KEY_DETAILS_TAB = "details_tab"
|
||||
const val KEY_READING_TIME = "reading_time"
|
||||
|
||||
// About
|
||||
const val KEY_APP_UPDATE = "app_update"
|
||||
|
||||
@@ -4,13 +4,12 @@ import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.IdRes
|
||||
import androidx.annotation.StringRes
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||
|
||||
enum class NavItem(
|
||||
@IdRes val id: Int,
|
||||
@StringRes val title: Int,
|
||||
@DrawableRes val icon: Int,
|
||||
) : ListModel {
|
||||
) {
|
||||
|
||||
HISTORY(R.id.nav_history, R.string.history, R.drawable.ic_history_selector),
|
||||
FAVORITES(R.id.nav_favorites, R.string.favourites, R.drawable.ic_favourites_selector),
|
||||
@@ -21,10 +20,6 @@ enum class NavItem(
|
||||
BOOKMARKS(R.id.nav_bookmarks, R.string.bookmarks, R.drawable.ic_bookmark_selector),
|
||||
;
|
||||
|
||||
override fun areItemsTheSame(other: ListModel): Boolean {
|
||||
return other is NavItem && ordinal == other.ordinal
|
||||
}
|
||||
|
||||
fun isAvailable(settings: AppSettings): Boolean = when (this) {
|
||||
SUGGESTIONS -> settings.isSuggestionsEnabled
|
||||
FEED -> settings.isTrackerEnabled
|
||||
|
||||
@@ -11,8 +11,10 @@ import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onCompletion
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.transform
|
||||
import kotlinx.coroutines.flow.transformLatest
|
||||
import org.koitharu.kotatsu.R
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
fun <T> Flow<T>.onFirst(action: suspend (T) -> Unit): Flow<T> {
|
||||
var isFirstCall = true
|
||||
@@ -37,6 +39,14 @@ fun <T> Flow<T>.onEachWhile(action: suspend (T) -> Boolean): Flow<T> {
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> Flow<T>.onEachIndexed(action: suspend (index: Int, T) -> Unit): Flow<T> {
|
||||
val counter = AtomicInteger(0)
|
||||
return transform { value ->
|
||||
action(counter.getAndIncrement(), value)
|
||||
return@transform emit(value)
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <T, R> Flow<List<T>>.mapItems(crossinline transform: (T) -> R): Flow<List<R>> {
|
||||
return map { list -> list.map(transform) }
|
||||
}
|
||||
|
||||
@@ -2,14 +2,20 @@ package org.koitharu.kotatsu.details.domain
|
||||
|
||||
import org.koitharu.kotatsu.core.model.MangaHistory
|
||||
import org.koitharu.kotatsu.core.model.findById
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.details.data.MangaDetails
|
||||
import org.koitharu.kotatsu.details.data.ReadingTime
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class ReadingTimeUseCase @Inject constructor() {
|
||||
class ReadingTimeUseCase @Inject constructor(
|
||||
private val settings: AppSettings,
|
||||
) {
|
||||
|
||||
fun invoke(manga: MangaDetails?, branch: String?, history: MangaHistory?): ReadingTime? {
|
||||
if (!settings.isReadingTimeEstimationEnabled) {
|
||||
return null
|
||||
}
|
||||
// FIXME MAXIMUM HARDCODE!!! To do calculation with user's page read speed and his favourites/history mangas average pages in chapter
|
||||
val chapters = manga?.chapters?.get(branch)
|
||||
if (chapters.isNullOrEmpty()) {
|
||||
|
||||
@@ -7,6 +7,7 @@ import androidx.activity.OnBackPressedCallback
|
||||
import androidx.annotation.IdRes
|
||||
import androidx.core.view.isEmpty
|
||||
import androidx.core.view.iterator
|
||||
import androidx.core.view.size
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
@@ -180,6 +181,9 @@ class MainNavigationDelegate(
|
||||
for (item in items) {
|
||||
menu.add(Menu.NONE, item.id, Menu.NONE, item.title)
|
||||
.setIcon(item.icon)
|
||||
if (menu.size >= navBar.maxItemCount) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,19 +9,22 @@ import android.graphics.Canvas
|
||||
import android.graphics.Color
|
||||
import android.graphics.Paint
|
||||
import android.graphics.Rect
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.BatteryManager
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.view.WindowInsets
|
||||
import androidx.annotation.AttrRes
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.withStyledAttributes
|
||||
import androidx.core.graphics.ColorUtils
|
||||
import androidx.core.graphics.withScale
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.util.ext.getThemeColor
|
||||
import org.koitharu.kotatsu.core.util.ext.measureDimension
|
||||
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
|
||||
import org.koitharu.kotatsu.core.util.ext.resolveDp
|
||||
import org.koitharu.kotatsu.parsers.util.format
|
||||
import org.koitharu.kotatsu.reader.ui.pager.ReaderUiState
|
||||
import java.time.LocalTime
|
||||
@@ -29,6 +32,7 @@ import java.time.format.DateTimeFormatter
|
||||
import java.time.format.FormatStyle
|
||||
import com.google.android.material.R as materialR
|
||||
|
||||
|
||||
class ReaderInfoBarView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
@@ -38,7 +42,7 @@ class ReaderInfoBarView @JvmOverloads constructor(
|
||||
private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
|
||||
private val textBounds = Rect()
|
||||
private val timeFormat = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT)
|
||||
private val timeReceiver = TimeReceiver()
|
||||
private val systemStateReceiver = SystemStateReceiver()
|
||||
private var insetLeft: Int = 0
|
||||
private var insetRight: Int = 0
|
||||
private var insetTop: Int = 0
|
||||
@@ -52,9 +56,12 @@ class ReaderInfoBarView @JvmOverloads constructor(
|
||||
context.getThemeColor(materialR.attr.colorSurface, Color.WHITE),
|
||||
200,
|
||||
)
|
||||
private val batteryIcon = ContextCompat.getDrawable(context, R.drawable.ic_battery_outline)
|
||||
|
||||
private var timeText = timeFormat.format(LocalTime.now())
|
||||
private var batteryText = ""
|
||||
private var text: String = ""
|
||||
private var prevTextHeight: Int = 0
|
||||
|
||||
private val innerHeight
|
||||
get() = height - paddingTop - paddingBottom - insetTop
|
||||
@@ -69,7 +76,10 @@ class ReaderInfoBarView @JvmOverloads constructor(
|
||||
}
|
||||
|
||||
init {
|
||||
paint.strokeWidth = context.resources.resolveDp(2f)
|
||||
context.withStyledAttributes(attrs, R.styleable.ReaderInfoBarView, defStyleAttr) {
|
||||
paint.strokeWidth = getDimension(R.styleable.ReaderInfoBarView_android_strokeWidth, 2f)
|
||||
paint.textSize = getDimension(R.styleable.ReaderInfoBarView_android_textSize, 16f)
|
||||
}
|
||||
val insetCorner = getSystemUiDimensionOffset("rounded_corner_content_padding")
|
||||
val fallbackInset = resources.getDimensionPixelOffset(R.dimen.reader_bar_inset_fallback)
|
||||
val insetStart = getSystemUiDimensionOffset("status_bar_padding_start", fallbackInset) + insetCorner
|
||||
@@ -82,7 +92,10 @@ class ReaderInfoBarView @JvmOverloads constructor(
|
||||
|
||||
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||
val desiredWidth = suggestedMinimumWidth + paddingLeft + paddingRight + insetLeft + insetRight
|
||||
val desiredHeight = suggestedMinimumHeight + paddingTop + paddingBottom + insetTop
|
||||
val desiredHeight = maxOf(
|
||||
computeTextHeight().also { prevTextHeight = it },
|
||||
suggestedMinimumHeight,
|
||||
) + paddingTop + paddingBottom + insetTop
|
||||
setMeasuredDimension(
|
||||
measureDimension(desiredWidth, widthMeasureSpec),
|
||||
measureDimension(desiredHeight, heightMeasureSpec),
|
||||
@@ -91,7 +104,9 @@ class ReaderInfoBarView @JvmOverloads constructor(
|
||||
|
||||
override fun onDraw(canvas: Canvas) {
|
||||
super.onDraw(canvas)
|
||||
val ty = innerHeight / 2f + textBounds.height() / 2f - textBounds.bottom
|
||||
computeTextHeight()
|
||||
val h = innerHeight.toFloat()
|
||||
val ty = h / 2f + textBounds.height() / 2f - textBounds.bottom
|
||||
paint.textAlign = Paint.Align.LEFT
|
||||
canvas.drawTextOutline(
|
||||
text,
|
||||
@@ -100,18 +115,32 @@ class ReaderInfoBarView @JvmOverloads constructor(
|
||||
)
|
||||
if (isTimeVisible) {
|
||||
paint.textAlign = Paint.Align.RIGHT
|
||||
canvas.drawTextOutline(
|
||||
timeText,
|
||||
(width - paddingRight - insetRight - cutoutInsetRight).toFloat(),
|
||||
paddingTop + insetTop + ty,
|
||||
)
|
||||
var endX = (width - paddingRight - insetRight - cutoutInsetRight).toFloat()
|
||||
canvas.drawTextOutline(timeText, endX, paddingTop + insetTop + ty)
|
||||
if (batteryText.isNotEmpty()) {
|
||||
paint.getTextBounds(timeText, 0, timeText.length, textBounds)
|
||||
endX -= textBounds.width()
|
||||
endX -= h * 0.6f
|
||||
canvas.drawTextOutline(batteryText, endX, paddingTop + insetTop + ty)
|
||||
batteryIcon?.let {
|
||||
paint.getTextBounds(batteryText, 0, batteryText.length, textBounds)
|
||||
endX -= textBounds.width()
|
||||
val iconCenter = paddingTop + insetTop + textBounds.height() / 2
|
||||
it.setBounds(
|
||||
(endX - h).toInt(),
|
||||
(iconCenter - h / 2).toInt(),
|
||||
endX.toInt(),
|
||||
(iconCenter + h / 2).toInt(),
|
||||
)
|
||||
it.drawWithOutline(canvas)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
|
||||
super.onSizeChanged(w, h, oldw, oldh)
|
||||
updateCutoutInsets(ViewCompat.getRootWindowInsets(this))
|
||||
updateTextSize()
|
||||
}
|
||||
|
||||
override fun onApplyWindowInsets(insets: WindowInsets): WindowInsets {
|
||||
@@ -123,8 +152,11 @@ class ReaderInfoBarView @JvmOverloads constructor(
|
||||
super.onAttachedToWindow()
|
||||
ContextCompat.registerReceiver(
|
||||
context,
|
||||
timeReceiver,
|
||||
IntentFilter(Intent.ACTION_TIME_TICK),
|
||||
systemStateReceiver,
|
||||
IntentFilter().apply {
|
||||
addAction(Intent.ACTION_TIME_TICK)
|
||||
addAction(Intent.ACTION_BATTERY_CHANGED)
|
||||
},
|
||||
ContextCompat.RECEIVER_EXPORTED,
|
||||
)
|
||||
updateCutoutInsets(ViewCompat.getRootWindowInsets(this))
|
||||
@@ -132,7 +164,7 @@ class ReaderInfoBarView @JvmOverloads constructor(
|
||||
|
||||
override fun onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow()
|
||||
context.unregisterReceiver(timeReceiver)
|
||||
context.unregisterReceiver(systemStateReceiver)
|
||||
}
|
||||
|
||||
fun update(state: ReaderUiState?) {
|
||||
@@ -151,17 +183,18 @@ class ReaderInfoBarView @JvmOverloads constructor(
|
||||
} else {
|
||||
""
|
||||
}
|
||||
updateTextSize()
|
||||
val newHeight = computeTextHeight()
|
||||
if (newHeight != prevTextHeight) {
|
||||
prevTextHeight = newHeight
|
||||
requestLayout()
|
||||
}
|
||||
invalidate()
|
||||
}
|
||||
|
||||
private fun updateTextSize() {
|
||||
val str = text + timeText
|
||||
val testTextSize = 48f
|
||||
paint.textSize = testTextSize
|
||||
paint.getTextBounds(str, 0, str.length, textBounds)
|
||||
paint.textSize = testTextSize * innerHeight / textBounds.height()
|
||||
private fun computeTextHeight(): Int {
|
||||
val str = text + batteryText + timeText
|
||||
paint.getTextBounds(str, 0, str.length, textBounds)
|
||||
return textBounds.height()
|
||||
}
|
||||
|
||||
private fun Canvas.drawTextOutline(text: String, x: Float, y: Float) {
|
||||
@@ -173,6 +206,20 @@ class ReaderInfoBarView @JvmOverloads constructor(
|
||||
drawText(text, x, y, paint)
|
||||
}
|
||||
|
||||
private fun Drawable.drawWithOutline(canvas: Canvas) {
|
||||
var requiredScale = (bounds.width() + paint.strokeWidth * 2f) / bounds.width().toFloat()
|
||||
setTint(colorOutline)
|
||||
canvas.withScale(requiredScale, requiredScale, bounds.exactCenterX(), bounds.exactCenterY()) {
|
||||
draw(canvas)
|
||||
}
|
||||
requiredScale = 1f / requiredScale
|
||||
canvas.withScale(requiredScale, requiredScale, bounds.exactCenterX(), bounds.exactCenterY()) {
|
||||
draw(canvas)
|
||||
}
|
||||
setTint(colorText)
|
||||
draw(canvas)
|
||||
}
|
||||
|
||||
private fun updateCutoutInsets(insetsCompat: WindowInsetsCompat?) {
|
||||
val cutouts = (insetsCompat ?: return).displayCutout?.boundingRects.orEmpty()
|
||||
cutoutInsetLeft = 0
|
||||
@@ -187,9 +234,15 @@ class ReaderInfoBarView @JvmOverloads constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private inner class TimeReceiver : BroadcastReceiver() {
|
||||
private inner class SystemStateReceiver : BroadcastReceiver() {
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
val level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
|
||||
val scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
|
||||
if (level != -1 && scale != -1) {
|
||||
batteryText = context.getString(R.string.percent_string_pattern, (level * 100 / scale).toString())
|
||||
}
|
||||
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
timeText = timeFormat.format(LocalTime.now())
|
||||
if (isTimeVisible) {
|
||||
invalidate()
|
||||
|
||||
@@ -12,6 +12,7 @@ import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.plus
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.core.prefs.NavItem
|
||||
import org.koitharu.kotatsu.core.ui.BaseViewModel
|
||||
@@ -20,6 +21,7 @@ import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||
import org.koitharu.kotatsu.main.ui.MainActivity
|
||||
import org.koitharu.kotatsu.parsers.util.move
|
||||
import org.koitharu.kotatsu.settings.nav.model.NavItemAddModel
|
||||
import org.koitharu.kotatsu.settings.nav.model.NavItemConfigModel
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
@@ -31,15 +33,18 @@ class NavConfigViewModel @Inject constructor(
|
||||
private val items = MutableStateFlow(settings.mainNavItems)
|
||||
|
||||
val content: StateFlow<List<ListModel>> = items.map { snapshot ->
|
||||
if (snapshot.size < NavItem.entries.size) {
|
||||
snapshot + NavItemAddModel(snapshot.size < 5)
|
||||
} else {
|
||||
snapshot
|
||||
buildList(snapshot.size + 1) {
|
||||
snapshot.mapTo(this) {
|
||||
NavItemConfigModel(it, getUnavailabilityHint(it))
|
||||
}
|
||||
if (size < NavItem.entries.size) {
|
||||
add(NavItemAddModel(size < 5))
|
||||
}
|
||||
}
|
||||
}.stateIn(
|
||||
viewModelScope + Dispatchers.Default,
|
||||
SharingStarted.WhileSubscribed(5000),
|
||||
emptyList()
|
||||
emptyList(),
|
||||
)
|
||||
|
||||
private var commitJob: Job? = null
|
||||
@@ -81,4 +86,12 @@ class NavConfigViewModel @Inject constructor(
|
||||
activityRecreationHandle.recreate(MainActivity::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getUnavailabilityHint(item: NavItem) = if (item.isAvailable(settings)) {
|
||||
0
|
||||
} else when (item) {
|
||||
NavItem.FEED -> R.string.check_for_new_chapters_disabled
|
||||
NavItem.SUGGESTIONS -> R.string.suggestions_unavailable_text
|
||||
else -> 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,33 +7,37 @@ import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.prefs.NavItem
|
||||
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
|
||||
import org.koitharu.kotatsu.core.util.ext.setTextAndVisible
|
||||
import org.koitharu.kotatsu.databinding.ItemNavAvailableBinding
|
||||
import org.koitharu.kotatsu.databinding.ItemNavConfigBinding
|
||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||
import org.koitharu.kotatsu.settings.nav.model.NavItemAddModel
|
||||
import org.koitharu.kotatsu.settings.nav.model.NavItemConfigModel
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
fun navConfigAD(
|
||||
clickListener: OnListItemClickListener<NavItem>,
|
||||
) = adapterDelegateViewBinding<NavItem, ListModel, ItemNavConfigBinding>(
|
||||
) = adapterDelegateViewBinding<NavItemConfigModel, ListModel, ItemNavConfigBinding>(
|
||||
{ layoutInflater, parent -> ItemNavConfigBinding.inflate(layoutInflater, parent, false) },
|
||||
) {
|
||||
|
||||
val eventListener = object : View.OnClickListener, View.OnTouchListener {
|
||||
override fun onClick(v: View) = clickListener.onItemClick(item, v)
|
||||
override fun onClick(v: View) = clickListener.onItemClick(item.item, v)
|
||||
|
||||
override fun onTouch(v: View?, event: MotionEvent): Boolean =
|
||||
event.actionMasked == MotionEvent.ACTION_DOWN &&
|
||||
clickListener.onItemLongClick(item, itemView)
|
||||
clickListener.onItemLongClick(item.item, itemView)
|
||||
}
|
||||
binding.imageViewRemove.setOnClickListener(eventListener)
|
||||
binding.imageViewReorder.setOnTouchListener(eventListener)
|
||||
|
||||
bind {
|
||||
with(binding.textViewTitle) {
|
||||
setText(item.title)
|
||||
setCompoundDrawablesRelativeWithIntrinsicBounds(item.icon, 0, 0, 0)
|
||||
isEnabled = item.disabledHintResId == 0
|
||||
setText(item.item.title)
|
||||
setCompoundDrawablesRelativeWithIntrinsicBounds(item.item.icon, 0, 0, 0)
|
||||
}
|
||||
binding.textViewHint.setTextAndVisible(item.disabledHintResId)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package org.koitharu.kotatsu.settings.nav.model
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import org.koitharu.kotatsu.core.prefs.NavItem
|
||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||
|
||||
data class NavItemConfigModel(
|
||||
val item: NavItem,
|
||||
@StringRes val disabledHintResId: Int,
|
||||
) : ListModel {
|
||||
|
||||
override fun areItemsTheSame(other: ListModel): Boolean {
|
||||
return other is NavItemConfigModel && other.item == item
|
||||
}
|
||||
}
|
||||
@@ -68,6 +68,7 @@ import org.koitharu.kotatsu.parsers.model.MangaTag
|
||||
import org.koitharu.kotatsu.parsers.model.SortOrder
|
||||
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
|
||||
import org.koitharu.kotatsu.reader.ui.ReaderActivity.IntentBuilder
|
||||
import org.koitharu.kotatsu.settings.SettingsActivity
|
||||
import org.koitharu.kotatsu.settings.work.PeriodicWorkScheduler
|
||||
import org.koitharu.kotatsu.suggestions.domain.MangaSuggestion
|
||||
import org.koitharu.kotatsu.suggestions.domain.SuggestionRepository
|
||||
@@ -76,6 +77,7 @@ import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.pow
|
||||
import kotlin.random.Random
|
||||
import com.google.android.material.R as materialR
|
||||
|
||||
@HiltWorker
|
||||
class SuggestionsWorker @AssistedInject constructor(
|
||||
@@ -86,6 +88,7 @@ class SuggestionsWorker @AssistedInject constructor(
|
||||
private val historyRepository: HistoryRepository,
|
||||
private val favouritesRepository: FavouritesRepository,
|
||||
private val appSettings: AppSettings,
|
||||
private val workManager: WorkManager,
|
||||
private val mangaRepositoryFactory: MangaRepository.Factory,
|
||||
private val sourcesRepository: MangaSourcesRepository,
|
||||
) : CoroutineWorker(appContext, params) {
|
||||
@@ -116,6 +119,19 @@ class SuggestionsWorker @AssistedInject constructor(
|
||||
|
||||
val notification = NotificationCompat.Builder(applicationContext, WORKER_CHANNEL_ID)
|
||||
.setContentTitle(title)
|
||||
.setContentIntent(
|
||||
PendingIntentCompat.getActivity(
|
||||
applicationContext,
|
||||
0,
|
||||
SettingsActivity.newSuggestionsSettingsIntent(applicationContext),
|
||||
0,
|
||||
false,
|
||||
),
|
||||
).addAction(
|
||||
materialR.drawable.material_ic_clear_black_24dp,
|
||||
applicationContext.getString(android.R.string.cancel),
|
||||
workManager.createCancelPendingIntent(id),
|
||||
)
|
||||
.setPriority(NotificationCompat.PRIORITY_MIN)
|
||||
.setCategory(NotificationCompat.CATEGORY_SERVICE)
|
||||
.setDefaults(0)
|
||||
@@ -123,7 +139,13 @@ class SuggestionsWorker @AssistedInject constructor(
|
||||
.setSilent(true)
|
||||
.setProgress(0, 0, true)
|
||||
.setSmallIcon(android.R.drawable.stat_notify_sync)
|
||||
.setForegroundServiceBehavior(NotificationCompat.FOREGROUND_SERVICE_DEFERRED)
|
||||
.setForegroundServiceBehavior(
|
||||
if (TAG_ONESHOT in tags) {
|
||||
NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE
|
||||
} else {
|
||||
NotificationCompat.FOREGROUND_SERVICE_DEFERRED
|
||||
},
|
||||
)
|
||||
.build()
|
||||
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
@@ -207,7 +229,7 @@ class SuggestionsWorker @AssistedInject constructor(
|
||||
val order = preferredSortOrders.first { it in availableOrders }
|
||||
val availableTags = repository.getTags()
|
||||
val tag = tags.firstNotNullOfOrNull { title ->
|
||||
availableTags.find { x -> x.title.almostEquals(title, TAG_EQ_THRESHOLD) }
|
||||
availableTags.find { x -> x !in blacklist && x.title.almostEquals(title, TAG_EQ_THRESHOLD) }
|
||||
}
|
||||
val list = repository.getList(
|
||||
offset = 0,
|
||||
|
||||
@@ -39,7 +39,6 @@ import kotlinx.coroutines.NonCancellable
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.channelFlow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.toList
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runInterruptible
|
||||
@@ -54,6 +53,7 @@ import org.koitharu.kotatsu.core.logs.TrackerLogger
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.core.util.ext.awaitUniqueWorkInfoByName
|
||||
import org.koitharu.kotatsu.core.util.ext.checkNotificationPermission
|
||||
import org.koitharu.kotatsu.core.util.ext.onEachIndexed
|
||||
import org.koitharu.kotatsu.core.util.ext.toBitmapOrNull
|
||||
import org.koitharu.kotatsu.core.util.ext.trySetForeground
|
||||
import org.koitharu.kotatsu.details.ui.DetailsActivity
|
||||
@@ -61,11 +61,13 @@ import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaChapter
|
||||
import org.koitharu.kotatsu.parsers.util.mapToSet
|
||||
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
|
||||
import org.koitharu.kotatsu.settings.SettingsActivity
|
||||
import org.koitharu.kotatsu.settings.work.PeriodicWorkScheduler
|
||||
import org.koitharu.kotatsu.tracker.domain.Tracker
|
||||
import org.koitharu.kotatsu.tracker.domain.model.MangaUpdates
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
import com.google.android.material.R as materialR
|
||||
|
||||
@HiltWorker
|
||||
class TrackWorker @AssistedInject constructor(
|
||||
@@ -74,6 +76,7 @@ class TrackWorker @AssistedInject constructor(
|
||||
private val coil: ImageLoader,
|
||||
private val settings: AppSettings,
|
||||
private val tracker: Tracker,
|
||||
private val workManager: WorkManager,
|
||||
@TrackerLogger private val logger: FileLogger,
|
||||
) : CoroutineWorker(context, workerParams) {
|
||||
|
||||
@@ -164,7 +167,10 @@ class TrackWorker @AssistedInject constructor(
|
||||
}
|
||||
}
|
||||
}
|
||||
}.onEach {
|
||||
}.onEachIndexed { index, it ->
|
||||
if (applicationContext.checkNotificationPermission()) {
|
||||
notificationManager.notify(WORKER_NOTIFICATION_ID, createWorkerNotification(tracks.size, index + 1))
|
||||
}
|
||||
when (it) {
|
||||
is MangaUpdates.Failure -> {
|
||||
val e = it.error
|
||||
@@ -254,12 +260,11 @@ class TrackWorker @AssistedInject constructor(
|
||||
}
|
||||
|
||||
override suspend fun getForegroundInfo(): ForegroundInfo {
|
||||
val title = applicationContext.getString(R.string.check_for_new_chapters)
|
||||
val channel = NotificationChannelCompat.Builder(
|
||||
WORKER_CHANNEL_ID,
|
||||
NotificationManagerCompat.IMPORTANCE_LOW
|
||||
NotificationManagerCompat.IMPORTANCE_LOW,
|
||||
)
|
||||
.setName(title)
|
||||
.setName(applicationContext.getString(R.string.check_for_new_chapters))
|
||||
.setShowBadge(false)
|
||||
.setVibrationEnabled(false)
|
||||
.setSound(null, null)
|
||||
@@ -267,28 +272,56 @@ class TrackWorker @AssistedInject constructor(
|
||||
.build()
|
||||
notificationManager.createNotificationChannel(channel)
|
||||
|
||||
val notification = NotificationCompat.Builder(applicationContext, WORKER_CHANNEL_ID)
|
||||
.setContentTitle(title)
|
||||
.setPriority(NotificationCompat.PRIORITY_MIN)
|
||||
.setCategory(NotificationCompat.CATEGORY_SERVICE)
|
||||
.setDefaults(0)
|
||||
.setOngoing(false)
|
||||
.setSilent(true)
|
||||
.setProgress(0, 0, true)
|
||||
.setSmallIcon(android.R.drawable.stat_notify_sync)
|
||||
.setForegroundServiceBehavior(NotificationCompat.FOREGROUND_SERVICE_DEFERRED)
|
||||
.build()
|
||||
val notification = createWorkerNotification(0, 0)
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
ForegroundInfo(
|
||||
WORKER_NOTIFICATION_ID,
|
||||
notification,
|
||||
ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC
|
||||
ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC,
|
||||
)
|
||||
} else {
|
||||
ForegroundInfo(WORKER_NOTIFICATION_ID, notification)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createWorkerNotification(max: Int, progress: Int) = NotificationCompat.Builder(
|
||||
applicationContext,
|
||||
WORKER_CHANNEL_ID,
|
||||
).apply {
|
||||
setContentTitle(applicationContext.getString(R.string.check_for_new_chapters))
|
||||
setPriority(NotificationCompat.PRIORITY_MIN)
|
||||
setCategory(NotificationCompat.CATEGORY_SERVICE)
|
||||
setDefaults(0)
|
||||
setOngoing(false)
|
||||
setSilent(true)
|
||||
setContentIntent(
|
||||
PendingIntentCompat.getActivity(
|
||||
applicationContext,
|
||||
0,
|
||||
SettingsActivity.newTrackerSettingsIntent(applicationContext),
|
||||
0,
|
||||
false,
|
||||
),
|
||||
)
|
||||
addAction(
|
||||
materialR.drawable.material_ic_clear_black_24dp,
|
||||
applicationContext.getString(android.R.string.cancel),
|
||||
workManager.createCancelPendingIntent(id),
|
||||
)
|
||||
if (max > 0) {
|
||||
setSubText(applicationContext.getString(R.string.fraction_pattern, progress, max))
|
||||
}
|
||||
setProgress(max, progress, max == 0)
|
||||
setSmallIcon(android.R.drawable.stat_notify_sync)
|
||||
setForegroundServiceBehavior(
|
||||
if (TAG_ONESHOT in tags) {
|
||||
NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE
|
||||
} else {
|
||||
NotificationCompat.FOREGROUND_SERVICE_DEFERRED
|
||||
},
|
||||
)
|
||||
}.build()
|
||||
|
||||
private suspend fun setRetryIds(ids: Set<Long>) = runInterruptible(Dispatchers.IO) {
|
||||
val prefs = applicationContext.getSharedPreferences(TAG, Context.MODE_PRIVATE)
|
||||
prefs.edit(commit = true) {
|
||||
|
||||
10
app/src/main/res/drawable/ic_battery_outline.xml
Normal file
10
app/src/main/res/drawable/ic_battery_outline.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#000"
|
||||
android:pathData="M16,20H8V6H16M16.67,4H15V2H9V4H7.33A1.33,1.33 0 0,0 6,5.33V20.67C6,21.4 6.6,22 7.33,22H16.67A1.33,1.33 0 0,0 18,20.67V5.33C18,4.6 17.4,4 16.67,4Z" />
|
||||
</vector>
|
||||
@@ -28,7 +28,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="top"
|
||||
android:minHeight="12sp"
|
||||
android:textSize="12sp"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
|
||||
@@ -5,43 +5,57 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:windowBackground"
|
||||
android:baselineAligned="false"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:orientation="vertical"
|
||||
android:paddingVertical="@dimen/margin_small"
|
||||
android:paddingStart="?listPreferredItemPaddingStart"
|
||||
android:paddingEnd="?listPreferredItemPaddingEnd">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:baselineAligned="false"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:drawablePadding="?listPreferredItemPaddingStart"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="?attr/textAppearanceBodyLarge"
|
||||
tools:drawableStart="@drawable/ic_explore_selector"
|
||||
tools:text="@string/explore" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imageView_remove"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/remove"
|
||||
android:padding="@dimen/margin_small"
|
||||
android:scaleType="center"
|
||||
android:src="@drawable/ic_delete" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imageView_reorder"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/reorder"
|
||||
android:padding="@dimen/margin_small"
|
||||
android:scaleType="center"
|
||||
android:src="@drawable/ic_reorder_handle" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView_title"
|
||||
android:layout_width="0dp"
|
||||
android:id="@+id/textView_hint"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:drawablePadding="?listPreferredItemPaddingStart"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="?attr/textAppearanceBodyLarge"
|
||||
tools:drawableStart="@drawable/ic_explore_selector"
|
||||
tools:text="@string/explore" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imageView_remove"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/remove"
|
||||
android:padding="@dimen/margin_small"
|
||||
android:scaleType="center"
|
||||
android:src="@drawable/ic_delete" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imageView_reorder"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/reorder"
|
||||
android:padding="@dimen/margin_small"
|
||||
android:scaleType="center"
|
||||
android:src="@drawable/ic_reorder_handle" />
|
||||
android:textAppearance="?attr/textAppearanceBodySmall"
|
||||
tools:text="@string/suggestions_unavailable_text" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@@ -240,7 +240,7 @@
|
||||
<string name="removed_from_history">Выдалена з гісторыі</string>
|
||||
<string name="dns_over_https">DNS праз HTTPS</string>
|
||||
<string name="detect_reader_mode">Аўтавызначэнне рэжыму чытання</string>
|
||||
<string name="detect_reader_mode_summary">Аўтаматычна вызначае, ці з\'яўляецца манга вэб-коміксам</string>
|
||||
<string name="detect_reader_mode_summary">Аўтаматычна вызначаць, ці з\'яўляецца манга манхвой</string>
|
||||
<string name="new_sources_text">Даступныя новыя крыніцы мангі</string>
|
||||
<string name="download_slowdown">Запавольванне спампоўкі</string>
|
||||
<string name="suggestions_excluded_genres">Выключыць жанры</string>
|
||||
@@ -426,7 +426,7 @@
|
||||
<string name="show_pages_numbers_summary">Паказаць нумары старонак у ніжнім куце</string>
|
||||
<string name="network">Сетка</string>
|
||||
<string name="data_and_privacy">Дадзеныя і канфідэнцыяльнасць</string>
|
||||
<string name="webtoon_zoom_summary">Уключыць жэст павелічэння маштабу ў рэжыме манхвы</string>
|
||||
<string name="webtoon_zoom_summary">Дазволіць жэсты маштабавання ў рэжыме манхвы</string>
|
||||
<string name="details_button_tip">Націсніце і ўтрымлівайце кнопку \"Чытаць\", каб убачыць дадатковыя параметры</string>
|
||||
<string name="restore_summary">Аднавіць раней створаную рэзервовую копію</string>
|
||||
<string name="reader_info_bar_summary">Паказаць бягучы час і ход чытання ў верхняй частцы экрана</string>
|
||||
@@ -581,4 +581,7 @@
|
||||
<string name="email_password_enter_hint">Каб працягнуць, увядзіце адрас электроннай пошты і пароль</string>
|
||||
<string name="config_reset_confirm">Скінуць налады да значэнняў па змаўчанні? Гэта дзеянне нельга адмяніць.</string>
|
||||
<string name="use_two_pages_landscape">Выкарыстоўвайце двухстаронкавы макет у альбомнай арыентацыі (бэта)</string>
|
||||
<string name="default_webtoon_zoom_out">Аддаленне ў рэжыме манхвы</string>
|
||||
<string name="fullscreen_mode">Поўнаэкранны рэжым</string>
|
||||
<string name="reader_fullscreen_summary">Схаваць інтэрфейс сістэмы</string>
|
||||
</resources>
|
||||
@@ -582,4 +582,6 @@
|
||||
<string name="none">Ninguno</string>
|
||||
<string name="config_reset_confirm">¿Restablecer los valores por defecto? Esta acción no se puede deshacer.</string>
|
||||
<string name="default_webtoon_zoom_out">Alejar el zoom del webtoon predeterminado</string>
|
||||
<string name="fullscreen_mode">Modo de pantalla completa</string>
|
||||
<string name="reader_fullscreen_summary">Ocultar las barras de estado y navegación del sistema</string>
|
||||
</resources>
|
||||
@@ -8,4 +8,32 @@
|
||||
<item quantity="one">%1$d fejezet</item>
|
||||
<item quantity="other">%1$d fejezetek</item>
|
||||
</plurals>
|
||||
<plurals name="items">
|
||||
<item quantity="one">%1$d tétel</item>
|
||||
<item quantity="other">%1$d tételek</item>
|
||||
</plurals>
|
||||
<plurals name="minutes_ago">
|
||||
<item quantity="one">%1$d perce</item>
|
||||
<item quantity="other">%1$d perce</item>
|
||||
</plurals>
|
||||
<plurals name="hours_ago">
|
||||
<item quantity="one">%1$d órája</item>
|
||||
<item quantity="other">%1$d órája</item>
|
||||
</plurals>
|
||||
<plurals name="days_ago">
|
||||
<item quantity="one">%1$d napja</item>
|
||||
<item quantity="other">%1$d napja</item>
|
||||
</plurals>
|
||||
<plurals name="months_ago">
|
||||
<item quantity="one">%1$d hónapja</item>
|
||||
<item quantity="other">%1$d hónapja</item>
|
||||
</plurals>
|
||||
<plurals name="hours">
|
||||
<item quantity="one">%1$d óra</item>
|
||||
<item quantity="other">%1$d óra</item>
|
||||
</plurals>
|
||||
<plurals name="minutes">
|
||||
<item quantity="one">%1$d perc</item>
|
||||
<item quantity="other">%1$d perc</item>
|
||||
</plurals>
|
||||
</resources>
|
||||
63
app/src/main/res/values-hu/strings.xml
Normal file
63
app/src/main/res/values-hu/strings.xml
Normal file
@@ -0,0 +1,63 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="history">Előzmények</string>
|
||||
<string name="list">Lista</string>
|
||||
<string name="detailed_list">Részletes lista</string>
|
||||
<string name="grid">Rács</string>
|
||||
<string name="list_mode">Lista mód</string>
|
||||
<string name="settings">Beállítások</string>
|
||||
<string name="remote_sources">Manga források</string>
|
||||
<string name="loading_">Betöltés…</string>
|
||||
<string name="computing_">Számítás…</string>
|
||||
<string name="chapter_d_of_d">Fejezet %1$d / %2$d</string>
|
||||
<string name="try_again">Próbálja újra</string>
|
||||
<string name="nothing_found">Nem található</string>
|
||||
<string name="history_is_empty">Nincs még előzmény</string>
|
||||
<string name="read">Olvas</string>
|
||||
<string name="you_have_not_favourites_yet">Nincsenek még kedvencek</string>
|
||||
<string name="add">Hozzáadás</string>
|
||||
<string name="save">Mentés</string>
|
||||
<string name="share">Megosztás</string>
|
||||
<string name="create_shortcut">Parancsikon létrehozása…</string>
|
||||
<string name="share_s">Megosztás %s</string>
|
||||
<string name="search">Keresés</string>
|
||||
<string name="search_manga">Manga keresése</string>
|
||||
<string name="processing_">Feldolgozás…</string>
|
||||
<string name="download_complete">Letöltött</string>
|
||||
<string name="downloads">Letöltések</string>
|
||||
<string name="by_name">Név</string>
|
||||
<string name="updated">Frissített</string>
|
||||
<string name="newest">Legújabb</string>
|
||||
<string name="sort_order">Rendezési sorrend</string>
|
||||
<string name="by_rating">Értékelés</string>
|
||||
<string name="filter">Szűrő</string>
|
||||
<string name="light">Fényes</string>
|
||||
<string name="automatic">Rendszer alapján</string>
|
||||
<string name="clear">Törlés</string>
|
||||
<string name="text_clear_history_prompt">Véglegesen törli az összes olvasási előzményt?</string>
|
||||
<string name="remove">Eltávolítás</string>
|
||||
<string name="save_page">Oldal mentése</string>
|
||||
<string name="share_image">Kép megosztása</string>
|
||||
<string name="_import">Importálás</string>
|
||||
<string name="operation_not_supported">Ez a művelet nem engedélyezett</string>
|
||||
<string name="text_file_not_supported">Csak ZIP és CBZ kiterjesztés elfogadott.</string>
|
||||
<string name="no_description">Nincs leírás</string>
|
||||
<string name="local_storage">Helyi tárhely</string>
|
||||
<string name="favourites">Kedvencek</string>
|
||||
<string name="error_occurred">Hiba</string>
|
||||
<string name="network_error">Hálózati hiba</string>
|
||||
<string name="close">Bezárás</string>
|
||||
<string name="details">Részletek</string>
|
||||
<string name="chapters">Fejezetek</string>
|
||||
<string name="clear_history">Előzmények törlése</string>
|
||||
<string name="add_to_favourites">Kedvencekhez adás</string>
|
||||
<string name="add_new_category">Új kategória</string>
|
||||
<string name="manga_downloading_">Letöltés…</string>
|
||||
<string name="popular">Népszerű</string>
|
||||
<string name="theme">Téma</string>
|
||||
<string name="dark">Sötét</string>
|
||||
<string name="pages">Oldalak</string>
|
||||
<string name="_s_deleted_from_local_storage">%s törölve lett a helyi tárhelyből</string>
|
||||
<string name="page_saved">Mentve</string>
|
||||
<string name="delete">Törlés</string>
|
||||
</resources>
|
||||
@@ -267,13 +267,13 @@
|
||||
<string name="_s_deleted_from_local_storage">„%s” usunięte z pamięci lokalnej</string>
|
||||
<string name="clear_updates_feed">Wyczyść tablicę aktualizacji</string>
|
||||
<string name="feed">Tablica</string>
|
||||
<string name="text_delete_local_manga">Usunąć trwale „%s” z urządzenia?</string>
|
||||
<string name="text_delete_local_manga">Trwale usunąć „%s” z urządzenia?</string>
|
||||
<string name="clear_thumbs_cache">Wyczyść pamięć podręczną miniatur</string>
|
||||
<string name="text_search_holder_secondary">Spróbuj przeformułować zapytanie.</string>
|
||||
<string name="text_history_holder_primary">To co czytasz będzie wyświetlane tutaj</string>
|
||||
<string name="text_history_holder_secondary">Znajdź rzeczy do przeczytania w sekcji Przegląd</string>
|
||||
<string name="text_local_holder_secondary">Zapisz ze źródeł online lub zaimportuj pliki.</string>
|
||||
<string name="manga_save_location">Folder pobranych</string>
|
||||
<string name="text_local_holder_secondary">Zapisz coś z katalogu online lub zaimportuj z pliku.</string>
|
||||
<string name="manga_save_location">Folder Pobrane</string>
|
||||
<string name="feed_will_update_soon">Aktualizacja tablicy rozpocznie się wkrótce</string>
|
||||
<string name="passwords_mismatch">Niezgodne hasła</string>
|
||||
<string name="right_to_left">Od prawej do lewej</string>
|
||||
@@ -476,4 +476,14 @@
|
||||
<string name="manga_list">Lista mang</string>
|
||||
<string name="disable_nsfw">Wyłącz NSFW</string>
|
||||
<string name="show">Pokazywać</string>
|
||||
<string name="email_password_enter_hint">Wpisz swój adres e-mail i hasło, aby kontynuować</string>
|
||||
<string name="items_limit_exceeded">Nie można dodać więcej elementów</string>
|
||||
<string name="to_top">W górę</string>
|
||||
<string name="moved_to_top">Przeniesiono na górę</string>
|
||||
<string name="zoom_out">Pomniejsz</string>
|
||||
<string name="zoom_in">Zbliżenie</string>
|
||||
<string name="reader_zoom_buttons">Pokaż przyciski powiększania</string>
|
||||
<string name="reader_zoom_buttons_summary">Określa, czy wyświetlać elementy sterujące powiększeniem w prawym dolnym rogu</string>
|
||||
<string name="keep_screen_on">Pozostaw ekran włączony</string>
|
||||
<string name="keep_screen_on_summary">Nie wyłączaj ekranu podczas czytania mangi</string>
|
||||
</resources>
|
||||
@@ -581,4 +581,7 @@
|
||||
<string name="use_two_pages_landscape">Usar layout de duas páginas na orientação paisagem (beta)</string>
|
||||
<string name="last_read">Última leitura</string>
|
||||
<string name="none">Nenhum</string>
|
||||
<string name="default_webtoon_zoom_out">Diminuir zoom padrão do webtoon</string>
|
||||
<string name="fullscreen_mode">Modo de tela cheia</string>
|
||||
<string name="reader_fullscreen_summary">Ocultar a barra de status e navegação</string>
|
||||
</resources>
|
||||
@@ -554,7 +554,7 @@
|
||||
<string name="volume_">Volume %d</string>
|
||||
<string name="volume_unknown">Volume desconhecido</string>
|
||||
<string name="approximate_reading_time">Tempo aproximado de leitura</string>
|
||||
<string name="incognito_mode_hint">Seu processo de leitura não será salvo</string>
|
||||
<string name="incognito_mode_hint">Seu progresso de leitura não será salvo</string>
|
||||
<string name="vertical">Vertical</string>
|
||||
<string name="email_password_enter_hint">Coloque seu email e senha para continuar</string>
|
||||
<string name="mark_as_completed_prompt">Marcar o mangá selecionado como lido completamente?
|
||||
@@ -580,4 +580,8 @@
|
||||
<string name="two_pages">Duas páginas</string>
|
||||
<string name="mark_as_completed">Marcar como concluído</string>
|
||||
<string name="none">nenhum</string>
|
||||
<string name="last_read">Última leitura</string>
|
||||
<string name="default_webtoon_zoom_out">Diminuir para zoom padrão do webtoon</string>
|
||||
<string name="fullscreen_mode">Modo de tela cheia</string>
|
||||
<string name="reader_fullscreen_summary">Ocultar a barra de status e navegação</string>
|
||||
</resources>
|
||||
@@ -251,7 +251,7 @@
|
||||
<string name="dns_over_https">DNS поверх HTTPS</string>
|
||||
<string name="default_mode">Режим по умолчанию</string>
|
||||
<string name="detect_reader_mode">Автоопределение режима чтения</string>
|
||||
<string name="detect_reader_mode_summary">Автоматически определяет, является ли манга веб-комиксом</string>
|
||||
<string name="detect_reader_mode_summary">Автоматически определять, является ли манга манхвой</string>
|
||||
<string name="disable_battery_optimization">Отключить оптимизацию батареи</string>
|
||||
<string name="disable_battery_optimization_summary">Помогает с фоновой проверкой обновлений</string>
|
||||
<string name="crash_text">Что-то пошло не так. Пожалуйста, отправьте отчёт разработчикам, чтобы помочь всё исправить.</string>
|
||||
@@ -423,7 +423,7 @@
|
||||
<string name="images_proxy_title">Прокси для оптимизации изображений</string>
|
||||
<string name="images_procy_description">Используйте службу wsrv.nl, чтобы уменьшить использование трафика и ускорить загрузку изображений, если это возможно</string>
|
||||
<string name="invert_colors">Инвертировать цвета</string>
|
||||
<string name="webtoon_zoom_summary">Включить жест увеличения масштаба в режиме манхвы</string>
|
||||
<string name="webtoon_zoom_summary">Разрешить жесты масштабирования в режиме манхвы</string>
|
||||
<string name="network">Сеть</string>
|
||||
<string name="data_and_privacy">Данные и конфиденциальность</string>
|
||||
<string name="restore_summary">Восстановить ранее созданную резервную копию</string>
|
||||
@@ -583,5 +583,7 @@
|
||||
<string name="use_two_pages_landscape">Использовать двухстраничный макет в альбомной ориентации (бета)</string>
|
||||
<string name="default_webtoon_zoom_out">Отдаление в режиме манхвы</string>
|
||||
<string name="fullscreen_mode">На весь экран</string>
|
||||
<string name="reader_fullscreen_summary">Скрывать системный интерфейс</string>
|
||||
<string name="reader_fullscreen_summary">Скрывать интерфейс системы</string>
|
||||
<string name="reading_time_estimation">Отображать предполагаемое время чтения</string>
|
||||
<string name="reading_time_estimation_summary">Данное значение может быть неточным</string>
|
||||
</resources>
|
||||
@@ -581,4 +581,7 @@
|
||||
<string name="config_reset_confirm">Ayarlar öntanımlı değerlere sıfırlansın mı? Bu eylem geri alınamaz.</string>
|
||||
<string name="use_two_pages_landscape">Yatay yönde iki sayfa düzeni kullan (beta)</string>
|
||||
<string name="email_password_enter_hint">Devam etmek için e-posta adresinizi ve parolanızı girin</string>
|
||||
<string name="default_webtoon_zoom_out">Öntanımlı webtoon uzaklaştırması</string>
|
||||
<string name="fullscreen_mode">Tam ekran modu</string>
|
||||
<string name="reader_fullscreen_summary">Sistem durumunu ve gezinme çubuklarını gizle</string>
|
||||
</resources>
|
||||
@@ -58,7 +58,7 @@
|
||||
<string name="clear_pages_cache">Очистити кеш сторінок</string>
|
||||
<string name="text_file_sizes">Б|кБ|МБ|ГБ|ТБ</string>
|
||||
<string name="standard">Стандартний</string>
|
||||
<string name="webtoon">Вебтун</string>
|
||||
<string name="webtoon">Манхва</string>
|
||||
<string name="read_mode">Режим читання</string>
|
||||
<string name="grid_size">Розмір сітки</string>
|
||||
<string name="search_on_s">Пошук по %s</string>
|
||||
@@ -250,7 +250,7 @@
|
||||
<string name="removed_from_history">Видалено з історії</string>
|
||||
<string name="dns_over_https">DNS через HTTPS</string>
|
||||
<string name="default_mode">Режим за умовчанням</string>
|
||||
<string name="detect_reader_mode_summary">Автоматично визначати, чи є манґа вебтуном</string>
|
||||
<string name="detect_reader_mode_summary">Автоматично визначати, чи є манґа манхвою</string>
|
||||
<string name="detect_reader_mode">Автовизначення режиму читання</string>
|
||||
<string name="disable_battery_optimization">Вимкнути оптимізацію акумулятора</string>
|
||||
<string name="disable_battery_optimization_summary">Допомагає з перевірками фонових оновлень</string>
|
||||
@@ -342,7 +342,7 @@
|
||||
<string name="different_languages">Різні мови</string>
|
||||
<string name="network_unavailable">Мережа недоступна</string>
|
||||
<string name="network_unavailable_hint">Увімкніть Wi-Fi або мобільну мережу, щоб читати манґу онлайн</string>
|
||||
<string name="webtoon_zoom">Масштабування в режимі вебтуну</string>
|
||||
<string name="webtoon_zoom">Масштабування в режимі манхви</string>
|
||||
<string name="reader_slider">Відображати повзунок перемикання сторінок</string>
|
||||
<string name="compact">Компактно</string>
|
||||
<string name="prefetch_content">Передвчасне завантаження контенту</string>
|
||||
@@ -430,7 +430,7 @@
|
||||
<string name="show_pages_numbers_summary">Показати номери сторінок у нижньому куті</string>
|
||||
<string name="pages_animation_summary">Анімація перегортання сторінок</string>
|
||||
<string name="details_button_tip">Натисніть і утримуйте кнопку «Читати», щоб переглянути додаткові параметри</string>
|
||||
<string name="webtoon_zoom_summary">Дозволити жест збільшення в режимі webtoon</string>
|
||||
<string name="webtoon_zoom_summary">Дозволити жести масштабування в режимі манхви</string>
|
||||
<string name="clear_source_cookies_summary">Очистити файли cookie лише для вказаного домену. У більшості випадків авторизація анулюється</string>
|
||||
<string name="pick_custom_directory">Вибрати користувальницький каталог</string>
|
||||
<string name="no_access_to_file">Ви не маєте доступу до цього файлу чи каталогу</string>
|
||||
@@ -581,4 +581,9 @@
|
||||
<string name="email_password_enter_hint">Введіть свою адресу електронної пошти та пароль, щоб продовжити</string>
|
||||
<string name="config_reset_confirm">Повернути налаштування до значень за замовчуванням? Цю дію неможливо скасувати.</string>
|
||||
<string name="use_two_pages_landscape">Використовувати макет двох сторінок у альбомній орієнтації (бета)</string>
|
||||
<string name="fullscreen_mode">Повноекранний режим</string>
|
||||
<string name="reader_fullscreen_summary">Приховувати інтерфейс системи</string>
|
||||
<string name="default_webtoon_zoom_out">Віддалення у режимі манхви</string>
|
||||
<string name="reading_time_estimation">Відображати передбачуваний час читання</string>
|
||||
<string name="reading_time_estimation_summary">Це значення може бути неточним</string>
|
||||
</resources>
|
||||
@@ -37,9 +37,9 @@
|
||||
<string name="various_languages">多语言</string>
|
||||
<string name="search_chapters">查找章节</string>
|
||||
<string name="suggestions_excluded_genres">排除分类</string>
|
||||
<string name="suggestions_updating">漫画推荐更新</string>
|
||||
<string name="suggestions_updating">正在更新漫画推荐</string>
|
||||
<string name="check_new_chapters_title">检查新章节并通知结果</string>
|
||||
<string name="details">作品详情界面</string>
|
||||
<string name="details">作品详情</string>
|
||||
<string name="detailed_list">卡片</string>
|
||||
<string name="grid">网格</string>
|
||||
<string name="list_mode">视图选项</string>
|
||||
@@ -48,7 +48,7 @@
|
||||
<string name="computing_">计算中…</string>
|
||||
<string name="chapter_d_of_d">%1$d/%2$d 章</string>
|
||||
<string name="close">关闭</string>
|
||||
<string name="try_again">再试一次</string>
|
||||
<string name="try_again">重试</string>
|
||||
<string name="clear_history">清除历史</string>
|
||||
<string name="nothing_found">结果为空</string>
|
||||
<string name="history_is_empty">暂无历史记录</string>
|
||||
@@ -121,11 +121,11 @@
|
||||
<string name="notification_sound">通知声音</string>
|
||||
<string name="light_indicator">LED指示器</string>
|
||||
<string name="vibration">振动</string>
|
||||
<string name="favourites_categories">收藏更新范围</string>
|
||||
<string name="favourites_categories">收藏分类管理</string>
|
||||
<string name="remove_category">删除分类</string>
|
||||
<string name="text_empty_holder_primary">什么都没有…</string>
|
||||
<string name="text_search_holder_secondary">试试换一个词再搜索。</string>
|
||||
<string name="text_history_holder_primary">看过的内容将在这里显示</string>
|
||||
<string name="text_history_holder_primary">看过的漫画将在这里显示</string>
|
||||
<string name="text_history_holder_secondary">在<浏览>页面搜索要读的漫画</string>
|
||||
<string name="text_local_holder_primary">请先在线下载或进行本地导入</string>
|
||||
<string name="text_local_holder_secondary">下载图源内容或通过本地文件导入。</string>
|
||||
@@ -141,7 +141,7 @@
|
||||
<string name="favourites_category_empty">目前分类为空</string>
|
||||
<string name="read_later">稍后阅读</string>
|
||||
<string name="updates">更新内容</string>
|
||||
<string name="text_feed_holder">正在阅读的新章节将在这里显示</string>
|
||||
<string name="text_feed_holder">正在阅读漫画的新章节将在这里显示</string>
|
||||
<string name="search_results">搜索结果</string>
|
||||
<string name="new_version_s">新版本: %s</string>
|
||||
<string name="clear_updates_feed">清除订阅更新记录</string>
|
||||
@@ -227,7 +227,7 @@
|
||||
<string name="suggestions_excluded_genres_summary">输入不希望在推荐中看到的分类</string>
|
||||
<string name="text_delete_local_manga_batch">要从系统中永久删除所选项目吗?</string>
|
||||
<string name="removal_completed">删除成功</string>
|
||||
<string name="download_slowdown">下载速度减慢</string>
|
||||
<string name="download_slowdown">减慢下载速度</string>
|
||||
<string name="download_slowdown_summary">有助于避免封禁你的IP地址</string>
|
||||
<string name="local_manga_processing">正在处理已保存漫画</string>
|
||||
<string name="chapters_will_removed_background">章节将在后台被删除</string>
|
||||
@@ -244,7 +244,7 @@
|
||||
<string name="bookmark_removed">书签已删除</string>
|
||||
<string name="bookmark_added">书签已添加</string>
|
||||
<string name="undo">撤销</string>
|
||||
<string name="removed_from_history">从历史记录中删除</string>
|
||||
<string name="removed_from_history">已从历史记录中删除</string>
|
||||
<string name="dns_over_https">基于 HTTPS 的 DNS</string>
|
||||
<string name="default_mode">默认阅读模式</string>
|
||||
<string name="detect_reader_mode">自动检测阅读模式</string>
|
||||
@@ -271,7 +271,7 @@
|
||||
<string name="exclude_nsfw_from_history_summary">标记为成人内容的漫画将不会添加到历史记录,也不会保存阅读记录</string>
|
||||
<string name="clear_cookies_summary">能对部分问题起到一些作用。所有网站的授权将会失效</string>
|
||||
<string name="show_all">显示全部</string>
|
||||
<string name="manga_error_description_pattern">错误详情:<br><tt>%1$s</tt><br><br>1.尝试<a href=%2$s>在网络浏览器中打开漫画</a>以确保在其图源中可用<br>2. 请确保使用的是<a href=kotatsu://about>最新版本的Kotatsu</a><br>3.若图源没有问题,请向开发人员发送错误报告。</string>
|
||||
<string name="manga_error_description_pattern">错误详情:<br><tt>%1$s</tt><br><br>1.尝试<a href=%2$s>在网络浏览器中打开漫画</a>以确保在其图源中可用<br>2.请确保使用的是<a href=kotatsu://about>最新版本的Kotatsu</a><br>3.若图源没有问题,请向开发人员发送错误报告。</string>
|
||||
<string name="invalid_domain_message">无效域名</string>
|
||||
<string name="text_shelf_holder_primary">此处将显示你的漫画</string>
|
||||
<string name="text_shelf_holder_secondary">在<浏览>页面搜索要读的漫画</string>
|
||||
@@ -315,7 +315,7 @@
|
||||
<string name="other_cache">其他缓存</string>
|
||||
<string name="storage_usage">存储占用</string>
|
||||
<string name="available">可用</string>
|
||||
<string name="removed_from_favourites">从收藏中删除</string>
|
||||
<string name="removed_from_favourites">已从收藏中删除</string>
|
||||
<string name="options">选项</string>
|
||||
<string name="incognito_mode">无痕模式</string>
|
||||
<string name="no_chapters">没有章节</string>
|
||||
@@ -411,7 +411,7 @@
|
||||
<string name="address">地址</string>
|
||||
<string name="clear_network_cache">清除网络缓存</string>
|
||||
<string name="proxy">代理</string>
|
||||
<string name="type">漫画类型</string>
|
||||
<string name="type">类型</string>
|
||||
<string name="invalid_value_message">无效值</string>
|
||||
<string name="network">网络</string>
|
||||
<string name="restore_summary">从以前创建的备份恢复</string>
|
||||
@@ -449,7 +449,7 @@
|
||||
<string name="languages">语言</string>
|
||||
<string name="captcha_required_summary">%s 需要通过验证才能正常运行</string>
|
||||
<string name="progress">阅读进度</string>
|
||||
<string name="error_corrupted_file">无效数据回传或文件已损坏</string>
|
||||
<string name="error_corrupted_file">回传的数据无效或文件已损坏</string>
|
||||
<string name="related_manga_summary">显示相关漫画。可能并不准确或缺失</string>
|
||||
<string name="tracker_wifi_only_summary">使用移动网络时停止检查新章节</string>
|
||||
<string name="order_added">添加日期</string>
|
||||
@@ -520,7 +520,7 @@
|
||||
<string name="downloads_settings_info">若遇到服务器端阻塞,可以在图源设置中为每个图源单独开启限速下载功能</string>
|
||||
<string name="skip">跳过</string>
|
||||
<string name="backup_date_">备份日期:%s</string>
|
||||
<string name="content_rating">内容评级</string>
|
||||
<string name="content_rating">内容分级</string>
|
||||
<string name="genres_exclude">排除分类</string>
|
||||
<string name="rating_safe">全年龄</string>
|
||||
<string name="rating_suggestive">R15</string>
|
||||
@@ -539,10 +539,10 @@
|
||||
<string name="available_d">%1$d 个可用</string>
|
||||
<string name="disable_nsfw_summary">禁用成人内容图源并尽可能从列表中隐藏成人漫画</string>
|
||||
<string name="speed_value">x%.1f</string>
|
||||
<string name="error_filter_locale_genre_not_supported">此图源不支持同时按分类和区域过滤</string>
|
||||
<string name="error_filter_states_genre_not_supported">此图源不支持同时按分类和状态过滤</string>
|
||||
<string name="error_filter_locale_genre_not_supported">此图源不支持同时按分类和区域筛选</string>
|
||||
<string name="error_filter_states_genre_not_supported">此图源不支持同时按分类和状态筛选</string>
|
||||
<string name="genres_search_hint">开始输入分类名称</string>
|
||||
<string name="state_paused">暂停</string>
|
||||
<string name="state_paused">休刊中</string>
|
||||
<string name="reader_optimize">降低内存占用(测试)</string>
|
||||
<string name="reader_optimize_summary">降低当前画面外的页面质量以减少内存占用</string>
|
||||
<string name="disable_battery_optimization_summary_downloads">可能帮助解决下载过程相关的问题</string>
|
||||
@@ -551,19 +551,19 @@
|
||||
<string name="error_multiple_genres_not_supported">此图源不支持按多个分类筛选</string>
|
||||
<string name="error_multiple_states_not_supported">此图源不支持按多个状态筛选</string>
|
||||
<string name="by_relevance">关联</string>
|
||||
<string name="mark_as_completed">标记为已读完</string>
|
||||
<string name="mark_as_completed_prompt">要将选定的漫画标记为已读完吗?
|
||||
<string name="mark_as_completed">标记为已读</string>
|
||||
<string name="mark_as_completed_prompt">要将选定的漫画标记为已读吗?
|
||||
\n
|
||||
\n警告: 当前的阅读进度将会丢失。</string>
|
||||
<string name="category_hidden_done">此分类已从主页隐藏,可通过菜单 → 管理分类来访问</string>
|
||||
<string name="approximate_reading_time">大约需要的阅读时间</string>
|
||||
<string name="approximate_remaining_time">大约剩余时间</string>
|
||||
<string name="approximate_reading_time">估计所需阅读时间</string>
|
||||
<string name="approximate_remaining_time">估计剩余阅读时间</string>
|
||||
<string name="remaining_time_pattern">%1$s %2$s</string>
|
||||
<string name="volume_">第 %d 卷</string>
|
||||
<string name="volume_unknown">未知卷</string>
|
||||
<string name="incognito_mode_hint">阅读进度不会保存</string>
|
||||
<string name="vertical">垂直</string>
|
||||
<string name="last_read">上次阅读</string>
|
||||
<string name="last_read">最近阅读</string>
|
||||
<string name="switch_pages_volume_buttons_summary">使用音量键翻页</string>
|
||||
<string name="two_pages">双页</string>
|
||||
<string name="show_menu">显示菜单</string>
|
||||
@@ -581,4 +581,7 @@
|
||||
<string name="use_two_pages_landscape">在横屏时开启双页模式(测试)</string>
|
||||
<string name="config_reset_confirm">要恢复为默认设置吗?恢复后无法撤销。</string>
|
||||
<string name="email_password_enter_hint">输入邮箱和密码以继续</string>
|
||||
<string name="fullscreen_mode">全屏模式</string>
|
||||
<string name="default_webtoon_zoom_out">条漫默认缩小值</string>
|
||||
<string name="reader_fullscreen_summary">将系统状态栏与通知栏隐藏</string>
|
||||
</resources>
|
||||
@@ -167,4 +167,9 @@
|
||||
<attr name="chipStyle" />
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="ReaderInfoBarView">
|
||||
<attr name="android:textSize" />
|
||||
<attr name="android:strokeWidth" />
|
||||
</declare-styleable>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -588,4 +588,9 @@
|
||||
<string name="default_webtoon_zoom_out">Default webtoon zoom out</string>
|
||||
<string name="fullscreen_mode">Fullscreen mode</string>
|
||||
<string name="reader_fullscreen_summary">Hide system status and navigation bars</string>
|
||||
<string name="fraction_pattern" translatable="false">%1$d/%2$d</string>
|
||||
<string name="reading_time_estimation">Show estimated reading time</string>
|
||||
<string name="reading_time_estimation_summary">The time estimation value may be inaccurate</string>
|
||||
<string name="suggestions_unavailable_text">Suggestions feature is disabled</string>
|
||||
<string name="check_for_new_chapters_disabled">Checking for new chapters is disabled</string>
|
||||
</resources>
|
||||
|
||||
@@ -49,6 +49,12 @@
|
||||
<PreferenceCategory
|
||||
android:title="@string/details">
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="reading_time"
|
||||
android:summary="@string/reading_time_estimation_summary"
|
||||
android:title="@string/reading_time_estimation" />
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="0"
|
||||
android:entries="@array/details_tabs"
|
||||
|
||||
Reference in New Issue
Block a user