Compare commits

..

26 Commits

Author SHA1 Message Date
656a707b4c Bump version 2023-01-01 08:49:15 +02:00
04afe7a934 Bind ssiv with lifecycle 2023-01-01 08:17:07 +02:00
689670b3ff Show inconito mode indicator on Read button 2023-01-01 08:17:03 +02:00
6273a9decb Merge pull request #281 from weblate/weblate-kotatsu-strings
Translations update from Hosted Weblate
2022-12-31 22:37:57 +03:00
Eric
72336d4f71 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (399 of 399 strings)

Co-authored-by: Eric <hamburger2048@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2022-12-31 20:33:30 +01:00
J. Lavoie
731e998eb2 Translated using Weblate (French)
Currently translated at 100.0% (399 of 399 strings)

Translated using Weblate (Italian)

Currently translated at 79.9% (319 of 399 strings)

Translated using Weblate (German)

Currently translated at 97.2% (388 of 399 strings)

Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/de/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fr/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/it/
Translation: Kotatsu/Strings
2022-12-31 20:33:30 +01:00
gallegonovato
9bf53114de Translated using Weblate (Spanish)
Currently translated at 100.0% (399 of 399 strings)

Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/
Translation: Kotatsu/Strings
2022-12-31 20:33:30 +01:00
0e1b8db688 Update parsers, Happy New Year! 2022-12-31 22:32:35 +03:00
3a62e2e6c0 Add monochrome icon on One UI 5.0 2022-12-31 15:08:47 +03:00
08764cb3cb Translated using Weblate (Russian)
Currently translated at 100.0% (399 of 399 strings)

Co-authored-by: Koitharu <nvasya95@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ru/
Translation: Kotatsu/Strings
2022-12-27 09:00:05 +02:00
Evgeniy Khramov
9c52545f63 Translated using Weblate (Russian)
Currently translated at 100.0% (398 of 398 strings)

Translated using Weblate (Russian)

Currently translated at 100.0% (8 of 8 strings)

Co-authored-by: Evgeniy Khramov <thejenjagamertjg@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/plurals/ru/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ru/
Translation: Kotatsu/Strings
Translation: Kotatsu/plurals
2022-12-27 09:00:05 +02:00
gallegonovato
a6c30d33d4 Translated using Weblate (Spanish)
Currently translated at 100.0% (398 of 398 strings)

Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/es/
Translation: Kotatsu/Strings
2022-12-27 09:00:05 +02:00
Neko Nekowazarashi
25974af229 Translated using Weblate (Indonesian)
Currently translated at 90.2% (359 of 398 strings)

Co-authored-by: Neko Nekowazarashi <kodra@nekoweb.my.id>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/id/
Translation: Kotatsu/Strings
2022-12-27 09:00:05 +02:00
Andy Hong
607dfc9be3 Translated using Weblate (Korean)
Currently translated at 26.8% (107 of 398 strings)

Added translation using Weblate (Korean)

Added translation using Weblate (Korean)

Co-authored-by: Andy Hong <andy963963@icloud.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ko/
Translation: Kotatsu/Strings
2022-12-27 09:00:05 +02:00
mondstern
560e669700 Translated using Weblate (German)
Currently translated at 97.2% (387 of 398 strings)

Co-authored-by: mondstern <mondstern@snopyta.org>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/de/
Translation: Kotatsu/Strings
2022-12-27 09:00:05 +02:00
J. Lavoie
ba403c9360 Translated using Weblate (French)
Currently translated at 100.0% (398 of 398 strings)

Translated using Weblate (German)

Currently translated at 96.2% (383 of 398 strings)

Co-authored-by: J. Lavoie <j.lavoie@net-c.ca>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/de/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fr/
Translation: Kotatsu/Strings
2022-12-27 09:00:05 +02:00
Eric
0f1c9ff05d Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (398 of 398 strings)

Co-authored-by: Eric <hamburger1024@duck.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/zh_Hans/
Translation: Kotatsu/Strings
2022-12-27 09:00:05 +02:00
kuragehime
662f08e115 Translated using Weblate (Japanese)
Currently translated at 100.0% (398 of 398 strings)

