From f730e80bb721cfb68e3174b3b29b3f61765c3598 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Thu, 29 Feb 2024 11:20:10 +0200 Subject: [PATCH 1/8] Use numeric keyboard if app password is numeric (cherry picked from commit f98bb87d6e561e4763314d0a0f40c960dc842cad) --- .../org/koitharu/kotatsu/core/prefs/AppSettings.kt | 10 +++++++--- .../kotatsu/main/ui/protect/ProtectActivity.kt | 6 ++++++ .../kotatsu/main/ui/protect/ProtectViewModel.kt | 4 ++++ .../kotatsu/settings/protect/ProtectSetupViewModel.kt | 2 ++ 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppSettings.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppSettings.kt index 7101b175c..4bd1c642a 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppSettings.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppSettings.kt @@ -27,6 +27,7 @@ import org.koitharu.kotatsu.explore.data.SourcesSortOrder import org.koitharu.kotatsu.list.domain.ListSortOrder import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.util.find +import org.koitharu.kotatsu.parsers.util.isNumeric import org.koitharu.kotatsu.parsers.util.mapNotNullToSet import org.koitharu.kotatsu.parsers.util.mapToSet import org.koitharu.kotatsu.reader.domain.ReaderColorFilter @@ -191,11 +192,13 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) { var appPassword: String? get() = prefs.getString(KEY_APP_PASSWORD, null) set(value) = prefs.edit { - if (value != null) putString(KEY_APP_PASSWORD, value) else remove( - KEY_APP_PASSWORD, - ) + if (value != null) putString(KEY_APP_PASSWORD, value) else remove(KEY_APP_PASSWORD) } + var isAppPasswordNumeric: Boolean + get() = prefs.getBoolean(KEY_APP_PASSWORD_NUMERIC, false) + set(value) = prefs.edit { putBoolean(KEY_APP_PASSWORD_NUMERIC, value) } + val isLoggingEnabled: Boolean get() = prefs.getBoolean(KEY_LOGGING_ENABLED, false) @@ -528,6 +531,7 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) { const val KEY_READER_MODE = "reader_mode" const val KEY_READER_MODE_DETECT = "reader_mode_detect" const val KEY_APP_PASSWORD = "app_password" + const val KEY_APP_PASSWORD_NUMERIC = "app_password_num" const val KEY_PROTECT_APP = "protect_app" const val KEY_PROTECT_APP_BIOMETRIC = "protect_app_bio" const val KEY_APP_VERSION = "app_version" diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/protect/ProtectActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/protect/ProtectActivity.kt index ff6bf07bf..8ad250394 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/protect/ProtectActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/protect/ProtectActivity.kt @@ -44,6 +44,12 @@ class ProtectActivity : viewBinding.buttonNext.setOnClickListener(this) viewBinding.buttonCancel.setOnClickListener(this) + viewBinding.editPassword.inputType = if (viewModel.isNumericPassword) { + EditorInfo.TYPE_CLASS_NUMBER or EditorInfo.TYPE_NUMBER_VARIATION_PASSWORD + } else { + EditorInfo.TYPE_CLASS_TEXT or EditorInfo.TYPE_TEXT_VARIATION_PASSWORD + } + viewModel.onError.observeEvent(this, this::onError) viewModel.isLoading.observe(this, this::onLoadingStateChanged) viewModel.onUnlockSuccess.observeEvent(this) { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/protect/ProtectViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/protect/ProtectViewModel.kt index 7f0d8f5b5..b9a407a4e 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/protect/ProtectViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/protect/ProtectViewModel.kt @@ -8,6 +8,7 @@ import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.ui.BaseViewModel import org.koitharu.kotatsu.core.util.ext.MutableEventFlow import org.koitharu.kotatsu.core.util.ext.call +import org.koitharu.kotatsu.parsers.util.isNumeric import org.koitharu.kotatsu.parsers.util.md5 import javax.inject.Inject @@ -26,6 +27,9 @@ class ProtectViewModel @Inject constructor( val isBiometricEnabled get() = settings.isBiometricProtectionEnabled + val isNumericPassword + get() = settings.isAppPasswordNumeric + fun tryUnlock(password: String) { if (job?.isActive == true) { return diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/protect/ProtectSetupViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/protect/ProtectSetupViewModel.kt index 73b5597b3..95180d359 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/protect/ProtectSetupViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/protect/ProtectSetupViewModel.kt @@ -12,6 +12,7 @@ import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.ui.BaseViewModel import org.koitharu.kotatsu.core.util.ext.MutableEventFlow import org.koitharu.kotatsu.core.util.ext.call +import org.koitharu.kotatsu.parsers.util.isNumeric import org.koitharu.kotatsu.parsers.util.md5 import javax.inject.Inject @@ -39,6 +40,7 @@ class ProtectSetupViewModel @Inject constructor( } else { if (firstPassword.value == password) { settings.appPassword = password.md5() + settings.isAppPasswordNumeric = password.isNumeric() onPasswordSet.call(Unit) } else { onPasswordMismatch.call(Unit) From 640fe272c86c0c5408f50a8de7f1e3d883597ef6 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Mon, 4 Mar 2024 19:58:46 +0200 Subject: [PATCH 2/8] Fix passing intent data to ViewModels (cherry picked from commit 094b0f694caf2370f8752f564c77864e54907a6d) --- .../main/kotlin/org/koitharu/kotatsu/core/ui/BaseActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BaseActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BaseActivity.kt index 7e889dd46..9342e30cf 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BaseActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/BaseActivity.kt @@ -60,11 +60,11 @@ abstract class BaseActivity : if (isAmoledTheme) { setTheme(R.style.ThemeOverlay_Kotatsu_Amoled) } + putDataToExtras(intent) super.onCreate(savedInstanceState) WindowCompat.setDecorFitsSystemWindows(window, false) insetsDelegate.handleImeInsets = true insetsDelegate.addInsetsListener(this) - putDataToExtras(intent) } override fun onPostCreate(savedInstanceState: Bundle?) { From f97d4d452fe7d39ae78e68f3b4967f62e89c6c55 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Mon, 4 Mar 2024 20:03:52 +0200 Subject: [PATCH 3/8] Fix null url crash (cherry picked from commit 1e39ae48ecdb52fbd375cf8657e44618c46cc300) --- .../koitharu/kotatsu/browser/BrowserActivity.kt | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/browser/BrowserActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/browser/BrowserActivity.kt index 15c03582d..35a3413e7 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/browser/BrowserActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/browser/BrowserActivity.kt @@ -14,6 +14,7 @@ import androidx.core.view.isVisible import androidx.core.view.updatePadding import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.ui.BaseActivity +import org.koitharu.kotatsu.core.util.ext.toUriOrNull import org.koitharu.kotatsu.databinding.ActivityBrowserBinding import org.koitharu.kotatsu.parsers.network.UserAgents import com.google.android.material.R as materialR @@ -80,11 +81,14 @@ class BrowserActivity : BaseActivity(), BrowserCallback } R.id.action_browser -> { - val intent = Intent(Intent.ACTION_VIEW) - intent.data = Uri.parse(viewBinding.webView.url) - try { - startActivity(Intent.createChooser(intent, item.title)) - } catch (_: ActivityNotFoundException) { + val url = viewBinding.webView.url?.toUriOrNull() + if (url != null) { + val intent = Intent(Intent.ACTION_VIEW) + intent.data = url + try { + startActivity(Intent.createChooser(intent, item.title)) + } catch (_: ActivityNotFoundException) { + } } true } From b2c5ec50825043c7aa483328252d9e657f22697a Mon Sep 17 00:00:00 2001 From: Kaorun Date: Sat, 2 Mar 2024 11:31:32 +0300 Subject: [PATCH 4/8] Fixed hover color (cherry picked from commit 63470db6f57de41303829bc5bd91d3b9fb831a9e) --- app/src/main/res/color-v23/selector_overlay.xml | 2 +- app/src/main/res/color/selector_overlay.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/color-v23/selector_overlay.xml b/app/src/main/res/color-v23/selector_overlay.xml index 538011ef8..ef98d7d9e 100644 --- a/app/src/main/res/color-v23/selector_overlay.xml +++ b/app/src/main/res/color-v23/selector_overlay.xml @@ -1,4 +1,4 @@ - + diff --git a/app/src/main/res/color/selector_overlay.xml b/app/src/main/res/color/selector_overlay.xml index 515d4a190..a4b34206f 100644 --- a/app/src/main/res/color/selector_overlay.xml +++ b/app/src/main/res/color/selector_overlay.xml @@ -1,5 +1,5 @@ - + From 750bf11fdce86578c0dbb2f205c5cc875d6e9f5c Mon Sep 17 00:00:00 2001 From: Koitharu Date: Wed, 6 Mar 2024 16:16:37 +0200 Subject: [PATCH 5/8] Update app/src/main/res/color-v23/selector_overlay.xml (cherry picked from commit ba88ca8234fda84450f5fe5bf87847991e3811db) --- app/src/main/res/color-v23/selector_overlay.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/color-v23/selector_overlay.xml b/app/src/main/res/color-v23/selector_overlay.xml index ef98d7d9e..c2d5a252d 100644 --- a/app/src/main/res/color-v23/selector_overlay.xml +++ b/app/src/main/res/color-v23/selector_overlay.xml @@ -1,4 +1,4 @@ - + From 3c54fe4217f45c14c12df07dd4721e74fc040b35 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Wed, 6 Mar 2024 16:18:27 +0200 Subject: [PATCH 6/8] Fix crash on text selection (cherry picked from commit 65abfc3a49b1b288ce0b12aec9742ebaee84917d) --- app/src/main/res/layout/sheet_scrobbling.xml | 2 +- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/layout/sheet_scrobbling.xml b/app/src/main/res/layout/sheet_scrobbling.xml index 9728fdfdf..b61b10051 100644 --- a/app/src/main/res/layout/sheet_scrobbling.xml +++ b/app/src/main/res/layout/sheet_scrobbling.xml @@ -112,7 +112,7 @@ app:barrierMargin="8dp" app:constraint_referenced_ids="imageView_cover,spinner_status" /> - Date: Sat, 9 Mar 2024 13:05:02 +0200 Subject: [PATCH 7/8] Update parsers --- app/build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index b65af9ece..16552e455 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -16,8 +16,8 @@ android { applicationId 'org.koitharu.kotatsu' minSdk = 21 targetSdk = 34 - versionCode = 626 - versionName = '6.7.4' + versionCode = 627 + versionName = '6.7.5' generatedDensities = [] testInstrumentationRunner 'org.koitharu.kotatsu.HiltTestRunner' ksp { @@ -82,7 +82,7 @@ afterEvaluate { } dependencies { //noinspection GradleDependency - implementation('com.github.KotatsuApp:kotatsu-parsers:103f578c61') { + implementation('com.github.KotatsuApp:kotatsu-parsers:0aa4ea01f7') { exclude group: 'org.json', module: 'json' } From 8c2bff78f70a490482755882750dfd38e9be66ec Mon Sep 17 00:00:00 2001 From: Koitharu Date: Sat, 9 Mar 2024 14:27:12 +0200 Subject: [PATCH 8/8] Fix chapters duplication --- app/build.gradle | 2 +- .../kotatsu/reader/domain/ChapterPages.kt | 19 ++++++++++++++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 16552e455..9db761d08 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -82,7 +82,7 @@ afterEvaluate { } dependencies { //noinspection GradleDependency - implementation('com.github.KotatsuApp:kotatsu-parsers:0aa4ea01f7') { + implementation('com.github.KotatsuApp:kotatsu-parsers:b7613606c0') { exclude group: 'org.json', module: 'json' } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/ChapterPages.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/ChapterPages.kt index 7175f53f2..c86159033 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/ChapterPages.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/ChapterPages.kt @@ -14,6 +14,7 @@ class ChapterPages private constructor(private val pages: ArrayDeque val chaptersSize: Int get() = indices.size() + @Synchronized fun removeFirst() { val chapterId = pages.first().chapterId indices.remove(chapterId) @@ -25,6 +26,7 @@ class ChapterPages private constructor(private val pages: ArrayDeque shiftIndices(delta) } + @Synchronized fun removeLast() { val chapterId = pages.last().chapterId indices.remove(chapterId) @@ -33,17 +35,28 @@ class ChapterPages private constructor(private val pages: ArrayDeque } } - fun addLast(id: Long, newPages: List) { + @Synchronized + fun addLast(id: Long, newPages: List): Boolean { + if (id in indices) { + return false + } indices.put(id, pages.size until (pages.size + newPages.size)) pages.addAll(newPages) + return true } - fun addFirst(id: Long, newPages: List) { + @Synchronized + fun addFirst(id: Long, newPages: List): Boolean { + if (id in indices) { + return false + } shiftIndices(newPages.size) indices.put(id, newPages.indices) pages.addAll(0, newPages) + return true } + @Synchronized fun clear() { indices.clear() pages.clear() @@ -58,7 +71,7 @@ class ChapterPages private constructor(private val pages: ArrayDeque return pages.subList(range.first, range.last + 1) } - operator fun contains(chapterId: Long) = indices.contains(chapterId) + operator fun contains(chapterId: Long) = chapterId in indices private fun shiftIndices(delta: Int) { for (i in 0 until indices.size()) {