Compare commits

...

11 Commits

Author SHA1 Message Date
Koitharu
f1f208ad15 Merge branch 'master' into devel 2023-06-16 10:45:12 +03:00
Koitharu
c6983d794c Fix tablet portrait layout 2023-06-16 10:42:19 +03:00
Koitharu
8228153c83 Fix tablet portrait layout 2023-06-16 10:41:32 +03:00
Koitharu
844bd13a07 Fix filter lifecycle 2023-06-16 10:23:40 +03:00
Koitharu
60a5620134 Schedule workers only on demand 2023-06-16 09:50:02 +03:00
qrynill
dd09a39077 Translated using Weblate (Norwegian Nynorsk)
Currently translated at 82.0% (357 of 435 strings)

Co-authored-by: qrynill <tryvseu@tuta.io>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/nn/
Translation: Kotatsu/Strings
2023-06-15 09:45:35 +03:00
MaSHiNiK
1511bd3279 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (435 of 435 strings)

Co-authored-by: MaSHiNiK <infinitymashinik456@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/uk/
Translation: Kotatsu/Strings
2023-06-15 09:45:35 +03:00
Макар Разин
259c335607 Translated using Weblate (Turkish)
Currently translated at 100.0% (435 of 435 strings)

Translated using Weblate (French)

Currently translated at 100.0% (435 of 435 strings)

Translated using Weblate (Portuguese)

