Manga repository authorization support
This commit is contained in:
@@ -23,7 +23,9 @@
|
||||
android:theme="@style/AppTheme"
|
||||
android:usesCleartextTraffic="true"
|
||||
tools:ignore="UnusedAttribute">
|
||||
<activity android:name="org.koitharu.kotatsu.main.ui.MainActivity">
|
||||
<activity
|
||||
android:name="org.koitharu.kotatsu.main.ui.MainActivity"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
@@ -32,12 +34,16 @@
|
||||
android:name="android.app.default_searchable"
|
||||
android:value=".ui.search.SearchActivity" />
|
||||
</activity>
|
||||
<activity android:name="org.koitharu.kotatsu.details.ui.DetailsActivity">
|
||||
<activity
|
||||
android:name="org.koitharu.kotatsu.details.ui.DetailsActivity"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="${applicationId}.action.VIEW_MANGA" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name="org.koitharu.kotatsu.reader.ui.ReaderActivity">
|
||||
<activity
|
||||
android:name="org.koitharu.kotatsu.reader.ui.ReaderActivity"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="${applicationId}.action.READ_MANGA" />
|
||||
</intent-filter>
|
||||
@@ -50,13 +56,19 @@
|
||||
android:label="@string/settings" />
|
||||
<activity
|
||||
android:name="org.koitharu.kotatsu.reader.ui.SimpleSettingsActivity"
|
||||
android:exported="true"
|
||||
android:label="@string/settings">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MANAGE_NETWORK_USAGE" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name="org.koitharu.kotatsu.browser.BrowserActivity" />
|
||||
<activity
|
||||
android:name="org.koitharu.kotatsu.browser.BrowserActivity"
|
||||
android:windowSoftInputMode="adjustResize" />
|
||||
<activity
|
||||
android:name="org.koitharu.kotatsu.settings.sources.auth.SourceAuthActivity"
|
||||
android:windowSoftInputMode="adjustResize" />
|
||||
<activity
|
||||
android:name="org.koitharu.kotatsu.core.ui.CrashActivity"
|
||||
android:label="@string/error_occurred"
|
||||
|
||||
@@ -67,6 +67,23 @@ open class MangaLoaderContext(
|
||||
})
|
||||
}
|
||||
|
||||
fun getCookies(domain: String): List<Cookie> {
|
||||
val url = HttpUrl.Builder()
|
||||
.scheme(SCHEME_HTTP)
|
||||
.host(domain)
|
||||
.build()
|
||||
return cookieJar.loadForRequest(url)
|
||||
}
|
||||
|
||||
fun copyCookies(oldDomain: String, newDomain: String) {
|
||||
val url = HttpUrl.Builder()
|
||||
.scheme(SCHEME_HTTP)
|
||||
.host(oldDomain)
|
||||
val cookies = cookieJar.loadForRequest(url.build())
|
||||
url.host(newDomain)
|
||||
cookieJar.saveFromResponse(url.build(), cookies)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
||||
private const val SCHEME_HTTP = "http"
|
||||
|
||||
@@ -38,6 +38,7 @@ abstract class BaseFragment<B : ViewBinding> : Fragment(), OnApplyWindowInsetsLi
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
lastInsets = Insets.NONE
|
||||
ViewCompat.setOnApplyWindowInsetsListener(view, this)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package org.koitharu.kotatsu.browser
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.webkit.WebResourceResponse
|
||||
import android.webkit.WebView
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
import org.koitharu.kotatsu.core.network.WebViewClientCompat
|
||||
@@ -27,19 +25,4 @@ class BrowserClient(private val callback: BrowserCallback) : WebViewClientCompat
|
||||
super.onPageCommitVisible(view, url)
|
||||
callback.onTitleChanged(view.title.orEmpty(), url)
|
||||
}
|
||||
|
||||
override fun shouldInterceptRequestCompat(view: WebView, url: String): WebResourceResponse? {
|
||||
return runCatching {
|
||||
val request = Request.Builder()
|
||||
.url(url)
|
||||
.build()
|
||||
val response = okHttp.newCall(request).execute()
|
||||
val ct = response.body?.contentType()
|
||||
WebResourceResponse(
|
||||
"${ct?.type}/${ct?.subtype}",
|
||||
ct?.charset()?.name() ?: "utf-8",
|
||||
response.body?.byteStream()
|
||||
)
|
||||
}.getOrNull()
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,6 @@ import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
data class MangaFilter(
|
||||
val sortOrder: SortOrder,
|
||||
val tag: MangaTag?
|
||||
val sortOrder: SortOrder?,
|
||||
val tag: MangaTag?,
|
||||
) : Parcelable
|
||||
@@ -0,0 +1,8 @@
|
||||
package org.koitharu.kotatsu.core.parser
|
||||
|
||||
interface MangaRepositoryAuthProvider {
|
||||
|
||||
val authUrl: String
|
||||
|
||||
fun isAuthorized(): Boolean
|
||||
}
|
||||
@@ -27,5 +27,6 @@ interface SourceSettings {
|
||||
|
||||
const val KEY_DOMAIN = "domain"
|
||||
const val KEY_USE_SSL = "ssl"
|
||||
const val KEY_AUTH = "auth"
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,6 @@ import org.koitharu.kotatsu.core.model.MangaFilter
|
||||
import org.koitharu.kotatsu.core.model.MangaTag
|
||||
import org.koitharu.kotatsu.core.model.SortOrder
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
class FilterAdapter(
|
||||
sortOrders: List<SortOrder> = emptyList(),
|
||||
@@ -19,7 +18,7 @@ class FilterAdapter(
|
||||
private val sortOrders = ArrayList<SortOrder>(sortOrders)
|
||||
private val tags = ArrayList(Collections.singletonList(null) + tags)
|
||||
|
||||
private var currentState = state ?: MangaFilter(sortOrders.first(), null)
|
||||
private var currentState = state ?: MangaFilter(sortOrders.firstOrNull(), null)
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = when (viewType) {
|
||||
VIEW_TYPE_SORT -> FilterSortHolder(parent).apply {
|
||||
|
||||
@@ -61,7 +61,7 @@ class LocalListViewModel(
|
||||
launchLoadingJob(Dispatchers.Default) {
|
||||
try {
|
||||
listError.value = null
|
||||
mangaList.value = repository.getList(0)
|
||||
mangaList.value = repository.getList(0, tags = null)
|
||||
} catch (e: Throwable) {
|
||||
listError.value = e
|
||||
}
|
||||
|
||||
@@ -3,16 +3,19 @@ package org.koitharu.kotatsu.reader.ui
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import androidx.core.graphics.Insets
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.fragment.app.commit
|
||||
import org.koitharu.kotatsu.BuildConfig
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.BaseActivity
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.databinding.ActivitySettingsSimpleBinding
|
||||
import org.koitharu.kotatsu.settings.MainSettingsFragment
|
||||
import org.koitharu.kotatsu.settings.NetworkSettingsFragment
|
||||
import org.koitharu.kotatsu.settings.ReaderSettingsFragment
|
||||
import org.koitharu.kotatsu.settings.SourceSettingsFragment
|
||||
|
||||
class SimpleSettingsActivity : BaseActivity<ActivitySettingsSimpleBinding>() {
|
||||
|
||||
@@ -25,6 +28,9 @@ class SimpleSettingsActivity : BaseActivity<ActivitySettingsSimpleBinding>() {
|
||||
R.id.container, when (intent?.action) {
|
||||
Intent.ACTION_MANAGE_NETWORK_USAGE -> NetworkSettingsFragment()
|
||||
ACTION_READER -> ReaderSettingsFragment()
|
||||
ACTION_SOURCE -> SourceSettingsFragment.newInstance(
|
||||
intent.getParcelableExtra(EXTRA_SOURCE) ?: MangaSource.LOCAL
|
||||
)
|
||||
else -> MainSettingsFragment()
|
||||
}
|
||||
)
|
||||
@@ -43,9 +49,17 @@ class SimpleSettingsActivity : BaseActivity<ActivitySettingsSimpleBinding>() {
|
||||
|
||||
private const val ACTION_READER =
|
||||
"${BuildConfig.APPLICATION_ID}.action.MANAGE_READER_SETTINGS"
|
||||
private const val ACTION_SOURCE =
|
||||
"${BuildConfig.APPLICATION_ID}.action.MANAGE_SOURCE_SETTINGS"
|
||||
private const val EXTRA_SOURCE = "source"
|
||||
|
||||
fun newReaderSettingsIntent(context: Context) =
|
||||
Intent(context, SimpleSettingsActivity::class.java)
|
||||
.setAction(ACTION_READER)
|
||||
|
||||
fun newSourceSettingsIntent(context: Context, source: MangaSource) =
|
||||
Intent(context, SimpleSettingsActivity::class.java)
|
||||
.setAction(ACTION_SOURCE)
|
||||
.putExtra(EXTRA_SOURCE, source as Parcelable)
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,15 @@
|
||||
package org.koitharu.kotatsu.remotelist.ui
|
||||
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||
import org.koin.core.parameter.parametersOf
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.MangaFilter
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.list.ui.MangaListFragment
|
||||
import org.koitharu.kotatsu.reader.ui.SimpleSettingsActivity
|
||||
import org.koitharu.kotatsu.utils.ext.parcelableArgument
|
||||
import org.koitharu.kotatsu.utils.ext.withArgs
|
||||
|
||||
@@ -29,6 +34,26 @@ class RemoteListFragment : MangaListFragment() {
|
||||
super.onFilterChanged(filter)
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater)
|
||||
inflater.inflate(R.menu.opt_list_remote, menu)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.action_source_settings -> {
|
||||
startActivity(
|
||||
SimpleSettingsActivity.newSourceSettingsIntent(
|
||||
context ?: return false,
|
||||
source,
|
||||
)
|
||||
)
|
||||
true
|
||||
}
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val ARG_SOURCE = "provider"
|
||||
|
||||
@@ -90,6 +90,9 @@ class RemoteListViewModel(
|
||||
}
|
||||
hasNextPage.value = list.isNotEmpty()
|
||||
} catch (e: Throwable) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
listError.value = e
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.list.ui.MangaListViewModel
|
||||
import org.koitharu.kotatsu.list.ui.model.*
|
||||
import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct
|
||||
import java.util.*
|
||||
|
||||
class SearchViewModel(
|
||||
private val repository: MangaRepository,
|
||||
@@ -74,6 +73,7 @@ class SearchViewModel(
|
||||
listError.value = null
|
||||
val list = repository.getList(
|
||||
offset = if (append) mangaList.value?.size ?: 0 else 0,
|
||||
tags = null,
|
||||
query = query
|
||||
)
|
||||
if (!append) {
|
||||
|
||||
@@ -76,15 +76,7 @@ class HistorySettingsFragment : BasePreferenceFragment(R.string.history_and_cach
|
||||
true
|
||||
}
|
||||
AppSettings.KEY_COOKIES_CLEAR -> {
|
||||
viewLifecycleScope.launch {
|
||||
val cookieJar = get<AndroidCookieJar>()
|
||||
cookieJar.clear()
|
||||
Snackbar.make(
|
||||
listView ?: return@launch,
|
||||
R.string.cookies_cleared,
|
||||
Snackbar.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
clearCookies()
|
||||
true
|
||||
}
|
||||
AppSettings.KEY_SEARCH_HISTORY_CLEAR -> {
|
||||
@@ -144,4 +136,22 @@ class HistorySettingsFragment : BasePreferenceFragment(R.string.history_and_cach
|
||||
}
|
||||
}.show()
|
||||
}
|
||||
|
||||
private fun clearCookies() {
|
||||
AlertDialog.Builder(context ?: return)
|
||||
.setTitle(R.string.clear_cookies)
|
||||
.setMessage(R.string.text_clear_cookies_prompt)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setPositiveButton(R.string.clear) { _, _ ->
|
||||
viewLifecycleScope.launch {
|
||||
val cookieJar = get<AndroidCookieJar>()
|
||||
cookieJar.clear()
|
||||
Snackbar.make(
|
||||
listView ?: return@launch,
|
||||
R.string.cookies_cleared,
|
||||
Snackbar.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
@@ -9,8 +9,10 @@ import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.TwoStatePreference
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.core.parser.MangaRepositoryAuthProvider
|
||||
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository
|
||||
import org.koitharu.kotatsu.core.prefs.SourceSettings
|
||||
import org.koitharu.kotatsu.settings.sources.auth.SourceAuthActivity
|
||||
import org.koitharu.kotatsu.settings.utils.EditTextBindListener
|
||||
import org.koitharu.kotatsu.settings.utils.EditTextDefaultSummaryProvider
|
||||
import org.koitharu.kotatsu.utils.ext.mangaRepositoryOf
|
||||
@@ -20,6 +22,7 @@ import org.koitharu.kotatsu.utils.ext.withArgs
|
||||
class SourceSettingsFragment : PreferenceFragmentCompat() {
|
||||
|
||||
private val source by parcelableArgument<MangaSource>(EXTRA_SOURCE)
|
||||
private var repository: RemoteMangaRepository? = null
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
@@ -29,6 +32,7 @@ class SourceSettingsFragment : PreferenceFragmentCompat() {
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
preferenceManager.sharedPreferencesName = source.name
|
||||
val repo = mangaRepositoryOf(source) as? RemoteMangaRepository ?: return
|
||||
repository = repo
|
||||
addPreferencesFromResource(R.xml.pref_source)
|
||||
val screen = preferenceScreen
|
||||
val prefsMap = ArrayMap<String, Any>(screen.preferenceCount)
|
||||
@@ -41,13 +45,32 @@ class SourceSettingsFragment : PreferenceFragmentCompat() {
|
||||
initPreferenceWithDefaultValue(pref, defValue)
|
||||
}
|
||||
}
|
||||
findPreference<Preference>(SourceSettings.KEY_AUTH)?.run {
|
||||
isVisible = repo is MangaRepositoryAuthProvider
|
||||
isEnabled = (repo as? MangaRepositoryAuthProvider)?.isAuthorized() == false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPreferenceTreeClick(preference: Preference?): Boolean {
|
||||
return when (preference?.key) {
|
||||
SourceSettings.KEY_AUTH -> {
|
||||
startActivity(
|
||||
SourceAuthActivity.newIntent(
|
||||
context ?: return false,
|
||||
source,
|
||||
)
|
||||
)
|
||||
true
|
||||
}
|
||||
else -> super.onPreferenceTreeClick(preference)
|
||||
}
|
||||
}
|
||||
|
||||
private fun initPreferenceWithDefaultValue(preference: Preference, defaultValue: Any) {
|
||||
when(preference) {
|
||||
when (preference) {
|
||||
is EditTextPreference -> {
|
||||
preference.summaryProvider = EditTextDefaultSummaryProvider(defaultValue.toString())
|
||||
when(preference.key) {
|
||||
when (preference.key) {
|
||||
SourceSettings.KEY_DOMAIN -> preference.setOnBindEditTextListener(
|
||||
EditTextBindListener(
|
||||
EditorInfo.TYPE_CLASS_TEXT or EditorInfo.TYPE_TEXT_VARIATION_URI,
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
package org.koitharu.kotatsu.settings.sources.auth
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.view.MenuItem
|
||||
import android.widget.Toast
|
||||
import androidx.core.graphics.Insets
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.updatePadding
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.BaseActivity
|
||||
import org.koitharu.kotatsu.browser.BrowserCallback
|
||||
import org.koitharu.kotatsu.browser.BrowserClient
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.core.parser.MangaRepositoryAuthProvider
|
||||
import org.koitharu.kotatsu.databinding.ActivityBrowserBinding
|
||||
import org.koitharu.kotatsu.utils.ext.mangaRepositoryOf
|
||||
|
||||
class SourceAuthActivity : BaseActivity<ActivityBrowserBinding>(), BrowserCallback {
|
||||
|
||||
private lateinit var repository: MangaRepositoryAuthProvider
|
||||
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(ActivityBrowserBinding.inflate(layoutInflater))
|
||||
val source = intent?.getParcelableExtra<MangaSource>(EXTRA_SOURCE)
|
||||
if (source == null) {
|
||||
finish()
|
||||
return
|
||||
}
|
||||
repository = mangaRepositoryOf(source) as? MangaRepositoryAuthProvider ?: run {
|
||||
Toast.makeText(
|
||||
this,
|
||||
getString(R.string.auth_not_supported_by, source.title),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
finishAfterTransition()
|
||||
return
|
||||
}
|
||||
supportActionBar?.run {
|
||||
setDisplayHomeAsUpEnabled(true)
|
||||
setHomeAsUpIndicator(R.drawable.ic_cross)
|
||||
}
|
||||
with(binding.webView.settings) {
|
||||
javaScriptEnabled = true
|
||||
}
|
||||
binding.webView.webViewClient = BrowserClient(this)
|
||||
val url = repository.authUrl
|
||||
onTitleChanged(
|
||||
source.title,
|
||||
getString(R.string.loading_)
|
||||
)
|
||||
binding.webView.loadUrl(url)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean = when (item.itemId) {
|
||||
android.R.id.home -> {
|
||||
binding.webView.stopLoading()
|
||||
finishAfterTransition()
|
||||
true
|
||||
}
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
if (binding.webView.canGoBack()) {
|
||||
binding.webView.goBack()
|
||||
} else {
|
||||
super.onBackPressed()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
binding.webView.onPause()
|
||||
super.onPause()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
binding.webView.onResume()
|
||||
}
|
||||
|
||||
override fun onLoadingStateChanged(isLoading: Boolean) {
|
||||
binding.progressBar.isVisible = isLoading
|
||||
if (!isLoading && repository.isAuthorized()) {
|
||||
Toast.makeText(this, R.string.auth_complete, Toast.LENGTH_SHORT).show()
|
||||
finishAfterTransition()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTitleChanged(title: CharSequence, subtitle: CharSequence?) {
|
||||
this.title = title
|
||||
supportActionBar?.subtitle = subtitle
|
||||
}
|
||||
|
||||
override fun onWindowInsetsChanged(insets: Insets) {
|
||||
binding.appbar.updatePadding(top = insets.top)
|
||||
binding.webView.updatePadding(bottom = insets.bottom)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val EXTRA_SOURCE = "source"
|
||||
|
||||
fun newIntent(context: Context, source: MangaSource): Intent {
|
||||
return Intent(context, SourceAuthActivity::class.java)
|
||||
.putExtra(EXTRA_SOURCE, source as Parcelable)
|
||||
}
|
||||
}
|
||||
}
|
||||
11
app/src/main/res/menu/opt_list_remote.xml
Normal file
11
app/src/main/res/menu/opt_list_remote.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/action_source_settings"
|
||||
android:orderInCategory="50"
|
||||
android:title="@string/settings"
|
||||
app:showAsAction="never" />
|
||||
</menu>
|
||||
@@ -213,24 +213,27 @@
|
||||
<string name="other">Другие</string>
|
||||
<string name="description">Описание</string>
|
||||
<string name="languages">Языки</string>
|
||||
<string name="welcome">Добро пожаловать</string>
|
||||
<string name="text_clear_search_history_prompt">Вы действительно хотите удалить все недавние поисковые запросы? Это действие не может быть отменено.</string>
|
||||
<string name="backup_saved">Резервная копия успешно сохранена</string>
|
||||
<string name="tracker_warning">Некоторые производители могут изменять поведение системы, нарушая работу фоновых задач.</string>
|
||||
<string name="read_more">Подробнее</string>
|
||||
<string name="queued">В очереди</string>
|
||||
<string name="text_downloads_holder">На данный момент нет активных загрузок</string>
|
||||
<string name="chapter_is_missing">Глава отсутствует</string>
|
||||
<string name="chapter_is_missing_text">Эта глава отсутствует на вашем устройстве. Скачайте или прочитайте её онлайн.</string>
|
||||
<string name="about_app_translation_summary">Помочь с переводом приложения</string>
|
||||
<string name="about_app_translation">Перевод</string>
|
||||
<string name="about_author">Автор</string>
|
||||
<string name="about_feedback_4pda">Тема на 4PDA</string>
|
||||
<string name="about_feedback">Обратная связь</string>
|
||||
<string name="about_support_developer">Поддержать разработчика</string>
|
||||
<string name="about_support_developer_summary">Если вам нравится это приложение, вы можете помочь финансово с помощью ЮMoney (бывш. Яндекс.Деньги)</string>
|
||||
<string name="about_gratitudes">Благодарности</string>
|
||||
<string name="about_gratitudes_summary">Эти люди помогают Kotatsu стать лучше!</string>
|
||||
<string name="about_copyright_and_licenses">Авторские права и лицензии</string>
|
||||
<string name="about_license">Лицензия</string>
|
||||
<string name="welcome">Добро пожаловать</string>
|
||||
<string name="text_clear_search_history_prompt">Вы действительно хотите удалить все недавние поисковые запросы? Это действие не может быть отменено.</string>
|
||||
<string name="backup_saved">Резервная копия успешно сохранена</string>
|
||||
<string name="tracker_warning">Некоторые производители могут изменять поведение системы, нарушая работу фоновых задач.</string>
|
||||
<string name="read_more">Подробнее</string>
|
||||
<string name="queued">В очереди</string>
|
||||
<string name="text_downloads_holder">На данный момент нет активных загрузок</string>
|
||||
<string name="chapter_is_missing">Глава отсутствует</string>
|
||||
<string name="chapter_is_missing_text">Эта глава отсутствует на вашем устройстве. Скачайте или прочитайте её онлайн.</string>
|
||||
<string name="about_app_translation_summary">Помочь с переводом приложения</string>
|
||||
<string name="about_app_translation">Перевод</string>
|
||||
<string name="about_author">Автор</string>
|
||||
<string name="about_feedback_4pda">Тема на 4PDA</string>
|
||||
<string name="about_feedback">Обратная связь</string>
|
||||
<string name="about_support_developer">Поддержать разработчика</string>
|
||||
<string name="about_support_developer_summary">Если вам нравится это приложение, вы можете помочь финансово с помощью ЮMoney (бывш. Яндекс.Деньги)</string>
|
||||
<string name="about_gratitudes">Благодарности</string>
|
||||
<string name="about_gratitudes_summary">Эти люди помогают Kotatsu стать лучше!</string>
|
||||
<string name="about_copyright_and_licenses">Авторские права и лицензии</string>
|
||||
<string name="about_license">Лицензия</string>
|
||||
<string name="auth_complete">Авторизация выполнена</string>
|
||||
<string name="auth_not_supported_by">Авторизация в %s не поддерживается</string>
|
||||
<string name="text_clear_cookies_prompt">Вы выйдете из всех источников, в которых Вы авторизованы</string>
|
||||
</resources>
|
||||
@@ -216,24 +216,27 @@
|
||||
<string name="text_clear_search_history_prompt">Do you really want to remove all recent search queries? This action cannot be undone.</string>
|
||||
<string name="other">Other</string>
|
||||
<string name="languages">Languages</string>
|
||||
<string name="welcome">Welcome</string>
|
||||
<string name="description">Description</string>
|
||||
<string name="backup_saved">Backup saved successfully</string>
|
||||
<string name="tracker_warning">Some manufacturers can change the system behavior, which may breaks background tasks.</string>
|
||||
<string name="read_more">Read more</string>
|
||||
<string name="queued">Queued</string>
|
||||
<string name="text_downloads_holder">There are currently no active downloads</string>
|
||||
<string name="chapter_is_missing_text">This chapter is missing on your device. Download or read it online.</string>
|
||||
<string name="chapter_is_missing">Chapter is missing</string>
|
||||
<string name="about_app_translation_summary">Translate this app</string>
|
||||
<string name="about_app_translation">Translation</string>
|
||||
<string name="about_author">Author</string>
|
||||
<string name="about_feedback">Feedback</string>
|
||||
<string name="about_feedback_4pda">Topic on 4PDA</string>
|
||||
<string name="about_support_developer">Support the developer</string>
|
||||
<string name="about_support_developer_summary">If you like this app, you can help financially through Yoomoney (ex. Yandex.Money)</string>
|
||||
<string name="about_gratitudes">Gratitudes</string>
|
||||
<string name="about_gratitudes_summary">These people make Kotatsu become better!</string>
|
||||
<string name="about_copyright_and_licenses">Copyright & Licenses</string>
|
||||
<string name="about_license">License</string>
|
||||
<string name="welcome">Welcome</string>
|
||||
<string name="description">Description</string>
|
||||
<string name="backup_saved">Backup saved successfully</string>
|
||||
<string name="tracker_warning">Some manufacturers can change the system behavior, which may breaks background tasks.</string>
|
||||
<string name="read_more">Read more</string>
|
||||
<string name="queued">Queued</string>
|
||||
<string name="text_downloads_holder">There are currently no active downloads</string>
|
||||
<string name="chapter_is_missing_text">This chapter is missing on your device. Download or read it online.</string>
|
||||
<string name="chapter_is_missing">Chapter is missing</string>
|
||||
<string name="about_app_translation_summary">Translate this app</string>
|
||||
<string name="about_app_translation">Translation</string>
|
||||
<string name="about_author">Author</string>
|
||||
<string name="about_feedback">Feedback</string>
|
||||
<string name="about_feedback_4pda">Topic on 4PDA</string>
|
||||
<string name="about_support_developer">Support the developer</string>
|
||||
<string name="about_support_developer_summary">If you like this app, you can help financially through Yoomoney (ex. Yandex.Money)</string>
|
||||
<string name="about_gratitudes">Gratitudes</string>
|
||||
<string name="about_gratitudes_summary">These people make Kotatsu become better!</string>
|
||||
<string name="about_copyright_and_licenses">Copyright & Licenses</string>
|
||||
<string name="about_license">License</string>
|
||||
<string name="auth_complete">Authorization complete</string>
|
||||
<string name="auth_not_supported_by">Authorization on %s is not supported</string>
|
||||
<string name="text_clear_cookies_prompt">You will be logged out from all sources that you are authorized in</string>
|
||||
</resources>
|
||||
@@ -14,4 +14,11 @@
|
||||
android:title="@string/use_ssl"
|
||||
app:iconSpaceReserved="false" />
|
||||
|
||||
<Preference
|
||||
android:key="auth"
|
||||
android:persistent="false"
|
||||
android:title="@string/sign_in"
|
||||
app:allowDividerAbove="true"
|
||||
app:iconSpaceReserved="false" />
|
||||
|
||||
</PreferenceScreen>
|
||||
Reference in New Issue
Block a user