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'
minSdkVersion 21
targetSdkVersion 33
versionCode 506
versionName '4.0.6'
versionCode 508
versionName '4.1.1'
generatedDensities = []
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@@ -83,7 +83,7 @@ afterEvaluate {
}
}
dependencies {
implementation('com.github.KotatsuApp:kotatsu-parsers:add70b4790') {
implementation('com.github.KotatsuApp:kotatsu-parsers:c4acb9725f') {
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-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 'ch.acra:acra-http:5.9.7'

View File

@@ -29,6 +29,7 @@
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:largeHeap="true"
android:localeConfig="@xml/locales"
android:networkSecurityConfig="@xml/network_security_config"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
@@ -247,6 +248,9 @@
<meta-data
android:name="android.webkit.WebView.MetricsOptOut"
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>

View File

@@ -228,18 +228,18 @@ class DetailsActivity :
}
}
private fun onHistoryChanged(info: HistoryInfo?) {
private fun onHistoryChanged(info: HistoryInfo) {
with(binding.buttonRead) {
if (info?.history != null) {
if (info.history != null) {
setText(R.string._continue)
setIconResource(R.drawable.ic_play)
setIconResource(if (info.isIncognitoMode) R.drawable.ic_incognito else R.drawable.ic_play)
} else {
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 {
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.totalChapters == 0 -> getString(R.string.no_chapters)
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 com.google.android.material.chip.Chip
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
import kotlinx.coroutines.launch
import org.koitharu.kotatsu.R
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.bookmarks.domain.Bookmark
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.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.ScrollingInfoAdapter
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.SearchActivity
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 javax.inject.Inject
@AndroidEntryPoint
class DetailsFragment :
@@ -75,7 +86,7 @@ class DetailsFragment :
binding.chipsTags.onChipClickListener = this
viewModel.manga.observe(viewLifecycleOwner, ::onMangaUpdated)
viewModel.isLoading.observe(viewLifecycleOwner, ::onLoadingStateChanged)
viewModel.readingHistory.observe(viewLifecycleOwner, ::onHistoryChanged)
viewModel.historyInfo.observe(viewLifecycleOwner, ::onHistoryChanged)
viewModel.bookmarks.observe(viewLifecycleOwner, ::onBookmarksChanged)
viewModel.scrobblingInfo.observe(viewLifecycleOwner, ::onScrobblingInfoChanged)
viewModel.description.observe(viewLifecycleOwner, ::onDescriptionChanged)
@@ -123,12 +134,14 @@ class DetailsFragment :
drawableTop = ContextCompat.getDrawable(context, R.drawable.ic_state_finished)
}
}
MangaState.ONGOING -> {
infoLayout.textViewState.apply {
textAndVisible = resources.getString(R.string.state_ongoing)
drawableTop = ContextCompat.getDrawable(context, R.drawable.ic_state_ongoing)
}
}
else -> infoLayout.textViewState.isVisible = false
}
if (manga.source == MangaSource.LOCAL) {
@@ -178,8 +191,8 @@ class DetailsFragment :
}
}
private fun onHistoryChanged(history: MangaHistory?) {
binding.progressView.setPercent(history?.percent ?: PROGRESS_NONE, animate = true)
private fun onHistoryChanged(history: HistoryInfo) {
binding.progressView.setPercent(history.history?.percent ?: PROGRESS_NONE, animate = true)
}
private fun onLoadingStateChanged(isLoading: Boolean) {
@@ -229,6 +242,7 @@ class DetailsFragment :
),
)
}
R.id.textView_source -> {
startActivity(
MangaListActivity.newIntent(
@@ -237,6 +251,7 @@ class DetailsFragment :
),
)
}
R.id.imageView_cover -> {
startActivity(
ImageActivity.newIntent(v.context, manga.largeCoverUrl.ifNullOrEmpty { manga.coverUrl }),
@@ -249,7 +264,7 @@ class DetailsFragment :
override fun onLongClick(v: View): Boolean {
when (v.id) {
R.id.button_read -> {
if (viewModel.readingHistory.value == null) {
if (viewModel.historyInfo.value?.history == null) {
return false
}
val menu = PopupMenu(v.context, v)
@@ -271,12 +286,14 @@ class DetailsFragment :
)
true
}
else -> false
}
}
menu.show()
return true
}
else -> return false
}
}

View File

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

View File

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

View File

@@ -2,8 +2,10 @@ package org.koitharu.kotatsu.explore.ui
import android.os.Bundle
import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.widget.PopupMenu
import androidx.core.graphics.Insets
import androidx.core.view.updatePadding
import androidx.fragment.app.viewModels
@@ -11,11 +13,12 @@ import androidx.recyclerview.widget.RecyclerView
import coil.ImageLoader
import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
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.list.OnListItemClickListener
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.databinding.FragmentExploreBinding
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.suggestions.ui.SuggestionsActivity
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
import javax.inject.Inject
@AndroidEntryPoint
class ExploreFragment :
@@ -67,6 +71,7 @@ class ExploreFragment :
}
viewModel.onError.observe(viewLifecycleOwner, ::onError)
viewModel.onOpenManga.observe(viewLifecycleOwner, ::onOpenManga)
viewModel.onActionDone.observe(viewLifecycleOwner, ::onActionDone)
}
override fun onDestroyView() {
@@ -95,6 +100,7 @@ class ExploreFragment :
viewModel.openRandom()
return
}
else -> return
}
startActivity(intent)
@@ -105,6 +111,14 @@ class ExploreFragment :
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 onEmptyActionClick() = onManageClick(requireView())
@@ -124,6 +138,37 @@ class ExploreFragment :
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 {
fun newInstance() = ExploreFragment()

View File

@@ -4,11 +4,17 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.asFlow
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
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.base.domain.ReversibleHandle
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.explore.domain.ExploreRepository
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.utils.SingleLiveEvent
import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct
import javax.inject.Inject
@HiltViewModel
class ExploreViewModel @Inject constructor(
@@ -24,6 +31,7 @@ class ExploreViewModel @Inject constructor(
) : BaseViewModel() {
val onOpenManga = SingleLiveEvent<Manga>()
val onActionDone = SingleLiveEvent<ReversibleAction>()
val content: LiveData<List<ExploreItem>> = isLoading.asFlow().flatMapLatest { 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()
.filter {
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.MangaSource
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.deleteAwait
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) {
var number = 0
for (file in root.listFiles()) {
for (file in root.listFiles().sortedWith(compareBy(AlphanumComparator()) { it.name.orEmpty() })) {
when {
file.isDirectory -> {
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.github.AppUpdateRepository
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.history.domain.HistoryRepository
import org.koitharu.kotatsu.parsers.model.Manga
@@ -34,9 +35,12 @@ class MainViewModel @Inject constructor(
val onOpenReader = SingleLiveEvent<Manga>()
val isResumeEnabled = historyRepository
.observeHasItems()
.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, false)
val isResumeEnabled = combine(
historyRepository.observeHasItems(),
settings.observeAsFlow(AppSettings.KEY_INCOGNITO_MODE) { isIncognitoModeEnabled },
) { hasItems, incognito ->
hasItems && !incognito
}.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, false)
val isFeedAvailable = settings.observeAsLiveData(
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.view.Gravity
import android.widget.FrameLayout
import androidx.lifecycle.LifecycleOwner
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
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
class ReversedPageHolder(
owner: LifecycleOwner,
binding: ItemPageBinding,
loader: PageLoader,
settings: ReaderSettings,
networkState: NetworkState,
exceptionResolver: ExceptionResolver,
) : PageHolder(binding, loader, settings, networkState, exceptionResolver) {
) : PageHolder(owner, binding, loader, settings, networkState, exceptionResolver) {
init {
(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.ViewGroup
import androidx.lifecycle.LifecycleOwner
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
import org.koitharu.kotatsu.core.os.NetworkState
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
class ReversedPagesAdapter(
private val lifecycleOwner: LifecycleOwner,
loader: PageLoader,
settings: ReaderSettings,
networkState: NetworkState,
@@ -23,6 +25,7 @@ class ReversedPagesAdapter(
networkState: NetworkState,
exceptionResolver: ExceptionResolver,
) = ReversedPageHolder(
owner = lifecycleOwner,
binding = ItemPageBinding.inflate(LayoutInflater.from(parent.context), parent, false),
loader = loader,
settings = settings,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -5,12 +5,16 @@ import android.content.Context
import android.content.Intent
import android.speech.RecognizerIntent
import androidx.activity.result.contract.ActivityResultContract
import androidx.core.os.ConfigurationCompat
import java.util.Locale
class VoiceInputContract : ActivityResultContract<String?, String?>() {
override fun createIntent(context: Context, input: String?): Intent {
val intent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)
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)
return intent
}
@@ -23,4 +27,4 @@ class VoiceInputContract : ActivityResultContract<String?, String?>() {
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="chapters">Kapitel</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="history">Verlauf</string>
<string name="favourites">Favoriten</string>
@@ -372,4 +372,23 @@
<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_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>

View File

@@ -6,7 +6,7 @@
<string name="favourites">Favoritos</string>
<string name="history">Historial</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="chapters">Capítulos</string>
<string name="list">Lista</string>
@@ -266,7 +266,7 @@
<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="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="hide">Ocultar</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="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="feed">Feed</string>
<string name="feed">Fuente</string>
<string name="downloading_manga">Descargando manga</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>
@@ -384,10 +384,17 @@
<string name="brightness">Brillo</string>
<string name="contrast">Contraste</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="error_no_space_left">Sin espacio en dispositivo</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="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>

View File

@@ -202,7 +202,7 @@
<string name="list">Liste</string>
<string name="chapters">Chapitres</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="history">Historique</string>
<string name="favourites">Favoris</string>
@@ -395,4 +395,5 @@
<string name="compact">Compact</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="source_disabled">Source désactivée</string>
</resources>

View File

@@ -102,15 +102,15 @@
<string name="notification_sound">Suara pemberitahuan</string>
<string name="categories_">Kategori…</string>
<string name="rename">Ubah Nama</string>
<string name="category_delete_confirm">"Hapus kategori \"%s\" dari favorit Anda\?
\nSemua manga disana akan hilang."</string>
<string name="category_delete_confirm">Hapus kategori \"%s\" dari favorit Anda\?
\nSemua manga di situ akan hilang.</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_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_local_holder_primary">Simpan sesuatu dulu</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="manga_save_location">Folder untuk unduhan</string>
<string name="not_available">Tidak tersedia</string>
@@ -298,7 +298,7 @@
<string name="status_completed">Selesai</string>
<string name="canceled">Dibatalkan</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="logout">Keluar</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">Konfirmasi keluar</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="available">Tersedia</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="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="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="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\?
\n Semua manga di sana akan hilang dan ini tidak bisa diurungkan.</string>
<string name="reorder">Atur Ulang</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="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>
@@ -372,4 +372,5 @@
<string name="gestures_only">Hanya gestur</string>
<string name="dns_over_https">DNS melalui HTTPS</string>
<string name="status_dropped">Istirahat</string>
<string name="off_short">Mati</string>
</resources>

View File

@@ -320,4 +320,6 @@
<string name="invalid_domain_message">Dominio non valido</string>
<string name="select_range">Seleziona l\'intervallo</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>

View File

@@ -63,7 +63,7 @@
<string name="dark">ダークテーマ</string>
<string name="pages">ページ</string>
<string name="theme">テーマ</string>
<string name="network_error">インターネットに接続出来ませんでした</string>
<string name="network_error">ネットワークエラー</string>
<string name="enter_category_name">カテゴリー名を入力してください</string>
<string name="updated">アップデート</string>
<string name="cache">キャッシュ</string>
@@ -395,4 +395,5 @@
<string name="network_unavailable_hint">Wi-Fiまたはモバイルネットワークをオンにして、オンラインでマンガを読むことができます</string>
<string name="webtoon_zoom">Webtoonズーム</string>
<string name="webtoon_zoom_summary">ウェブトゥーンモードでズームイン/ズームアウトのジェスチャーを可能にする(ベータ版)</string>
<string name="compact">コンパクト</string>
</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"?>
<resources>
<plurals name="pages">
<item quantity="one">Всего %1$d страница</item>
<item quantity="few">Всего %1$d страницы</item>
<item quantity="many">Всего %1$d страниц</item>
</plurals>
<plurals name="items">
<item quantity="one">%1$d элемент</item>
<item quantity="few">%1$d элемента</item>
<item quantity="many">%1$d элементов</item>
</plurals>
<plurals name="new_chapters">
<item quantity="one">%1$d новая глава</item>
<item quantity="few">%1$d новых главы</item>
<item quantity="many">%1$d новых глав</item>
</plurals>
<plurals name="chapters">
<item quantity="one">%1$d глава</item>
<item quantity="few">%1$d главы</item>
<item quantity="many">%1$d глав</item>
</plurals>
<plurals name="chapters_from_x">
<item quantity="one">%1$d глава из %2$d</item>
<item quantity="few">%1$d главы из %2$d</item>
<item quantity="many">%1$d глав из %2$d</item>
</plurals>
<plurals name="minutes_ago">
<item quantity="one">%1$d минуту назад</item>
<item quantity="few">%1$d минуты назад</item>
<item quantity="many">%1$d минут назад</item>
</plurals>
<plurals name="hours_ago">
<item quantity="one">%1$d час назад</item>
<item quantity="few">%1$d часа назад</item>
<item quantity="many">%1$d часов назад</item>
</plurals>
<plurals name="days_ago">
<item quantity="one">%1$d день назад</item>
<item quantity="few">%1$d дня назад</item>
<item quantity="many">%1$d дней назад</item>
</plurals>
<plurals name="pages">
<item quantity="one">Всего %1$d страница</item>
<item quantity="few">Всего %1$d страницы</item>
<item quantity="many">Всего %1$d страниц</item>
</plurals>
<plurals name="items">
<item quantity="one">%1$d элемент</item>
<item quantity="few">%1$d элемента</item>
<item quantity="many">%1$d элементов</item>
</plurals>
<plurals name="new_chapters">
<item quantity="one">%1$d новая глава</item>
<item quantity="few">%1$d новые главы</item>
<item quantity="many">%1$d новых глав</item>
<item quantity="other">%1$d новых глав</item>
</plurals>
<plurals name="chapters">
<item quantity="one">%1$d глава</item>
<item quantity="few">%1$d главы</item>
<item quantity="many">%1$d глав</item>
</plurals>
<plurals name="chapters_from_x">
<item quantity="one">%1$d глава из %2$d</item>
<item quantity="few">%1$d главы из %2$d</item>
<item quantity="many">%1$d глав из %2$d</item>
</plurals>
<plurals name="minutes_ago">
<item quantity="one">%1$d минуту назад</item>
<item quantity="few">%1$d минуты назад</item>
<item quantity="many">%1$d минут назад</item>
</plurals>
<plurals name="hours_ago">
<item quantity="one">%1$d час назад</item>
<item quantity="few">%1$d часа назад</item>
<item quantity="many">%1$d часов назад</item>
</plurals>
<plurals name="days_ago">
<item quantity="one">%1$d день назад</item>
<item quantity="few">%1$d дня назад</item>
<item quantity="many">%1$d дней назад</item>
</plurals>
</resources>

View File

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

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<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="open_menu">Menüyü aç</string>
<string name="local_storage">Dahili Depolama</string>
@@ -395,4 +395,5 @@
<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="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>

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="history">历史</string>
<string name="error_occurred">发生了一个错误</string>
<string name="network_error">未能连接到互联网</string>
<string name="network_error">网络错误</string>
<string name="chapters">章节</string>
<string name="list">列表</string>
<string name="data_restored_with_errors">数据被恢复了,但有错误</string>
@@ -31,7 +31,7 @@
<string name="clear_cookies">清除cookies</string>
<string name="chapters_checking_progress">检查新的章节: %1$d/%2$d</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_info">所有的数据都在这个设备上进行本地分析. 您的个人数据不会被转移到任何服务机构</string>
<string name="never">从不</string>
@@ -48,7 +48,7 @@
<string name="detailed_list">详细列表</string>
<string name="grid">网格</string>
<string name="list_mode">列表模式</string>
<string name="remote_sources">远程资源</string>
<string name="remote_sources">远程源</string>
<string name="loading_">加载中…</string>
<string name="computing_">计算中…</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="auth_complete">授权</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="state_ongoing">连载中</string>
<string name="state_finished">已完结</string>
@@ -395,4 +395,5 @@
<string name="clear_new_chapters_counters">同样清除新章节信息</string>
<string name="server_error">服务器端错误 (%1$d)。请稍后再试</string>
<string name="compact">紧凑</string>
<string name="source_disabled">已禁用图源</string>
</resources>

View File

@@ -3,4 +3,5 @@
<bool name="is_tablet">false</bool>
<bool name="light_status_bar">true</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="clear_new_chapters_counters">Also clear information about new chapters</string>
<string name="compact">Compact</string>
<string name="source_disabled">Source disabled</string>
</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>