Currently translated at 86.2% (375 of 435 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (435 of 435 strings)

Co-authored-by: Макар Разин <makarrazin14@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/be/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/fr/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/pt/
Translate-URL: https://hosted.weblate.org/projects/kotatsu/strings/tr/
Translation: Kotatsu/Strings
2023-06-15 09:45:07 +03:00
Nick New
86367b6d3b Added translation using Weblate (Thai)
Co-authored-by: Nick New <newblackseries@gmail.com>
2023-06-15 09:45:07 +03:00
Koitharu
19b893738d Update parsers 2023-06-15 09:44:35 +03:00
Koitharu
d817ae0394 Fix Cloudflare bypass 2023-06-15 09:43:14 +03:00
34 changed files with 1424 additions and 1253 deletions

View File

@@ -15,8 +15,8 @@ android {
applicationId 'org.koitharu.kotatsu' applicationId 'org.koitharu.kotatsu'
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 33 targetSdkVersion 33
versionCode 553 versionCode 554
versionName '5.2.1' versionName '5.2.2'
generatedDensities = [] generatedDensities = []
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@@ -79,7 +79,7 @@ afterEvaluate {
} }
dependencies { dependencies {
//noinspection GradleDependency //noinspection GradleDependency
implementation('com.github.KotatsuApp:kotatsu-parsers:f732582d55') { implementation('com.github.KotatsuApp:kotatsu-parsers:86a82970fc') {
exclude group: 'org.json', module: 'json' exclude group: 'org.json', module: 'json'
} }
@@ -104,6 +104,7 @@ dependencies {
//noinspection LifecycleAnnotationProcessorWithJava8 //noinspection LifecycleAnnotationProcessorWithJava8
kapt 'androidx.lifecycle:lifecycle-compiler:2.6.1' kapt 'androidx.lifecycle:lifecycle-compiler:2.6.1'
// TODO https://issuetracker.google.com/issues/254846063
implementation 'androidx.work:work-runtime-ktx:2.8.1' implementation 'androidx.work:work-runtime-ktx:2.8.1'
//noinspection GradleDependency //noinspection GradleDependency
implementation('com.google.guava:guava:32.0.0-android') { implementation('com.google.guava:guava:32.0.0-android') {

View File

@@ -28,6 +28,7 @@ import org.koitharu.kotatsu.local.data.LocalMangaRepository
import org.koitharu.kotatsu.local.data.PagesCache import org.koitharu.kotatsu.local.data.PagesCache
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.reader.domain.PageLoader import org.koitharu.kotatsu.reader.domain.PageLoader
import org.koitharu.kotatsu.settings.work.WorkScheduleManager
import javax.inject.Inject import javax.inject.Inject
@HiltAndroidApp @HiltAndroidApp
@@ -51,6 +52,9 @@ class KotatsuApp : Application(), Configuration.Provider {
@Inject @Inject
lateinit var appValidator: AppValidator lateinit var appValidator: AppValidator
@Inject
lateinit var workScheduleManager: WorkScheduleManager
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
ACRA.errorReporter.putCustomData("isOriginalApp", appValidator.isOriginalApp.toString()) ACRA.errorReporter.putCustomData("isOriginalApp", appValidator.isOriginalApp.toString())
@@ -63,6 +67,7 @@ class KotatsuApp : Application(), Configuration.Provider {
processLifecycleScope.launch(Dispatchers.Default) { processLifecycleScope.launch(Dispatchers.Default) {
setupDatabaseObservers() setupDatabaseObservers()
} }
workScheduleManager.init()
WorkServiceStopHelper(applicationContext).setup() WorkServiceStopHelper(applicationContext).setup()
} }

View File

@@ -13,13 +13,13 @@ private const val SERVER_CLOUDFLARE = "cloudflare"
class CloudFlareInterceptor : Interceptor { class CloudFlareInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response { override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request() val response = chain.proceed(chain.request())
val response = chain.proceed(request)
if (response.code == HTTP_FORBIDDEN || response.code == HTTP_UNAVAILABLE) { if (response.code == HTTP_FORBIDDEN || response.code == HTTP_UNAVAILABLE) {
if (response.header(HEADER_SERVER)?.startsWith(SERVER_CLOUDFLARE) == true) { if (response.header(HEADER_SERVER)?.startsWith(SERVER_CLOUDFLARE) == true) {
val request = response.request
response.closeQuietly() response.closeQuietly()
throw CloudFlareProtectedException( throw CloudFlareProtectedException(
url = response.request.url.toString(), url = request.url.toString(),
headers = request.headers, headers = request.headers,
) )
} }

View File

@@ -61,6 +61,10 @@ class WorkManagerHelper(
return workManagerImpl.getWorkInfoById(id).await() return workManagerImpl.getWorkInfoById(id).await()
} }
suspend fun getUniqueWorkInfoByName(name: String): List<WorkInfo> {
return workManagerImpl.getWorkInfosForUniqueWork(name).await().orEmpty()
}
suspend fun updateWork(request: WorkRequest): WorkManager.UpdateResult { suspend fun updateWork(request: WorkRequest): WorkManager.UpdateResult {
return workManagerImpl.updateWork(request).await() return workManagerImpl.updateWork(request).await()
} }

View File

@@ -10,6 +10,7 @@ import androidx.core.net.toUri
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import kotlinx.coroutines.flow.StateFlow
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.ui.list.ListSelectionController import org.koitharu.kotatsu.core.ui.list.ListSelectionController
import org.koitharu.kotatsu.core.util.ShareHelper import org.koitharu.kotatsu.core.util.ShareHelper
@@ -17,12 +18,17 @@ import org.koitharu.kotatsu.core.util.ext.addMenuProvider
import org.koitharu.kotatsu.core.util.ext.observeEvent import org.koitharu.kotatsu.core.util.ext.observeEvent
import org.koitharu.kotatsu.core.util.ext.withArgs import org.koitharu.kotatsu.core.util.ext.withArgs
import org.koitharu.kotatsu.databinding.FragmentListBinding import org.koitharu.kotatsu.databinding.FragmentListBinding
import org.koitharu.kotatsu.filter.ui.FilterOwner
import org.koitharu.kotatsu.filter.ui.FilterSheetFragment import org.koitharu.kotatsu.filter.ui.FilterSheetFragment
import org.koitharu.kotatsu.filter.ui.model.FilterHeaderModel
import org.koitharu.kotatsu.filter.ui.model.FilterItem
import org.koitharu.kotatsu.list.ui.MangaListFragment import org.koitharu.kotatsu.list.ui.MangaListFragment
import org.koitharu.kotatsu.list.ui.model.ListModel
import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.remotelist.ui.RemoteListFragment import org.koitharu.kotatsu.remotelist.ui.RemoteListFragment
class LocalListFragment : MangaListFragment() { class LocalListFragment : MangaListFragment(), FilterOwner {
override val viewModel by viewModels<LocalListViewModel>() override val viewModel by viewModels<LocalListViewModel>()
@@ -65,6 +71,24 @@ class LocalListFragment : MangaListFragment() {
} }
} }
override val filterItems: StateFlow<List<ListModel>>
get() = viewModel.filterItems
override val header: StateFlow<FilterHeaderModel>
get() = viewModel.header
override fun applyFilter(tags: Set<MangaTag>) {
viewModel.applyFilter(tags)
}
override fun onSortItemClick(item: FilterItem.Sort) {
viewModel.onSortItemClick(item)
}
override fun onTagItemClick(item: FilterItem.Tag) {
viewModel.onTagItemClick(item)
}
private fun showDeletionConfirm(ids: Set<Long>, mode: ActionMode) { private fun showDeletionConfirm(ids: Set<Long>, mode: ActionMode) {
MaterialAlertDialogBuilder(context ?: return) MaterialAlertDialogBuilder(context ?: return)
.setTitle(R.string.delete_manga) .setTitle(R.string.delete_manga)

View File

@@ -9,6 +9,7 @@ import androidx.work.ExistingWorkPolicy
import androidx.work.OneTimeWorkRequestBuilder import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager import androidx.work.WorkManager
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import androidx.work.await
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedInject import dagger.assisted.AssistedInject
import org.koitharu.kotatsu.local.data.LocalMangaRepository import org.koitharu.kotatsu.local.data.LocalMangaRepository
@@ -33,7 +34,7 @@ class LocalStorageCleanupWorker @AssistedInject constructor(
private const val TAG = "cleanup" private const val TAG = "cleanup"
fun enqueue(context: Context) { suspend fun enqueue(context: Context) {
val constraints = Constraints.Builder() val constraints = Constraints.Builder()
.setRequiresBatteryNotLow(true) .setRequiresBatteryNotLow(true)
.build() .build()
@@ -42,7 +43,7 @@ class LocalStorageCleanupWorker @AssistedInject constructor(
.addTag(TAG) .addTag(TAG)
.setBackoffCriteria(BackoffPolicy.LINEAR, 1, TimeUnit.MINUTES) .setBackoffCriteria(BackoffPolicy.LINEAR, 1, TimeUnit.MINUTES)
.build() .build()
WorkManager.getInstance(context).enqueueUniqueWork(TAG, ExistingWorkPolicy.KEEP, request) WorkManager.getInstance(context).enqueueUniqueWork(TAG, ExistingWorkPolicy.KEEP, request).await()
} }
} }
} }

View File

@@ -69,8 +69,6 @@ import org.koitharu.kotatsu.search.ui.suggestion.SearchSuggestionViewModel
import org.koitharu.kotatsu.settings.newsources.NewSourcesDialogFragment import org.koitharu.kotatsu.settings.newsources.NewSourcesDialogFragment
import org.koitharu.kotatsu.settings.onboard.OnboardDialogFragment import org.koitharu.kotatsu.settings.onboard.OnboardDialogFragment
import org.koitharu.kotatsu.shelf.ui.ShelfFragment import org.koitharu.kotatsu.shelf.ui.ShelfFragment
import org.koitharu.kotatsu.suggestions.ui.SuggestionsWorker
import org.koitharu.kotatsu.tracker.work.TrackWorker
import javax.inject.Inject import javax.inject.Inject
import com.google.android.material.R as materialR import com.google.android.material.R as materialR
@@ -321,8 +319,6 @@ class MainActivity :
} }
} }
withContext(Dispatchers.Default) { withContext(Dispatchers.Default) {
TrackWorker.setup(applicationContext)
SuggestionsWorker.setup(applicationContext)
LocalStorageCleanupWorker.enqueue(applicationContext) LocalStorageCleanupWorker.enqueue(applicationContext)
} }
withResumed { withResumed {

View File

@@ -10,20 +10,26 @@ import androidx.appcompat.widget.SearchView
import androidx.core.view.MenuProvider import androidx.core.view.MenuProvider
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.StateFlow
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.ui.list.ListSelectionController import org.koitharu.kotatsu.core.ui.list.ListSelectionController
import org.koitharu.kotatsu.core.util.ext.addMenuProvider import org.koitharu.kotatsu.core.util.ext.addMenuProvider
import org.koitharu.kotatsu.core.util.ext.withArgs import org.koitharu.kotatsu.core.util.ext.withArgs
import org.koitharu.kotatsu.databinding.FragmentListBinding import org.koitharu.kotatsu.databinding.FragmentListBinding
import org.koitharu.kotatsu.filter.ui.FilterOwner
import org.koitharu.kotatsu.filter.ui.FilterSheetFragment import org.koitharu.kotatsu.filter.ui.FilterSheetFragment
import org.koitharu.kotatsu.filter.ui.model.FilterHeaderModel
import org.koitharu.kotatsu.filter.ui.model.FilterItem
import org.koitharu.kotatsu.list.ui.MangaListFragment import org.koitharu.kotatsu.list.ui.MangaListFragment
import org.koitharu.kotatsu.list.ui.model.ListModel
import org.koitharu.kotatsu.main.ui.owners.AppBarOwner import org.koitharu.kotatsu.main.ui.owners.AppBarOwner
import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.search.ui.SearchActivity import org.koitharu.kotatsu.search.ui.SearchActivity
import org.koitharu.kotatsu.settings.SettingsActivity import org.koitharu.kotatsu.settings.SettingsActivity
@AndroidEntryPoint @AndroidEntryPoint
class RemoteListFragment : MangaListFragment() { class RemoteListFragment : MangaListFragment(), FilterOwner {
override val viewModel by viewModels<RemoteListViewModel>() override val viewModel by viewModels<RemoteListViewModel>()
@@ -49,6 +55,24 @@ class RemoteListFragment : MangaListFragment() {
viewModel.resetFilter() viewModel.resetFilter()
} }
override val filterItems: StateFlow<List<ListModel>>
get() = viewModel.filterItems
override val header: StateFlow<FilterHeaderModel>
get() = viewModel.header
override fun applyFilter(tags: Set<MangaTag>) {
viewModel.applyFilter(tags)
}
override fun onSortItemClick(item: FilterItem.Sort) {
viewModel.onSortItemClick(item)
}
override fun onTagItemClick(item: FilterItem.Tag) {
viewModel.onTagItemClick(item)
}
private inner class RemoteListMenuProvider : private inner class RemoteListMenuProvider :
MenuProvider, MenuProvider,
SearchView.OnQueryTextListener, SearchView.OnQueryTextListener,

View File

@@ -26,7 +26,6 @@ import org.koitharu.kotatsu.databinding.ActivityMangaListBinding
import org.koitharu.kotatsu.filter.ui.FilterHeaderFragment import org.koitharu.kotatsu.filter.ui.FilterHeaderFragment
import org.koitharu.kotatsu.filter.ui.FilterOwner import org.koitharu.kotatsu.filter.ui.FilterOwner
import org.koitharu.kotatsu.filter.ui.FilterSheetFragment import org.koitharu.kotatsu.filter.ui.FilterSheetFragment
import org.koitharu.kotatsu.list.ui.MangaListFragment
import org.koitharu.kotatsu.local.ui.LocalListFragment import org.koitharu.kotatsu.local.ui.LocalListFragment
import org.koitharu.kotatsu.main.ui.owners.AppBarOwner import org.koitharu.kotatsu.main.ui.owners.AppBarOwner
import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaSource
@@ -74,7 +73,10 @@ class MangaListActivity :
private fun initList(source: MangaSource, tags: Set<MangaTag>?) { private fun initList(source: MangaSource, tags: Set<MangaTag>?) {
val fm = supportFragmentManager val fm = supportFragmentManager
if (fm.findFragmentById(R.id.container) == null) { val existingFragment = fm.findFragmentById(R.id.container)
if (existingFragment is FilterOwner) {
initFilter(existingFragment)
} else {
fm.commit { fm.commit {
setReorderingAllowed(true) setReorderingAllowed(true)
val fragment = if (source == MangaSource.LOCAL) { val fragment = if (source == MangaSource.LOCAL) {
@@ -83,17 +85,15 @@ class MangaListActivity :
RemoteListFragment.newInstance(source) RemoteListFragment.newInstance(source)
} }
replace(R.id.container, fragment) replace(R.id.container, fragment)
runOnCommit { initFilter() } runOnCommit { initFilter(fragment) }
if (!tags.isNullOrEmpty() && fragment is RemoteListFragment) { if (!tags.isNullOrEmpty()) {
runOnCommit(ApplyFilterRunnable(fragment, tags)) runOnCommit(ApplyFilterRunnable(fragment, tags))
} }
} }
} else {
initFilter()
} }
} }
private fun initFilter() { private fun initFilter(filterOwner: FilterOwner) {
if (viewBinding.containerFilter != null) { if (viewBinding.containerFilter != null) {
if (supportFragmentManager.findFragmentById(R.id.container_filter) == null) { if (supportFragmentManager.findFragmentById(R.id.container_filter) == null) {
supportFragmentManager.commit { supportFragmentManager.commit {
@@ -109,7 +109,6 @@ class MangaListActivity :
} }
} }
} }
val filterOwner = FilterOwner.from(this)
val chipSort = viewBinding.chipSort val chipSort = viewBinding.chipSort
if (chipSort != null) { if (chipSort != null) {
filterOwner.header.observe(this) { filterOwner.header.observe(this) {
@@ -126,14 +125,12 @@ class MangaListActivity :
} }
private class ApplyFilterRunnable( private class ApplyFilterRunnable(
private val fragment: MangaListFragment, private val filterOwner: FilterOwner,
private val tags: Set<MangaTag>, private val tags: Set<MangaTag>,
) : Runnable { ) : Runnable {
override fun run() { override fun run() {
checkNotNull(FilterOwner.find(fragment)) { filterOwner.applyFilter(tags)
"Cannot find FilterOwner"
}.applyFilter(tags)
} }
} }

View File

@@ -0,0 +1,12 @@
package org.koitharu.kotatsu.settings.work
import android.content.Context
interface PeriodicWorkScheduler {
suspend fun schedule(context: Context)
suspend fun unschedule(context: Context)
suspend fun isScheduled(context: Context): Boolean
}

View File

@@ -0,0 +1,49 @@
package org.koitharu.kotatsu.settings.work
import android.content.Context
import android.content.SharedPreferences
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.util.ext.processLifecycleScope
import org.koitharu.kotatsu.suggestions.ui.SuggestionsWorker
import org.koitharu.kotatsu.tracker.work.TrackWorker
import javax.inject.Inject
class WorkScheduleManager @Inject constructor(
@ApplicationContext private val context: Context,
private val settings: AppSettings,
) : SharedPreferences.OnSharedPreferenceChangeListener {
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
when (key) {
AppSettings.KEY_TRACKER_ENABLED -> updateWorker(TrackWorker, settings.isTrackerEnabled)
AppSettings.KEY_SUGGESTIONS -> updateWorker(SuggestionsWorker, settings.isSuggestionsEnabled)
}
}
fun init() {
settings.subscribe(this)
processLifecycleScope.launch(Dispatchers.Default) {
updateWorkerImpl(TrackWorker, settings.isTrackerEnabled)
updateWorkerImpl(SuggestionsWorker, settings.isSuggestionsEnabled)
}
}
private fun updateWorker(scheduler: PeriodicWorkScheduler, isEnabled: Boolean) {
processLifecycleScope.launch(Dispatchers.Default) {
updateWorkerImpl(scheduler, isEnabled)
}
}
private suspend fun updateWorkerImpl(scheduler: PeriodicWorkScheduler, isEnabled: Boolean) {
if (scheduler.isScheduled(context) != isEnabled) {
if (isEnabled) {
scheduler.schedule(context)
} else {
scheduler.unschedule(context)
}
}
}
}

View File

@@ -23,6 +23,7 @@ import androidx.work.OutOfQuotaPolicy
import androidx.work.PeriodicWorkRequestBuilder import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager import androidx.work.WorkManager
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import androidx.work.await
import androidx.work.workDataOf import androidx.work.workDataOf
import coil.ImageLoader import coil.ImageLoader
import coil.request.ImageRequest import coil.request.ImageRequest
@@ -38,6 +39,7 @@ import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.distinctById import org.koitharu.kotatsu.core.model.distinctById
import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.util.WorkManagerHelper
import org.koitharu.kotatsu.core.util.ext.almostEquals import org.koitharu.kotatsu.core.util.ext.almostEquals
import org.koitharu.kotatsu.core.util.ext.asArrayList import org.koitharu.kotatsu.core.util.ext.asArrayList
import org.koitharu.kotatsu.core.util.ext.flatten import org.koitharu.kotatsu.core.util.ext.flatten
@@ -55,6 +57,7 @@ import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
import org.koitharu.kotatsu.reader.ui.ReaderActivity.IntentBuilder import org.koitharu.kotatsu.reader.ui.ReaderActivity.IntentBuilder
import org.koitharu.kotatsu.settings.work.PeriodicWorkScheduler
import org.koitharu.kotatsu.suggestions.domain.MangaSuggestion import org.koitharu.kotatsu.suggestions.domain.MangaSuggestion
import org.koitharu.kotatsu.suggestions.domain.SuggestionRepository import org.koitharu.kotatsu.suggestions.domain.SuggestionRepository
import org.koitharu.kotatsu.suggestions.domain.TagsBlacklist import org.koitharu.kotatsu.suggestions.domain.TagsBlacklist
@@ -75,11 +78,11 @@ class SuggestionsWorker @AssistedInject constructor(
) : CoroutineWorker(appContext, params) { ) : CoroutineWorker(appContext, params) {
override suspend fun doWork(): Result { override suspend fun doWork(): Result {
trySetForeground()
if (!appSettings.isSuggestionsEnabled) { if (!appSettings.isSuggestionsEnabled) {
suggestionRepository.clear() suggestionRepository.clear()
return Result.success() return Result.success()
} }
trySetForeground()
val count = doWorkImpl() val count = doWorkImpl()
val outputData = workDataOf(DATA_COUNT to count) val outputData = workDataOf(DATA_COUNT to count)
return Result.success(outputData) return Result.success(outputData)
@@ -303,7 +306,7 @@ class SuggestionsWorker @AssistedInject constructor(
return -1 return -1
} }
companion object { companion object : PeriodicWorkScheduler {
private const val TAG = "suggestions" private const val TAG = "suggestions"
private const val TAG_ONESHOT = "suggestions_oneshot" private const val TAG_ONESHOT = "suggestions_oneshot"
@@ -324,7 +327,7 @@ class SuggestionsWorker @AssistedInject constructor(
SortOrder.RATING, SortOrder.RATING,
) )
fun setup(context: Context) { override suspend fun schedule(context: Context) {
val constraints = Constraints.Builder() val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED) .setRequiredNetworkType(NetworkType.UNMETERED)
.setRequiresBatteryNotLow(true) .setRequiresBatteryNotLow(true)
@@ -336,6 +339,19 @@ class SuggestionsWorker @AssistedInject constructor(
.build() .build()
WorkManager.getInstance(context) WorkManager.getInstance(context)
.enqueueUniquePeriodicWork(TAG, ExistingPeriodicWorkPolicy.KEEP, request) .enqueueUniquePeriodicWork(TAG, ExistingPeriodicWorkPolicy.KEEP, request)
.await()
}
override suspend fun unschedule(context: Context) {
WorkManager.getInstance(context)
.cancelUniqueWork(TAG)
.await()
}
override suspend fun isScheduled(context: Context): Boolean {
return WorkManagerHelper(WorkManager.getInstance(context))
.getUniqueWorkInfoByName(TAG)
.any { !it.state.isFinished }
} }
fun startNow(context: Context) { fun startNow(context: Context) {

View File

@@ -26,6 +26,7 @@ import androidx.work.WorkInfo
import androidx.work.WorkManager import androidx.work.WorkManager
import androidx.work.WorkQuery import androidx.work.WorkQuery
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import androidx.work.await
import coil.ImageLoader import coil.ImageLoader
import coil.request.ImageRequest import coil.request.ImageRequest
import dagger.assisted.Assisted import dagger.assisted.Assisted
@@ -42,12 +43,14 @@ import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.logs.FileLogger import org.koitharu.kotatsu.core.logs.FileLogger
import org.koitharu.kotatsu.core.logs.TrackerLogger import org.koitharu.kotatsu.core.logs.TrackerLogger
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.util.WorkManagerHelper
import org.koitharu.kotatsu.core.util.ext.toBitmapOrNull import org.koitharu.kotatsu.core.util.ext.toBitmapOrNull
import org.koitharu.kotatsu.core.util.ext.trySetForeground import org.koitharu.kotatsu.core.util.ext.trySetForeground
import org.koitharu.kotatsu.details.ui.DetailsActivity import org.koitharu.kotatsu.details.ui.DetailsActivity
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaChapter import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
import org.koitharu.kotatsu.settings.work.PeriodicWorkScheduler
import org.koitharu.kotatsu.tracker.domain.Tracker import org.koitharu.kotatsu.tracker.domain.Tracker
import org.koitharu.kotatsu.tracker.domain.model.MangaUpdates import org.koitharu.kotatsu.tracker.domain.model.MangaUpdates
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@@ -67,6 +70,7 @@ class TrackWorker @AssistedInject constructor(
} }
override suspend fun doWork(): Result { override suspend fun doWork(): Result {
trySetForeground()
logger.log("doWork()") logger.log("doWork()")
try { try {
return doWorkImpl() return doWorkImpl()
@@ -85,7 +89,6 @@ class TrackWorker @AssistedInject constructor(
if (!settings.isTrackerEnabled) { if (!settings.isTrackerEnabled) {
return Result.success(workDataOf(0, 0)) return Result.success(workDataOf(0, 0))
} }
trySetForeground()
val tracks = tracker.getAllTracks() val tracks = tracker.getAllTracks()
logger.log("Total ${tracks.size} tracks") logger.log("Total ${tracks.size} tracks")
if (tracks.isEmpty()) { if (tracks.isEmpty()) {
@@ -234,7 +237,7 @@ class TrackWorker @AssistedInject constructor(
.build() .build()
} }
companion object { companion object : PeriodicWorkScheduler {
private const val WORKER_CHANNEL_ID = "track_worker" private const val WORKER_CHANNEL_ID = "track_worker"
private const val WORKER_NOTIFICATION_ID = 35 private const val WORKER_NOTIFICATION_ID = 35
@@ -244,14 +247,28 @@ class TrackWorker @AssistedInject constructor(
private const val DATA_KEY_SUCCESS = "success" private const val DATA_KEY_SUCCESS = "success"
private const val DATA_KEY_FAILED = "failed" private const val DATA_KEY_FAILED = "failed"
fun setup(context: Context) { override suspend fun schedule(context: Context) {
val constraints = Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build() val constraints = Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()
val request = PeriodicWorkRequestBuilder<TrackWorker>(4, TimeUnit.HOURS) val request = PeriodicWorkRequestBuilder<TrackWorker>(4, TimeUnit.HOURS)
.setConstraints(constraints) .setConstraints(constraints)
.addTag(TAG) .addTag(TAG)
.setBackoffCriteria(BackoffPolicy.LINEAR, 30, TimeUnit.MINUTES) .setBackoffCriteria(BackoffPolicy.LINEAR, 30, TimeUnit.MINUTES)
.build() .build()
WorkManager.getInstance(context).enqueueUniquePeriodicWork(TAG, ExistingPeriodicWorkPolicy.KEEP, request) WorkManager.getInstance(context)
.enqueueUniquePeriodicWork(TAG, ExistingPeriodicWorkPolicy.KEEP, request)
.await()
}
override suspend fun unschedule(context: Context) {
WorkManager.getInstance(context)
.cancelUniqueWork(TAG)
.await()
}
override suspend fun isScheduled(context: Context): Boolean {
return WorkManagerHelper(WorkManager.getInstance(context))
.getUniqueWorkInfoByName(TAG)
.any { !it.state.isFinished }
} }
fun startNow(context: Context) { fun startNow(context: Context) {

View File

@@ -56,7 +56,7 @@
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/barrier_top" app:layout_constraintTop_toBottomOf="@id/barrier_top"
app:trackColor="?colorPrimaryContainer" app:trackColor="?android:colorBackground"
tools:progress="25" /> tools:progress="25" />
<TextView <TextView

View File

@@ -95,7 +95,7 @@
<string name="vibration">Вібрацыя</string> <string name="vibration">Вібрацыя</string>
<string name="favourites_categories">Катэгорыі абранага</string> <string name="favourites_categories">Катэгорыі абранага</string>
<string name="remove_category">Выдаліць катэгорыю</string> <string name="remove_category">Выдаліць катэгорыю</string>
<string name="manga_shelf">Паліца з мангай</string> <string name="manga_shelf">Паліца</string>
<string name="recent_manga">Нядаўняя манга</string> <string name="recent_manga">Нядаўняя манга</string>
<string name="pages_animation">Анімацыя гартання</string> <string name="pages_animation">Анімацыя гартання</string>
<string name="manga_save_location">Месца спампоўвання мангі</string> <string name="manga_save_location">Месца спампоўвання мангі</string>
@@ -201,7 +201,7 @@
<string name="screenshots_block_all">Заўсёды блакуйце</string> <string name="screenshots_block_all">Заўсёды блакуйце</string>
<string name="screenshots_block_nsfw">Блок на NSFW</string> <string name="screenshots_block_nsfw">Блок на NSFW</string>
<string name="filter_load_error">Немагчыма загрузіць спіс жанраў</string> <string name="filter_load_error">Немагчыма загрузіць спіс жанраў</string>
<string name="disabled">Непрацаздольны</string> <string name="disabled">Адключаны</string>
<string name="enabled">Уключаны</string> <string name="enabled">Уключаны</string>
<string name="exclude_nsfw_from_suggestions">Не прапануйце мангу NSFW</string> <string name="exclude_nsfw_from_suggestions">Не прапануйце мангу NSFW</string>
<string name="text_suggestion_holder">Пачніце чытаць мангу, і вы атрымаеце персаналізаваныя прапановы</string> <string name="text_suggestion_holder">Пачніце чытаць мангу, і вы атрымаеце персаналізаваныя прапановы</string>
@@ -255,7 +255,7 @@
<string name="edit">Змяніць</string> <string name="edit">Змяніць</string>
<string name="edit_category">Змяніць катэгорыю</string> <string name="edit_category">Змяніць катэгорыю</string>
<string name="bookmark_add">Дадаць закладку</string> <string name="bookmark_add">Дадаць закладку</string>
<string name="undo">Адмяніць</string> <string name="undo">Адмена</string>
<string name="disable_battery_optimization">Адключыць аптымізацыю акумулятара</string> <string name="disable_battery_optimization">Адключыць аптымізацыю акумулятара</string>
<string name="disable_battery_optimization_summary">Дапамагае з фонавай праверкай абнаўленняў</string> <string name="disable_battery_optimization_summary">Дапамагае з фонавай праверкай абнаўленняў</string>
<string name="crash_text">Штосьці пайшло не так. Калі ласка, адпраўце справаздачу пра памылку распрацоўшчыкам, каб дапамагчы нам яе выправіць.</string> <string name="crash_text">Штосьці пайшло не так. Калі ласка, адпраўце справаздачу пра памылку распрацоўшчыкам, каб дапамагчы нам яе выправіць.</string>
@@ -327,7 +327,7 @@
<string name="enable_logging_summary">Запішыце некаторыя дзеянні для адладкі</string> <string name="enable_logging_summary">Запішыце некаторыя дзеянні для адладкі</string>
<string name="show_suspicious_content">Паказаць падазроны кантэнт</string> <string name="show_suspicious_content">Паказаць падазроны кантэнт</string>
<string name="text_shelf_holder_primary">Ваша манга будзе адлюстроўвацца тут</string> <string name="text_shelf_holder_primary">Ваша манга будзе адлюстроўвацца тут</string>
<string name="text_shelf_holder_secondary">Знайдзіце, што пачытаць, у раздзеле «Даследаваць»</string> <string name="text_shelf_holder_secondary">Знайдзіце, што пачытаць, у раздзеле «Агляд»</string>
<string name="canceled">Адменена</string> <string name="canceled">Адменена</string>
<string name="manage">Кіраваць</string> <string name="manage">Кіраваць</string>
<string name="available">Даступны</string> <string name="available">Даступны</string>
@@ -356,7 +356,7 @@
<string name="random">Выпадковы</string> <string name="random">Выпадковы</string>
<string name="reorder">Змяніць парадак</string> <string name="reorder">Змяніць парадак</string>
<string name="empty">Пуста</string> <string name="empty">Пуста</string>
<string name="explore">Дасьледуйце</string> <string name="explore">Агляд</string>
<string name="confirm_exit">Націсніце \"Назад\" яшчэ раз, каб выйсці</string> <string name="confirm_exit">Націсніце \"Назад\" яшчэ раз, каб выйсці</string>
<string name="exit_confirmation_summary">Двойчы націсніце \"Назад\", каб выйсці з праграмы</string> <string name="exit_confirmation_summary">Двойчы націсніце \"Назад\", каб выйсці з праграмы</string>
<string name="exit_confirmation">Пацверджанне выхаду</string> <string name="exit_confirmation">Пацверджанне выхаду</string>
@@ -425,7 +425,7 @@
<string name="invert_colors">Інвертаваць колеры</string> <string name="invert_colors">Інвертаваць колеры</string>
<string name="show_pages_numbers_summary">Паказаць нумары старонак у ніжнім куце</string> <string name="show_pages_numbers_summary">Паказаць нумары старонак у ніжнім куце</string>
<string name="network">Сетка</string> <string name="network">Сетка</string>
<string name="data_and_privacy">Дадзеныя і прыватнасць</string> <string name="data_and_privacy">Дадзеныя і канфідэнцыяльнасць</string>
<string name="webtoon_zoom_summary">Дазволіць жэст для павелічэння ў рэжыме webtoon</string> <string name="webtoon_zoom_summary">Дазволіць жэст для павелічэння ў рэжыме webtoon</string>
<string name="details_button_tip">Націсніце і ўтрымлівайце кнопку \"Чытаць\", каб убачыць дадатковыя параметры</string> <string name="details_button_tip">Націсніце і ўтрымлівайце кнопку \"Чытаць\", каб убачыць дадатковыя параметры</string>
<string name="restore_summary">Аднавіць раней створаную рэзервовую копію</string> <string name="restore_summary">Аднавіць раней створаную рэзервовую копію</string>

View File

@@ -422,4 +422,13 @@
<string name="password">Mot de passe</string> <string name="password">Mot de passe</string>
<string name="invalid_value_message">Valeur invalide</string> <string name="invalid_value_message">Valeur invalide</string>
<string name="authorization_optional">Autorisation (optionnel)</string> <string name="authorization_optional">Autorisation (optionnel)</string>
<string name="invalid_port_number">Numéro de port invalide</string>
<string name="restore_summary">Restaurer la sauvegarde précédemment créée</string>
<string name="webtoon_zoom_summary">Autoriser le geste de zoom avant en mode webtoon</string>
<string name="reader_info_bar_summary">Afficher l\'heure actuelle et la progression de la lecture en haut de l\'écran</string>
<string name="pages_animation_summary">Animation de tournage de page</string>
<string name="details_button_tip">Appuyez et maintenez le bouton Lire pour voir plus d\'options</string>
<string name="network">Réseau</string>
<string name="data_and_privacy">Données et confidentialité</string>
<string name="show_pages_numbers_summary">Afficher les numéros de page dans le coin inférieur</string>
</resources> </resources>

View File

@@ -359,4 +359,5 @@
<string name="allow_unstable_updates">Tillat ustøe oppdateringar</string> <string name="allow_unstable_updates">Tillat ustøe oppdateringar</string>
<string name="downloads_wifi_only">Hent berre på WiFi</string> <string name="downloads_wifi_only">Hent berre på WiFi</string>
<string name="downloads_wifi_only_summary">Stans all henting når du byter til eit mobilnettverk</string> <string name="downloads_wifi_only_summary">Stans all henting når du byter til eit mobilnettverk</string>
<string name="find_similar">Finn liknande</string>
</resources> </resources>

View File

@@ -75,7 +75,7 @@
<string name="download">Download</string> <string name="download">Download</string>
<string name="notifications_settings">Configurações das notificações</string> <string name="notifications_settings">Configurações das notificações</string>
<string name="light_indicator">Indicador LED</string> <string name="light_indicator">Indicador LED</string>
<string name="remote_sources">Fontes remotas</string> <string name="remote_sources">Fontes de mangá</string>
<string name="close">Fechar</string> <string name="close">Fechar</string>
<string name="light">Claro</string> <string name="light">Claro</string>
<string name="history">Histórico</string> <string name="history">Histórico</string>
@@ -114,7 +114,7 @@
<string name="app_version">Versão %s</string> <string name="app_version">Versão %s</string>
<string name="check_for_updates">Verifique se há atualizações</string> <string name="check_for_updates">Verifique se há atualizações</string>
<string name="no_update_available">Nenhuma atualização disponível</string> <string name="no_update_available">Nenhuma atualização disponível</string>
<string name="right_to_left">Da direita para a esquerda</string> <string name="right_to_left">Da direita para a esquerda (←)</string>
<string name="create_category">Nova categoria</string> <string name="create_category">Nova categoria</string>
<string name="scale_mode">Modo de escala</string> <string name="scale_mode">Modo de escala</string>
<string name="zoom_mode_fit_center">Centro de ajuste</string> <string name="zoom_mode_fit_center">Centro de ajuste</string>
@@ -201,7 +201,7 @@
<string name="screenshots_policy">Política de captura de ecrã</string> <string name="screenshots_policy">Política de captura de ecrã</string>
<string name="screenshots_block_all">Sempre bloquear</string> <string name="screenshots_block_all">Sempre bloquear</string>
<string name="suggestions_summary">Sugira mangá com base nas suas preferências</string> <string name="suggestions_summary">Sugira mangá com base nas suas preferências</string>
<string name="suggestions_info">Todos os dados são analisados localmente neste dispositivo. Não há transferência dos seus dados pessoais para nenhum serviço</string> <string name="suggestions_info">Todos os dados são analisados apenas localmente neste dispositivo e nunca são enviados para qualquer lugar.</string>
<string name="text_suggestion_holder">Comece a ler mangá e receberá sugestões personalizadas</string> <string name="text_suggestion_holder">Comece a ler mangá e receberá sugestões personalizadas</string>
<string name="suggestions">Sugestões</string> <string name="suggestions">Sugestões</string>
<string name="suggestions_enable">Ativar sugestões</string> <string name="suggestions_enable">Ativar sugestões</string>
@@ -225,127 +225,127 @@
<string name="percent_string_pattern">%1$s%%</string> <string name="percent_string_pattern">%1$s%%</string>
<string name="text_shelf_holder_primary">O seu mangá será exibido aqui</string> <string name="text_shelf_holder_primary">O seu mangá será exibido aqui</string>
<string name="color_correction">Correção de cor</string> <string name="color_correction">Correção de cor</string>
<string name="server_error">Erro do lado do servidor (%1$d). Por favor, tente novamente mais tarde</string> <string name="server_error">Erro do servidor (%1$d). Por favor, tente novamente mais tarde</string>
<string name="clear_new_chapters_counters">Também limpar informações sobre capítulos novos</string> <string name="clear_new_chapters_counters">Apagar informações sobre novos capítulos</string>
<string name="hide">Esconder</string> <string name="hide">Ocultar</string>
<string name="text_delete_local_manga_batch">Apagar itens selecionados do aparelho permanentemente\?</string> <string name="text_delete_local_manga_batch">Excluir os itens selecionados do dispositivo permanentemente\?</string>
<string name="compact">Compactar</string> <string name="compact">Compactar</string>
<string name="bookmark_added">Marcador adicionado</string> <string name="bookmark_added">Marcador adicionado</string>
<string name="prefetch_content">Pré-carregamento de conteúdo</string> <string name="prefetch_content">Pré-carregamento de conteúdo</string>
<string name="invalid_domain_message">Endereço inválido</string> <string name="invalid_domain_message">Domínio inválido</string>
<string name="use_fingerprint">Usar impressão digital, se disponível</string> <string name="use_fingerprint">Usar impressão digital, se estiver disponível</string>
<string name="appwidget_shelf_description">Mangás dos seus favoritos</string> <string name="appwidget_shelf_description">Mangá dos seus favoritos</string>
<string name="appwidget_recent_description">Os seus mangás recentemente lidos</string> <string name="appwidget_recent_description">Mangás lidos recentemente</string>
<string name="suggestions_excluded_genres_summary">Especifique os gêneros que não deseja ver nas sugestões</string> <string name="suggestions_excluded_genres_summary">Especifique os gêneros que você não deseja ver nas sugestões</string>
<string name="removal_completed">Remoção concluída</string> <string name="removal_completed">Remoção concluída</string>
<string name="check_new_chapters_title">Verifique se há novos capítulos e notifique sobre isso</string> <string name="check_new_chapters_title">Verifique se há novos capítulos e notifique se houver</string>
<string name="default_mode">Modo padrão</string> <string name="default_mode">Modo padrão</string>
<string name="mark_as_current">Marcar como atual</string> <string name="mark_as_current">Marcar como atual</string>
<string name="error_no_space_left">Não há espaço disponível no aparelho</string> <string name="error_no_space_left">Não há espaço disponível no dispositivo</string>
<string name="different_languages">Idiomas diferentes</string> <string name="different_languages">Idiomas diferentes</string>
<string name="network_unavailable">A rede não está disponível</string> <string name="network_unavailable">A rede não está disponível</string>
<string name="network_unavailable_hint">Ative o Wi-Fi ou a rede móvel para ler mangá online</string> <string name="network_unavailable_hint">Ative o Wi-Fi ou a rede móvel para ler o mangá online</string>
<string name="name">Nome</string> <string name="name">Nome</string>
<string name="logout">Terminar sessão</string> <string name="logout">Sair</string>
<string name="edit">Editar</string> <string name="edit">Editar</string>
<string name="edit_category">Editar categoria</string> <string name="edit_category">Editar categoria</string>
<string name="tracking">Monitoramento</string> <string name="tracking">Monitoramento</string>
<string name="empty_favourite_categories">Nenhuma categoria favorita</string> <string name="empty_favourite_categories">Nenhuma categoria favorita</string>
<string name="removed_from_history">Removido do histórico</string> <string name="removed_from_history">Removido do histórico</string>
<string name="send">Enviar</string> <string name="send">Enviar</string>
<string name="text_shelf_holder_secondary">Encontre o que ler na secção &lt;«Explorar»</string> <string name="text_shelf_holder_secondary">Encontre o que ler na secção «Explorar»</string>
<string name="suggestions_excluded_genres">Excluir gêneros</string> <string name="suggestions_excluded_genres">Excluir gêneros</string>
<string name="download_slowdown">Lentidão de descarga</string> <string name="download_slowdown">Download lento</string>
<string name="download_slowdown_summary">Ajuda a evitar o bloqueio do seu endereço IP</string> <string name="download_slowdown_summary">Ajude a evitar o bloqueio do seu endereço IP</string>
<string name="local_manga_processing">Processamento de mangá gravado</string> <string name="local_manga_processing">Processando mangá salvo</string>
<string name="chapters_will_removed_background">Os capítulos serão removidos em segundo plano. Pode levar algum tempo</string> <string name="chapters_will_removed_background">Os capítulos serão removidos em segundo plano</string>
<string name="canceled">Cancelado</string> <string name="canceled">Cancelado</string>
<string name="email_enter_hint">Digite o seu e-mail para continuar</string> <string name="email_enter_hint">Digite seu e-mail para continuar</string>
<string name="new_sources_text">Novas fontes de mangá estão disponíveis</string> <string name="new_sources_text">Novas fontes de mangá estão disponíveis</string>
<string name="show_notification_new_chapters_on">Receberá notificações sobre atualizações do mangá que está lendo</string> <string name="show_notification_new_chapters_on">Você receberá notificações sobre atualizações do mangá que está lendo</string>
<string name="notifications_enable">Ativar notificações</string> <string name="notifications_enable">Ativar notificações</string>
<string name="crash_text">Algo deu errado. Por favor, envie um relatório de bug para ajudar os programadores a consertarem isso.</string> <string name="crash_text">Algo deu errado. Por favor, envie um relatório de bug para os desenvolvedores para nos ajudar a corrigi-lo.</string>
<string name="status_planned">Planejado</string> <string name="status_planned">Planejado</string>
<string name="status_reading">Lendo</string> <string name="status_reading">Leitura</string>
<string name="status_re_reading">Relendo</string> <string name="status_re_reading">Relendo</string>
<string name="status_completed">Concluído</string> <string name="status_completed">Concluído</string>
<string name="status_on_hold">Em espera</string> <string name="status_on_hold">Em espera</string>
<string name="show_reading_indicators">Mostrar indicadores de progresso de leitura</string> <string name="show_reading_indicators">Mostrar indicadores de progresso de leitura</string>
<string name="data_deletion">Exclusão de dados</string> <string name="data_deletion">Exclusão de dados</string>
<string name="clear_cookies_summary">Pode ajudar no caso de alguns problemas. Todas as autorizações serão invalidadas</string> <string name="clear_cookies_summary">Pode ajudar em caso de alguns problemas. Todas as autorizações serão invalidadas</string>
<string name="show_all">Mostrar tudo</string> <string name="show_all">Mostrar tudo</string>
<string name="clear_all_history">Limpar todo o histórico</string> <string name="clear_all_history">Apagar todo o histórico</string>
<string name="last_2_hours">Ultimas 2 horas</string> <string name="last_2_hours">Últimas 2 horas</string>
<string name="categories_delete_confirm">Tem certeza que deseja apagar as categorias favoritas selecionadas\? <string name="categories_delete_confirm">Tem certeza de que deseja excluir as categorias favoritas selecionadas\?
\nTodos os mangás serão perdidos e isso não pode ser desfeito.</string> \nTodos os mangás serão perdidos e isso não pode ser desfeito.</string>
<string name="reorder">Reordenar</string> <string name="reorder">Reorganizar</string>
<string name="empty">Vazio</string> <string name="empty">Vazio</string>
<string name="explore">Explorar</string> <string name="explore">Explorar</string>
<string name="comics_archive">Arquivo de banda desenhada</string> <string name="comics_archive">Arquivos de quadrinhos</string>
<string name="folder_with_images">Pasta com imagens</string> <string name="folder_with_images">Pasta com imagens</string>
<string name="importing_manga">Importando mangá(s)</string> <string name="importing_manga">Importando mangá</string>
<string name="saved_manga">Mangás gravados</string> <string name="saved_manga">Mangás salvos</string>
<string name="history_shortcuts">Mostrar atalhos de mangás recentes</string> <string name="history_shortcuts">Mostrar atalhos de mangá recentes</string>
<string name="history_shortcuts_summary">Torne os mangás recentes visíveis pressionando o ícone da aplicação</string> <string name="history_shortcuts_summary">Disponibilizar mangás recentes pressionando por um curto período de tempo o ícone do aplicativo</string>
<string name="brightness">Luminosidade</string> <string name="brightness">Brilho</string>
<string name="contrast">Contraste</string> <string name="contrast">Contraste</string>
<string name="reset">Redefinir</string> <string name="reset">Redefinir</string>
<string name="text_unsaved_changes_prompt">Gravar ou descartar alterações não gravadas\?</string> <string name="text_unsaved_changes_prompt">Salvar ou descartar alterações não salvas\?</string>
<string name="select_range">Selecionar intervalo</string> <string name="select_range">Selecionar intervalo</string>
<string name="reader_slider">Mostrar controle deslizante de troca de página</string> <string name="reader_slider">Mostrar controle de leitura deslizante</string>
<string name="source_disabled">Fonte desativada</string> <string name="source_disabled">Fonte desativada</string>
<string name="account_already_exists">Essa conta já existe</string> <string name="account_already_exists">Essa conta já existe</string>
<string name="back">Voltar</string> <string name="back">Voltar</string>
<string name="sync">Sincronização</string> <string name="sync">Sincronização</string>
<string name="sync_title">Sincronize os seus dados</string> <string name="sync_title">Sincronizar os seus dados</string>
<string name="show_notification_new_chapters_off">Não receberá notificações, mas novos capítulos serão destacados nas listas</string> <string name="show_notification_new_chapters_off">Você não receberá notificações, mas novos capítulos serão destacados nas listas</string>
<string name="bookmark_add">Adicionar marcador</string> <string name="bookmark_add">Adicionar marcador</string>
<string name="bookmark_remove">Remover marcador</string> <string name="bookmark_remove">Remover marcador</string>
<string name="bookmarks">Marcadores</string> <string name="bookmarks">Marcadores</string>
<string name="bookmark_removed">Marcador removido</string> <string name="bookmark_removed">Marcador removido</string>
<string name="undo">Desfazer</string> <string name="undo">Desfazer</string>
<string name="dns_over_https">DNS sobre HTTPS</string> <string name="dns_over_https">DNS sobre HTTPS</string>
<string name="detect_reader_mode">Detecção automática do modo de leitura</string> <string name="detect_reader_mode">Modo de leitor de detecção automática</string>
<string name="detect_reader_mode_summary">Detetar automaticamente se o mangá é webtoon</string> <string name="detect_reader_mode_summary">Detectar automaticamente se o mangá é webtoon</string>
<string name="disable_battery_optimization">Desative a otimização da bateria</string> <string name="disable_battery_optimization">Desativar otimização de bateria</string>
<string name="disable_battery_optimization_summary">Ajuda com verificações de atualizações em segundo plano</string> <string name="disable_battery_optimization_summary">Ajuda com verificações de atualizações em segundo plano</string>
<string name="status_dropped">Desistido</string> <string name="status_dropped">Dropado</string>
<string name="disable_all">Desativar tudo</string> <string name="disable_all">Desativar tudo</string>
<string name="report">Reportar</string> <string name="report">Relatório</string>
<string name="show_reading_indicators_summary">Mostrar percentual de leitura no histórico e nos favoritos</string> <string name="show_reading_indicators_summary">Mostrar porcentagem lida no histórico e favoritos</string>
<string name="exclude_nsfw_from_history_summary">Mangás marcados como +18 nunca serão adicionados ao histórico e o seu progresso não sera gravado</string> <string name="exclude_nsfw_from_history_summary">Mangás marcados como NSFW nunca serão adicionados ao seu histórico e seu progresso não será salvo</string>
<string name="history_cleared">Histórico apagado</string> <string name="history_cleared">Histórico deletado</string>
<string name="manage">Gerir</string> <string name="manage">Gerenciar</string>
<string name="no_bookmarks_yet">Sem páginas marcadas ainda</string> <string name="no_bookmarks_yet">Ainda não há marcadores</string>
<string name="no_bookmarks_summary">Pode criar um marcador de página enquanto lé o mangá</string> <string name="no_bookmarks_summary">Você pode criar marcadores enquanto lê o mangá</string>
<string name="bookmarks_removed">Marcadores de página removidos</string> <string name="bookmarks_removed">Marcadores removidos</string>
<string name="no_manga_sources">Sem fontes de mangás</string> <string name="no_manga_sources">Sem fontes de mangá</string>
<string name="no_manga_sources_text">Ative as fontes de mangá para ler online</string> <string name="no_manga_sources_text">Habilitar fontes de mangá para ler o mangá online</string>
<string name="random">Aleatório</string> <string name="random">Aleatório</string>
<string name="confirm_exit">Pressione Voltar novamente para sair</string> <string name="confirm_exit">Pressione Voltar novamente para sair</string>
<string name="exit_confirmation_summary">Pressione Voltar duas vezes para sair do app</string> <string name="exit_confirmation_summary">Pressione Voltar duas vezes para sair do aplicativo</string>
<string name="exit_confirmation">Confirmação de saída</string> <string name="exit_confirmation">Confirmação de saída</string>
<string name="pages_cache">Cache de páginas</string> <string name="pages_cache">Cache de páginas</string>
<string name="other_cache">Outro cache</string> <string name="other_cache">Outros cache</string>
<string name="storage_usage">Uso de armazenamento</string> <string name="storage_usage">Armazenamento usado</string>
<string name="available">Disponível</string> <string name="available">Disponível</string>
<string name="memory_usage_pattern">%s - %s</string> <string name="memory_usage_pattern">%s - %s</string>
<string name="removed_from_favourites">Removido dos favoritos</string> <string name="removed_from_favourites">Removido dos favoritos</string>
<string name="options">Opções</string> <string name="options">Opções</string>
<string name="not_found_404">Conteúdo não encontrado ou removido</string> <string name="not_found_404">Conteúdo não encontrado ou removido</string>
<string name="incognito_mode">Modo anônimo</string> <string name="incognito_mode">Modo de navegação anônima</string>
<string name="no_chapters">Sem capítulos</string> <string name="no_chapters">Sem capítulos</string>
<string name="automatic_scroll">Rolagem automática</string> <string name="automatic_scroll">Rolagem automática</string>
<string name="reader_info_pattern">Cap. %1$d/%2$d Pág. %3$d/%4$d</string> <string name="reader_info_pattern">Cap. %1$d/%2$d Pág. %3$d/%4$d</string>
<string name="reader_info_bar">Mostrar barra de informações no leitor</string> <string name="reader_info_bar">Mostrar barra de informações no leitor</string>
<string name="import_completed">Importação completa</string> <string name="import_completed">Importação concluída</string>
<string name="import_completed_hint">Pode apagar o ficheiro original do aparelho para poupar espaço</string> <string name="import_completed_hint">Você pode excluir o arquivo original do armazenamento para economizar espaço</string>
<string name="import_will_start_soon">A importação começará em breve</string> <string name="import_will_start_soon">A importação começará em breve</string>
<string name="feed">Feed</string> <string name="feed">Fluxo de conteúdo</string>
<string name="manga_error_description_pattern">Detalhes do erro:&lt;br&gt;&lt;tt&gt;%1$s&lt;/tt&gt;&lt;br&gt;&lt;br&gt;1. Tente &lt;a href=%2$s&gt;abrir o mangá num navegador de internet&lt;/a&gt;para garantir que ele está disponível na fonte&lt;br&gt;2. Se estiver disponível, envie um relatório de erro para os programadores.</string> <string name="manga_error_description_pattern">Detalhes do erro:&lt;br&gt;&lt;tt&gt;%1$s&lt;/tt&gt;&lt;br&gt;&lt;br&gt;1. Tente &lt;a href=%2$s&gt;abra a página do mangá em um navegador da web&lt;/a&gt; para garantir que o mesmo esteja disponível em sua fonte&lt;br&gt;2. Se estiver disponível, envie um relatório de erro para os desenvolvedores.</string>
<string name="reader_control_ltr_summary">Tocar na borda direita ou pressionar a tecla direita sempre passa para a próxima página</string> <string name="reader_control_ltr_summary">Tocar na borda direita ou pressionar a tecla direita sempre muda para a próxima página</string>
<string name="reader_control_ltr">Controle de leitura ergonômico</string> <string name="reader_control_ltr">Controle ergonômico do leitor</string>
<string name="color_correction_hint">As configurações de cor escolhidas serão lembradas para esse mangá</string> <string name="color_correction_hint">As configurações de cores escolhidas serão lembradas para este mangá</string>
<string name="discard">Descartar</string> <string name="discard">Descartar</string>
<string name="language">Idioma</string> <string name="language">Idioma</string>
<string name="theme_name_mamimi">Mamimi</string> <string name="theme_name_mamimi">Mamimi</string>
@@ -366,4 +366,9 @@
<string name="theme_name_asuka">Asuka</string> <string name="theme_name_asuka">Asuka</string>
<string name="theme_name_mion">Mion</string> <string name="theme_name_mion">Mion</string>
<string name="settings_apply_restart_required">Por favor, reinicie o app para aplicar essas mudanças</string> <string name="settings_apply_restart_required">Por favor, reinicie o app para aplicar essas mudanças</string>
<string name="theme_name_kanade">Kanade</string>
<string name="scrobbling_empty_hint">Para acompanhar o progresso da leitura, selecione Menu → Vá até a tela de detalhes do mangá.</string>
<string name="details_button_tip">Pressione e segure o botão Ler para ver mais opções</string>
<string name="webtoon_zoom">Zoom Webtoon</string>
<string name="allow_unstable_updates_summary">Propor atualizações para versões beta do aplicativo</string>
</resources> </resources>

View File

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

View File

@@ -203,7 +203,7 @@
<string name="suggestions">Öneriler</string> <string name="suggestions">Öneriler</string>
<string name="suggestions_enable">Önerileri etkinleştir</string> <string name="suggestions_enable">Önerileri etkinleştir</string>
<string name="suggestions_summary">Tercihlerinize göre manga önerileri alın</string> <string name="suggestions_summary">Tercihlerinize göre manga önerileri alın</string>
<string name="suggestions_info">Tüm veriler sadece bu cihaz üzerinde yerel olarak işlenir ve asla herhangi bir yere satılmaz.</string> <string name="suggestions_info">Tüm veriler bu cihazda yalnızca yerel olarak analiz edilir ve asla hbir yere gönderilmez.</string>
<string name="text_suggestion_holder">Manga okumaya başladıktan sonra kişiselleştirilmiş öneriler alacaksınız</string> <string name="text_suggestion_holder">Manga okumaya başladıktan sonra kişiselleştirilmiş öneriler alacaksınız</string>
<string name="exclude_nsfw_from_suggestions">Uygunsuz manga önerme</string> <string name="exclude_nsfw_from_suggestions">Uygunsuz manga önerme</string>
<string name="enabled">Etkin</string> <string name="enabled">Etkin</string>
@@ -227,7 +227,7 @@
<string name="suggestions_excluded_genres_summary">Önerilerde görmek istemediğiniz türleri belirtin</string> <string name="suggestions_excluded_genres_summary">Önerilerde görmek istemediğiniz türleri belirtin</string>
<string name="text_delete_local_manga_batch">Seçilen ögeler aygıttan kalıcı olarak silinsin mi\?</string> <string name="text_delete_local_manga_batch">Seçilen ögeler aygıttan kalıcı olarak silinsin mi\?</string>
<string name="removal_completed">Kaldırma tamamlandı</string> <string name="removal_completed">Kaldırma tamamlandı</string>
<string name="chapters_will_removed_background">Bölümler arka planda kaldırılacak.</string> <string name="chapters_will_removed_background">Bölümler arka planda kaldırılacak</string>
<string name="download_slowdown">İndirmeyi yavaşlat</string> <string name="download_slowdown">İndirmeyi yavaşlat</string>
<string name="download_slowdown_summary">IP adresinizin engellenmesinden kaçınmanıza yardımcı olur</string> <string name="download_slowdown_summary">IP adresinizin engellenmesinden kaçınmanıza yardımcı olur</string>
<string name="local_manga_processing">Kaydedilen manga işleme</string> <string name="local_manga_processing">Kaydedilen manga işleme</string>
@@ -302,7 +302,7 @@
<string name="removed_from_favourites">Favorilerden kaldırıldı</string> <string name="removed_from_favourites">Favorilerden kaldırıldı</string>
<string name="exit_confirmation">Çıkış doğrulaması</string> <string name="exit_confirmation">Çıkış doğrulaması</string>
<string name="comics_archive">Çizgi roman arşivi</string> <string name="comics_archive">Çizgi roman arşivi</string>
<string name="manga_error_description_pattern">Hata ayrıntıları:&lt;br&gt;&lt;tt&gt;%1$s&lt;/tt&gt;&lt;br&gt;&lt;br&gt;1.Mangayı &lt;a href=%2$s&gt;kaynağında mevcut olduğuna emin olmak için&lt;/a&gt; bir web tarayıcısında açın&lt;br&gt;2. &lt;a href=kotatsu://about&gt; Kotatsunun son sürümünü kullandığnızdan emin olun.&lt;/a&gt;/br&gt; 3. Mevcutsa, geliştiricilere bir hata reporu gönderin.</string> <string name="manga_error_description_pattern">Hata ayrıntıları:&lt;br&gt;&lt;tt&gt;%1$s&lt;/tt&gt;&lt;br&gt;&lt;br&gt;1. Kaynağında bulunduğundan emin olmak için &lt;a href=%2$s&gt;mangayı bir web tarayıcısında açmayı&lt;/a&gt; deneyin&lt;br&gt;2. &lt;a href=kotatsu://about&gt;Kotatsu\'nun en son sürümünü&lt;/a&gt;&lt;br&gt;3 kullandığınızdan emin olun. Varsa, geliştiricilere bir hata raporu gönderin.</string>
<string name="text_shelf_holder_secondary">«Keşfet» kısmında neler okuyacağınızı bulun</string> <string name="text_shelf_holder_secondary">«Keşfet» kısmında neler okuyacağınızı bulun</string>
<string name="categories_delete_confirm">Seçilen favori kategorileri silmek istediğinizden emin misiniz\? <string name="categories_delete_confirm">Seçilen favori kategorileri silmek istediğinizden emin misiniz\?
\nİçindeki tüm mangalar kaybolur ve bu işlem geri alınamaz.</string> \nİçindeki tüm mangalar kaybolur ve bu işlem geri alınamaz.</string>
@@ -379,7 +379,7 @@
<string name="clear_network_cache">İnternet geçmişini temizle</string> <string name="clear_network_cache">İnternet geçmişini temizle</string>
<string name="sync_settings">Eşitleme seçenekleri</string> <string name="sync_settings">Eşitleme seçenekleri</string>
<string name="server_address">Sunucu adresi</string> <string name="server_address">Sunucu adresi</string>
<string name="sync_host_description">"Şirket içinde barındırılan bir eşitleme sunucusu veya varsayılan bir sunucu kullanabilirsiniz. Ne yaptığınızdan emin değilseniz bunu değiştirmeyin."</string> <string name="sync_host_description">Şirket içinde barındırılan bir eşitleme sunucusu veya varsayılan bir sunucu kullanabilirsiniz. Ne yaptığınızdan emin değilseniz bunu değiştirmeyin.</string>
<string name="mirror_switching_summary">Yansıtmalar varsa, hatalarda uzak kaynaklar için etki alanlarını otomatik olarak değiştir</string> <string name="mirror_switching_summary">Yansıtmalar varsa, hatalarda uzak kaynaklar için etki alanlarını otomatik olarak değiştir</string>
<string name="downloads_wifi_only_summary">Mobil ağa geçerken indirmeyi durdur</string> <string name="downloads_wifi_only_summary">Mobil ağa geçerken indirmeyi durdur</string>
<string name="remove_completed">Bitirilenleri kaldır</string> <string name="remove_completed">Bitirilenleri kaldır</string>
@@ -392,7 +392,7 @@
<string name="speed">Hız</string> <string name="speed">Hız</string>
<string name="restore_backup_description">Kullanıcı verilerinin önceden oluşturulmuş bir yedeğini içe aktarın</string> <string name="restore_backup_description">Kullanıcı verilerinin önceden oluşturulmuş bir yedeğini içe aktarın</string>
<string name="show_on_shelf">Rafta Göster</string> <string name="show_on_shelf">Rafta Göster</string>
<string name="sync_auth_hint">Mevcut bir hesapta oturum açabilir veya yeni bir hesap oluşturabilirsiniz.</string> <string name="sync_auth_hint">Mevcut bir hesapta oturum açabilir veya yeni bir hesap oluşturabilirsiniz</string>
<string name="ignore_ssl_errors">SSL hatalarını görmezden gel</string> <string name="ignore_ssl_errors">SSL hatalarını görmezden gel</string>
<string name="pause">Durdur</string> <string name="pause">Durdur</string>
<string name="resume">Devam et</string> <string name="resume">Devam et</string>
@@ -423,4 +423,12 @@
<string name="downloaded">İndirildi</string> <string name="downloaded">İndirildi</string>
<string name="images_procy_description">Trafik kullanımını azaltmak ve mümkünse resim yüklemeyi hızlandırmak için wsrv.nl hizmetini kullanın</string> <string name="images_procy_description">Trafik kullanımını azaltmak ve mümkünse resim yüklemeyi hızlandırmak için wsrv.nl hizmetini kullanın</string>
<string name="username">Kullanıcı adı</string> <string name="username">Kullanıcı adı</string>
<string name="network"></string>
<string name="data_and_privacy">Veri ve gizlilik</string>
<string name="restore_summary">Önceden oluşturulmuş yedeği geri yükle</string>
<string name="webtoon_zoom_summary">Webtoon modunda yakınlaştırma hareketine izin ver</string>
<string name="reader_info_bar_summary">Geçerli saati ve okuma ilerlemesini ekranın üst kısmında gösterin</string>
<string name="show_pages_numbers_summary">Sayfa numaralarını alt köşede göster</string>
<string name="pages_animation_summary">Sayfa Çevirme Animasyonu</string>
<string name="details_button_tip">Daha fazla seçenek görmek için Oku düğmesini basılı tutun</string>
</resources> </resources>

View File

@@ -22,7 +22,7 @@
<string name="detailed_list">Детальний список</string> <string name="detailed_list">Детальний список</string>
<string name="list_mode">Режим списку</string> <string name="list_mode">Режим списку</string>
<string name="settings">Налаштування</string> <string name="settings">Налаштування</string>
<string name="remote_sources">Джерела манги</string> <string name="remote_sources">Джерела манґи</string>
<string name="loading_">Завантаження…</string> <string name="loading_">Завантаження…</string>
<string name="computing_">Обчислення…</string> <string name="computing_">Обчислення…</string>
<string name="chapter_d_of_d">Розділ %1$d із %2$d</string> <string name="chapter_d_of_d">Розділ %1$d із %2$d</string>