Co-authored-by: kuragehime <kuragehime641@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/ja/
Translation: Kotatsu/Strings
2022-12-27 09:00:05 +02:00
Oğuz Ersen
d647a32e9f Translated using Weblate (Turkish)
Currently translated at 100.0% (399 of 399 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (398 of 398 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/
Translation: Kotatsu/Strings
2022-12-27 09:00:05 +02:00
375e72cb98 Pass language to voice search 2022-12-27 08:55:39 +02:00
34c7cafdfe Use AlphanumComparator for importing manga dir 2022-12-27 08:39:27 +02:00
NOTMASTER09
03e0eefe4d Fix DirMangaImporter 2022-12-27 08:36:18 +02:00
f41425f03d Popup menu on sources in Explore fragment 2022-12-26 20:02:02 +02:00
400b91278f Allow source login on error 2022-12-26 19:27:38 +02:00
9088f77ae5 Update dependencies 2022-12-26 19:15:27 +02:00
86da3217d1 Add A13 locale list 2022-12-26 19:15:17 +02:00
38 changed files with 433 additions and 114 deletions

View File

@@ -15,8 +15,8 @@ android {
applicationId 'org.koitharu.kotatsu' applicationId 'org.koitharu.kotatsu'
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 33 targetSdkVersion 33
versionCode 506 versionCode 508
versionName '4.0.6' versionName '4.1.1'
generatedDensities = [] generatedDensities = []
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@@ -83,7 +83,7 @@ afterEvaluate {
} }
} }
dependencies { dependencies {
implementation('com.github.KotatsuApp:kotatsu-parsers:add70b4790') { implementation('com.github.KotatsuApp:kotatsu-parsers:c4acb9725f') {
exclude group: 'org.json', module: 'json' exclude group: 'org.json', module: 'json'
} }
@@ -125,7 +125,7 @@ dependencies {
implementation 'io.coil-kt:coil-base:2.2.2' implementation 'io.coil-kt:coil-base:2.2.2'
implementation 'io.coil-kt:coil-svg:2.2.2' implementation 'io.coil-kt:coil-svg:2.2.2'
implementation 'com.github.KotatsuApp:subsampling-scale-image-view:f8a38b08fe' implementation 'com.github.KotatsuApp:subsampling-scale-image-view:1b19231b2f'
implementation 'com.github.solkin:disk-lru-cache:1.4' implementation 'com.github.solkin:disk-lru-cache:1.4'
implementation 'ch.acra:acra-http:5.9.7' implementation 'ch.acra:acra-http:5.9.7'

View File

@@ -29,6 +29,7 @@
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:largeHeap="true" android:largeHeap="true"
android:localeConfig="@xml/locales"
android:networkSecurityConfig="@xml/network_security_config" android:networkSecurityConfig="@xml/network_security_config"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
@@ -247,6 +248,9 @@
<meta-data <meta-data
android:name="android.webkit.WebView.MetricsOptOut" android:name="android.webkit.WebView.MetricsOptOut"
android:value="true" /> android:value="true" />
<meta-data
android:name="com.samsung.android.icon_container.has_icon_container"
android:value="@bool/com_samsung_android_icon_container_has_icon_container"/>
</application> </application>

View File

@@ -228,18 +228,18 @@ class DetailsActivity :
} }
} }
private fun onHistoryChanged(info: HistoryInfo?) { private fun onHistoryChanged(info: HistoryInfo) {
with(binding.buttonRead) { with(binding.buttonRead) {
if (info?.history != null) { if (info.history != null) {
setText(R.string._continue) setText(R.string._continue)
setIconResource(R.drawable.ic_play) setIconResource(if (info.isIncognitoMode) R.drawable.ic_incognito else R.drawable.ic_play)
} else { } else {
setText(R.string.read) setText(R.string.read)
setIconResource(R.drawable.ic_read) setIconResource(if (info.isIncognitoMode) R.drawable.ic_incognito else R.drawable.ic_play)
} }
} }
val text = when { val text = when {
info == null -> getString(R.string.loading_) !info.isValid -> getString(R.string.loading_)
info.currentChapter >= 0 -> getString(R.string.chapter_d_of_d, info.currentChapter + 1, info.totalChapters) info.currentChapter >= 0 -> getString(R.string.chapter_d_of_d, info.currentChapter + 1, info.totalChapters)
info.totalChapters == 0 -> getString(R.string.no_chapters) info.totalChapters == 0 -> getString(R.string.no_chapters)
else -> resources.getQuantityString(R.plurals.chapters, info.totalChapters, info.totalChapters) else -> resources.getQuantityString(R.plurals.chapters, info.totalChapters, info.totalChapters)

View File

@@ -18,7 +18,6 @@ import coil.request.ImageRequest
import coil.util.CoilUtils import coil.util.CoilUtils
import com.google.android.material.chip.Chip import com.google.android.material.chip.Chip
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.ui.BaseFragment import org.koitharu.kotatsu.base.ui.BaseFragment
@@ -27,9 +26,9 @@ import org.koitharu.kotatsu.base.ui.list.decor.SpacingItemDecoration
import org.koitharu.kotatsu.base.ui.widgets.ChipsView import org.koitharu.kotatsu.base.ui.widgets.ChipsView
import org.koitharu.kotatsu.bookmarks.domain.Bookmark import org.koitharu.kotatsu.bookmarks.domain.Bookmark
import org.koitharu.kotatsu.bookmarks.ui.adapter.BookmarksAdapter import org.koitharu.kotatsu.bookmarks.ui.adapter.BookmarksAdapter
import org.koitharu.kotatsu.core.model.MangaHistory
import org.koitharu.kotatsu.databinding.FragmentDetailsBinding import org.koitharu.kotatsu.databinding.FragmentDetailsBinding
import org.koitharu.kotatsu.details.ui.model.ChapterListItem import org.koitharu.kotatsu.details.ui.model.ChapterListItem
import org.koitharu.kotatsu.details.ui.model.HistoryInfo
import org.koitharu.kotatsu.details.ui.scrobbling.ScrobblingItemDecoration import org.koitharu.kotatsu.details.ui.scrobbling.ScrobblingItemDecoration
import org.koitharu.kotatsu.details.ui.scrobbling.ScrollingInfoAdapter import org.koitharu.kotatsu.details.ui.scrobbling.ScrollingInfoAdapter
import org.koitharu.kotatsu.history.domain.PROGRESS_NONE import org.koitharu.kotatsu.history.domain.PROGRESS_NONE
@@ -45,8 +44,20 @@ import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblingInfo
import org.koitharu.kotatsu.search.ui.MangaListActivity import org.koitharu.kotatsu.search.ui.MangaListActivity
import org.koitharu.kotatsu.search.ui.SearchActivity import org.koitharu.kotatsu.search.ui.SearchActivity
import org.koitharu.kotatsu.utils.FileSize import org.koitharu.kotatsu.utils.FileSize
import org.koitharu.kotatsu.utils.ext.* import org.koitharu.kotatsu.utils.ext.computeSize
import org.koitharu.kotatsu.utils.ext.crossfade
import org.koitharu.kotatsu.utils.ext.drawableTop
import org.koitharu.kotatsu.utils.ext.enqueueWith
import org.koitharu.kotatsu.utils.ext.ifNullOrEmpty
import org.koitharu.kotatsu.utils.ext.measureHeight
import org.koitharu.kotatsu.utils.ext.referer
import org.koitharu.kotatsu.utils.ext.resolveDp
import org.koitharu.kotatsu.utils.ext.scaleUpActivityOptionsOf
import org.koitharu.kotatsu.utils.ext.textAndVisible
import org.koitharu.kotatsu.utils.ext.toFileOrNull
import org.koitharu.kotatsu.utils.ext.viewLifecycleScope
import org.koitharu.kotatsu.utils.image.CoverSizeResolver import org.koitharu.kotatsu.utils.image.CoverSizeResolver
import javax.inject.Inject
@AndroidEntryPoint @AndroidEntryPoint
class DetailsFragment : class DetailsFragment :
@@ -75,7 +86,7 @@ class DetailsFragment :
binding.chipsTags.onChipClickListener = this binding.chipsTags.onChipClickListener = this
viewModel.manga.observe(viewLifecycleOwner, ::onMangaUpdated) viewModel.manga.observe(viewLifecycleOwner, ::onMangaUpdated)
viewModel.isLoading.observe(viewLifecycleOwner, ::onLoadingStateChanged) viewModel.isLoading.observe(viewLifecycleOwner, ::onLoadingStateChanged)
viewModel.readingHistory.observe(viewLifecycleOwner, ::onHistoryChanged) viewModel.historyInfo.observe(viewLifecycleOwner, ::onHistoryChanged)
viewModel.bookmarks.observe(viewLifecycleOwner, ::onBookmarksChanged) viewModel.bookmarks.observe(viewLifecycleOwner, ::onBookmarksChanged)
viewModel.scrobblingInfo.observe(viewLifecycleOwner, ::onScrobblingInfoChanged) viewModel.scrobblingInfo.observe(viewLifecycleOwner, ::onScrobblingInfoChanged)
viewModel.description.observe(viewLifecycleOwner, ::onDescriptionChanged) viewModel.description.observe(viewLifecycleOwner, ::onDescriptionChanged)
@@ -123,12 +134,14 @@ class DetailsFragment :
drawableTop = ContextCompat.getDrawable(context, R.drawable.ic_state_finished) drawableTop = ContextCompat.getDrawable(context, R.drawable.ic_state_finished)
} }
} }
MangaState.ONGOING -> { MangaState.ONGOING -> {
infoLayout.textViewState.apply { infoLayout.textViewState.apply {
textAndVisible = resources.getString(R.string.state_ongoing) textAndVisible = resources.getString(R.string.state_ongoing)
drawableTop = ContextCompat.getDrawable(context, R.drawable.ic_state_ongoing) drawableTop = ContextCompat.getDrawable(context, R.drawable.ic_state_ongoing)
} }
} }
else -> infoLayout.textViewState.isVisible = false else -> infoLayout.textViewState.isVisible = false
} }
if (manga.source == MangaSource.LOCAL) { if (manga.source == MangaSource.LOCAL) {
@@ -178,8 +191,8 @@ class DetailsFragment :
} }
} }
private fun onHistoryChanged(history: MangaHistory?) { private fun onHistoryChanged(history: HistoryInfo) {
binding.progressView.setPercent(history?.percent ?: PROGRESS_NONE, animate = true) binding.progressView.setPercent(history.history?.percent ?: PROGRESS_NONE, animate = true)
} }
private fun onLoadingStateChanged(isLoading: Boolean) { private fun onLoadingStateChanged(isLoading: Boolean) {
@@ -229,6 +242,7 @@ class DetailsFragment :
), ),
) )
} }
R.id.textView_source -> { R.id.textView_source -> {
startActivity( startActivity(
MangaListActivity.newIntent( MangaListActivity.newIntent(
@@ -237,6 +251,7 @@ class DetailsFragment :
), ),
) )
} }
R.id.imageView_cover -> { R.id.imageView_cover -> {
startActivity( startActivity(
ImageActivity.newIntent(v.context, manga.largeCoverUrl.ifNullOrEmpty { manga.coverUrl }), ImageActivity.newIntent(v.context, manga.largeCoverUrl.ifNullOrEmpty { manga.coverUrl }),
@@ -249,7 +264,7 @@ class DetailsFragment :
override fun onLongClick(v: View): Boolean { override fun onLongClick(v: View): Boolean {
when (v.id) { when (v.id) {
R.id.button_read -> { R.id.button_read -> {
if (viewModel.readingHistory.value == null) { if (viewModel.historyInfo.value?.history == null) {
return false return false
} }
val menu = PopupMenu(v.context, v) val menu = PopupMenu(v.context, v)
@@ -271,12 +286,14 @@ class DetailsFragment :
) )
true true
} }
else -> false else -> false
} }
} }
menu.show() menu.show()
return true return true
} }
else -> return false else -> return false
} }
} }

View File

