Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 656a707b4c | |||
| 04afe7a934 | |||
| 689670b3ff | |||
| 6273a9decb | |||
|
|
72336d4f71 | ||
|
|
731e998eb2 | ||
|
|
9bf53114de | ||
| 0e1b8db688 | |||
| 3a62e2e6c0 | |||
| 08764cb3cb | |||
|
|
9c52545f63 | ||
|
|
a6c30d33d4 | ||
|
|
25974af229 | ||
|
|
607dfc9be3 | ||
|
|
560e669700 | ||
|
|
ba403c9360 | ||
|
|
0f1c9ff05d | ||
|
|
662f08e115 | ||
|
|
d647a32e9f | ||
| 375e72cb98 | |||
| 34c7cafdfe | |||
|
|
03e0eefe4d | ||
| f41425f03d | |||
| 400b91278f | |||
| 9088f77ae5 | |||
| 86da3217d1 |
@@ -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'
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 ||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) -> {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
13
app/src/main/res/menu/popup_source.xml
Normal file
13
app/src/main/res/menu/popup_source.xml
Normal 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>
|
||||
@@ -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>
|
||||
@@ -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:<br><tt>%1$s</tt><br><br>1. Intenta <a href=%2$s>abrir el manga en un navegador web</a> para asegurarte de que está disponible en tu fuente<br>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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
2
app/src/main/res/values-ko/plurals.xml
Normal file
2
app/src/main/res/values-ko/plurals.xml
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
108
app/src/main/res/values-ko/strings.xml
Normal file
108
app/src/main/res/values-ko/strings.xml
Normal 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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
4
app/src/main/res/values-v33/bools.xml
Normal file
4
app/src/main/res/values-v33/bools.xml
Normal 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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
28
app/src/main/res/xml/locales.xml
Normal file
28
app/src/main/res/xml/locales.xml
Normal 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>
|
||||
Reference in New Issue
Block a user