Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d93ff92cc9 | ||
|
|
8eda113f3b | ||
|
|
3916c2619e | ||
|
|
1d3e8e55ca | ||
|
|
2c3b4f29eb | ||
|
|
ee530002b6 | ||
|
|
59d530e0dc | ||
|
|
52a132caed | ||
|
|
379d2dd8d4 | ||
|
|
f8cefa3e8d | ||
|
|
5e1eda850c | ||
|
|
18cc0ad0fb | ||
|
|
11dd49c626 | ||
|
|
2ad8ab0258 | ||
|
|
4f8c5325a4 | ||
|
|
6e181a59a3 | ||
|
|
7a7d20dbf4 | ||
|
|
83d5f8e378 | ||
|
|
5ac9bad728 |
@@ -21,8 +21,8 @@ android {
|
||||
applicationId 'org.koitharu.kotatsu'
|
||||
minSdk = 21
|
||||
targetSdk = 36
|
||||
versionCode = 1024
|
||||
versionName = '9.1'
|
||||
versionCode = 1026
|
||||
versionName = '9.1.2'
|
||||
generatedDensities = []
|
||||
testInstrumentationRunner 'org.koitharu.kotatsu.HiltTestRunner'
|
||||
ksp {
|
||||
|
||||
@@ -17,6 +17,7 @@ import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.alternatives.domain.AutoFixUseCase
|
||||
import org.koitharu.kotatsu.alternatives.domain.AutoFixUseCase.NoAlternativesException
|
||||
import org.koitharu.kotatsu.core.ErrorReporterReceiver
|
||||
import org.koitharu.kotatsu.core.model.getTitle
|
||||
import org.koitharu.kotatsu.core.model.isNsfw
|
||||
@@ -47,7 +48,7 @@ class AutoFixService : CoroutineIntentService() {
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
notificationManager = NotificationManagerCompat.from(applicationContext)
|
||||
notificationManager = NotificationManagerCompat.from(this)
|
||||
}
|
||||
|
||||
override suspend fun IntentJobContext.processIntent(intent: Intent) {
|
||||
@@ -58,7 +59,7 @@ class AutoFixService : CoroutineIntentService() {
|
||||
val result = runCatchingCancellable {
|
||||
autoFixUseCase.invoke(mangaId)
|
||||
}
|
||||
if (applicationContext.checkNotificationPermission(CHANNEL_ID)) {
|
||||
if (checkNotificationPermission(CHANNEL_ID)) {
|
||||
val notification = buildNotification(startId, result)
|
||||
notificationManager.notify(TAG, startId, notification)
|
||||
}
|
||||
@@ -67,7 +68,7 @@ class AutoFixService : CoroutineIntentService() {
|
||||
}
|
||||
|
||||
override fun IntentJobContext.onError(error: Throwable) {
|
||||
if (applicationContext.checkNotificationPermission(CHANNEL_ID)) {
|
||||
if (checkNotificationPermission(CHANNEL_ID)) {
|
||||
val notification = runBlocking { buildNotification(startId, Result.failure(error)) }
|
||||
notificationManager.notify(TAG, startId, notification)
|
||||
}
|
||||
@@ -75,7 +76,7 @@ class AutoFixService : CoroutineIntentService() {
|
||||
|
||||
@SuppressLint("InlinedApi")
|
||||
private fun startForeground(jobContext: IntentJobContext) {
|
||||
val title = applicationContext.getString(R.string.fixing_manga)
|
||||
val title = getString(R.string.fixing_manga)
|
||||
val channel = NotificationChannelCompat.Builder(CHANNEL_ID, NotificationManagerCompat.IMPORTANCE_MIN)
|
||||
.setName(title)
|
||||
.setShowBadge(false)
|
||||
@@ -85,7 +86,7 @@ class AutoFixService : CoroutineIntentService() {
|
||||
.build()
|
||||
notificationManager.createNotificationChannel(channel)
|
||||
|
||||
val notification = NotificationCompat.Builder(applicationContext, CHANNEL_ID)
|
||||
val notification = NotificationCompat.Builder(this, CHANNEL_ID)
|
||||
.setContentTitle(title)
|
||||
.setPriority(NotificationCompat.PRIORITY_MIN)
|
||||
.setDefaults(0)
|
||||
@@ -97,7 +98,7 @@ class AutoFixService : CoroutineIntentService() {
|
||||
.setCategory(NotificationCompat.CATEGORY_PROGRESS)
|
||||
.addAction(
|
||||
appcompatR.drawable.abc_ic_clear_material,
|
||||
applicationContext.getString(android.R.string.cancel),
|
||||
getString(android.R.string.cancel),
|
||||
jobContext.getCancelIntent(),
|
||||
)
|
||||
.build()
|
||||
@@ -110,7 +111,7 @@ class AutoFixService : CoroutineIntentService() {
|
||||
}
|
||||
|
||||
private suspend fun buildNotification(startId: Int, result: Result<Pair<Manga, Manga?>>): Notification {
|
||||
val notification = NotificationCompat.Builder(applicationContext, CHANNEL_ID)
|
||||
val notification = NotificationCompat.Builder(this, CHANNEL_ID)
|
||||
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
|
||||
.setDefaults(0)
|
||||
.setSilent(true)
|
||||
@@ -119,17 +120,17 @@ class AutoFixService : CoroutineIntentService() {
|
||||
if (replacement != null) {
|
||||
notification.setLargeIcon(
|
||||
coil.execute(
|
||||
ImageRequest.Builder(applicationContext)
|
||||
ImageRequest.Builder(this)
|
||||
.data(replacement.coverUrl)
|
||||
.mangaSourceExtra(replacement.source)
|
||||
.build(),
|
||||
).toBitmapOrNull(),
|
||||
)
|
||||
notification.setSubText(replacement.title)
|
||||
val intent = AppRouter.detailsIntent(applicationContext, replacement)
|
||||
val intent = AppRouter.detailsIntent(this, replacement)
|
||||
notification.setContentIntent(
|
||||
PendingIntentCompat.getActivity(
|
||||
applicationContext,
|
||||
this,
|
||||
replacement.id.toInt(),
|
||||
intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT,
|
||||
@@ -143,35 +144,35 @@ class AutoFixService : CoroutineIntentService() {
|
||||
},
|
||||
)
|
||||
notification
|
||||
.setContentTitle(applicationContext.getString(R.string.fixed))
|
||||
.setContentTitle(getString(R.string.fixed))
|
||||
.setContentText(
|
||||
applicationContext.getString(
|
||||
getString(
|
||||
R.string.manga_replaced,
|
||||
seed.title,
|
||||
seed.source.getTitle(applicationContext),
|
||||
seed.source.getTitle(this),
|
||||
replacement.title,
|
||||
replacement.source.getTitle(applicationContext),
|
||||
replacement.source.getTitle(this),
|
||||
),
|
||||
)
|
||||
.setSmallIcon(R.drawable.ic_stat_done)
|
||||
} else {
|
||||
notification
|
||||
.setContentTitle(applicationContext.getString(R.string.fixing_manga))
|
||||
.setContentText(applicationContext.getString(R.string.no_fix_required, seed.title))
|
||||
.setContentTitle(getString(R.string.fixing_manga))
|
||||
.setContentText(getString(R.string.no_fix_required, seed.title))
|
||||
.setSmallIcon(android.R.drawable.stat_sys_warning)
|
||||
}
|
||||
}.onFailure { error ->
|
||||
notification
|
||||
.setContentTitle(applicationContext.getString(R.string.error_occurred))
|
||||
.setContentTitle(getString(R.string.error_occurred))
|
||||
.setContentText(
|
||||
if (error is AutoFixUseCase.NoAlternativesException) {
|
||||
applicationContext.getString(R.string.no_alternatives_found, error.seed.manga.title)
|
||||
if (error is NoAlternativesException) {
|
||||
getString(R.string.no_alternatives_found, error.seed.manga.title)
|
||||
} else {
|
||||
error.getDisplayMessage(applicationContext.resources)
|
||||
error.getDisplayMessage(resources)
|
||||
},
|
||||
).setSmallIcon(android.R.drawable.stat_notify_error)
|
||||
ErrorReporterReceiver.getNotificationAction(
|
||||
context = applicationContext,
|
||||
context = this,
|
||||
e = error,
|
||||
notificationId = startId,
|
||||
notificationTag = TAG,
|
||||
|
||||
@@ -4,7 +4,6 @@ import android.app.PendingIntent
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.BadParcelableException
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.core.app.PendingIntentCompat
|
||||
@@ -65,7 +64,7 @@ class ErrorReporterReceiver : BroadcastReceiver() {
|
||||
e: Throwable,
|
||||
notificationId: Int,
|
||||
notificationTag: String?,
|
||||
): PendingIntent? = try {
|
||||
): PendingIntent? = runCatching {
|
||||
val intent = Intent(context, ErrorReporterReceiver::class.java)
|
||||
intent.setAction(ACTION_REPORT)
|
||||
intent.setData("err://${e.hashCode()}".toUri())
|
||||
@@ -73,9 +72,9 @@ class ErrorReporterReceiver : BroadcastReceiver() {
|
||||
intent.putExtra(EXTRA_NOTIFICATION_ID, notificationId)
|
||||
intent.putExtra(EXTRA_NOTIFICATION_TAG, notificationTag)
|
||||
PendingIntentCompat.getBroadcast(context, 0, intent, 0, false)
|
||||
} catch (e: BadParcelableException) {
|
||||
}.onFailure { e ->
|
||||
// probably cannot write exception as serializable
|
||||
e.printStackTraceDebug()
|
||||
null
|
||||
}
|
||||
}.getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ import org.koitharu.kotatsu.core.util.ext.processLifecycleScope
|
||||
import org.koitharu.kotatsu.core.util.ext.toBitmapOrNull
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.parsers.network.CloudFlareHelper
|
||||
import org.koitharu.kotatsu.parsers.util.mapToArray
|
||||
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Provider
|
||||
@@ -152,6 +153,15 @@ class CaptchaHandler @Inject constructor(
|
||||
.setOnlyAlertOnce(true)
|
||||
.setSmallIcon(R.drawable.ic_bot)
|
||||
.setGroup(GROUP_CAPTCHA)
|
||||
.setContentIntent(
|
||||
PendingIntentCompat.getActivities(
|
||||
context, GROUP_NOTIFICATION_ID,
|
||||
exceptions.mapToArray { e ->
|
||||
AppRouter.cloudFlareResolveIntent(context, e)
|
||||
},
|
||||
0, false,
|
||||
),
|
||||
)
|
||||
.setContentText(
|
||||
context.getString(
|
||||
R.string.captcha_required_summary, context.getString(R.string.app_name),
|
||||
@@ -172,7 +182,6 @@ class CaptchaHandler @Inject constructor(
|
||||
|
||||
private suspend fun buildNotification(exception: CloudFlareProtectedException): Notification {
|
||||
val intent = AppRouter.cloudFlareResolveIntent(context, exception)
|
||||
.setData(exception.url.toUri())
|
||||
val discardIntent = Intent(ACTION_DISCARD)
|
||||
.putExtra(AppRouter.KEY_SOURCE, exception.source.name)
|
||||
.setData("source://${exception.source.name}".toUri())
|
||||
|
||||
@@ -31,8 +31,8 @@ open class MultiMutex<T : Any> {
|
||||
contract {
|
||||
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
||||
}
|
||||
lock(element)
|
||||
return try {
|
||||
lock(element)
|
||||
block()
|
||||
} finally {
|
||||
unlock(element)
|
||||
|
||||
@@ -183,6 +183,8 @@ fun View.setTooltipCompat(tooltip: CharSequence?) {
|
||||
}
|
||||
}
|
||||
|
||||
fun View.setTooltipCompat(@StringRes tooltipResId: Int) = setTooltipCompat(context.getString(tooltipResId))
|
||||
|
||||
val Toolbar.menuView: ActionMenuView?
|
||||
get() {
|
||||
menu // to call ensureMenu()
|
||||
|
||||
@@ -35,7 +35,7 @@ class ExploreRepository @Inject constructor(
|
||||
val details = runCatchingCancellable {
|
||||
mangaRepositoryFactory.create(manga.source).getDetails(manga)
|
||||
}.getOrNull() ?: continue
|
||||
if ((settings.isSuggestionsExcludeNsfw && details.isNsfw) || details in tagsBlacklist) {
|
||||
if ((settings.isSuggestionsExcludeNsfw && details.isNsfw()) || details in tagsBlacklist) {
|
||||
continue
|
||||
}
|
||||
return details
|
||||
@@ -55,7 +55,7 @@ class ExploreRepository @Inject constructor(
|
||||
val details = runCatchingCancellable {
|
||||
mangaRepositoryFactory.create(manga.source).getDetails(manga)
|
||||
}.getOrNull() ?: continue
|
||||
if ((skipNsfw && details.isNsfw) || details in tagsBlacklist) {
|
||||
if ((skipNsfw && details.isNsfw()) || details in tagsBlacklist) {
|
||||
continue
|
||||
}
|
||||
return details
|
||||
@@ -80,7 +80,7 @@ class ExploreRepository @Inject constructor(
|
||||
filter = MangaListFilter(tags = setOfNotNull(tag)),
|
||||
).asArrayList()
|
||||
if (settings.isSuggestionsExcludeNsfw) {
|
||||
list.removeAll { it.isNsfw }
|
||||
list.removeAll { it.isNsfw() }
|
||||
}
|
||||
if (blacklist.isNotEmpty()) {
|
||||
list.removeAll { manga -> manga in blacklist }
|
||||
|
||||
@@ -11,6 +11,7 @@ import androidx.core.view.isVisible
|
||||
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.util.ext.getQuantityStringSafe
|
||||
import org.koitharu.kotatsu.core.util.ext.setTooltipCompat
|
||||
import org.koitharu.kotatsu.databinding.ItemCategoriesAllBinding
|
||||
import org.koitharu.kotatsu.databinding.ItemCategoryBinding
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.FavouriteCategoriesListListener
|
||||
@@ -91,6 +92,13 @@ fun allCategoriesAD(
|
||||
R.drawable.ic_eye_off
|
||||
},
|
||||
)
|
||||
binding.imageViewVisible.setTooltipCompat(
|
||||
if (item.isVisible) {
|
||||
R.string.hide
|
||||
} else {
|
||||
R.string.show
|
||||
},
|
||||
)
|
||||
binding.coversView.setCoversAsync(item.covers)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.onStart
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.plus
|
||||
import org.koitharu.kotatsu.core.model.isNsfw
|
||||
import org.koitharu.kotatsu.core.parser.MangaDataRepository
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.core.prefs.ListMode
|
||||
@@ -45,7 +46,7 @@ abstract class MangaListViewModel(
|
||||
abstract fun onRetry()
|
||||
|
||||
protected fun List<Manga>.skipNsfwIfNeeded() = if (settings.isNsfwContentDisabled) {
|
||||
filterNot { it.isNsfw }
|
||||
filterNot { it.isNsfw() }
|
||||
} else {
|
||||
this
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runInterruptible
|
||||
import org.koitharu.kotatsu.core.model.LocalMangaSource
|
||||
import org.koitharu.kotatsu.core.model.isLocal
|
||||
import org.koitharu.kotatsu.core.model.isNsfw
|
||||
import org.koitharu.kotatsu.core.parser.MangaRepository
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.core.util.AlphanumComparator
|
||||
@@ -94,7 +95,7 @@ class LocalMangaRepository @Inject constructor(
|
||||
}
|
||||
val list = getRawList()
|
||||
if (settings.isNsfwContentDisabled) {
|
||||
list.removeAll { it.manga.isNsfw }
|
||||
list.removeAll { it.manga.isNsfw() }
|
||||
}
|
||||
if (filter != null) {
|
||||
val query = filter.query
|
||||
@@ -109,7 +110,7 @@ class LocalMangaRepository @Inject constructor(
|
||||
}
|
||||
filter.contentRating.singleOrNull()?.let { contentRating ->
|
||||
val isNsfw = contentRating == ContentRating.ADULT
|
||||
list.retainAll { it.manga.isNsfw == isNsfw }
|
||||
list.retainAll { it.manga.isNsfw() == isNsfw }
|
||||
}
|
||||
if (!query.isNullOrEmpty() && order == SortOrder.RELEVANCE) {
|
||||
list.sortBy { it.manga.title.levenshteinDistance(query) }
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
package org.koitharu.kotatsu.main.ui
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.Gravity
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.FrameLayout
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.annotation.IdRes
|
||||
import androidx.core.view.isEmpty
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.iterator
|
||||
import androidx.core.view.size
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
@@ -66,6 +69,9 @@ class MainNavigationDelegate(
|
||||
navBar.setOnItemSelectedListener(this)
|
||||
navBar.setOnItemReselectedListener(this)
|
||||
navRailHeader?.run {
|
||||
root.updateLayoutParams<FrameLayout.LayoutParams> {
|
||||
gravity = Gravity.TOP or Gravity.CENTER
|
||||
}
|
||||
val horizontalPadding = (navBar as NavigationRailView).itemActiveIndicatorMarginHorizontal
|
||||
root.setPadding(horizontalPadding, 0, horizontalPadding, 0)
|
||||
buttonExpand.setOnClickListener(this@MainNavigationDelegate)
|
||||
@@ -295,6 +301,9 @@ class MainNavigationDelegate(
|
||||
if (value) {
|
||||
navBar.expand()
|
||||
navRailHeader?.run {
|
||||
root.updateLayoutParams<FrameLayout.LayoutParams> {
|
||||
gravity = Gravity.TOP or Gravity.START
|
||||
}
|
||||
railFab.extend()
|
||||
buttonExpand.setImageResource(R.drawable.ic_drawer_menu_open)
|
||||
buttonExpand.setContentDescriptionAndTooltip(R.string.collapse)
|
||||
@@ -304,6 +313,9 @@ class MainNavigationDelegate(
|
||||
} else {
|
||||
navBar.collapse()
|
||||
navRailHeader?.run {
|
||||
root.updateLayoutParams<FrameLayout.LayoutParams> {
|
||||
gravity = Gravity.TOP or Gravity.CENTER
|
||||
}
|
||||
railFab.shrink()
|
||||
buttonExpand.setImageResource(R.drawable.ic_drawer_menu)
|
||||
buttonExpand.setContentDescriptionAndTooltip(R.string.expand)
|
||||
|
||||
@@ -76,7 +76,7 @@ class SearchV2Helper @AssistedInject constructor(
|
||||
|
||||
private fun MutableList<Manga>.postFilter(query: String, kind: SearchKind) {
|
||||
if (settings.isNsfwContentDisabled) {
|
||||
removeAll { it.isNsfw }
|
||||
removeAll { it.isNsfw() }
|
||||
}
|
||||
when (kind) {
|
||||
SearchKind.TITLE -> retainAll { m ->
|
||||
|
||||
@@ -229,7 +229,7 @@ class SuggestionsWorker @AssistedInject constructor(
|
||||
if (details.rating > 0 && details.rating < RATING_MIN) {
|
||||
continue
|
||||
}
|
||||
if (details.isNsfw && (appSettings.isSuggestionsExcludeNsfw || appSettings.isNsfwContentDisabled)) {
|
||||
if (details.isNsfw() && (appSettings.isSuggestionsExcludeNsfw || appSettings.isNsfwContentDisabled)) {
|
||||
continue
|
||||
}
|
||||
if (details in tagsBlacklist) {
|
||||
@@ -277,7 +277,7 @@ class SuggestionsWorker @AssistedInject constructor(
|
||||
filter = MangaListFilter(tags = setOfNotNull(tag)),
|
||||
).asArrayList()
|
||||
if (appSettings.isSuggestionsExcludeNsfw) {
|
||||
list.removeAll { it.isNsfw }
|
||||
list.removeAll { it.isNsfw() }
|
||||
}
|
||||
if (blacklist.isNotEmpty()) {
|
||||
list.removeAll { manga -> manga in blacklist }
|
||||
|
||||
@@ -5,18 +5,20 @@ import android.accounts.AccountAuthenticatorResponse
|
||||
import android.accounts.AccountManager
|
||||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.view.View
|
||||
import android.widget.Button
|
||||
import android.view.ViewGroup.MarginLayoutParams
|
||||
import android.widget.Toast
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.activity.viewModels
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.isInvisible
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.fragment.app.FragmentResultListener
|
||||
import androidx.transition.Fade
|
||||
import androidx.transition.TransitionManager
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.transition.MaterialSharedAxis
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.ui.BaseActivity
|
||||
@@ -31,13 +33,20 @@ import org.koitharu.kotatsu.databinding.ActivitySyncAuthBinding
|
||||
import org.koitharu.kotatsu.sync.data.SyncSettings
|
||||
import org.koitharu.kotatsu.sync.domain.SyncAuthResult
|
||||
|
||||
private const val PAGE_EMAIL = 0
|
||||
private const val PAGE_PASSWORD = 1
|
||||
private const val PASSWORD_MIN_LENGTH = 4
|
||||
|
||||
@AndroidEntryPoint
|
||||
class SyncAuthActivity : BaseActivity<ActivitySyncAuthBinding>(), View.OnClickListener, FragmentResultListener {
|
||||
class SyncAuthActivity : BaseActivity<ActivitySyncAuthBinding>(), View.OnClickListener, FragmentResultListener,
|
||||
DefaultTextWatcher {
|
||||
|
||||
private var accountAuthenticatorResponse: AccountAuthenticatorResponse? = null
|
||||
private var resultBundle: Bundle? = null
|
||||
private val pageBackCallback = PageBackCallback()
|
||||
|
||||
private val regexEmail = Regex("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$", RegexOption.IGNORE_CASE)
|
||||
|
||||
private val viewModel by viewModels<SyncAuthViewModel>()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@@ -46,14 +55,11 @@ class SyncAuthActivity : BaseActivity<ActivitySyncAuthBinding>(), View.OnClickLi
|
||||
accountAuthenticatorResponse =
|
||||
intent.getParcelableExtraCompat(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE)
|
||||
accountAuthenticatorResponse?.onRequestContinued()
|
||||
viewBinding.buttonCancel.setOnClickListener(this)
|
||||
viewBinding.buttonNext.setOnClickListener(this)
|
||||
viewBinding.buttonBack.setOnClickListener(this)
|
||||
viewBinding.buttonDone.setOnClickListener(this)
|
||||
viewBinding.layoutProgress.setOnClickListener(this)
|
||||
viewBinding.buttonSettings.setOnClickListener(this)
|
||||
viewBinding.editEmail.addTextChangedListener(EmailTextWatcher(viewBinding.buttonNext))
|
||||
viewBinding.editPassword.addTextChangedListener(PasswordTextWatcher(viewBinding.buttonDone))
|
||||
viewBinding.editEmail.addTextChangedListener(this)
|
||||
viewBinding.editPassword.addTextChangedListener(this)
|
||||
|
||||
onBackPressedDispatcher.addCallback(pageBackCallback)
|
||||
|
||||
@@ -65,17 +71,25 @@ class SyncAuthActivity : BaseActivity<ActivitySyncAuthBinding>(), View.OnClickLi
|
||||
}
|
||||
|
||||
supportFragmentManager.setFragmentResultListener(SyncHostDialogFragment.REQUEST_KEY, this, this)
|
||||
pageBackCallback.update()
|
||||
if (savedInstanceState == null) {
|
||||
setPage(PAGE_EMAIL)
|
||||
} else {
|
||||
pageBackCallback.update()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onApplyWindowInsets(v: View, insets: WindowInsetsCompat): WindowInsetsCompat {
|
||||
val barsInsets = insets.systemBarsInsets
|
||||
val basePadding = resources.getDimensionPixelOffset(R.dimen.screen_padding)
|
||||
viewBinding.root.setPadding(
|
||||
barsInsets.left + basePadding,
|
||||
barsInsets.top + basePadding,
|
||||
barsInsets.right + basePadding,
|
||||
barsInsets.bottom + basePadding,
|
||||
viewBinding.root.updatePadding(top = barsInsets.top)
|
||||
viewBinding.dockedToolbarChild.updateLayoutParams<MarginLayoutParams> {
|
||||
leftMargin = barsInsets.left
|
||||
rightMargin = barsInsets.right
|
||||
bottomMargin = barsInsets.bottom
|
||||
}
|
||||
val basePadding = viewBinding.layoutContent.paddingBottom
|
||||
viewBinding.layoutContent.updatePadding(
|
||||
left = barsInsets.left + basePadding,
|
||||
right = barsInsets.right + basePadding,
|
||||
)
|
||||
return insets.consumeAllSystemBarsInsets()
|
||||
}
|
||||
@@ -88,22 +102,18 @@ class SyncAuthActivity : BaseActivity<ActivitySyncAuthBinding>(), View.OnClickLi
|
||||
}
|
||||
|
||||
R.id.button_next -> {
|
||||
viewBinding.groupLogin.isVisible = false
|
||||
viewBinding.groupPassword.isVisible = true
|
||||
pageBackCallback.update()
|
||||
setPage(PAGE_PASSWORD)
|
||||
viewBinding.editPassword.requestFocus()
|
||||
}
|
||||
|
||||
R.id.button_back -> {
|
||||
viewBinding.groupPassword.isVisible = false
|
||||
viewBinding.groupLogin.isVisible = true
|
||||
pageBackCallback.update()
|
||||
setPage(PAGE_EMAIL)
|
||||
viewBinding.editEmail.requestFocus()
|
||||
}
|
||||
|
||||
R.id.button_done -> {
|
||||
viewModel.obtainToken(
|
||||
email = viewBinding.editEmail.text.toString(),
|
||||
email = viewBinding.editEmail.text.toString().trim(),
|
||||
password = viewBinding.editPassword.text.toString(),
|
||||
)
|
||||
}
|
||||
@@ -128,12 +138,39 @@ class SyncAuthActivity : BaseActivity<ActivitySyncAuthBinding>(), View.OnClickLi
|
||||
super.finish()
|
||||
}
|
||||
|
||||
override fun afterTextChanged(s: Editable?) {
|
||||
val isLoading = viewModel.isLoading.value
|
||||
val email = viewBinding.editEmail.text?.trim()?.toString()
|
||||
val password = viewBinding.editPassword.text?.toString()
|
||||
viewBinding.buttonNext.isEnabled = !isLoading && !email.isNullOrEmpty() && regexEmail.matches(email)
|
||||
viewBinding.buttonDone.isEnabled = !isLoading && password != null && password.length >= PASSWORD_MIN_LENGTH
|
||||
}
|
||||
|
||||
private fun onLoadingStateChanged(isLoading: Boolean) {
|
||||
if (isLoading == viewBinding.layoutProgress.isVisible) {
|
||||
return
|
||||
with(viewBinding) {
|
||||
progressBar.isInvisible = !isLoading
|
||||
editEmail.isEnabled = !isLoading
|
||||
editPassword.isEnabled = !isLoading
|
||||
}
|
||||
afterTextChanged(null)
|
||||
pageBackCallback.update()
|
||||
}
|
||||
|
||||
private fun setPage(page: Int) {
|
||||
with(viewBinding) {
|
||||
val currentPage = if (layoutEmail.isVisible) PAGE_EMAIL else PAGE_PASSWORD
|
||||
if (currentPage != page) {
|
||||
val transition = MaterialSharedAxis(MaterialSharedAxis.X, page > currentPage)
|
||||
TransitionManager.beginDelayedTransition(layoutContent, transition)
|
||||
}
|
||||
buttonNext.isVisible = page == PAGE_EMAIL
|
||||
buttonBack.isVisible = page == PAGE_PASSWORD
|
||||
buttonSettings.isVisible = page == PAGE_EMAIL
|
||||
buttonDone.isVisible = page == PAGE_PASSWORD
|
||||
buttonCancel.isVisible = page == PAGE_EMAIL
|
||||
layoutEmail.isVisible = page == PAGE_EMAIL
|
||||
layoutPassword.isVisible = page == PAGE_PASSWORD
|
||||
}
|
||||
TransitionManager.beginDelayedTransition(viewBinding.root, Fade())
|
||||
viewBinding.layoutProgress.isVisible = isLoading
|
||||
pageBackCallback.update()
|
||||
}
|
||||
|
||||
@@ -174,43 +211,16 @@ class SyncAuthActivity : BaseActivity<ActivitySyncAuthBinding>(), View.OnClickLi
|
||||
super.finishAfterTransition()
|
||||
}
|
||||
|
||||
private class EmailTextWatcher(
|
||||
private val button: Button,
|
||||
) : TextWatcher {
|
||||
|
||||
private val regexEmail = Regex("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$", RegexOption.IGNORE_CASE)
|
||||
|
||||
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) = Unit
|
||||
|
||||
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) = Unit
|
||||
|
||||
override fun afterTextChanged(s: Editable?) {
|
||||
val text = s?.toString()
|
||||
button.isEnabled = !text.isNullOrEmpty() && regexEmail.matches(text)
|
||||
}
|
||||
}
|
||||
|
||||
private class PasswordTextWatcher(
|
||||
private val button: Button,
|
||||
) : DefaultTextWatcher {
|
||||
|
||||
override fun afterTextChanged(s: Editable?) {
|
||||
val text = s?.toString()
|
||||
button.isEnabled = text != null && text.length >= 4
|
||||
}
|
||||
}
|
||||
|
||||
private inner class PageBackCallback : OnBackPressedCallback(false) {
|
||||
|
||||
override fun handleOnBackPressed() {
|
||||
viewBinding.groupLogin.isVisible = true
|
||||
viewBinding.groupPassword.isVisible = false
|
||||
setPage(PAGE_EMAIL)
|
||||
viewBinding.editEmail.requestFocus()
|
||||
update()
|
||||
}
|
||||
|
||||
fun update() {
|
||||
isEnabled = !viewBinding.layoutProgress.isVisible && viewBinding.groupPassword.isVisible
|
||||
isEnabled = !viewBinding.progressBar.isVisible && viewBinding.editPassword.isVisible
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,227 +1,156 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/screen_padding">
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawablePadding="16dp"
|
||||
android:layout_marginHorizontal="@dimen/screen_padding"
|
||||
android:layout_marginTop="24dp"
|
||||
android:drawablePadding="@dimen/screen_padding"
|
||||
android:gravity="center_horizontal"
|
||||
android:text="@string/sync_title"
|
||||
android:textAppearance="?textAppearanceHeadline5"
|
||||
app:drawableTint="?colorPrimary"
|
||||
app:drawableTopCompat="@drawable/ic_sync"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
app:drawableTopCompat="@drawable/ic_sync" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/button_settings"
|
||||
android:layout_width="wrap_content"
|
||||
<com.google.android.material.progressindicator.LinearProgressIndicator
|
||||
android:id="@+id/progressBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/settings"
|
||||
android:tooltipText="@string/settings"
|
||||
android:padding="4dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/ic_settings" />
|
||||
android:layout_marginHorizontal="@dimen/screen_padding"
|
||||
android:layout_marginTop="@dimen/screen_padding"
|
||||
android:max="100"
|
||||
android:visibility="invisible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView_subtitle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:text="@string/email_enter_hint"
|
||||
android:textAppearance="?textAppearanceSubtitle1"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/textView_title" />
|
||||
<ScrollView
|
||||
android:id="@+id/scrollView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/layout_email"
|
||||
style="?textInputOutlinedStyle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="30dp"
|
||||
app:errorIconDrawable="@null"
|
||||
app:helperText="@string/sync_auth_hint"
|
||||
app:hintEnabled="false"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/textView_subtitle">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/edit_email"
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:autofillHints="username"
|
||||
android:imeOptions="actionDone"
|
||||
android:inputType="textEmailAddress"
|
||||
android:singleLine="true"
|
||||
android:textSize="16sp"
|
||||
tools:text="test@mail.com" />
|
||||
android:orientation="vertical"
|
||||
android:paddingHorizontal="@dimen/screen_padding"
|
||||
android:paddingBottom="@dimen/screen_padding">
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
<TextView
|
||||
android:id="@+id/textView_subtitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/sync_auth_hint"
|
||||
android:textAppearance="?textAppearanceBodySmall" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_cancel"
|
||||
style="?materialButtonOutlinedStyle"
|
||||
android:layout_width="wrap_content"
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/layout_email"
|
||||
style="?textInputOutlinedStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="30dp"
|
||||
app:errorIconDrawable="@null">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/edit_email"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:autofillHints="username"
|
||||
android:hint="@string/email"
|
||||
android:imeOptions="actionDone"
|
||||
android:inputType="textEmailAddress"
|
||||
android:singleLine="true"
|
||||
android:textSize="16sp" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/layout_password"
|
||||
style="?textInputOutlinedStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="30dp"
|
||||
app:endIconMode="password_toggle"
|
||||
app:errorIconDrawable="@null">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/edit_password"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:autofillHints="password"
|
||||
android:hint="@string/password"
|
||||
android:imeOptions="actionDone"
|
||||
android:inputType="textPassword"
|
||||
android:maxLength="24"
|
||||
android:singleLine="true"
|
||||
android:textSize="16sp" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_settings"
|
||||
style="?borderlessButtonStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="@string/settings" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
<com.google.android.material.dockedtoolbar.DockedToolbarLayout
|
||||
android:id="@+id/docked_toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@android:string/cancel"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
android:fitsSystemWindows="false">
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_next"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:enabled="false"
|
||||
android:text="@string/next"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView_subtitle_2"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:text="@string/enter_password"
|
||||
android:textAppearance="?textAppearanceSubtitle1"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/textView_title" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/layout_password"
|
||||
style="?textInputOutlinedStyle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="30dp"
|
||||
app:endIconMode="password_toggle"
|
||||
app:errorIconDrawable="@null"
|
||||
app:hintEnabled="false"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/textView_subtitle_2">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/edit_password"
|
||||
<FrameLayout
|
||||
android:id="@+id/docked_toolbar_child"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:autofillHints="password"
|
||||
android:imeOptions="actionDone"
|
||||
android:inputType="textPassword"
|
||||
android:maxLength="24"
|
||||
android:singleLine="true"
|
||||
android:textSize="16sp"
|
||||
tools:text="qwerty" />
|
||||
android:layout_height="@dimen/m3_comp_toolbar_docked_container_height">
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
<Button
|
||||
android:id="@+id/button_cancel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical|start"
|
||||
android:text="@android:string/cancel" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_back"
|
||||
style="?materialButtonOutlinedStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/back"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
<Button
|
||||
android:id="@+id/button_back"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical|start"
|
||||
android:text="@string/back"
|
||||
android:visibility="gone" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_done"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:enabled="false"
|
||||
android:text="@string/done"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
<Button
|
||||
android:id="@+id/button_next"
|
||||
style="?materialButtonTonalStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:enabled="false"
|
||||
android:text="@string/next" />
|
||||
|
||||
<androidx.constraintlayout.widget.Group
|
||||
android:id="@+id/group_login"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:constraint_referenced_ids="textView_subtitle,button_cancel,button_next,layout_email" />
|
||||
<Button
|
||||
android:id="@+id/button_done"
|
||||
style="?materialButtonTonalStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:enabled="false"
|
||||
android:text="@string/done"
|
||||
android:visibility="gone" />
|
||||
|
||||
<androidx.constraintlayout.widget.Group
|
||||
android:id="@+id/group_password"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
app:constraint_referenced_ids="textView_subtitle_2,button_back,button_done,layout_password" />
|
||||
</FrameLayout>
|
||||
</com.google.android.material.dockedtoolbar.DockedToolbarLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.Barrier
|
||||
android:id="@+id/barrier_input"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:barrierDirection="bottom"
|
||||
app:constraint_referenced_ids="layout_email,layout_password" />
|
||||
|
||||
<View
|
||||
android:id="@+id/view_line"
|
||||
android:layout_width="4dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="@drawable/bg_chip"
|
||||
android:backgroundTint="?colorError"
|
||||
app:layout_constraintBottom_toBottomOf="@id/textView_hint_body"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/textView_hint_title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView_hint_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="32dp"
|
||||
android:drawablePadding="10dp"
|
||||
android:gravity="center_vertical"
|
||||
android:text="@string/unstable_feature"
|
||||
android:textAppearance="?textAppearanceTitleMedium"
|
||||
app:drawableStartCompat="@drawable/ic_alert_outline"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/view_line"
|
||||
app:layout_constraintTop_toBottomOf="@id/barrier_input" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView_hint_body"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:paddingBottom="6dp"
|
||||
android:text="@string/unstable_feature_summary"
|
||||
android:textAppearance="?textAppearanceBodyMedium"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="@id/textView_hint_title"
|
||||
app:layout_constraintTop_toBottomOf="@id/textView_hint_title" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/layout_progress"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="?android:windowBackground"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/textView_title">
|
||||
|
||||
<com.google.android.material.progressindicator.CircularProgressIndicator
|
||||
android:id="@+id/circularProgressIndicator"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:indeterminate="true" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</LinearLayout>
|
||||
|
||||
@@ -794,4 +794,17 @@
|
||||
<string name="global_search">البحث العالمي</string>
|
||||
<string name="search_everywhere">البحث في كل مكان</string>
|
||||
<string name="badges_in_lists">الشارات في القوائم</string>
|
||||
<string name="nsfw_16">16+</string>
|
||||
<string name="reader_navigation_inverted">عكس التنقل اثناء التصفح</string>
|
||||
<string name="reader_navigation_inverted_summary">عكس اتجاه زر التحكم في الصوت ومفتاح التنقل الاتجاهي في الأجهزة (يسار/أعلى/أسفل/يمين)</string>
|
||||
<string name="clear_browser_data">مسح بيانات المتصفح</string>
|
||||
<string name="clear_browser_data_summary">مسح بيانات المتصفح، مثل ذاكرة التخزين المؤقت وملفات تعريف الارتباط. تحذير: قد يصبح التفويض في مصادر المانجا غير صالح.</string>
|
||||
<string name="no_write_permission_to_file">ليس لديك صلاحية لكتابة ملف.</string>
|
||||
<string name="exclude_nsfw_from_suggestions_summary">لن تظهر المانغا المخصصة للبالغين في الاقتراحات. قد لا يعمل هذا الخيار بدقة مع بعض المصادر.</string>
|
||||
<string name="include_disabled_sources">"شمل المصادر المعطلة."</string>
|
||||
<string name="suggestions_disabled_sources_summary">"اضهار الاقتراحات من كل مصادر المانقا شامل المعطلين."</string>
|
||||
<string name="tags_warnings">ابراز التصنيفات الخطيرة</string>
|
||||
<string name="tags_warnings_summary">ابراز التصنيفات التي قد تكون غير مناسبة لغالبية المستخدين.</string>
|
||||
<string name="error_non_file_uri">لا يمكن استخدام المسار المحدد لأنه لا يشير إلى ملف أو دليل.</string>
|
||||
<string name="manga_override_hint">ستؤثر هذه التغييرات على كيفية عرض المانجا في التطبيق.</string>
|
||||
</resources>
|
||||
|
||||
@@ -835,4 +835,28 @@
|
||||
<string name="theme_name_itsuka">Іцука</string>
|
||||
<string name="theme_name_totoro">Тоторо</string>
|
||||
<string name="book_effect">Жаўтлявы фон (фільтр сіняга)</string>
|
||||
<string name="local_storage_cleanup">Ачыстка лакальнага сховішча</string>
|
||||
<string name="packup_creation_failed">Рэзервовае капіраванне не атрымалася</string>
|
||||
<string name="main_screen">Галоўны экран</string>
|
||||
<string name="main_screen_fab">Паказаць плаваючую кнопку «Працягнуць»</string>
|
||||
<string name="main_screen_fab_summary">Дазваляе працягнуць чытанне адным пстрычкай мышы. Гэтая кнопка не адлюстроўваецца ў рэжыме інкогніта або калі гісторыя пустая</string>
|
||||
<string name="error_corrupted_zip">Пашкоджаны ZIP-архіў (%s)</string>
|
||||
<string name="discord_rpc">Discord Rich Presence</string>
|
||||
<string name="discord_token">Токен Discord</string>
|
||||
<string name="discord_token_summary">Увядзіце свой токен Discord, каб уключыць Rich Presence</string>
|
||||
<string name="discord_token_description">Увядзіце свой токен Discord або націсніце %s, каб атрымаць яго з дапамогай браўзера</string>
|
||||
<string name="discord_token_hint">Устаўце сюды свой токен Discord</string>
|
||||
<string name="discord_rpc_summary">Пакажыце свой статус чытання ў Discord</string>
|
||||
<string name="obtain">Атрымаць</string>
|
||||
<string name="discord_rpc_description">Чытанне мангі на Kotatsu - праграма для чытання мангі</string>
|
||||
<string name="reading_s">Чытанне %s</string>
|
||||
<string name="read_on_s">Чытаць далей %s</string>
|
||||
<string name="rpc_skip_nsfw_summary">Не выкарыстоўваць RPC для дарослага кантэнту</string>
|
||||
<string name="invalid_token">Няправільны токен: %s</string>
|
||||
<string name="show_floating_control_button">Паказаць плаваючую кнопку кіравання</string>
|
||||
<string name="unavailable">Недаступна</string>
|
||||
<string name="manga_restricted_description">Гэтая манга недаступная для чытання на гэтай крыніцы. Паспрабуйце знайсці яе на іншых крыніцах або адкрыйце ў браўзеры для атрымання дадатковай інфармацыі</string>
|
||||
<string name="no_chapters_in_manga">Гэтая манга не ўтрымлівае раздзелаў</string>
|
||||
<string name="chapters_load_failed">Не атрымалася загрузіць спіс раздзелаў</string>
|
||||
<string name="telegram_integration">Інтэграцыя з Telegram</string>
|
||||
</resources>
|
||||
|
||||
@@ -856,4 +856,5 @@
|
||||
<string name="manga_restricted_description">Ce manga n’est pas disponible à la lecture sur cette source. Essaie de le chercher dans d’autres sources ou ouvre-le dans un navigateur pour plus d’informations</string>
|
||||
<string name="no_chapters_in_manga">Ce manga ne contient aucun chapitre</string>
|
||||
<string name="chapters_load_failed">Échec du chargement de la liste des chapitres</string>
|
||||
<string name="telegram_integration">Intégration Telegram</string>
|
||||
</resources>
|
||||
|
||||
@@ -44,12 +44,12 @@
|
||||
<string name="nothing_found">Ništa nije pronađeno</string>
|
||||
<string name="read">Čitaj</string>
|
||||
<string name="you_have_not_favourites_yet">Još nema favorita</string>
|
||||
<string name="add_to_favourites">Označite ovo kao favorit</string>
|
||||
<string name="add_to_favourites">Dodaj u favorite</string>
|
||||
<string name="add_new_category">Nova kategorija</string>
|
||||
<string name="add">Dodaj</string>
|
||||
<string name="save">Sačuvaj</string>
|
||||
<string name="share">Podijeli</string>
|
||||
<string name="create_shortcut">Napravi prečicu…</string>
|
||||
<string name="create_shortcut">Napravi prečicu</string>
|
||||
<string name="share_s">Podijeli %s</string>
|
||||
<string name="search">Pretraži</string>
|
||||
<string name="search_manga">Pretraži mangu</string>
|
||||
@@ -266,7 +266,7 @@
|
||||
<string name="enable_logging">Omogući bilježenje</string>
|
||||
<string name="enable_logging_summary">Snimite neke radnje u svrhu otklanjanja pogrešaka. Nemojte ga uključivati ako niste sigurni što radite</string>
|
||||
<string name="show_suspicious_content">Prikaži sumnjiv sadržaj</string>
|
||||
<string name="theme_name_dynamic">Dinamičan</string>
|
||||
<string name="theme_name_dynamic">Dinamična</string>
|
||||
<string name="color_theme">Shema boja</string>
|
||||
<string name="show_in_grid_view">Prikaži u mrežnom prikazu</string>
|
||||
<string name="theme_name_miku">Miku</string>
|
||||
@@ -474,7 +474,7 @@
|
||||
<string name="file_not_found">Datoteka nije pronađena</string>
|
||||
<string name="data_restored_success">Svi podaci su vraćeni</string>
|
||||
<string name="data_restored_with_errors">Podaci su vraćeni, ali ima grešaka</string>
|
||||
<string name="backup_information">Možete stvoriti sigurnosnu kopiju svoje povijesti i favorita i vratiti je</string>
|
||||
<string name="backup_information">Možete stvoriti sigurnosnu kopiju svoje povijesti i favorita i obnoviti je</string>
|
||||
<string name="yesterday">Jučer</string>
|
||||
<string name="long_ago">Davno</string>
|
||||
<string name="data_restored">Vraćeno</string>
|
||||
@@ -782,4 +782,24 @@
|
||||
<string name="global_search">Globalna pretraga</string>
|
||||
<string name="search_everywhere">Traži svuda</string>
|
||||
<string name="badges_in_lists">Značke u popisima</string>
|
||||
<string name="nsfw_16">16+</string>
|
||||
<string name="theme_name_expressive">Ekspresivna (test)</string>
|
||||
<string name="chapter_volume_number">Svezak %1$s Poglavlje %2$s</string>
|
||||
<string name="chapter_number">Poglavlje %s</string>
|
||||
<string name="unnamed_chapter">Neimenovano poglavlje</string>
|
||||
<string name="search_disabled_sources">Pretraži deaktivirane izvore</string>
|
||||
<string name="error_details">Detalji greške</string>
|
||||
<string name="error_disclaimer_manga">Pokušaj otvoriti manga u web pregledniku kako bi provjerio/la je li dostupan na izvornom mjestu.</string>
|
||||
<string name="error_disclaimer_app_outdated">Izgleda da je tvoja Kotatsu verzija zastarjela. Instaliraj najnoviju verziju za dobivanje svih dostupnih ispravki.</string>
|
||||
<string name="link_to_manga_in_app">Poveznica na manga u Kotatsu</string>
|
||||
<string name="link_to_manga_on_s">Poveznica na manga na %s</string>
|
||||
<string name="error_disclaimer_report">Pošalji izvještaj o grešci programerima. To će nam pomoći da istražimo i ispravimo problem.</string>
|
||||
<string name="clear_browser_data">Izbriši podatke iz preglednika</string>
|
||||
<string name="clear_browser_data_summary">Izbriši podatke iz preglednika poput predmemorije i kolačića. Upozorenje: Autorizacija na izvorima mange može postati nevažeća</string>
|
||||
<string name="no_write_permission_to_file">Nema dozvolu za pisanje u datoteku</string>
|
||||
<string name="exclude_nsfw_from_suggestions_summary">Manga za odrasle se neće prikazivati u prijedlozima. Ova opcija možda neće točno funkcionirati s nekim izvorima</string>
|
||||
<string name="include_disabled_sources">Uključi deaktivirane izvore</string>
|
||||
<string name="suggestions_disabled_sources_summary">Prikaži prijedloge iz svih izvora mange, uključujući deaktivirane</string>
|
||||
<string name="tags_warnings">Istakni opasne žanrove</string>
|
||||
<string name="tags_warnings_summary">Istakni žanrove koji bi mogli biti neprikladni za većinu korisnika</string>
|
||||
</resources>
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
<string name="detailed_list">Elenco dettagliato</string>
|
||||
<string name="text_delete_local_manga">Vuoi davvero eliminare \" %s\" dalla memoria locale del tuo dispositivo?</string>
|
||||
<string name="_s_deleted_from_local_storage">\"%s\" eliminato dall\'archiviazione locale</string>
|
||||
<string name="list">Liste</string>
|
||||
<string name="list">Lista</string>
|
||||
<string name="chapters">Capitoli</string>
|
||||
<string name="details">Dettagli</string>
|
||||
<string name="network_error">Errore di connessione</string>
|
||||
@@ -318,7 +318,7 @@
|
||||
<string name="importing_manga">Importazione di manga</string>
|
||||
<string name="import_will_start_soon">L\'importazione inizierà presto</string>
|
||||
<string name="feed">Flusso</string>
|
||||
<string name="reader_control_ltr_summary">Non adattare la direzione di cambio pagina alla modalità di lettura; ad esempio, premendo il tasto destro, si passa sempre alla pagina successiva. Questa opzione riguarda solo i dispositivi di input hardware</string>
|
||||
<string name="reader_control_ltr_summary">Non adeguare la direzione dello sfoglio alla modalità di lettura impostata. Ad esempio: premere la freccia destra passerà sempre alla pagina seguente. Questa impostazione ha effetto solo sui dispositivi di input hardware</string>
|
||||
<string name="contrast">Contrasto</string>
|
||||
<string name="reset">Ripristina</string>
|
||||
<string name="reader_slider">Mostra il cursore di cambio pagina</string>
|
||||
@@ -543,7 +543,7 @@
|
||||
<string name="last_read">Ultima lettura</string>
|
||||
<string name="reading_time_estimation_summary">Il tempo di lettura stimato potrebbe essere inaccurato</string>
|
||||
<string name="reading_time_estimation">Mostra il tempo di lettura stimato</string>
|
||||
<string name="email_password_enter_hint">Inserisci la tua email e password per continuare</string>
|
||||
<string name="email_password_enter_hint">Inserisci email e password per continuare</string>
|
||||
<string name="show_menu">Mostra menu</string>
|
||||
<string name="switch_pages_volume_buttons_summary">Usa i pulsanti del volume per cambiare pagine</string>
|
||||
<string name="tap_action">Azioni tap</string>
|
||||
@@ -566,7 +566,7 @@
|
||||
<string name="toggle_ui">Mostra/nascondi UI</string>
|
||||
<string name="next_chapter">Prossimo capitolo</string>
|
||||
<string name="prev_page">Pagina precedente</string>
|
||||
<string name="next_page">Prossima pagina</string>
|
||||
<string name="next_page">Pagina successiva</string>
|
||||
<string name="reader_actions">Azioni del lettore</string>
|
||||
<string name="switch_pages_volume_buttons">Abilita pulsanti del volume</string>
|
||||
<string name="reader_fullscreen_summary">Nascondi le barre di stato e di notifica</string>
|
||||
@@ -603,7 +603,7 @@
|
||||
<string name="three_months">Tre mesi</string>
|
||||
<string name="empty_stats_text">Non ci sono statistiche per il periodo selezionato</string>
|
||||
<string name="ask_for_dest_dir_every_time">Chiedi per la cartella di destinazione ogni volta</string>
|
||||
<string name="pages_saving">Salva pagine</string>
|
||||
<string name="pages_saving">Salvando le pagine</string>
|
||||
<string name="preferred_download_format">Formato download preferito</string>
|
||||
<string name="single_cbz_file">File CBZ singolo</string>
|
||||
<string name="multiple_cbz_files">Molti file CBZ</string>
|
||||
@@ -647,10 +647,10 @@
|
||||
<string name="chapters_read">Capitoli letti</string>
|
||||
<string name="chapters_left">Capitoli rimasti</string>
|
||||
<string name="default_webtoon_zoom_out">Riduzione dello zoom Webtoon predefinito</string>
|
||||
<string name="crop_pages">Ritagliare le pagine</string>
|
||||
<string name="unpin">Sblocca</string>
|
||||
<string name="source_unpinned">Fonte non individuata</string>
|
||||
<string name="sources_unpinned">Fonti non individuate</string>
|
||||
<string name="crop_pages">Ritaglia le pagine</string>
|
||||
<string name="unpin">Rimuovi</string>
|
||||
<string name="source_unpinned">Fonte rimossa</string>
|
||||
<string name="sources_unpinned">Fonti rimosse</string>
|
||||
<string name="tracker_debug_info_summary">Informazioni di debug sui controlli in background per i nuovi capitoli</string>
|
||||
<string name="location">Posizione</string>
|
||||
<string name="chapters_deleted_pattern">Rimosso %1$s, cancellato %2$s</string>
|
||||
@@ -857,4 +857,6 @@
|
||||
<string name="unavailable">Non disponibile</string>
|
||||
<string name="manga_restricted_description">Questo manga non è disponibile per la lettura da questa fonte. Prova a cercarlo in altre fonti o aprilo in un browser per maggiori informazioni</string>
|
||||
<string name="no_chapters_in_manga">Questo manga non contiene capitoli</string>
|
||||
<string name="telegram_integration">Integrazione con Telegram</string>
|
||||
<string name="chapters_load_failed">Errore nel caricamento della lista dei capitoli</string>
|
||||
</resources>
|
||||
|
||||
@@ -22,11 +22,11 @@
|
||||
<string name="history_is_empty">まだ履歴はありません</string>
|
||||
<string name="read">読む</string>
|
||||
<string name="you_have_not_favourites_yet">お気に入りの本はありません</string>
|
||||
<string name="add_to_favourites">お気に入り</string>
|
||||
<string name="add_to_favourites">お気に入りに追加</string>
|
||||
<string name="add_new_category">新しいカテゴリー</string>
|
||||
<string name="add">追加</string>
|
||||
<string name="save">保存</string>
|
||||
<string name="create_shortcut">ショートカットを作成…</string>
|
||||
<string name="create_shortcut">ショートカットを作成</string>
|
||||
<string name="share_s">%s を共有する</string>
|
||||
<string name="manga_downloading_">ダウンロード中…</string>
|
||||
<string name="processing_">処理中…</string>
|
||||
@@ -305,7 +305,7 @@
|
||||
<string name="incognito_mode">シークレットモード</string>
|
||||
<string name="folder_with_images">画像を含むフォルダ</string>
|
||||
<string name="import_will_start_soon">まもなくインポートが開始されます</string>
|
||||
<string name="removed_from_favourites">お気に入りから削除</string>
|
||||
<string name="removed_from_favourites">お気に入りから削除されました</string>
|
||||
<string name="options">オプション</string>
|
||||
<string name="import_completed_hint">ストレージから元のファイルを削除して、容量を節約することができます</string>
|
||||
<string name="reader_info_pattern">Ch.%1$d/%2$d Pg.%3$d/%4$d</string>
|
||||
@@ -472,4 +472,6 @@
|
||||
<string name="enable_all_sources">すべての漫画ソースを有効にする</string>
|
||||
<string name="enable_all_sources_summary">利用可能なすべての漫画ソースを永久に有効にする</string>
|
||||
<string name="all_sources_enabled">すべてのソースが有効</string>
|
||||
<string name="automatic">自動</string>
|
||||
<string name="invalid_server_address_message">無効なサーバーアドレス</string>
|
||||
</resources>
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
<string name="app_update_available">Uma nova versão do app está disponível</string>
|
||||
<string name="open_in_browser">Abrir no navegador da web</string>
|
||||
<string name="notifications">Notificações</string>
|
||||
<string name="new_chapters">Capítulos novos</string>
|
||||
<string name="new_chapters">Novos capítulos</string>
|
||||
<string name="download">Download</string>
|
||||
<string name="notifications_settings">Configurações das notificações</string>
|
||||
<string name="light_indicator">Indicador LED</string>
|
||||
@@ -330,7 +330,7 @@
|
||||
<string name="import_will_start_soon">A importação começará em breve</string>
|
||||
<string name="feed">Fluxo</string>
|
||||
<string name="manga_error_description_pattern">Detalhes do erro:<br><tt>%1$s</tt><br><br>1. Tente <a href=%2$s>abra a página do mangá em um navegador da web</a> para garantir que o mesmo esteja disponível em sua fonte<br>2. Se estiver disponível, envie um relatório de erro para os desenvolvedores.</string>
|
||||
<string name="reader_control_ltr_summary">Tocar a borda direita ou pressionar a tecla direita, sempre mudará para a próxima página.</string>
|
||||
<string name="reader_control_ltr_summary">Não ajustar a direção da mudança de página no modo de editor, por exemplo, pressionar a tecla direita muda sempre para a página seguinte. Esta opção só afeta os dispositivos de hardware de entrada</string>
|
||||
<string name="reader_control_ltr">Controle ergonômico do leitor</string>
|
||||
<string name="discard">Descartar</string>
|
||||
<string name="language">Idioma</string>
|
||||
@@ -836,4 +836,7 @@
|
||||
<string name="book_effect">Fundo amarelaso (filtro de luz azul)</string>
|
||||
<string name="local_storage_cleanup">Limpeza do armazenamento local</string>
|
||||
<string name="packup_creation_failed">Falha ao criar backup</string>
|
||||
<string name="main_screen">Ecrã principal</string>
|
||||
<string name="main_screen_fab">Mostrar botão flutuante \"Continuar\"</string>
|
||||
<string name="discord_token">Código do Discord</string>
|
||||
</resources>
|
||||
|
||||
@@ -835,4 +835,28 @@
|
||||
<string name="book_effect">Желтоватый фон (фильтр синего)</string>
|
||||
<string name="reader_navigation_inverted_summary">Поменять местами направление кнопки регулировки громкости и аппаратной клавиши навигации (влево/вверх/вниз/вправо)</string>
|
||||
<string name="reader_multitask_summary">Позволяет держать открытыми несколько читалок с разной мангой одновременно</string>
|
||||
<string name="local_storage_cleanup">Очистка локального хранилища</string>
|
||||
<string name="packup_creation_failed">Не удалось создать резервную копию</string>
|
||||
<string name="main_screen">Главный экран</string>
|
||||
<string name="main_screen_fab">Показать плавающую кнопку «Продолжить»</string>
|
||||
<string name="main_screen_fab_summary">Позволяет продолжить чтение одним кликом. Эта кнопка не отображается в режиме инкогнито или при пустой истории</string>
|
||||
<string name="error_corrupted_zip">Повреждённый ZIP-архив (%s)</string>
|
||||
<string name="discord_rpc">Discord Rich Presence</string>
|
||||
<string name="discord_token">Токен Discord</string>
|
||||
<string name="discord_token_summary">Введите свой токен Discord, чтобы включить Rich Presence</string>
|
||||
<string name="discord_token_description">Введите свой токен Discord или нажмите %s, чтобы получить его через браузер</string>
|
||||
<string name="discord_token_hint">Вставьте свой токен Discord сюда</string>
|
||||
<string name="discord_rpc_summary">Покажите свой статус чтения в Discord</string>
|
||||
<string name="obtain">Получить</string>
|
||||
<string name="discord_rpc_description">Чтение манги в Kotatsu — приложение для чтения манги</string>
|
||||
<string name="reading_s">Чтение %s</string>
|
||||
<string name="read_on_s">Читать дальше %s</string>
|
||||
<string name="rpc_skip_nsfw_summary">Не использовать RPC для контента для взрослых</string>
|
||||
<string name="invalid_token">Недействительный токен: %s</string>
|
||||
<string name="show_floating_control_button">Показать плавающую кнопку управления</string>
|
||||
<string name="unavailable">Недоступно</string>
|
||||
<string name="manga_restricted_description">Эта манга недоступна для чтения в этом источнике. Попробуйте поискать её в других источниках или открыть в браузере, чтобы узнать больше</string>
|
||||
<string name="no_chapters_in_manga">Эта манга не содержит глав</string>
|
||||
<string name="chapters_load_failed">Не удалось загрузить список глав</string>
|
||||
<string name="telegram_integration">Интеграция с Telegram</string>
|
||||
</resources>
|
||||
|
||||
@@ -858,4 +858,5 @@
|
||||
<string name="manga_restricted_description">Bu manga, okumak için bu kaynakta mevcut değil. Başka kaynaklarda aramayı ya da daha fazla bilgi için tarayıcıda açmayı deneyin</string>
|
||||
<string name="no_chapters_in_manga">Bu manga bölüm içermiyor</string>
|
||||
<string name="chapters_load_failed">Bölüm listesi yüklenemedi</string>
|
||||
<string name="telegram_integration">Telegram entegrasyonu</string>
|
||||
</resources>
|
||||
|
||||
@@ -856,4 +856,5 @@
|
||||
<string name="manga_restricted_description">Truyện này không có sẵn trên nguồn này. Hãy thử tìm kiếm truyện này với nguồn đọc khác hoặc mở nó trong trình duyệt để biết thêm chi tiết</string>
|
||||
<string name="no_chapters_in_manga">Truyện này không có sẵn chương nào cả ツ</string>
|
||||
<string name="chapters_load_failed">Không thể tải danh sách chương hiện có</string>
|
||||
<string name="telegram_integration">Tích hợp Telegram</string>
|
||||
</resources>
|
||||
|
||||
@@ -854,4 +854,5 @@
|
||||
<string name="no_chapters_in_manga">没有找到此漫画的任何章节</string>
|
||||
<string name="chapters_load_failed">加载章节列表失败</string>
|
||||
<string name="manga_restricted_description">此漫画在图源中无法阅读,尝试在别的图源中搜索此漫画或打开内置浏览器获取更多信息</string>
|
||||
<string name="telegram_integration">Telegram集成</string>
|
||||
</resources>
|
||||
|
||||
@@ -51,17 +51,16 @@
|
||||
app:isPreferenceVisible="false" />
|
||||
|
||||
<PreferenceCategory
|
||||
android:key="backup_periodic_tg"
|
||||
android:title="@string/telegram_integration"
|
||||
app:isPreferenceVisible="false"
|
||||
android:key="backup_periodic_tg"
|
||||
tools:isPreferenceVisible="true">
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:dependency="backup_periodic"
|
||||
android:key="backup_periodic_tg_enabled"
|
||||
android:title="@string/send_backups_telegram"
|
||||
app:allowDividerAbove="true" />
|
||||
android:title="@string/send_backups_telegram" />
|
||||
|
||||
<EditTextPreference
|
||||
android:dependency="backup_periodic_tg_enabled"
|
||||
|
||||
@@ -34,12 +34,12 @@ material = "1.14.0-alpha03"
|
||||
moshi = "1.15.2"
|
||||
okhttp = "4.12.0"
|
||||
okio = "3.12.0"
|
||||
parsers = "74d0951d3d"
|
||||
parsers = "fd0df2414e"
|
||||
preference = "1.2.1"
|
||||
recyclerview = "1.4.0"
|
||||
room = "2.7.2"
|
||||
serialization = "1.8.1"
|
||||
ssiv = "5132f1e609"
|
||||
ssiv = "376930523c"
|
||||
swiperefreshlayout = "1.1.0"
|
||||
testRules = "1.6.1"
|
||||
testRunner = "1.6.2"
|
||||
|
||||
Reference in New Issue
Block a user