@@ -13,10 +13,18 @@ import androidx.lifecycle.viewModelScope
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject import dagger.assisted.AssistedInject
import java.io.IOException
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChangedBy
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.transformLatest
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.plus import kotlinx.coroutines.plus
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
@@ -46,6 +54,7 @@ import org.koitharu.kotatsu.utils.asFlowLiveData
import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct
import org.koitharu.kotatsu.utils.ext.printStackTraceDebug import org.koitharu.kotatsu.utils.ext.printStackTraceDebug
import org.koitharu.kotatsu.utils.ext.runCatchingCancellable import org.koitharu.kotatsu.utils.ext.runCatchingCancellable
import java.io.IOException
class DetailsViewModel @AssistedInject constructor( class DetailsViewModel @AssistedInject constructor(
@Assisted intent: MangaIntent, @Assisted intent: MangaIntent,
@@ -91,17 +100,18 @@ class DetailsViewModel @AssistedInject constructor(
val manga = delegate.manga.filterNotNull().asLiveData(viewModelScope.coroutineContext) val manga = delegate.manga.filterNotNull().asLiveData(viewModelScope.coroutineContext)
val favouriteCategories = favourite.asLiveData(viewModelScope.coroutineContext) val favouriteCategories = favourite.asLiveData(viewModelScope.coroutineContext)
val newChaptersCount = newChapters.asLiveData(viewModelScope.coroutineContext) val newChaptersCount = newChapters.asLiveData(viewModelScope.coroutineContext)
@Deprecated("")
val readingHistory = history.asLiveData(viewModelScope.coroutineContext)
val isChaptersReversed = chaptersReversed.asLiveData(viewModelScope.coroutineContext) val isChaptersReversed = chaptersReversed.asLiveData(viewModelScope.coroutineContext)
val historyInfo = combine( val historyInfo: LiveData<HistoryInfo> = combine(
delegate.manga, delegate.manga,
history, history,
) { m, h -> settings.observeAsFlow(AppSettings.KEY_INCOGNITO_MODE) { isIncognitoModeEnabled },
HistoryInfo(m, h) ) { m, h, im ->
}.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, null) HistoryInfo(m, h, im)
}.asFlowLiveData(
context = viewModelScope.coroutineContext + Dispatchers.Default,
defaultValue = HistoryInfo(null, null, false),
)
val bookmarks = delegate.manga.flatMapLatest { val bookmarks = delegate.manga.flatMapLatest {
if (it != null) bookmarksRepository.observeBookmarks(it) else flowOf(emptyList()) if (it != null) bookmarksRepository.observeBookmarks(it) else flowOf(emptyList())

View File

@@ -7,8 +7,12 @@ class HistoryInfo(
val totalChapters: Int, val totalChapters: Int,
val currentChapter: Int, val currentChapter: Int,
val history: MangaHistory?, val history: MangaHistory?,
val isIncognitoMode: Boolean,
) { ) {
val isValid: Boolean
get() = totalChapters >= 0
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
if (this === other) return true if (this === other) return true
if (javaClass != other?.javaClass) return false if (javaClass != other?.javaClass) return false
@@ -18,6 +22,7 @@ class HistoryInfo(
if (totalChapters != other.totalChapters) return false if (totalChapters != other.totalChapters) return false
if (currentChapter != other.currentChapter) return false if (currentChapter != other.currentChapter) return false
if (history != other.history) return false if (history != other.history) return false
if (isIncognitoMode != other.isIncognitoMode) return false
return true return true
} }
@@ -26,20 +31,21 @@ class HistoryInfo(
var result = totalChapters var result = totalChapters
result = 31 * result + currentChapter result = 31 * result + currentChapter
result = 31 * result + (history?.hashCode() ?: 0) result = 31 * result + (history?.hashCode() ?: 0)
result = 31 * result + isIncognitoMode.hashCode()
return result return result
} }
} }
@Suppress("FunctionName") fun HistoryInfo(manga: Manga?, history: MangaHistory?, isIncognitoMode: Boolean): HistoryInfo {
fun HistoryInfo(manga: Manga?, history: MangaHistory?): HistoryInfo? { val chapters = manga?.chapters
val chapters = manga?.chapters ?: return null
return HistoryInfo( return HistoryInfo(
totalChapters = chapters.size, totalChapters = chapters?.size ?: -1,
currentChapter = if (history != null) { currentChapter = if (history != null && !chapters.isNullOrEmpty()) {
chapters.indexOfFirst { it.id == history.chapterId } chapters.indexOfFirst { it.id == history.chapterId }
} else { } else {
-1 -1
}, },
history = history, history = history,
isIncognitoMode = isIncognitoMode,
) )
} }

View File

@@ -2,8 +2,10 @@ package org.koitharu.kotatsu.explore.ui
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.appcompat.widget.PopupMenu
import androidx.core.graphics.Insets import androidx.core.graphics.Insets
import androidx.core.view.updatePadding import androidx.core.view.updatePadding
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
@@ -11,11 +13,12 @@ import androidx.recyclerview.widget.RecyclerView
import coil.ImageLoader import coil.ImageLoader
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.domain.reverseAsync
import org.koitharu.kotatsu.base.ui.BaseFragment import org.koitharu.kotatsu.base.ui.BaseFragment
import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.base.ui.util.RecyclerViewOwner import org.koitharu.kotatsu.base.ui.util.RecyclerViewOwner
import org.koitharu.kotatsu.base.ui.util.ReversibleAction
import org.koitharu.kotatsu.bookmarks.ui.BookmarksActivity import org.koitharu.kotatsu.bookmarks.ui.BookmarksActivity
import org.koitharu.kotatsu.databinding.FragmentExploreBinding import org.koitharu.kotatsu.databinding.FragmentExploreBinding
import org.koitharu.kotatsu.details.ui.DetailsActivity import org.koitharu.kotatsu.details.ui.DetailsActivity
@@ -31,6 +34,7 @@ import org.koitharu.kotatsu.search.ui.MangaListActivity
import org.koitharu.kotatsu.settings.SettingsActivity import org.koitharu.kotatsu.settings.SettingsActivity
import org.koitharu.kotatsu.suggestions.ui.SuggestionsActivity import org.koitharu.kotatsu.suggestions.ui.SuggestionsActivity
import org.koitharu.kotatsu.utils.ext.getDisplayMessage import org.koitharu.kotatsu.utils.ext.getDisplayMessage
import javax.inject.Inject
@AndroidEntryPoint @AndroidEntryPoint
class ExploreFragment : class ExploreFragment :
@@ -67,6 +71,7 @@ class ExploreFragment :
} }
viewModel.onError.observe(viewLifecycleOwner, ::onError) viewModel.onError.observe(viewLifecycleOwner, ::onError)
viewModel.onOpenManga.observe(viewLifecycleOwner, ::onOpenManga) viewModel.onOpenManga.observe(viewLifecycleOwner, ::onOpenManga)
viewModel.onActionDone.observe(viewLifecycleOwner, ::onActionDone)
} }
override fun onDestroyView() { override fun onDestroyView() {
@@ -95,6 +100,7 @@ class ExploreFragment :
viewModel.openRandom() viewModel.openRandom()
return return
} }
else -> return else -> return
} }
startActivity(intent) startActivity(intent)
@@ -105,6 +111,14 @@ class ExploreFragment :
startActivity(intent) startActivity(intent)
} }
override fun onItemLongClick(item: ExploreItem.Source, view: View): Boolean {
val menu = PopupMenu(view.context, view)
menu.inflate(R.menu.popup_source)
menu.setOnMenuItemClickListener(SourceMenuListener(item))
menu.show()
return true
}
override fun onRetryClick(error: Throwable) = Unit override fun onRetryClick(error: Throwable) = Unit
override fun onEmptyActionClick() = onManageClick(requireView()) override fun onEmptyActionClick() = onManageClick(requireView())
@@ -124,6 +138,37 @@ class ExploreFragment :
startActivity(intent) startActivity(intent)
} }
private fun onActionDone(action: ReversibleAction) {
val handle = action.handle
val length = if (handle == null) Snackbar.LENGTH_SHORT else Snackbar.LENGTH_LONG
val snackbar = Snackbar.make(binding.recyclerView, action.stringResId, length)
if (handle != null) {
snackbar.setAction(R.string.undo) { handle.reverseAsync() }
}
snackbar.anchorView = (activity as? BottomNavOwner)?.bottomNav
snackbar.show()
}
private inner class SourceMenuListener(
private val sourceItem: ExploreItem.Source,
) : PopupMenu.OnMenuItemClickListener {
override fun onMenuItemClick(item: MenuItem): Boolean {
when (item.itemId) {
R.id.action_settings -> {
startActivity(SettingsActivity.newSourceSettingsIntent(requireContext(), sourceItem.source))
}
R.id.action_hide -> {
viewModel.hideSource(sourceItem.source)
}
else -> return false
}
return true
}
}
companion object { companion object {
fun newInstance() = ExploreFragment() fun newInstance() = ExploreFragment()

View File

@@ -4,11 +4,17 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.asFlow import androidx.lifecycle.asFlow
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.domain.ReversibleHandle
import org.koitharu.kotatsu.base.ui.BaseViewModel import org.koitharu.kotatsu.base.ui.BaseViewModel
import org.koitharu.kotatsu.base.ui.util.ReversibleAction
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.explore.domain.ExploreRepository import org.koitharu.kotatsu.explore.domain.ExploreRepository
import org.koitharu.kotatsu.explore.ui.model.ExploreItem import org.koitharu.kotatsu.explore.ui.model.ExploreItem
@@ -16,6 +22,7 @@ import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.utils.SingleLiveEvent import org.koitharu.kotatsu.utils.SingleLiveEvent
import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct
import javax.inject.Inject
@HiltViewModel @HiltViewModel
class ExploreViewModel @Inject constructor( class ExploreViewModel @Inject constructor(
@@ -24,6 +31,7 @@ class ExploreViewModel @Inject constructor(
) : BaseViewModel() { ) : BaseViewModel() {
val onOpenManga = SingleLiveEvent<Manga>() val onOpenManga = SingleLiveEvent<Manga>()
val onActionDone = SingleLiveEvent<ReversibleAction>()
val content: LiveData<List<ExploreItem>> = isLoading.asFlow().flatMapLatest { loading -> val content: LiveData<List<ExploreItem>> = isLoading.asFlow().flatMapLatest { loading ->
if (loading) { if (loading) {
@@ -40,6 +48,16 @@ class ExploreViewModel @Inject constructor(
} }
} }
fun hideSource(source: MangaSource) {
launchJob(Dispatchers.Default) {
settings.hiddenSources += source.name
val rollback = ReversibleHandle {
settings.hiddenSources -= source.name
}
onActionDone.postCall(ReversibleAction(R.string.source_disabled, rollback))
}
}
private fun createContentFlow() = settings.observe() private fun createContentFlow() = settings.observe()
.filter { .filter {
it == AppSettings.KEY_SOURCES_HIDDEN || it == AppSettings.KEY_SOURCES_HIDDEN ||

View File

@@ -13,6 +13,7 @@ import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaChapter import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.model.RATING_UNKNOWN import org.koitharu.kotatsu.parsers.model.RATING_UNKNOWN
import org.koitharu.kotatsu.utils.AlphanumComparator
import org.koitharu.kotatsu.utils.ext.copyToSuspending import org.koitharu.kotatsu.utils.ext.copyToSuspending
import org.koitharu.kotatsu.utils.ext.deleteAwait import org.koitharu.kotatsu.utils.ext.deleteAwait
import org.koitharu.kotatsu.utils.ext.longOf import org.koitharu.kotatsu.utils.ext.longOf
@@ -58,7 +59,7 @@ class DirMangaImporter(
private suspend fun addPages(output: CbzMangaOutput, root: DocumentFile, path: String, state: State) { private suspend fun addPages(output: CbzMangaOutput, root: DocumentFile, path: String, state: State) {
var number = 0 var number = 0
for (file in root.listFiles()) { for (file in root.listFiles().sortedWith(compareBy(AlphanumComparator()) { it.name.orEmpty() })) {
when { when {
file.isDirectory -> { file.isDirectory -> {
addPages(output, file, path + "/" + file.name, state) addPages(output, file, path + "/" + file.name, state)

View File

@@ -12,6 +12,7 @@ import org.koitharu.kotatsu.core.db.MangaDatabase
import org.koitharu.kotatsu.core.exceptions.EmptyHistoryException import org.koitharu.kotatsu.core.exceptions.EmptyHistoryException
import org.koitharu.kotatsu.core.github.AppUpdateRepository import org.koitharu.kotatsu.core.github.AppUpdateRepository
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.prefs.observeAsFlow
import org.koitharu.kotatsu.core.prefs.observeAsLiveData import org.koitharu.kotatsu.core.prefs.observeAsLiveData
import org.koitharu.kotatsu.history.domain.HistoryRepository import org.koitharu.kotatsu.history.domain.HistoryRepository
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
@@ -34,9 +35,12 @@ class MainViewModel @Inject constructor(
val onOpenReader = SingleLiveEvent<Manga>() val onOpenReader = SingleLiveEvent<Manga>()
val isResumeEnabled = historyRepository val isResumeEnabled = combine(
.observeHasItems() historyRepository.observeHasItems(),
.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, false) settings.observeAsFlow(AppSettings.KEY_INCOGNITO_MODE) { isIncognitoModeEnabled },
) { hasItems, incognito ->
hasItems && !incognito
}.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, false)
val isFeedAvailable = settings.observeAsLiveData( val isFeedAvailable = settings.observeAsLiveData(
context = viewModelScope.coroutineContext + Dispatchers.Default, context = viewModelScope.coroutineContext + Dispatchers.Default,

View File

@@ -3,6 +3,7 @@ package org.koitharu.kotatsu.reader.ui.pager.reversed
import android.graphics.PointF import android.graphics.PointF
import android.view.Gravity import android.view.Gravity
import android.widget.FrameLayout import android.widget.FrameLayout
import androidx.lifecycle.LifecycleOwner
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
import org.koitharu.kotatsu.core.model.ZoomMode import org.koitharu.kotatsu.core.model.ZoomMode
@@ -13,12 +14,13 @@ import org.koitharu.kotatsu.reader.ui.config.ReaderSettings
import org.koitharu.kotatsu.reader.ui.pager.standard.PageHolder import org.koitharu.kotatsu.reader.ui.pager.standard.PageHolder
class ReversedPageHolder( class ReversedPageHolder(
owner: LifecycleOwner,
binding: ItemPageBinding, binding: ItemPageBinding,
loader: PageLoader, loader: PageLoader,
settings: ReaderSettings, settings: ReaderSettings,
networkState: NetworkState, networkState: NetworkState,
exceptionResolver: ExceptionResolver, exceptionResolver: ExceptionResolver,
) : PageHolder(binding, loader, settings, networkState, exceptionResolver) { ) : PageHolder(owner, binding, loader, settings, networkState, exceptionResolver) {
init { init {
(binding.textViewNumber.layoutParams as FrameLayout.LayoutParams) (binding.textViewNumber.layoutParams as FrameLayout.LayoutParams)

View File

@@ -2,6 +2,7 @@ package org.koitharu.kotatsu.reader.ui.pager.reversed
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import androidx.lifecycle.LifecycleOwner
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
import org.koitharu.kotatsu.core.os.NetworkState import org.koitharu.kotatsu.core.os.NetworkState
import org.koitharu.kotatsu.databinding.ItemPageBinding import org.koitharu.kotatsu.databinding.ItemPageBinding
@@ -10,6 +11,7 @@ import org.koitharu.kotatsu.reader.ui.config.ReaderSettings
import org.koitharu.kotatsu.reader.ui.pager.BaseReaderAdapter import org.koitharu.kotatsu.reader.ui.pager.BaseReaderAdapter
class ReversedPagesAdapter( class ReversedPagesAdapter(
private val lifecycleOwner: LifecycleOwner,
loader: PageLoader, loader: PageLoader,
settings: ReaderSettings, settings: ReaderSettings,
networkState: NetworkState, networkState: NetworkState,
@@ -23,6 +25,7 @@ class ReversedPagesAdapter(
networkState: NetworkState, networkState: NetworkState,
exceptionResolver: ExceptionResolver, exceptionResolver: ExceptionResolver,
) = ReversedPageHolder( ) = ReversedPageHolder(
owner = lifecycleOwner,
binding = ItemPageBinding.inflate(LayoutInflater.from(parent.context), parent, false), binding = ItemPageBinding.inflate(LayoutInflater.from(parent.context), parent, false),
loader = loader, loader = loader,
settings = settings, settings = settings,

View File

@@ -39,10 +39,11 @@ class ReversedReaderFragment : BaseReader<FragmentReaderStandardBinding>() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
pagerAdapter = ReversedPagesAdapter( pagerAdapter = ReversedPagesAdapter(
viewModel.pageLoader, lifecycleOwner = viewLifecycleOwner,
viewModel.readerSettings, loader = viewModel.pageLoader,
networkState, settings = viewModel.readerSettings,
exceptionResolver, networkState = networkState,
exceptionResolver = exceptionResolver,
) )
with(binding.pager) { with(binding.pager) {
adapter = pagerAdapter adapter = pagerAdapter

View File

@@ -5,6 +5,7 @@ import android.graphics.PointF
import android.net.Uri import android.net.Uri
import android.view.View import android.view.View
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.lifecycle.LifecycleOwner
import com.davemorrissey.labs.subscaleview.ImageSource import com.davemorrissey.labs.subscaleview.ImageSource
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
@@ -19,6 +20,7 @@ import org.koitharu.kotatsu.reader.ui.pager.ReaderPage
import org.koitharu.kotatsu.utils.ext.* import org.koitharu.kotatsu.utils.ext.*
open class PageHolder( open class PageHolder(
owner: LifecycleOwner,
binding: ItemPageBinding, binding: ItemPageBinding,
loader: PageLoader, loader: PageLoader,
settings: ReaderSettings, settings: ReaderSettings,
@@ -28,6 +30,7 @@ open class PageHolder(
View.OnClickListener { View.OnClickListener {
init { init {
binding.ssiv.bindToLifecycle(owner)
binding.ssiv.isEagerLoadingEnabled = !isLowRamDevice(context) binding.ssiv.isEagerLoadingEnabled = !isLowRamDevice(context)
binding.ssiv.addOnImageEventListener(delegate) binding.ssiv.addOnImageEventListener(delegate)
@Suppress("LeakingThis") @Suppress("LeakingThis")

View File

@@ -38,10 +38,11 @@ class PagerReaderFragment : BaseReader<FragmentReaderStandardBinding>() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
pagesAdapter = PagesAdapter( pagesAdapter = PagesAdapter(
viewModel.pageLoader, lifecycleOwner = viewLifecycleOwner,
viewModel.readerSettings, loader = viewModel.pageLoader,
networkState, settings = viewModel.readerSettings,
exceptionResolver, networkState = networkState,
exceptionResolver = exceptionResolver,
) )
with(binding.pager) { with(binding.pager) {
adapter = pagesAdapter adapter = pagesAdapter

View File

@@ -2,6 +2,7 @@ package org.koitharu.kotatsu.reader.ui.pager.standard
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import androidx.lifecycle.LifecycleOwner
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
import org.koitharu.kotatsu.core.os.NetworkState import org.koitharu.kotatsu.core.os.NetworkState
import org.koitharu.kotatsu.databinding.ItemPageBinding import org.koitharu.kotatsu.databinding.ItemPageBinding
@@ -10,6 +11,7 @@ import org.koitharu.kotatsu.reader.ui.config.ReaderSettings
import org.koitharu.kotatsu.reader.ui.pager.BaseReaderAdapter import org.koitharu.kotatsu.reader.ui.pager.BaseReaderAdapter
class PagesAdapter( class PagesAdapter(
private val lifecycleOwner: LifecycleOwner,
loader: PageLoader, loader: PageLoader,
settings: ReaderSettings, settings: ReaderSettings,
networkState: NetworkState, networkState: NetworkState,
@@ -23,6 +25,7 @@ class PagesAdapter(
networkState: NetworkState, networkState: NetworkState,
exceptionResolver: ExceptionResolver, exceptionResolver: ExceptionResolver,
) = PageHolder( ) = PageHolder(
owner = lifecycleOwner,
binding = ItemPageBinding.inflate(LayoutInflater.from(parent.context), parent, false), binding = ItemPageBinding.inflate(LayoutInflater.from(parent.context), parent, false),
loader = loader, loader = loader,
settings = settings, settings = settings,

View File

@@ -2,6 +2,7 @@ package org.koitharu.kotatsu.reader.ui.pager.webtoon
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import androidx.lifecycle.LifecycleOwner
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
import org.koitharu.kotatsu.core.os.NetworkState import org.koitharu.kotatsu.core.os.NetworkState
import org.koitharu.kotatsu.databinding.ItemPageWebtoonBinding import org.koitharu.kotatsu.databinding.ItemPageWebtoonBinding
@@ -10,6 +11,7 @@ import org.koitharu.kotatsu.reader.ui.config.ReaderSettings
import org.koitharu.kotatsu.reader.ui.pager.BaseReaderAdapter import org.koitharu.kotatsu.reader.ui.pager.BaseReaderAdapter
class WebtoonAdapter( class WebtoonAdapter(
private val lifecycleOwner: LifecycleOwner,
loader: PageLoader, loader: PageLoader,
settings: ReaderSettings, settings: ReaderSettings,
networkState: NetworkState, networkState: NetworkState,
@@ -23,6 +25,7 @@ class WebtoonAdapter(
networkState: NetworkState, networkState: NetworkState,
exceptionResolver: ExceptionResolver, exceptionResolver: ExceptionResolver,
) = WebtoonHolder( ) = WebtoonHolder(
owner = lifecycleOwner,
binding = ItemPageWebtoonBinding.inflate( binding = ItemPageWebtoonBinding.inflate(
LayoutInflater.from(parent.context), LayoutInflater.from(parent.context),
parent, parent,

View File

@@ -3,6 +3,7 @@ package org.koitharu.kotatsu.reader.ui.pager.webtoon
import android.net.Uri import android.net.Uri
import android.view.View import android.view.View
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.lifecycle.LifecycleOwner
import com.davemorrissey.labs.subscaleview.ImageSource import com.davemorrissey.labs.subscaleview.ImageSource
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import com.davemorrissey.labs.subscaleview.decoder.SkiaPooledImageRegionDecoder import com.davemorrissey.labs.subscaleview.decoder.SkiaPooledImageRegionDecoder
@@ -22,6 +23,7 @@ import org.koitharu.kotatsu.utils.ext.setProgressCompat
import org.koitharu.kotatsu.utils.ext.showCompat import org.koitharu.kotatsu.utils.ext.showCompat
class WebtoonHolder( class WebtoonHolder(
owner: LifecycleOwner,
binding: ItemPageWebtoonBinding, binding: ItemPageWebtoonBinding,
loader: PageLoader, loader: PageLoader,
settings: ReaderSettings, settings: ReaderSettings,
@@ -34,6 +36,7 @@ class WebtoonHolder(
private val goneOnInvisibleListener = GoneOnInvisibleListener(bindingInfo.progressBar) private val goneOnInvisibleListener = GoneOnInvisibleListener(bindingInfo.progressBar)
init { init {
binding.ssiv.bindToLifecycle(owner)
binding.ssiv.regionDecoderFactory = SkiaPooledImageRegionDecoder.Factory() binding.ssiv.regionDecoderFactory = SkiaPooledImageRegionDecoder.Factory()
binding.ssiv.addOnImageEventListener(delegate) binding.ssiv.addOnImageEventListener(delegate)
bindingInfo.buttonRetry.setOnClickListener(this) bindingInfo.buttonRetry.setOnClickListener(this)

View File

@@ -35,10 +35,11 @@ class WebtoonReaderFragment : BaseReader<FragmentReaderWebtoonBinding>() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
webtoonAdapter = WebtoonAdapter( webtoonAdapter = WebtoonAdapter(
viewModel.pageLoader, lifecycleOwner = viewLifecycleOwner,
viewModel.readerSettings, loader = viewModel.pageLoader,
networkState, settings = viewModel.readerSettings,
exceptionResolver, networkState = networkState,
exceptionResolver = exceptionResolver,
) )
with(binding.recyclerView) { with(binding.recyclerView) {
setHasFixedSize(true) setHasFixedSize(true)

View File

@@ -86,7 +86,6 @@ class SourceSettingsFragment : BasePreferenceFragment(0) {
}.onSuccess { username -> }.onSuccess { username ->
preference.title = getString(R.string.logged_in_as, username) preference.title = getString(R.string.logged_in_as, username)
}.onFailure { error -> }.onFailure { error ->
preference.isEnabled = error is AuthRequiredException
when { when {
error is AuthRequiredException -> Unit error is AuthRequiredException -> Unit
ExceptionResolver.canResolve(error) -> { ExceptionResolver.canResolve(error) -> {

View File

@@ -5,12 +5,16 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.speech.RecognizerIntent import android.speech.RecognizerIntent
import androidx.activity.result.contract.ActivityResultContract import androidx.activity.result.contract.ActivityResultContract
import androidx.core.os.ConfigurationCompat
import java.util.Locale
class VoiceInputContract : ActivityResultContract<String?, String?>() { class VoiceInputContract : ActivityResultContract<String?, String?>() {
override fun createIntent(context: Context, input: String?): Intent { override fun createIntent(context: Context, input: String?): Intent {
val intent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH) val intent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM) intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM)
val locale = ConfigurationCompat.getLocales(context.resources.configuration).get(0) ?: Locale.getDefault()
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, locale.toLanguageTag())
intent.putExtra(RecognizerIntent.EXTRA_PROMPT, input) intent.putExtra(RecognizerIntent.EXTRA_PROMPT, input)
return intent return intent
} }
@@ -23,4 +27,4 @@ class VoiceInputContract : ActivityResultContract<String?, String?>() {
null null
} }
} }
} }

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<menu
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/action_settings"
android:title="@string/settings" />
<item
android:id="@+id/action_hide"
android:title="@string/hide" />
</menu>

View File

@@ -70,7 +70,7 @@
<string name="list">Liste</string> <string name="list">Liste</string>
<string name="chapters">Kapitel</string> <string name="chapters">Kapitel</string>
<string name="details">Einzelheiten</string> <string name="details">Einzelheiten</string>
<string name="network_error">Keine Verbindung zum Internet möglich</string> <string name="network_error">Netzwerkfehler</string>
<string name="error_occurred">Es ist ein Fehler aufgetreten</string> <string name="error_occurred">Es ist ein Fehler aufgetreten</string>
<string name="history">Verlauf</string> <string name="history">Verlauf</string>
<string name="favourites">Favoriten</string> <string name="favourites">Favoriten</string>
@@ -372,4 +372,23 @@
<string name="import_completed">Import abgeschlossen</string> <string name="import_completed">Import abgeschlossen</string>
<string name="import_completed_hint">Du kannst die Originaldatei aus dem Speicher löschen, um Platz zu sparen</string> <string name="import_completed_hint">Du kannst die Originaldatei aus dem Speicher löschen, um Platz zu sparen</string>
<string name="import_will_start_soon">Import wird bald beginnen</string> <string name="import_will_start_soon">Import wird bald beginnen</string>
<string name="server_error">Serverseitiger Fehler (%1$d). Bitte versuchen Sie es später noch einmal</string>
<string name="compact">Kompakt</string>
<string name="contrast">Kontrast</string>
<string name="network_unavailable_hint">Schalten Sie Wi-Fi oder ein mobiles Netzwerk ein, um Manga online zu lesen</string>
<string name="clear_new_chapters_counters">Auch klare Informationen über neue Kapitel</string>
<string name="text_unsaved_changes_prompt">Ungespeicherte Änderungen speichern oder verwerfen\?</string>
<string name="discard">Verwerfen</string>
<string name="reset">Zurücksetzen</string>
<string name="brightness">Helligkeit</string>
<string name="color_correction_hint">Die gewählten Farbeinstellungen werden für diesen Manga in Erinnerung bleiben</string>
<string name="color_correction">Farbkorrektur</string>
<string name="error_no_space_left">Kein Platz mehr auf dem Gerät</string>
<string name="different_languages">Verschiedene Sprachen</string>
<string name="network_unavailable">Netzwerk ist nicht verfügbar</string>
<string name="webtoon_zoom_summary">Vergrößerungs-/Verkleinerungsgesten im Webtoon-Modus zulassen (beta)</string>
<string name="reader_control_ltr">Ergonomische Leserkontrolle</string>
<string name="reader_control_ltr_summary">Tippe auf den rechten Rand oder drücke die rechte Taste, um immer zur nächsten Seite zu wechseln</string>
<string name="reader_slider">Seitenwechsel-Schieberegler anzeigen</string>
<string name="source_disabled">Quelle deaktiviert</string>
</resources> </resources>

View File

@@ -6,7 +6,7 @@
<string name="favourites">Favoritos</string> <string name="favourites">Favoritos</string>
<string name="history">Historial</string> <string name="history">Historial</string>
<string name="error_occurred">Ocurrió un error</string> <string name="error_occurred">Ocurrió un error</string>
<string name="network_error">No se pudo conectar a Internet</string> <string name="network_error">Error en la red</string>
<string name="details">Detalles</string> <string name="details">Detalles</string>
<string name="chapters">Capítulos</string> <string name="chapters">Capítulos</string>
<string name="list">Lista</string> <string name="list">Lista</string>
@@ -266,7 +266,7 @@
<string name="suggestions_excluded_genres">Excluir géneros</string> <string name="suggestions_excluded_genres">Excluir géneros</string>
<string name="suggestions_excluded_genres_summary">Especifica los géneros que no quieres ver en las sugerencias</string> <string name="suggestions_excluded_genres_summary">Especifica los géneros que no quieres ver en las sugerencias</string>
<string name="removal_completed">Remoción completada</string> <string name="removal_completed">Remoción completada</string>
<string name="batch_manga_save_confirm">¿Estás seguro de que quieres descargar todos los manga seleccionados con todos sus capítulos\? Esta acción puede consumir mucho tráfico y almacenamiento</string> <string name="batch_manga_save_confirm">¿Descargar todos los mangas seleccionados y sus capítulos\? Esto puede consumir mucho tráfico y almacenamiento.</string>
<string name="text_delete_local_manga_batch">¿Eliminar elementos seleccionados del dispositivo de forma permanente\?</string> <string name="text_delete_local_manga_batch">¿Eliminar elementos seleccionados del dispositivo de forma permanente\?</string>
<string name="hide">Ocultar</string> <string name="hide">Ocultar</string>
<string name="download_slowdown">Ralentización de la descarga</string> <string name="download_slowdown">Ralentización de la descarga</string>
@@ -375,7 +375,7 @@
<string name="manga_error_description_pattern">Detalles del error:&lt;br&gt;&lt;tt&gt;%1$s&lt;/tt&gt;&lt;br&gt;&lt;br&gt;1. Intenta &lt;a href=%2$s&gt;abrir el manga en un navegador web&lt;/a&gt; para asegurarte de que está disponible en tu fuente&lt;br&gt;2. Si está disponible, envía un informe de error a los desarrolladores.</string> <string name="manga_error_description_pattern">Detalles del error:&lt;br&gt;&lt;tt&gt;%1$s&lt;/tt&gt;&lt;br&gt;&lt;br&gt;1. Intenta &lt;a href=%2$s&gt;abrir el manga en un navegador web&lt;/a&gt; para asegurarte de que está disponible en tu fuente&lt;br&gt;2. Si está disponible, envía un informe de error a los desarrolladores.</string>
<string name="history_shortcuts_summary">Hacer que los mangas recientes estén disponibles mediante una pulsación larga en el icono de la aplicación</string> <string name="history_shortcuts_summary">Hacer que los mangas recientes estén disponibles mediante una pulsación larga en el icono de la aplicación</string>
<string name="color_correction_hint">Los ajustes de color elegidos serán recordados para este manga</string> <string name="color_correction_hint">Los ajustes de color elegidos serán recordados para este manga</string>
<string name="feed">Feed</string> <string name="feed">Fuente</string>
<string name="downloading_manga">Descargando manga</string> <string name="downloading_manga">Descargando manga</string>
<string name="history_shortcuts">Mostrar los accesos directos a los mangas recientes</string> <string name="history_shortcuts">Mostrar los accesos directos a los mangas recientes</string>
<string name="reader_control_ltr_summary">Tocando el borde derecho o pulsando la tecla derecha se pasa siempre a la página siguiente</string> <string name="reader_control_ltr_summary">Tocando el borde derecho o pulsando la tecla derecha se pasa siempre a la página siguiente</string>
@@ -384,10 +384,17 @@
<string name="brightness">Brillo</string> <string name="brightness">Brillo</string>
<string name="contrast">Contraste</string> <string name="contrast">Contraste</string>
<string name="reset">Restablecer</string> <string name="reset">Restablecer</string>
<string name="text_unsaved_changes_prompt">Tienes cambios sin guardar. ¿Quieres guardarlos o descartarlos\?</string> <string name="text_unsaved_changes_prompt">¿Guardar o descartar los cambios no guardados\?</string>
<string name="discard">Descartar</string> <string name="discard">Descartar</string>
<string name="error_no_space_left">Sin espacio en dispositivo</string> <string name="error_no_space_left">Sin espacio en dispositivo</string>
<string name="webtoon_zoom">Zoom de webtoon</string> <string name="webtoon_zoom">Zoom de webtoon</string>
<string name="webtoon_zoom_summary">Permitir el gesto de acercamiento/alejamiento en modo webtoon (beta)</string> <string name="webtoon_zoom_summary">Permitir el gesto de acercamiento/alejamiento en modo webtoon (beta)</string>
<string name="reader_slider">Mostrar el deslizador de cambio de página</string> <string name="reader_slider">Mostrar el deslizador de cambio de página</string>
<string name="server_error">Error del servidor (%1$d). Vuelva a intentarlo más tarde</string>
<string name="clear_new_chapters_counters">Información clara sobre los nuevos capítulos</string>
<string name="different_languages">Diferentes idiomas</string>
<string name="network_unavailable">La red no está disponible</string>
<string name="compact">Compacta</string>
<string name="network_unavailable_hint">Enciende la Wi-Fi o la red móvil para leer los mangas en línea</string>
<string name="source_disabled">Fuente desactivada</string>
</resources> </resources>

View File

@@ -202,7 +202,7 @@
<string name="list">Liste</string> <string name="list">Liste</string>
<string name="chapters">Chapitres</string> <string name="chapters">Chapitres</string>
<string name="details">Détails</string> <string name="details">Détails</string>
<string name="network_error">Impossible de se connecter à Internet</string> <string name="network_error">Erreur réseau</string>
<string name="error_occurred">Une erreur s\'est produite</string> <string name="error_occurred">Une erreur s\'est produite</string>
<string name="history">Historique</string> <string name="history">Historique</string>
<string name="favourites">Favoris</string> <string name="favourites">Favoris</string>
@@ -395,4 +395,5 @@
<string name="compact">Compact</string> <string name="compact">Compact</string>
<string name="server_error">Erreur côté serveur (%1$d). Veuillez réessayer plus tard</string> <string name="server_error">Erreur côté serveur (%1$d). Veuillez réessayer plus tard</string>
<string name="clear_new_chapters_counters">Effacer aussi les informations sur les nouveaux chapitres</string> <string name="clear_new_chapters_counters">Effacer aussi les informations sur les nouveaux chapitres</string>
<string name="source_disabled">Source désactivée</string>
</resources> </resources>

View File

@@ -102,15 +102,15 @@
<string name="notification_sound">Suara pemberitahuan</string> <string name="notification_sound">Suara pemberitahuan</string>
<string name="categories_">Kategori…</string> <string name="categories_">Kategori…</string>
<string name="rename">Ubah Nama</string> <string name="rename">Ubah Nama</string>
<string name="category_delete_confirm">"Hapus kategori \"%s\" dari favorit Anda\? <string name="category_delete_confirm">Hapus kategori \"%s\" dari favorit Anda\?
\nSemua manga disana akan hilang."</string> \nSemua manga di situ akan hilang.</string>
<string name="text_empty_holder_primary">Sepi juga di sini…</string> <string name="text_empty_holder_primary">Sepi juga di sini…</string>
<string name="text_categories_holder">Anda bisa menggunakan kategori untuk mengelola favorit Anda. Tekan «+» untuk membuat kategori</string> <string name="text_categories_holder">Anda bisa menggunakan kategori untuk mengelola favorit Anda. Tekan «+» untuk membuat kategori</string>
<string name="text_history_holder_primary">Apa yang Anda baca akan ditampilkan di sini</string> <string name="text_history_holder_primary">Apa yang Anda baca akan ditampilkan di sini</string>
<string name="text_history_holder_secondary">Cari apa untuk di baca di bilah samping.</string> <string name="text_history_holder_secondary">Cari apa untuk di baca di bilah samping.</string>
<string name="text_local_holder_primary">Simpan sesuatu dulu</string> <string name="text_local_holder_primary">Simpan sesuatu dulu</string>
<string name="manga_shelf">Rak</string> <string name="manga_shelf">Rak</string>
<string name="recent_manga">Terbaru</string> <string name="recent_manga">Baru-baru ini</string>
<string name="pages_animation">Animasi halaman</string> <string name="pages_animation">Animasi halaman</string>
<string name="manga_save_location">Folder untuk unduhan</string> <string name="manga_save_location">Folder untuk unduhan</string>
<string name="not_available">Tidak tersedia</string> <string name="not_available">Tidak tersedia</string>
@@ -298,7 +298,7 @@
<string name="status_completed">Selesai</string> <string name="status_completed">Selesai</string>
<string name="canceled">Dibatalkan</string> <string name="canceled">Dibatalkan</string>
<string name="sync_title">Sinkronisasi data Anda</string> <string name="sync_title">Sinkronisasi data Anda</string>
<string name="enter_email_text">Masukkan email Anda untuk melanjutkan</string> <string name="enter_email_text">Masukkan surel Anda untuk melanjutkan</string>
<string name="tracking">Pelacakan</string> <string name="tracking">Pelacakan</string>
<string name="logout">Keluar</string> <string name="logout">Keluar</string>
<string name="sync">Sinkronisasi</string> <string name="sync">Sinkronisasi</string>
@@ -329,7 +329,7 @@
<string name="exit_confirmation_summary">Tekan Kembali dua kali untuk keluar dari aplikasi</string> <string name="exit_confirmation_summary">Tekan Kembali dua kali untuk keluar dari aplikasi</string>
<string name="exit_confirmation">Konfirmasi keluar</string> <string name="exit_confirmation">Konfirmasi keluar</string>
<string name="pages_cache">Tembolok halaman</string> <string name="pages_cache">Tembolok halaman</string>
<string name="other_cache">Cache lainnya</string> <string name="other_cache">Tembolok lainnya</string>
<string name="storage_usage">Penggunaan penyimpanan</string> <string name="storage_usage">Penggunaan penyimpanan</string>
<string name="available">Tersedia</string> <string name="available">Tersedia</string>
<string name="incognito_mode">Mode Incognito</string> <string name="incognito_mode">Mode Incognito</string>
@@ -356,14 +356,14 @@
<string name="crash_text">Ada sesuatu yang salah. Mohon untuk mengirim laporan kutu (bug) ke pengembang untuk membantu kami memperbaikinya.</string> <string name="crash_text">Ada sesuatu yang salah. Mohon untuk mengirim laporan kutu (bug) ke pengembang untuk membantu kami memperbaikinya.</string>
<string name="report">Lapor</string> <string name="report">Lapor</string>
<string name="exclude_nsfw_from_history_summary">Manga yang ditandai sebagai NSFW tidak akan ditambahkan ke riwayat dan progres Anda tidak akan disimpan</string> <string name="exclude_nsfw_from_history_summary">Manga yang ditandai sebagai NSFW tidak akan ditambahkan ke riwayat dan progres Anda tidak akan disimpan</string>
<string name="clear_cookies_summary">Bisa membantu dalam beberapa masalah. Seluruh otorisasi akan menjadi tidak valid.</string> <string name="clear_cookies_summary">Bisa membantu dalam beberapa masalah. Seluruh otorisasi akan menjadi tidak valid</string>
<string name="manage">Kelola</string> <string name="manage">Kelola</string>
<string name="no_manga_sources_text">Aktifkan sumber manga untuk membaca manga daring</string> <string name="no_manga_sources_text">Aktifkan sumber manga untuk membaca manga daring</string>
<string name="categories_delete_confirm">Apakah Anda yakin ingin menghapus kategori favorit yang dipilih\? <string name="categories_delete_confirm">Apakah Anda yakin ingin menghapus kategori favorit yang dipilih\?
\n Semua manga di sana akan hilang dan ini tidak bisa diurungkan.</string> \n Semua manga di sana akan hilang dan ini tidak bisa diurungkan.</string>
<string name="reorder">Atur Ulang</string> <string name="reorder">Atur Ulang</string>
<string name="saved_manga">Manga tersimpan</string> <string name="saved_manga">Manga tersimpan</string>
<string name="confirm_exit">Tekan lagi untuk keluar</string> <string name="confirm_exit">Tekan Kembali lagi untuk keluar</string>
<string name="no_chapters">Tidak ada bab</string> <string name="no_chapters">Tidak ada bab</string>
<string name="history_shortcuts">Tampilkan pintasan manga baru-baru ini</string> <string name="history_shortcuts">Tampilkan pintasan manga baru-baru ini</string>
<string name="history_shortcuts_summary">Buat manga baru-baru ini tersedia dengan menekan panjang pada ikon aplikasi</string> <string name="history_shortcuts_summary">Buat manga baru-baru ini tersedia dengan menekan panjang pada ikon aplikasi</string>
@@ -372,4 +372,5 @@
<string name="gestures_only">Hanya gestur</string> <string name="gestures_only">Hanya gestur</string>
<string name="dns_over_https">DNS melalui HTTPS</string> <string name="dns_over_https">DNS melalui HTTPS</string>
<string name="status_dropped">Istirahat</string> <string name="status_dropped">Istirahat</string>
<string name="off_short">Mati</string>
</resources> </resources>

View File

@@ -320,4 +320,6 @@
<string name="invalid_domain_message">Dominio non valido</string> <string name="invalid_domain_message">Dominio non valido</string>
<string name="select_range">Seleziona l\'intervallo</string> <string name="select_range">Seleziona l\'intervallo</string>
<string name="not_found_404">Contenuto non trovato o rimosso</string> <string name="not_found_404">Contenuto non trovato o rimosso</string>
<string name="compact">Compatto</string>
<string name="source_disabled">Fonte disabilitata</string>
</resources> </resources>

View File

@@ -63,7 +63,7 @@
<string name="dark">ダークテーマ</string> <string name="dark">ダークテーマ</string>
<string name="pages">ページ</string> <string name="pages">ページ</string>
<string name="theme">テーマ</string> <string name="theme">テーマ</string>
<string name="network_error">インターネットに接続出来ませんでした</string> <string name="network_error">ネットワークエラー</string>
<string name="enter_category_name">カテゴリー名を入力してください</string> <string name="enter_category_name">カテゴリー名を入力してください</string>
<string name="updated">アップデート</string> <string name="updated">アップデート</string>
<string name="cache">キャッシュ</string> <string name="cache">キャッシュ</string>
@@ -395,4 +395,5 @@
<string name="network_unavailable_hint">Wi-Fiまたはモバイルネットワークをオンにして、オンラインでマンガを読むことができます</string> <string name="network_unavailable_hint">Wi-Fiまたはモバイルネットワークをオンにして、オンラインでマンガを読むことができます</string>
<string name="webtoon_zoom">Webtoonズーム</string> <string name="webtoon_zoom">Webtoonズーム</string>
<string name="webtoon_zoom_summary">ウェブトゥーンモードでズームイン/ズームアウトのジェスチャーを可能にする(ベータ版)</string> <string name="webtoon_zoom_summary">ウェブトゥーンモードでズームイン/ズームアウトのジェスチャーを可能にする(ベータ版)</string>
<string name="compact">コンパクト</string>
</resources> </resources>

View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>

View File

@@ -0,0 +1,108 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="sort_order">정렬 기준</string>
<string name="_import">불러오기</string>
<string name="network_error">네트워크 오류</string>
<string name="list">목록</string>
<string name="save">저장</string>
<string name="share">공유하기</string>
<string name="share_s">%s 공유</string>
<string name="search">검색하기</string>
<string name="warning">경고</string>
<string name="internal_storage">내부 저장소</string>
<string name="external_storage">외부 저장소</string>
<string name="domain">도메인</string>
<string name="app_update_available">새 버전이 존재합니다</string>
<string name="open_in_browser">웹 브라우저에서 열기</string>
<string name="save_manga">저장</string>
<string name="notifications">알림</string>
<string name="read_from_start">처음부터 읽기</string>
<string name="light_indicator">LED 표시</string>
<string name="vibration">진동</string>
<string name="rename">이름 바꾸기</string>
<string name="category_delete_confirm">즐겨찾기에서 \"%s\" 카테고리를 제거하시겠습니까\?
\n포함된 모든 만화가 지워집니다.</string>
<string name="remove_category">지우기</string>
<string name="text_search_holder_secondary">쿼리를 재구성하십시오.</string>
<string name="text_history_holder_secondary">사이드 메뉴에서 만화를 탐색해보세요.</string>
<string name="text_shelf_holder_primary">만화가 여기에 표시됩니다</string>
<string name="text_shelf_holder_secondary">«탐색» 섹션에서 만화를 탐색해보세요</string>
<string name="pages_animation">페이지 전환 효과</string>
<string name="cannot_find_available_storage">사용 가능한 저장소 없음</string>
<string name="done">완료</string>
<string name="favourites_category_empty">빈 카테고리</string>
<string name="updates">업데이트</string>
<string name="new_version_s">새 버전: %s</string>
<string name="waiting_for_network">네트워크 연결을 기다리는 중…</string>
<string name="clear_updates_feed">업데이트 피드 지우기</string>
<string name="close_menu">메뉴 닫기</string>
<string name="open_menu">메뉴 열기</string>
<string name="local_storage">내장 메모리</string>
<string name="favourites">즐겨찾기</string>
<string name="remove">지우기</string>
<string name="settings">설정</string>
<string name="loading_">불러오는 중…</string>
<string name="close">닫기</string>
<string name="try_again">다시 시도</string>
<string name="you_have_not_favourites_yet">즐겨찾기가 비어있음</string>
<string name="filter">필터링</string>
<string name="light">밝게</string>
<string name="dark">어둡게</string>
<string name="pages">페이지</string>
<string name="read">지금 읽기</string>
<string name="by_name">이름 순</string>
<string name="popular">인기 순</string>
<string name="chapter_d_of_d">%2$d화 중 %1$d화</string>
<string name="downloads">다운로드</string>
<string name="by_rating">평점 순</string>
<string name="save_page">페이지 저장</string>
<string name="page_saved">저장됨</string>
<string name="share_image">이미지 공유하기</string>
<string name="text_file_not_supported">ZIP 혹은 CBZ 파일을 선택하세요.</string>
<string name="history_and_cache">기록 및 캐시</string>
<string name="cache">캐시</string>
<string name="delete_manga">만화 제거</string>
<string name="volume_buttons">볼륨 키</string>
<string name="nothing_found">결과 없음</string>
<string name="add_to_favourites">즐겨찾기 추가</string>
<string name="download_complete">다운로드 완료</string>
<string name="add_new_category">새 카테고리</string>
<string name="search_manga">만화를 검색하세요</string>
<string name="manga_downloading_">다운로드 중…</string>
<string name="processing_">처리중…</string>
<string name="updated">최근 업데이트 순</string>
<string name="newest">최근 발간 순</string>
<string name="automatic">시스템 설정</string>
<string name="delete">지우기</string>
<string name="wait_for_loading_finish">잠시만 기다려주세요…</string>
<string name="text_file_sizes">바이트|kB|MB|GB|TB</string>
<string name="clear_pages_cache">페이지 캐시 지우기</string>
<string name="read_mode">읽기 모드</string>
<string name="grid_size">격자 크기</string>
<string name="search_on_s">%s에서 검색</string>
<string name="text_delete_local_manga">장치에서 \"%s\"를 영구적으로 삭제하시겠습니까\?</string>
<string name="switch_pages">페이지 전환</string>
<string name="taps_on_edges">가장자리 탭</string>
<string name="webtoon">웹툰</string>
<string name="clear_search_history">검색 기록 지우기</string>
<string name="reader_settings">읽기 모드</string>
<string name="network_consumption_warning">이 동작은 많은 데이터 사용을</string>
<string name="clear_thumbs_cache">썸네일 캐시 지우기</string>
<string name="dont_ask_again">다시 묻지 않음</string>
<string name="cancelling_">취소 중…</string>
<string name="error">오류</string>
<string name="application_update">업데이트 확인</string>
<string name="show_notification_app_update">업데이트 가능 시 알림 설정</string>
<string name="large_manga_save_confirm">이 만화에는 %s가 있습니다. 모두 저장하시겠습니까\?</string>
<string name="favourites_categories">즐겨찾기 카테고리</string>
<string name="download">다운로드</string>
<string name="notifications_settings">알림 설정</string>
<string name="notification_sound">알림음</string>
<string name="categories_">카테고리…</string>
<string name="text_history_holder_primary">읽은 내용이 여기에 표시됩니다</string>
<string name="not_available">사용할 수 없음</string>
<string name="all_favourites">모든 즐겨찾기</string>
<string name="read_later">나중에 읽기</string>
<string name="search_results">검색 결과</string>
<string name="size_s">크기: %s</string>
</resources>

View File

@@ -1,44 +1,44 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<plurals name="pages"> <plurals name="pages">
<item quantity="one">Всего %1$d страница</item> <item quantity="one">Всего %1$d страница</item>
<item quantity="few">Всего %1$d страницы</item> <item quantity="few">Всего %1$d страницы</item>
<item quantity="many">Всего %1$d страниц</item> <item quantity="many">Всего %1$d страниц</item>
</plurals> </plurals>
<plurals name="items"> <plurals name="items">
<item quantity="one">%1$d элемент</item> <item quantity="one">%1$d элемент</item>
<item quantity="few">%1$d элемента</item> <item quantity="few">%1$d элемента</item>
<item quantity="many">%1$d элементов</item> <item quantity="many">%1$d элементов</item>
</plurals> </plurals>
<plurals name="new_chapters"> <plurals name="new_chapters">
<item quantity="one">%1$d новая глава</item> <item quantity="one">%1$d новая глава</item>
<item quantity="few">%1$d новых главы</item> <item quantity="few">%1$d новые главы</item>
<item quantity="many">%1$d новых глав</item> <item quantity="many">%1$d новых глав</item>
</plurals> <item quantity="other">%1$d новых глав</item>
<plurals name="chapters"> </plurals>
<item quantity="one">%1$d глава</item> <plurals name="chapters">
<item quantity="few">%1$d главы</item> <item quantity="one">%1$d глава</item>
<item quantity="many">%1$d глав</item> <item quantity="few">%1$d главы</item>
</plurals> <item quantity="many">%1$d глав</item>
<plurals name="chapters_from_x"> </plurals>
<item quantity="one">%1$d глава из %2$d</item> <plurals name="chapters_from_x">
<item quantity="few">%1$d главы из %2$d</item> <item quantity="one">%1$d глава из %2$d</item>
<item quantity="many">%1$d глав из %2$d</item> <item quantity="few">%1$d главы из %2$d</item>
</plurals> <item quantity="many">%1$d глав из %2$d</item>
</plurals>
<plurals name="minutes_ago"> <plurals name="minutes_ago">
<item quantity="one">%1$d минуту назад</item> <item quantity="one">%1$d минуту назад</item>
<item quantity="few">%1$d минуты назад</item> <item quantity="few">%1$d минуты назад</item>
<item quantity="many">%1$d минут назад</item> <item quantity="many">%1$d минут назад</item>
</plurals> </plurals>
<plurals name="hours_ago"> <plurals name="hours_ago">
<item quantity="one">%1$d час назад</item> <item quantity="one">%1$d час назад</item>
<item quantity="few">%1$d часа назад</item> <item quantity="few">%1$d часа назад</item>
<item quantity="many">%1$d часов назад</item> <item quantity="many">%1$d часов назад</item>
</plurals> </plurals>
<plurals name="days_ago"> <plurals name="days_ago">
<item quantity="one">%1$d день назад</item> <item quantity="one">%1$d день назад</item>
<item quantity="few">%1$d дня назад</item> <item quantity="few">%1$d дня назад</item>
<item quantity="many">%1$d дней назад</item> <item quantity="many">%1$d дней назад</item>
</plurals> </plurals>
</resources> </resources>

View File

@@ -6,7 +6,7 @@
<string name="favourites">Избранное</string> <string name="favourites">Избранное</string>
<string name="history">История</string> <string name="history">История</string>
<string name="error_occurred">Произошла ошибка</string> <string name="error_occurred">Произошла ошибка</string>
<string name="network_error">Не удалось подключиться к интернету</string> <string name="network_error">Ошибка сети</string>
<string name="details">Подробности</string> <string name="details">Подробности</string>
<string name="chapters">Главы</string> <string name="chapters">Главы</string>
<string name="list">Список</string> <string name="list">Список</string>
@@ -396,4 +396,5 @@
<string name="clear_new_chapters_counters">Также очистить информацию о новых главах</string> <string name="clear_new_chapters_counters">Также очистить информацию о новых главах</string>
<string name="server_error">Внутренняя ошибка сервера (%1$d). Повторите попытку позже</string> <string name="server_error">Внутренняя ошибка сервера (%1$d). Повторите попытку позже</string>
<string name="compact">Компактно</string> <string name="compact">Компактно</string>
<string name="source_disabled">Источник отключен</string>
</resources> </resources>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"> <resources xmlns:tools="http://schemas.android.com/tools">
<string name="network_error">İnternete bağlı olduğunuzdan emin olunuz</string> <string name="network_error">Ağ hatası</string>
<string name="close_menu">Menüyü kapat</string> <string name="close_menu">Menüyü kapat</string>
<string name="open_menu">Menüyü aç</string> <string name="open_menu">Menüyü aç</string>
<string name="local_storage">Dahili Depolama</string> <string name="local_storage">Dahili Depolama</string>
@@ -395,4 +395,5 @@
<string name="saved_manga">Kaydedilen mangalar</string> <string name="saved_manga">Kaydedilen mangalar</string>
<string name="history_shortcuts_summary">Uygulama simgesine uzun basarak son mangaları kullanılabilir hale getirin</string> <string name="history_shortcuts_summary">Uygulama simgesine uzun basarak son mangaları kullanılabilir hale getirin</string>
<string name="reader_control_ltr_summary">Sağ kenara dokunulduğunda veya sağ tuşa basıldığında her zaman bir sonraki sayfaya geçilir</string> <string name="reader_control_ltr_summary">Sağ kenara dokunulduğunda veya sağ tuşa basıldığında her zaman bir sonraki sayfaya geçilir</string>
<string name="source_disabled">Kaynak devre dışı</string>
</resources> </resources>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<bool name="com_samsung_android_icon_container_has_icon_container">false</bool>
</resources>

View File

@@ -5,7 +5,7 @@
<string name="favourites">喜欢</string> <string name="favourites">喜欢</string>
<string name="history">历史</string> <string name="history">历史</string>
<string name="error_occurred">发生了一个错误</string> <string name="error_occurred">发生了一个错误</string>
<string name="network_error">未能连接到互联网</string> <string name="network_error">网络错误</string>
<string name="chapters">章节</string> <string name="chapters">章节</string>
<string name="list">列表</string> <string name="list">列表</string>
<string name="data_restored_with_errors">数据被恢复了,但有错误</string> <string name="data_restored_with_errors">数据被恢复了,但有错误</string>
@@ -31,7 +31,7 @@
<string name="clear_cookies">清除cookies</string> <string name="clear_cookies">清除cookies</string>
<string name="chapters_checking_progress">检查新的章节: %1$d/%2$d</string> <string name="chapters_checking_progress">检查新的章节: %1$d/%2$d</string>
<string name="error_empty_name">你必须输入一个名称</string> <string name="error_empty_name">你必须输入一个名称</string>
<string name="new_sources_text">新的漫画来源</string> <string name="new_sources_text">有新的漫画源可用</string>
<string name="suggestions_summary">根据你的喜好推荐漫画</string> <string name="suggestions_summary">根据你的喜好推荐漫画</string>
<string name="suggestions_info">所有的数据都在这个设备上进行本地分析. 您的个人数据不会被转移到任何服务机构</string> <string name="suggestions_info">所有的数据都在这个设备上进行本地分析. 您的个人数据不会被转移到任何服务机构</string>
<string name="never">从不</string> <string name="never">从不</string>
@@ -48,7 +48,7 @@
<string name="detailed_list">详细列表</string> <string name="detailed_list">详细列表</string>
<string name="grid">网格</string> <string name="grid">网格</string>
<string name="list_mode">列表模式</string> <string name="list_mode">列表模式</string>
<string name="remote_sources">远程资源</string> <string name="remote_sources">远程源</string>
<string name="loading_">加载中…</string> <string name="loading_">加载中…</string>
<string name="computing_">计算中…</string> <string name="computing_">计算中…</string>
<string name="chapter_d_of_d">%1$d/%2$d章节</string> <string name="chapter_d_of_d">%1$d/%2$d章节</string>
@@ -230,7 +230,7 @@
<string name="about_feedback_4pda">关于4PDA主题</string> <string name="about_feedback_4pda">关于4PDA主题</string>
<string name="auth_complete">授权</string> <string name="auth_complete">授权</string>
<string name="auth_not_supported_by">不支持在%s上登录</string> <string name="auth_not_supported_by">不支持在%s上登录</string>
<string name="text_clear_cookies_prompt">你将被从所有来源中注销</string> <string name="text_clear_cookies_prompt">你将退出登录所有来源</string>
<string name="genres">类型</string> <string name="genres">类型</string>
<string name="state_ongoing">连载中</string> <string name="state_ongoing">连载中</string>
<string name="state_finished">已完结</string> <string name="state_finished">已完结</string>
@@ -395,4 +395,5 @@
<string name="clear_new_chapters_counters">同样清除新章节信息</string> <string name="clear_new_chapters_counters">同样清除新章节信息</string>
<string name="server_error">服务器端错误 (%1$d)。请稍后再试</string> <string name="server_error">服务器端错误 (%1$d)。请稍后再试</string>
<string name="compact">紧凑</string> <string name="compact">紧凑</string>
<string name="source_disabled">已禁用图源</string>
</resources> </resources>

View File

@@ -3,4 +3,5 @@
<bool name="is_tablet">false</bool> <bool name="is_tablet">false</bool>
<bool name="light_status_bar">true</bool> <bool name="light_status_bar">true</bool>
<bool name="light_navigation_bar">false</bool> <bool name="light_navigation_bar">false</bool>
</resources> <bool name="com_samsung_android_icon_container_has_icon_container">true</bool>
</resources>

View File

@@ -398,4 +398,5 @@
<string name="server_error">Server side error (%1$d). Please try again later</string> <string name="server_error">Server side error (%1$d). Please try again later</string>
<string name="clear_new_chapters_counters">Also clear information about new chapters</string> <string name="clear_new_chapters_counters">Also clear information about new chapters</string>
<string name="compact">Compact</string> <string name="compact">Compact</string>
<string name="source_disabled">Source disabled</string>
</resources> </resources>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<locale-config
xmlns:android="http://schemas.android.com/apk/res/android">
<locale android:name="en" />
<locale android:name="ar" />
<locale android:name="be" />
<locale android:name="bn" />
<locale android:name="de" />
<locale android:name="el" />
<locale android:name="es" />
<locale android:name="fa" />
<locale android:name="fi" />
<locale android:name="fr" />
<locale android:name="in" />
<locale android:name="it" />
<locale android:name="ja" />
<locale android:name="nb-rNO" />
<locale android:name="pt" />
<locale android:name="pt-rBR" />
<locale android:name="ru" />
<locale android:name="si" />
<locale android:name="sr" />
<locale android:name="sv" />
<locale android:name="tr" />
<locale android:name="uk" />
<locale android:name="zh-rCN" />
<locale android:name="zh-rTW" />
</locale-config>