From 67c24ebf5e4ff4e5bcf55ff8ddbd43a1c81386f3 Mon Sep 17 00:00:00 2001 From: Daniel Collingwood <82693586+danzuep@users.noreply.github.com> Date: Sat, 28 Mar 2026 20:46:38 +0800 Subject: [PATCH 1/4] Added Dockerfile and devcontainer.json for VS Code --- .devcontainer/Dockerfile | 50 ++++++++ .devcontainer/devcontainer.json | 44 +++++++ .gitignore | 1 + .vscode/Joshua.code-workspace | 14 +++ README.md | 20 +++- docs/RELEASING.md | 8 ++ docs/SETUP.md | 201 ++++++++++++++++++++++++++++++++ 7 files changed, 332 insertions(+), 6 deletions(-) create mode 100644 .devcontainer/Dockerfile create mode 100644 .devcontainer/devcontainer.json create mode 100644 .vscode/Joshua.code-workspace create mode 100644 docs/SETUP.md diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 000000000..79cf7f6df --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,50 @@ +# Devcontainer image for building the Android app. +FROM mcr.microsoft.com/devcontainers/java + +USER root + +# Android SDK locations +ENV ANDROID_PLATFORM=android-36 +ENV ANDROID_BUILD_TOOLS=36.0.0 +ENV ANDROID_SDK_ROOT=/opt/android-sdk +ENV ANDROID_HOME=/opt/android-sdk +ENV ANDROID_CMDLINE_TOOLS_ROOT=/opt/android-sdk/cmdline-tools/latest +ENV PATH=${PATH}:${ANDROID_CMDLINE_TOOLS_ROOT}/bin:${ANDROID_HOME}/platform-tools + +# Remove broken/optional third-party apt sources that may be present in the base image/features +RUN rm -f /etc/apt/sources.list.d/yarn.list \ + /etc/apt/sources.list.d/yarn*.list \ + /etc/apt/sources.list.d/archive_uri-https_dl_yarnpkg_com_debian-bookworm.list || true + +# Install packages required for Android/Gradle workflows +RUN apt-get update \ + && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + curl \ + unzip \ + ca-certificates \ + git \ + bash \ + libc6 \ + libstdc++6 \ + libgcc1 \ + libbz2-1.0 \ + libncurses6 \ + zlib1g \ + # && uv tool install specify-cli --from git+https://github.com/github/spec-kit.git \ + && rm -rf /var/lib/apt/lists/* + +# Install Android command line tools +RUN mkdir -p ${ANDROID_HOME}/cmdline-tools \ + && curl -fsSL https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip -o /tmp/cmdline-tools.zip \ + && mkdir -p /tmp/android-cmdline-tools \ + && unzip -q /tmp/cmdline-tools.zip -d /tmp/android-cmdline-tools \ + && mv /tmp/android-cmdline-tools/cmdline-tools ${ANDROID_HOME}/cmdline-tools/latest \ + && rm -rf /tmp/cmdline-tools.zip /tmp/android-cmdline-tools \ + && chown -R vscode:vscode ${ANDROID_HOME} + +# Accept licenses and install commonly needed Android SDK components +RUN yes | sdkmanager --sdk_root=${ANDROID_HOME} --licenses > /dev/null || true \ + && sdkmanager --sdk_root=${ANDROID_HOME} \ + "platform-tools" \ + "build-tools;${ANDROID_BUILD_TOOLS}" \ + "platforms;${ANDROID_PLATFORM}" diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000..1e22dd4aa --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,44 @@ +{ + "name": "Kotlin Multiplatform Development", + "build": { + "dockerfile": "Dockerfile" + }, + "features": { + "ghcr.io/devcontainers/features/git:1": {}, + "ghcr.io/devcontainers/features/java:1": { + "version": "25", + "installGradle": "true", + "gradleVersion": "9.4" + }, + "ghcr.io/devcontainers-extra/features/uv:1": { + "version": "latest" + } + }, + "customizations": { + "vscode": { + "settings": { + "java.import.generatesMetadataFilesAtProjectRoot": false, + "java.import.gradle.wrapper.enabled": true, + "kotlin.languageServer.enabled": true, + "editor.formatOnSave": true, + "files.exclude": { + "**/.gradle": true, + "**/build": true + } + }, + "extensions": [ + "fwcd.kotlin", + "vscjava.vscode-java-pack", + "vscjava.vscode-gradle", + "redhat.vscode-yaml", + "GitHub.copilot" + ] + } + }, + "containerEnv": { + "ANDROID_HOME": "/opt/android-sdk", + "ANDROID_SDK_ROOT": "/opt/android-sdk" + }, + // "postCreateCommand": "bash -lc 'uv tool install specify-cli --from git+https://github.com/github/spec-kit.git && gradle --version'", + "remoteUser": "vscode" // More info: https://aka.ms/dev-containers-non-root. +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 904d0c1c5..c8d082931 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ build gen out .externalNativeBuild +.kotlin # Mac .DS_Store diff --git a/.vscode/Joshua.code-workspace b/.vscode/Joshua.code-workspace new file mode 100644 index 000000000..093ae58b6 --- /dev/null +++ b/.vscode/Joshua.code-workspace @@ -0,0 +1,14 @@ +{ + "folders": [ + { + "path": ".." + } + ], + "settings": { + "chat.tools.terminal.autoApprove": { + "gradle": true, + "./gradlew": true, + ".\\gradlew.bat": true + } + } +} \ No newline at end of file diff --git a/README.md b/README.md index 2139f7620..674e5eef2 100644 --- a/README.md +++ b/README.md @@ -4,12 +4,20 @@ [![API](https://img.shields.io/badge/API-19%2B-blue.svg?style=flat)](https://www.android.com/versions/kit-kat-4-4/) [![Apache License](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg?style=flat)](https://www.apache.org/licenses/LICENSE-2.0) +This project was forked [here](https://github.com/danzuep/Joshua) after the [original](https://github.com/xizzhu/Joshua) appears to have been abandoned. My goal was to work with the [WEB](https://ebible.org/engwebu/MRK01.htm) translator create a [FOSS](https://f-droid.org/) app for the many public domain licenced works he has, but I've only gotten as far as updating it from JDK 11 to build in a JDK 25 devcontainer. Some UI unit tests are still failing, feel free to pick some and fix them, but the backend should all be working. + Joshua ====== -A simple and easy-to-use Bible reader for your Android device, with minimalist design. It supports offline reading, multi-versions, full-text search, and many other features, while maintaining a small download and install size. +A simple and easy-to-use Bible reader for your Android device, with minimalist design. It supports offline reading, multi-versions, full-text search, and many other features, while maintaining a small download and install size. You can download the APK from [Play Store](https://play.google.com/store/apps/details?id=me.xizzhu.android.joshua) or [here](https://github.com/xizzhu/Joshua/releases). Recent changes are listed [here](docs/CHANGELOG.md). Feel free to request new features or report bugs [here](https://github.com/xizzhu/Joshua/issues). +You can download the APK from [GitHub](https://github.com/danzuep/Joshua/releases). Recent changes are listed [here](docs/CHANGELOG.md). Feel free to request new features or report bugs [here](https://github.com/danzuep/Joshua/issues). + + +A simple and easy-to-use Bible reader for your Android device, with minimalist design. It supports offline reading, multi-versions, full-text search, and many other features, while maintaining a small download and install size. + +~~You can download the APK from [Play Store](https://play.google.com/store/apps/details?id=me.xizzhu.android.joshua) or [here](https://github.com/xizzhu/Joshua/releases). Recent changes are listed [here](docs/CHANGELOG.md). Feel free to request new features or report bugs [here](https://github.com/xizzhu/Joshua/issues).~~ Main Features ------------- @@ -27,11 +35,11 @@ Main Features We currently support tens of different translations, with more added regularly. A full list of available translations can be found [here](docs/TRANSLATIONS.md). -Donations ---------- -If you would like to support this project, feel free to donate. Your support is highly appreciated. Thank you! -* [PayPal](https://paypal.me/xizzhu) -* [Venmo](https://www.venmo.com/u/xizzhu) +~~Donations~~ +~~---------~~ +~~If you would like to support this project, feel free to donate. Your support is highly appreciated. Thank you!~~ +~~* [PayPal](https://paypal.me/xizzhu)~~ +~~* [Venmo](https://www.venmo.com/u/xizzhu)~~ License ------- diff --git a/docs/RELEASING.md b/docs/RELEASING.md index 92d22e4bb..e581b9282 100644 --- a/docs/RELEASING.md +++ b/docs/RELEASING.md @@ -8,6 +8,14 @@ Releasing 5. `./gradlew clean assembleRelease` 6. `git push && git push --tags` +Debug in a dev container: +```shell +# ./gradlew :app:kaptDebugKotlin --stacktrace --no-daemon -q +# ./gradlew :app:dependencyInsight --dependency kotlin-stdlib --configuration debugCompileClasspath --no-daemon +gradle clean assembleDebug --stacktrace --full-stacktrace --no-daemon --console=plain 2>&1 | tee build/full.log +cat build/full.log | awk 'BEGIN{r=0} /KaptBaseError/{k=NR} {a[NR]=$0} END{for(i=k-1;i>=1;i--) if (a[i] ~ /Caused by: /) {start=i; break} if(!start) start=k-200; for(i=start;i<=k+20;i++) if(a[i]) print a[i]}' build/full.log +``` + We use [Semantic Versioning](https://semver.org/). Prerequisites diff --git a/docs/SETUP.md b/docs/SETUP.md new file mode 100644 index 000000000..b250e7f53 --- /dev/null +++ b/docs/SETUP.md @@ -0,0 +1,201 @@ +# Quickstart: Joshua Bible Reader + +## Prerequisites +- Visual Studio Code with Dev Containers extension +- Docker + +## Setup +1. Clone the repository: + ```bash + git clone https://github.com/danzuep/Joshua.git + cd Joshua + ``` + +2. Open in VS Code: + - File > Open Folder > Select the Joshua directory + - When prompted, click "Reopen in Container" to start the devcontainer + +3. Build the project: + ```bash + ./gradlew assembleDebug + ``` + +## Running the App +1. Connect an Android device or start an emulator (API 34+) +2. Run the app: + ```bash + ./gradlew installDebug + ``` + Or use VS Code's Run and Debug panel + +## First Use +1. The app will show a list of available translations +2. Download a translation (e.g., KJV) - requires internet +3. Once downloaded, you can read offline +4. Try searching for "love" to see search functionality +5. Bookmark a verse by long-pressing + +## Development +- Unit tests: `./gradlew test` +- Integration tests: `./gradlew connectedAndroidTest` +- Lint: `./gradlew lint` + +## Troubleshooting +- If build fails, check that devcontainer is running and Android SDK is available +- For emulator issues, ensure KVM is enabled in the container +- Network issues: Check internet for translation downloads + +## Local environment setup (PowerShell) + +The devcontainer provides these main tools: + +- Git +- Java 25 +- Gradle 9.4 +- `uv` +- Android SDK command line tools +- Android platform tools +- Android build tools 36.0.0 +- Android SDK platform `android-36` + +Below is a PowerShell-based setup sequence for a local Windows environment. + +### 1) Install required tools + +#### Install PowerShell and Git +```powershell +winget install -e --id Microsoft.PowerShell +winget install -e --id Git.Git +``` + +#### Install Java 25 +```powershell +# winget search Microsoft.OpenJDK +winget install -e --id Microsoft.OpenJDK.25 +``` + +#### Install Gradle 9.4 +```powershell +# winget search Gradle +winget install -e --id Gradle.Gradle +``` + +Here’s an alternative PowerShell (`pwsh`) way to download and install Gradle 9.4.1 from the ZIP URL. + +```powershell +$gradleUrl = 'https://services.gradle.org/distributions/gradle-9.4.1-bin.zip' +$installDir = "${env:USERPROFILE}/tools/gradle" +$tempZip = "${env:TEMP}gradle-9.4.1-bin.zip" +New-Item -ItemType Directory -Force -Path $installDir | Out-Null +Invoke-WebRequest -Uri $gradleUrl -OutFile $tempZip +Expand-Archive -Path $tempZip -DestinationPath $installDir -Force +``` + +This will create: + +```powershell +%USERPROFILE%\tools\gradle\gradle-9.4.1\ +``` + +then add Gradle to your PATH for the current session: + +```powershell +$env:Path = "$(Join-Path $installDir 'gradle-9.4.1\bin');$env:Path" +``` + +or optionally add it permanently for your user: + +```powershell +$gradleBin = Join-Path $installDir 'gradle-9.4.1\bin' +$userPath = [Environment]::GetEnvironmentVariable('Path', 'User') + +if ($userPath -notlike "*$gradleBin*") { + [Environment]::SetEnvironmentVariable('Path', "$userPath;$gradleBin", 'User') +} +``` + +#### Install `uv` for Spec-Driven Development +```powershell +# powershell -ExecutionPolicy Bypass -c "irm https://astral.sh/uv/install.ps1 | iex" +winget install -e --id astral-sh.uv +uv tool install specify-cli --from git+https://github.com/github/spec-kit.git +``` + +### 2) Install Android SDK command line tools +```powershell +# winget search Google.PlatformTools +winget install -e --id Google.PlatformTools +``` + +Alternatively, create a local SDK directory, then download and extract the Android command line tools: + +```powershell +$env:ANDROID_HOME = "C:\Android\Sdk" +$env:ANDROID_SDK_ROOT = $env:ANDROID_HOME +New-Item -ItemType Directory -Force -Path $env:ANDROID_HOME | Out-Null + +$androidToolsUrl = "https://dl.google.com/android/repository/commandlinetools-win-11076708_latest.zip" +$zip = "$env:TEMP\cmdline-tools.zip" +$extract = "$env:TEMP\android-cmdline-tools" + +Invoke-WebRequest -Uri $androidToolsUrl -OutFile $zip +New-Item -ItemType Directory -Force -Path $extract | Out-Null +Expand-Archive -Path $zip -DestinationPath $extract -Force + +New-Item -ItemType Directory -Force -Path "$env:ANDROID_HOME\cmdline-tools" | Out-Null +Move-Item -Force "$extract\cmdline-tools" "$env:ANDROID_HOME\cmdline-tools\latest" + +Remove-Item -Recurse -Force $zip, $extract +``` + +### 3) Add Android tools to your PATH + +For the current PowerShell session: + +```powershell +$env:PATH = "$env:ANDROID_HOME\cmdline-tools\latest\bin;$env:ANDROID_HOME\platform-tools;$env:PATH" +``` + +To persist it for your user account: + +```powershell +[Environment]::SetEnvironmentVariable( + "PATH", + "$env:ANDROID_HOME\cmdline-tools\latest\bin;$env:ANDROID_HOME\platform-tools;" + [Environment]::GetEnvironmentVariable("PATH", "User"), + "User" +) +``` + +### 4) Accept Android SDK licenses and install SDK components + +```powershell +sdkmanager --sdk_root=$env:ANDROID_HOME --licenses +sdkmanager --sdk_root=$env:ANDROID_HOME ` + "platform-tools" ` + "build-tools;36.0.0" ` + "platforms;android-36" +``` + +### 5) Verify the setup + +```powershell +git --version +java --version +gradle --version +uv --version +sdkmanager --list | Select-Object -First 20 +``` + +### 6) Verify the build +```powershell +gradle assembleDebug +gradle clean assembleDebug --stacktrace --full-stacktrace --no-daemon --console=plain 2>&1 | tee .gradle/full.log +cat .gradle/full.log | awk 'BEGIN{r=0} /KaptBaseError/{k=NR} {a[NR]=$0} END{for(i=k-1;i>=1;i--) if (a[i] ~ /Caused by: /) {start=i; break} if(!start) start=k-200; for(i=start;i<=k+20;i++) if(a[i]) print a[i]}' .gradle/full.log +``` + +### Notes + +- The devcontainer uses Linux paths and installs packages with `apt`, so the local Windows setup is equivalent rather than identical. +- If you want a closer match on Windows, consider using WSL2 and following the same steps inside a Linux shell. +- Make sure `JAVA_HOME` is set if your local tooling requires it. +``` \ No newline at end of file From 4a31209cbad068dd86d51ac2a012b421951e4dbf Mon Sep 17 00:00:00 2001 From: Daniel Collingwood <82693586+danzuep@users.noreply.github.com> Date: Sat, 28 Mar 2026 20:46:04 +0800 Subject: [PATCH 2/4] JavaVersion.VERSION_25 gradleVersion 9.4 Replaced the custom logger library with Kermit grep -r "android.logger\|Log\." app/src --include="*.kt" KSP added, kapt and kover removed Dagger cannot access Kotlin protected fields Fixed Hilt, Firebase bom and classpath --- app/build.gradle.kts | 72 +++++++----------- app/proguard-rules.pro | 12 ++- .../kotlin/me/xizzhu/android/joshua/App.kt | 19 +++-- .../me/xizzhu/android/joshua/Navigator.kt | 7 +- .../annotated/AnnotatedVerseViewModel.kt | 12 +-- .../joshua/core/BibleReadingManager.kt | 4 +- .../joshua/core/ReadingProgressManager.kt | 4 +- .../core/repository/BibleReadingRepository.kt | 8 +- .../repository/CrossReferencesRepository.kt | 8 +- .../core/repository/SettingsRepository.kt | 4 +- .../core/repository/StrongNumberRepository.kt | 8 +- .../core/repository/TranslationRepository.kt | 24 +++--- .../repository/VerseAnnotationRepository.kt | 4 +- .../local/android/db/StrongNumberWordDao.kt | 4 +- .../local/android/db/TranslationDao.kt | 6 +- .../remote/android/AndroidHttpService.kt | 8 +- .../repository/remote/android/JsonParser.kt | 18 ++--- .../android/joshua/infra/BaseActivity.kt | 22 +++--- .../android/joshua/infra/BaseActivityV2.kt | 22 +++--- .../android/joshua/infra/BaseFragment.kt | 22 +++--- .../progress/ReadingProgressViewModel.kt | 6 +- .../android/joshua/reading/ReadingActivity.kt | 16 ++-- .../joshua/reading/ReadingViewModel.kt | 18 ++--- .../chapter/ChapterSelectionViewModel.kt | 4 +- .../toolbar/ReadingToolbarViewModel.kt | 10 +-- .../joshua/search/RecentSearchProvider.kt | 2 +- .../android/joshua/search/SearchViewModel.kt | 10 +-- .../joshua/settings/SettingsActivity.kt | 6 +- .../joshua/settings/SettingsViewModel.kt | 16 ++-- .../strongnumber/StrongNumberViewModel.kt | 8 +- .../translations/TranslationsViewModel.kt | 10 +-- .../me/xizzhu/android/joshua/ui/View.kt | 4 +- .../me/xizzhu/android/joshua/utils/Context.kt | 4 +- .../kotlin/me/xizzhu/android/joshua/App.kt | 5 +- .../me/xizzhu/android/joshua/NavigatorTest.kt | 5 +- build.gradle.kts | 7 +- buildSrc/src/main/kotlin/Configurations.kt | 53 +++++++------ gradle.properties | 11 +-- gradle/wrapper/gradle-wrapper.jar | Bin 61574 -> 48966 bytes gradle/wrapper/gradle-wrapper.properties | 3 +- gradlew | 40 +++++----- gradlew.bat | 25 +++--- 42 files changed, 269 insertions(+), 282 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index d7f23599b..fe83e61a6 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -18,11 +18,10 @@ import java.util.Properties plugins { id("com.android.application") - id("com.google.firebase.crashlytics") - id("com.google.gms.google-services") + //id("com.google.firebase.crashlytics") + //id("com.google.gms.google-services") + id(Dependencies.Kotlin.Ksp.plugin) id(Dependencies.Hilt.plugin) - kotlin("android") - kotlin("kapt") } android { @@ -32,8 +31,10 @@ android { sourceCompatibility = Versions.java targetCompatibility = Versions.java } - kotlinOptions { - jvmTarget = Versions.Kotlin.jvmTarget + tasks.withType { + compilerOptions { + jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.fromTarget(Versions.Kotlin.jvmTarget)) + } } buildToolsVersion = Versions.Sdk.buildTools @@ -48,21 +49,19 @@ android { versionCode = Versions.App.code versionName = Versions.App.name - multiDexEnabled = true - - resourceConfigurations.addAll(Configurations.supportedLocales) + androidResources.localeFilters.addAll(Configurations.supportedLocales) } buildFeatures { viewBinding = true + buildConfig = true } sourceSets { - getByName("main").java.srcDirs("src/main/kotlin") - getByName("debug").java.srcDirs("src/debug/kotlin") - getByName("release").java.srcDirs("src/release/kotlin") - - getByName("test").java.srcDirs("src/test/kotlin") + getByName("main") { java.setSrcDirs(setOf("src/main/kotlin")) } + getByName("debug") { java.setSrcDirs(setOf("src/debug/kotlin")) } + getByName("release") { java.setSrcDirs(setOf("src/release/kotlin")) } + getByName("test") { java.setSrcDirs(setOf("src/test/kotlin")) } } signingConfigs { @@ -81,18 +80,23 @@ android { } buildTypes { - getByName("release") { + release { isMinifyEnabled = true isShrinkResources = true signingConfig = signingConfigs.getByName("release") proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") } - getByName("debug") { + debug { applicationIdSuffix = ".debug" versionNameSuffix = " debug" } } + compileOptions { + sourceCompatibility = Versions.java + targetCompatibility = Versions.java + } + testOptions { unitTests.isIncludeAndroidResources = true unitTests.isReturnDefaultValues = true @@ -102,31 +106,14 @@ android { } } - packagingOptions { - resources.excludes.addAll(listOf( - "META-INF/atomicfu.kotlin_module", "META-INF/AL2.0", "META-INF/LGPL2.1", "META-INF/licenses/*", - - // https://github.com/Kotlin/kotlinx.coroutines/tree/master/kotlinx-coroutines-debug#debug-agent-and-android - "win32-x86/attach_hotspot_windows.dll", "win32-x86-64/attach_hotspot_windows.dll" - )) - } -} - -// allow references to generated code -kapt { - correctErrorTypes = true -} - -tasks.withType { - kotlinOptions { - jvmTarget = Versions.Kotlin.jvmTarget + packaging { + resources.excludes.add("**/NOTNOTICE") + jniLibs.excludes.add("**/libshared.so") } } dependencies { implementation(Dependencies.Kotlin.coroutines) - - debugImplementation(Dependencies.AndroidX.multidex) implementation(Dependencies.AndroidX.activity) implementation(Dependencies.AndroidX.annotation) implementation(Dependencies.AndroidX.appCompat) @@ -147,10 +134,10 @@ dependencies { releaseImplementation(Dependencies.Firebase.Crashlytics.crashlytics) implementation(Dependencies.Hilt.android) - kapt(Dependencies.Hilt.compiler) + ksp(Dependencies.Hilt.compiler) implementation(Dependencies.ask) - implementation(Dependencies.logger) + implementation(Dependencies.kermit) implementation(Dependencies.materialComponent) testImplementation(Dependencies.Kotlin.test) @@ -158,15 +145,8 @@ dependencies { testImplementation(Dependencies.Kotlin.reflect) debugImplementation(Dependencies.AndroidX.Fragment.test) testImplementation(Dependencies.AndroidX.Test.core) - testImplementation("androidx.test.ext:junit:1.1.4") - kaptTest(Dependencies.Hilt.compiler) + testImplementation(Dependencies.AndroidX.Test.junit) testImplementation(Dependencies.Hilt.test) testImplementation(Dependencies.mockk) testImplementation(Dependencies.robolectric) } - -kover { - instrumentation { - excludeTasks.add("testDebugUnitTest") - } -} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index e8fbf4547..8af225a21 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -1,4 +1,8 @@ -# Crashlytics -# https://firebase.google.com/docs/crashlytics/get-deobfuscated-reports?platform=android --keepattributes SourceFile,LineNumberTable --keep public class * extends java.lang.Exception + +# Add project-specific ProGuard rules here. +# By default, the flags are kept minimal. + +## Crashlytics +## https://firebase.google.com/docs/crashlytics/get-deobfuscated-reports?platform=android +#-keepattributes SourceFile,LineNumberTable +#-keep public class * extends java.lang.Exception \ No newline at end of file diff --git a/app/src/debug/kotlin/me/xizzhu/android/joshua/App.kt b/app/src/debug/kotlin/me/xizzhu/android/joshua/App.kt index 83d07393f..2d9868519 100644 --- a/app/src/debug/kotlin/me/xizzhu/android/joshua/App.kt +++ b/app/src/debug/kotlin/me/xizzhu/android/joshua/App.kt @@ -16,19 +16,24 @@ package me.xizzhu.android.joshua +import android.app.Application import android.os.StrictMode import androidx.annotation.CallSuper -import androidx.multidex.MultiDexApplication -import me.xizzhu.android.logger.Log -import me.xizzhu.android.logger.LogcatLogger +import co.touchlab.kermit.Logger -abstract class BaseApp : MultiDexApplication() { +abstract class BaseApp : Application() { @CallSuper override fun onCreate() { super.onCreate() - StrictMode.enableDefaults() - - Log.addLogger(LogcatLogger()) + setupGlobalLogger() } } + +fun setupGlobalLogger() { + // Configure the global logger instance + Logger.setLogWriters(co.touchlab.kermit.platformLogWriter()) + + // Set an optional default tag for the global logger + Logger.withTag("Joshua") +} \ No newline at end of file diff --git a/app/src/main/kotlin/me/xizzhu/android/joshua/Navigator.kt b/app/src/main/kotlin/me/xizzhu/android/joshua/Navigator.kt index 2110d1cee..131fdd561 100644 --- a/app/src/main/kotlin/me/xizzhu/android/joshua/Navigator.kt +++ b/app/src/main/kotlin/me/xizzhu/android/joshua/Navigator.kt @@ -20,6 +20,7 @@ import android.app.Activity import android.content.Intent import android.net.Uri import android.os.Bundle +import androidx.activity.ComponentActivity import androidx.annotation.IntDef import me.xizzhu.android.joshua.annotated.bookmarks.BookmarksActivity import me.xizzhu.android.joshua.annotated.highlights.HighlightsActivity @@ -74,6 +75,10 @@ class Navigator { } fun goBack(activity: Activity) { - activity.finish() + if (activity is ComponentActivity) { + activity.onBackPressedDispatcher.onBackPressed() + } else { + activity.finish() + } } } diff --git a/app/src/main/kotlin/me/xizzhu/android/joshua/annotated/AnnotatedVerseViewModel.kt b/app/src/main/kotlin/me/xizzhu/android/joshua/annotated/AnnotatedVerseViewModel.kt index 84f6db228..7203c3b74 100644 --- a/app/src/main/kotlin/me/xizzhu/android/joshua/annotated/AnnotatedVerseViewModel.kt +++ b/app/src/main/kotlin/me/xizzhu/android/joshua/annotated/AnnotatedVerseViewModel.kt @@ -39,7 +39,7 @@ import me.xizzhu.android.joshua.core.VerseIndex import me.xizzhu.android.joshua.core.provider.TimeProvider import me.xizzhu.android.joshua.infra.BaseViewModelV2 import me.xizzhu.android.joshua.utils.firstNotEmpty -import me.xizzhu.android.logger.Log +import co.touchlab.kermit.Logger import java.util.Calendar import kotlin.collections.ArrayList import me.xizzhu.android.joshua.preview.Preview @@ -93,7 +93,7 @@ abstract class AnnotatedVerseViewModel( val items = loadAnnotatedVerses(settings, currentTranslation, sortOrder) updateViewState { it.copy(loading = false, items = items) } }.onFailure { e -> - Log.e(tag, "Error occurred while loading annotated verses", e) + Logger.withTag(tag).e(e) { "Error occurred while loading annotated verses" } updateViewState { it.copy(loading = false, error = ViewState.Error.AnnotatedVersesLoadingError) } } }.flowOn(coroutineDispatcherProvider.default).launchIn(viewModelScope) @@ -112,7 +112,7 @@ abstract class AnnotatedVerseViewModel( ) updateViewState { it.copy(loading = false, sortOrder = sortOrder, items = items) } }.onFailure { e -> - Log.e(tag, "Error occurred while loading annotated verses", e) + Logger.withTag(tag).e(e) { "Error occurred while loading annotated verses" } updateViewState { it.copy(loading = false, error = ViewState.Error.AnnotatedVersesLoadingError) } } } @@ -228,7 +228,7 @@ abstract class AnnotatedVerseViewModel( runCatching { verseAnnotationManager.saveSortOrder(sortOrder) }.onFailure { e -> - Log.e(tag, "Failed to save sort order", e) + Logger.withTag(tag).e(e) { "Failed to save sort order" } updateViewState { it.copy(error = ViewState.Error.SortOrderSavingError(sortOrder)) } } } @@ -240,7 +240,7 @@ abstract class AnnotatedVerseViewModel( bibleReadingManager.saveCurrentVerseIndex(verseToOpen) emitViewAction(ViewAction.OpenReadingScreen) }.onFailure { e -> - Log.e(tag, "Failed to save current verse", e) + Logger.withTag(tag).e(e) { "Failed to save current verse" } updateViewState { it.copy(error = ViewState.Error.VerseOpeningError(verseToOpen)) } } } @@ -260,7 +260,7 @@ abstract class AnnotatedVerseViewModel( ) updateViewState { it.copy(preview = preview) } }.onFailure { e -> - Log.e(tag, "Failed to load verses for preview", e) + Logger.withTag(tag).e(e) { "Failed to load verses for preview" } updateViewState { it.copy(error = ViewState.Error.PreviewLoadingError(verseToPreview)) } } } diff --git a/app/src/main/kotlin/me/xizzhu/android/joshua/core/BibleReadingManager.kt b/app/src/main/kotlin/me/xizzhu/android/joshua/core/BibleReadingManager.kt index f299694bb..37ee762df 100644 --- a/app/src/main/kotlin/me/xizzhu/android/joshua/core/BibleReadingManager.kt +++ b/app/src/main/kotlin/me/xizzhu/android/joshua/core/BibleReadingManager.kt @@ -23,7 +23,7 @@ import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch import me.xizzhu.android.joshua.core.repository.BibleReadingRepository import me.xizzhu.android.joshua.core.repository.TranslationRepository -import me.xizzhu.android.logger.Log +import co.touchlab.kermit.Logger data class VerseIndex(val bookIndex: Int, val chapterIndex: Int, val verseIndex: Int) { companion object { @@ -92,7 +92,7 @@ class BibleReadingManager( } } } catch (e: Exception) { - Log.e(TAG, "Error occurred while observing downloaded translations", e) + Logger.e(e) { "Error occurred while observing downloaded translations" } } } diff --git a/app/src/main/kotlin/me/xizzhu/android/joshua/core/ReadingProgressManager.kt b/app/src/main/kotlin/me/xizzhu/android/joshua/core/ReadingProgressManager.kt index 75ebcf830..d3b7df184 100644 --- a/app/src/main/kotlin/me/xizzhu/android/joshua/core/ReadingProgressManager.kt +++ b/app/src/main/kotlin/me/xizzhu/android/joshua/core/ReadingProgressManager.kt @@ -26,7 +26,7 @@ import me.xizzhu.android.joshua.core.provider.TimeProvider import me.xizzhu.android.joshua.core.repository.BibleReadingRepository import me.xizzhu.android.joshua.core.repository.ReadingProgressRepository import me.xizzhu.android.joshua.utils.filterIsValid -import me.xizzhu.android.logger.Log +import co.touchlab.kermit.Logger data class ReadingProgress(val continuousReadingDays: Int, val lastReadingTimestamp: Long, val chapterReadingStatus: List) { @@ -100,7 +100,7 @@ class ReadingProgressManager( readingProgressRepository.trackReadingProgress( verseIndex.bookIndex, verseIndex.chapterIndex, timeSpentInMillis, now) } catch (e: Exception) { - Log.e(TAG, "Failed to track reading progress", e) + Logger.e(e) { "Failed to track reading progress" } } } diff --git a/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/BibleReadingRepository.kt b/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/BibleReadingRepository.kt index 0dbb2f18b..3926384f7 100644 --- a/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/BibleReadingRepository.kt +++ b/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/BibleReadingRepository.kt @@ -26,7 +26,7 @@ import me.xizzhu.android.joshua.core.Verse import me.xizzhu.android.joshua.core.VerseIndex import me.xizzhu.android.joshua.core.VerseSearchQuery import me.xizzhu.android.joshua.core.repository.local.LocalReadingStorage -import me.xizzhu.android.logger.Log +import co.touchlab.kermit.Logger class BibleReadingRepository(private val localReadingStorage: LocalReadingStorage, appScope: CoroutineScope) { companion object { @@ -49,19 +49,19 @@ class BibleReadingRepository(private val localReadingStorage: LocalReadingStorag try { _currentVerseIndex.value = localReadingStorage.readCurrentVerseIndex() } catch (e: Exception) { - Log.e(TAG, "Failed to initialize current verse index", e) + Logger.withTag(TAG).e(e) { "Failed to initialize current verse index" } _currentVerseIndex.value = VerseIndex.INVALID } try { _currentTranslation.value = localReadingStorage.readCurrentTranslation() } catch (e: Exception) { - Log.e(TAG, "Failed to initialize current translation", e) + Logger.withTag(TAG).e(e) { "Failed to initialize current translation" } _currentTranslation.value = "" } try { _parallelTranslations.value = localReadingStorage.readParallelTranslations() } catch (e: Exception) { - Log.e(TAG, "Failed to initialize parallel translations", e) + Logger.withTag(TAG).e(e) { "Failed to initialize parallel translations" } _parallelTranslations.value = emptyList() } } diff --git a/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/CrossReferencesRepository.kt b/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/CrossReferencesRepository.kt index da3f4b9ea..1eecab577 100644 --- a/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/CrossReferencesRepository.kt +++ b/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/CrossReferencesRepository.kt @@ -24,7 +24,7 @@ import me.xizzhu.android.joshua.core.CrossReferences import me.xizzhu.android.joshua.core.VerseIndex import me.xizzhu.android.joshua.core.repository.local.LocalCrossReferencesStorage import me.xizzhu.android.joshua.core.repository.remote.RemoteCrossReferencesStorage -import me.xizzhu.android.logger.Log +import co.touchlab.kermit.Logger class CrossReferencesRepository(private val localCrossReferencesStorage: LocalCrossReferencesStorage, private val remoteCrossReferencesStorage: RemoteCrossReferencesStorage) { @@ -38,13 +38,13 @@ class CrossReferencesRepository(private val localCrossReferencesStorage: LocalCr val downloadProgressChannel = Channel(Channel.CONFLATED) launch { downloadProgressChannel.consumeEach { trySend(it) } } - Log.i(TAG, "Start downloading cross references") + Logger.withTag(TAG).i { "Start downloading cross references" } val downloaded = remoteCrossReferencesStorage.fetchCrossReferences(downloadProgressChannel) - Log.i(TAG, "Cross references downloaded") + Logger.withTag(TAG).i { "Cross references downloaded" } localCrossReferencesStorage.save(downloaded.references) remoteCrossReferencesStorage.removeCrossReferencesCache() - Log.i(TAG, "Cross references saved to database") + Logger.withTag(TAG).i { "Cross references saved to database" } downloadProgressChannel.trySend(100) downloadProgressChannel.close() } diff --git a/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/SettingsRepository.kt b/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/SettingsRepository.kt index 49fcd1f66..c151eb56b 100644 --- a/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/SettingsRepository.kt +++ b/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/SettingsRepository.kt @@ -21,7 +21,7 @@ import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import me.xizzhu.android.joshua.core.Settings import me.xizzhu.android.joshua.core.repository.local.LocalSettingsStorage -import me.xizzhu.android.logger.Log +import co.touchlab.kermit.Logger class SettingsRepository(private val localSettingsStorage: LocalSettingsStorage, appScope: CoroutineScope) { companion object { @@ -36,7 +36,7 @@ class SettingsRepository(private val localSettingsStorage: LocalSettingsStorage, try { _settings.value = localSettingsStorage.readSettings() } catch (e: Exception) { - Log.e(TAG, "Failed to initialize settings", e) + Logger.withTag(TAG).e(e) { "Failed to initialize settings" } _settings.value = Settings.DEFAULT } } diff --git a/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/StrongNumberRepository.kt b/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/StrongNumberRepository.kt index ee4e616aa..41cdf2971 100644 --- a/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/StrongNumberRepository.kt +++ b/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/StrongNumberRepository.kt @@ -24,7 +24,7 @@ import me.xizzhu.android.joshua.core.StrongNumber import me.xizzhu.android.joshua.core.VerseIndex import me.xizzhu.android.joshua.core.repository.local.LocalStrongNumberStorage import me.xizzhu.android.joshua.core.repository.remote.RemoteStrongNumberStorage -import me.xizzhu.android.logger.Log +import co.touchlab.kermit.Logger import kotlin.math.min class StrongNumberRepository(private val localStrongNumberStorage: LocalStrongNumberStorage, @@ -43,7 +43,7 @@ class StrongNumberRepository(private val localStrongNumberStorage: LocalStrongNu @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) fun download(versesDownloadProgress: Channel, wordsDownloadProgress: Channel) = channelFlow { - Log.i(TAG, "Start downloading Strong number") + Logger.withTag(TAG).i { "Start downloading Strong number" } versesDownloadProgress.trySend(0) wordsDownloadProgress.trySend(0) @@ -54,7 +54,7 @@ class StrongNumberRepository(private val localStrongNumberStorage: LocalStrongNu val remoteIndexesAsync = async { remoteStrongNumberStorage.fetchIndexes(versesDownloadProgress) } val remoteWords = remoteStrongNumberStorage.fetchWords(wordsDownloadProgress) val remoteIndexes = remoteIndexesAsync.await() - Log.i(TAG, "Strong number downloaded") + Logger.withTag(TAG).i { "Strong number downloaded" } versesDownloadProgress.close() wordsDownloadProgress.close() @@ -62,7 +62,7 @@ class StrongNumberRepository(private val localStrongNumberStorage: LocalStrongNu localStrongNumberStorage.save(remoteIndexes.indexes, remoteIndexes.reverseIndexes, remoteWords.words) remoteStrongNumberStorage.removeIndexesCache() remoteStrongNumberStorage.removeWordsCache() - Log.i(TAG, "Strong number saved to database") + Logger.withTag(TAG).i { "Strong number saved to database" } trySend(100) } } diff --git a/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/TranslationRepository.kt b/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/TranslationRepository.kt index dba529db1..c7ab60c02 100644 --- a/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/TranslationRepository.kt +++ b/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/TranslationRepository.kt @@ -31,7 +31,7 @@ import me.xizzhu.android.joshua.core.provider.TimeProvider import me.xizzhu.android.joshua.core.repository.local.LocalTranslationStorage import me.xizzhu.android.joshua.core.repository.remote.RemoteTranslationInfo import me.xizzhu.android.joshua.core.repository.remote.RemoteTranslationService -import me.xizzhu.android.logger.Log +import co.touchlab.kermit.Logger class TranslationRepository( private val localTranslationStorage: LocalTranslationStorage, @@ -57,7 +57,7 @@ class TranslationRepository( try { updateTranslations(readTranslationsFromLocal()) } catch (e: Exception) { - Log.e(TAG, "Failed to initialize translations", e) + Logger.e(e) { "Failed to initialize translations" } updateTranslations(emptyList()) } } @@ -90,12 +90,12 @@ class TranslationRepository( try { readTranslationsFromBackend() } catch (e: Exception) { - Log.e(TAG, "Failed to read translation list from backend", e) + Logger.e(e) { "Failed to read translation list from backend" } readTranslationsFromLocal() } } else { readTranslationsFromLocal().ifEmpty { - Log.w(TAG, "Have fresh but empty local translation list") + Logger.w { "Have fresh but empty local translation list" } readTranslationsFromBackend() } } @@ -108,9 +108,9 @@ class TranslationRepository( @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) suspend fun readTranslationsFromBackend(): List { - Log.i(TAG, "Start fetching translation list") + Logger.withTag(TAG).i { "Start fetching translation list" } val fetchedTranslations = remoteTranslationService.fetchTranslations() - Log.i(TAG, "Translation list downloaded") + Logger.withTag(TAG).i { "Translation list downloaded" } val localTranslations = readTranslationsFromLocal() val translations = ArrayList(fetchedTranslations.size) @@ -132,7 +132,7 @@ class TranslationRepository( localTranslationStorage.saveTranslationListRefreshTimestamp(timeProvider.currentTimeMillis) } } catch (e: Exception) { - Log.e(TAG, "Failed to save translation list refresh timestamp", e) + Logger.e(e) { "Failed to save translation list refresh timestamp" } } return translations @@ -168,10 +168,10 @@ class TranslationRepository( @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) suspend fun downloadTranslation(downloadProgressChannel: SendChannel, translationInfo: TranslationInfo) { - Log.i(TAG, "Start downloading translation - ${translationInfo.shortName}") + Logger.withTag(TAG).i { "Start downloading translation - ${translationInfo.shortName}" } val toDownload = RemoteTranslationInfo.fromTranslationInfo(translationInfo) val translation = remoteTranslationService.fetchTranslation(downloadProgressChannel, toDownload) - Log.i(TAG, "Translation downloaded") + Logger.withTag(TAG).i { "Translation downloaded" } downloadProgressChannel.trySend(100) localTranslationStorage.saveTranslation( @@ -179,15 +179,15 @@ class TranslationRepository( translation.bookNames, translation.bookShortNames, translation.verses ) remoteTranslationService.removeTranslationCache(toDownload) - Log.i(TAG, "Translation saved to database") + Logger.withTag(TAG).i { "Translation saved to database" } downloadProgressChannel.trySend(101) } suspend fun removeTranslation(translationInfo: TranslationInfo) { - Log.i(TAG, "Start removing translation - ${translationInfo.shortName}") + Logger.withTag(TAG).i { "Start removing translation - ${translationInfo.shortName}" } localTranslationStorage.removeTranslation(translationInfo) remoteTranslationService.removeTranslationCache(RemoteTranslationInfo.fromTranslationInfo(translationInfo)) - Log.i(TAG, "Translation removed") + Logger.withTag(TAG).i { "Translation removed" } val (available, downloaded) = synchronized(translationsLock) { var removed = false diff --git a/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/VerseAnnotationRepository.kt b/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/VerseAnnotationRepository.kt index 7e23a6e9d..bbf3a0a74 100644 --- a/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/VerseAnnotationRepository.kt +++ b/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/VerseAnnotationRepository.kt @@ -25,7 +25,7 @@ import me.xizzhu.android.joshua.core.Constants import me.xizzhu.android.joshua.core.VerseAnnotation import me.xizzhu.android.joshua.core.VerseIndex import me.xizzhu.android.joshua.core.repository.local.LocalVerseAnnotationStorage -import me.xizzhu.android.logger.Log +import co.touchlab.kermit.Logger class VerseAnnotationRepository( private val localVerseAnnotationStorage: LocalVerseAnnotationStorage, @@ -43,7 +43,7 @@ class VerseAnnotationRepository( try { _sortOrder.value = localVerseAnnotationStorage.readSortOrder() } catch (e: Exception) { - Log.e(TAG, "Failed to initialize sort order", e) + Logger.withTag(TAG).e(e) { "Failed to initialize sort order" } _sortOrder.value = Constants.DEFAULT_SORT_ORDER } } diff --git a/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/local/android/db/StrongNumberWordDao.kt b/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/local/android/db/StrongNumberWordDao.kt index 98586222c..c92b63c97 100644 --- a/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/local/android/db/StrongNumberWordDao.kt +++ b/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/local/android/db/StrongNumberWordDao.kt @@ -21,7 +21,7 @@ import android.database.sqlite.SQLiteOpenHelper import androidx.annotation.WorkerThread import me.xizzhu.android.ask.db.* import me.xizzhu.android.joshua.core.StrongNumber -import me.xizzhu.android.logger.Log +import co.touchlab.kermit.Logger class StrongNumberWordDao(sqliteHelper: SQLiteOpenHelper) { companion object { @@ -62,7 +62,7 @@ class StrongNumberWordDao(sqliteHelper: SQLiteOpenHelper) { return ArrayList(strongNumbers.size).apply { strongNumbers.forEach { sn -> words[sn]?.let { word -> add(word) } - ?: Log.e(TAG, "", IllegalArgumentException("Strong number $sn is not available")) + ?: Logger.withTag(TAG).w { "Strong number $sn is not available" } } } } diff --git a/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/local/android/db/TranslationDao.kt b/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/local/android/db/TranslationDao.kt index e3511b515..35cf6b2c7 100644 --- a/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/local/android/db/TranslationDao.kt +++ b/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/local/android/db/TranslationDao.kt @@ -24,7 +24,7 @@ import me.xizzhu.android.joshua.core.Bible import me.xizzhu.android.joshua.core.Verse import me.xizzhu.android.joshua.core.VerseIndex import me.xizzhu.android.joshua.core.VerseSearchQuery -import me.xizzhu.android.logger.Log +import co.touchlab.kermit.Logger import kotlin.math.max class TranslationDao(sqliteHelper: SQLiteOpenHelper) { @@ -53,7 +53,7 @@ class TranslationDao(sqliteHelper: SQLiteOpenHelper) { @WorkerThread private fun SQLiteDatabase.hasTableAndLogIfNoTable(table: String): Boolean = hasTable(table) - .also { hasTable -> if (!hasTable) Log.e(TAG, "", IllegalStateException("Missing translation $table")) } + .also { hasTable -> if (!hasTable) Logger.withTag(TAG).e { "Missing translation $table" } } @WorkerThread fun read(translationShortName: String, parallelTranslations: List, @@ -150,7 +150,7 @@ class TranslationDao(sqliteHelper: SQLiteOpenHelper) { @WorkerThread fun save(translationShortName: String, verses: Map, List>) = db.withTransaction { if (hasTable(translationShortName)) { - Log.e(TAG, "", IllegalStateException("Translation $translationShortName already installed")) + Logger.withTag(TAG).e { "Translation $translationShortName already installed" } remove(translationShortName) } createTable(translationShortName) { diff --git a/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/remote/android/AndroidHttpService.kt b/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/remote/android/AndroidHttpService.kt index 8785eb204..e6561b905 100644 --- a/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/remote/android/AndroidHttpService.kt +++ b/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/remote/android/AndroidHttpService.kt @@ -19,7 +19,7 @@ package me.xizzhu.android.joshua.core.repository.remote.android import android.os.Build import android.util.JsonReader import kotlinx.coroutines.channels.SendChannel -import me.xizzhu.android.logger.Log +import co.touchlab.kermit.Logger import java.io.ByteArrayOutputStream import java.io.File import java.io.FileOutputStream @@ -101,12 +101,12 @@ private fun HttpURLConnection.configureTLSIfNecessary(): URLConnection { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1 && this is HttpsURLConnection) { return this } - Log.d(TAG, "Enabling TLS v1.2...") + Logger.withTag(TAG).d { "Enabling TLS v1.2..." } try { (this as HttpsURLConnection).sslSocketFactory = tls12SocketFactory - Log.d(TAG, "TLS v1.2 enabled") + Logger.withTag(TAG).d { "TLS v1.2 enabled" } } catch (e: Exception) { - Log.e(TAG, "Failed to enable TLS v1.2", e) + Logger.withTag(TAG).e(e) { "Failed to enable TLS v1.2" } } return this } diff --git a/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/remote/android/JsonParser.kt b/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/remote/android/JsonParser.kt index 19ed920c9..599e50064 100644 --- a/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/remote/android/JsonParser.kt +++ b/app/src/main/kotlin/me/xizzhu/android/joshua/core/repository/remote/android/JsonParser.kt @@ -21,7 +21,7 @@ import androidx.annotation.VisibleForTesting import me.xizzhu.android.joshua.core.Bible import me.xizzhu.android.joshua.core.VerseIndex import me.xizzhu.android.joshua.core.repository.remote.RemoteTranslationInfo -import me.xizzhu.android.logger.Log +import co.touchlab.kermit.Logger private const val TAG = "JsonParser" @@ -34,7 +34,7 @@ internal fun JsonReader.readListJson(): List { } else -> { skipValue() - Log.w(TAG, "Unsupported JSON format", RuntimeException("Unsupported JSON format in list.json")) + Logger.withTag(TAG).w(RuntimeException("Unsupported JSON format in list.json")) { "Unsupported JSON format" } } } } @@ -68,13 +68,13 @@ internal fun JsonReader.readTranslation(): RemoteTranslationInfo? { "size" -> size = nextLong() else -> { skipValue() - Log.w(TAG, "Unsupported JSON format", RuntimeException("Unsupported JSON format in list.json")) + Logger.withTag(TAG).w(RuntimeException("Unsupported JSON format in list.json")) { "Unsupported JSON format" } } } } endObject() if (shortName == null || name == null || language == null || size == null) { - Log.w(TAG, "Unsupported JSON format", RuntimeException("Illegal 'translation' in list.json - short name: $shortName")) + Logger.withTag(TAG).w(RuntimeException("Illegal 'translation' in list.json - short name: $shortName")) { "Unsupported JSON format" } return null } return RemoteTranslationInfo(shortName, name, language, size) @@ -91,7 +91,7 @@ internal fun JsonReader.readBooksJson(bookNames: MutableList, bookShortN "bookShortNames" -> readStringsArray(bookShortNames) else -> { skipValue() - Log.w(TAG, "Unsupported JSON format", RuntimeException("Unsupported JSON format in books.json")) + Logger.withTag(TAG).w(RuntimeException("Unsupported JSON format in books.json")) { "Unsupported JSON format" } } } } @@ -122,7 +122,7 @@ internal fun JsonReader.readChapterJson(): List { } else -> { skipValue() - Log.w(TAG, "Unsupported JSON format", RuntimeException("Unsupported format in chapter JSON")) + Logger.withTag(TAG).w(RuntimeException("Unsupported format in chapter JSON")) { "Unsupported JSON format" } } } } @@ -142,7 +142,7 @@ internal fun JsonReader.readStrongNumberVerses(): Map> { } } catch (e: NumberFormatException) { skipValue() - Log.w(TAG, "Unsupported JSON format", RuntimeException("Unsupported format in Strong number chapter JSON")) + Logger.withTag(TAG).w(RuntimeException("Unsupported format in Strong number chapter JSON")) { "Unsupported JSON format" } } } endObject() @@ -171,7 +171,7 @@ internal fun JsonReader.readStrongNumberWords(): Map { words[nextName().toInt()] = nextString() } catch (e: NumberFormatException) { skipValue() - Log.w(TAG, "Unsupported JSON format", RuntimeException("Unsupported format in Strong number words JSON")) + Logger.withTag(TAG).w(RuntimeException("Unsupported format in Strong number words JSON")) { "Unsupported JSON format" } } } endObject() @@ -192,7 +192,7 @@ internal fun JsonReader.readCrossReferences(): Map> { } } catch (e: Exception) { skipValue() - Log.w(TAG, "Unsupported JSON format", RuntimeException("Unsupported format in cross reference chapter JSON")) + Logger.withTag(TAG).w(RuntimeException("Unsupported format in cross reference chapter JSON")) { "Unsupported JSON format" } } } endObject() diff --git a/app/src/main/kotlin/me/xizzhu/android/joshua/infra/BaseActivity.kt b/app/src/main/kotlin/me/xizzhu/android/joshua/infra/BaseActivity.kt index 248646f90..f88375ee1 100644 --- a/app/src/main/kotlin/me/xizzhu/android/joshua/infra/BaseActivity.kt +++ b/app/src/main/kotlin/me/xizzhu/android/joshua/infra/BaseActivity.kt @@ -24,21 +24,21 @@ import androidx.viewbinding.ViewBinding import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import me.xizzhu.android.joshua.Navigator -import me.xizzhu.android.logger.Log +import co.touchlab.kermit.Logger import javax.inject.Inject abstract class BaseActivity : AppCompatActivity() { protected val tag: String = javaClass.simpleName @Inject - protected lateinit var navigator: Navigator + internal lateinit var navigator: Navigator protected lateinit var viewBinding: VB @CallSuper override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - Log.i(tag, "onCreate()") + Logger.withTag(tag).i { "onCreate()" } viewBinding = inflateViewBinding() setContentView(viewBinding.root) @@ -61,48 +61,48 @@ abstract class BaseActivity : AppCompatAct @CallSuper override fun onStart() { super.onStart() - Log.i(tag, "onStart()") + Logger.withTag(tag).i { "onStart()" } } @CallSuper override fun onResume() { super.onResume() - Log.i(tag, "onResume()") + Logger.withTag(tag).i { "onResume()" } } @CallSuper override fun onPause() { super.onPause() - Log.i(tag, "onPause()") + Logger.withTag(tag).i { "onPause()" } } @CallSuper override fun onStop() { super.onStop() - Log.i(tag, "onStop()") + Logger.withTag(tag).i { "onStop()" } } @CallSuper override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) - Log.i(tag, "onSaveInstanceState()") + Logger.withTag(tag).i { "onSaveInstanceState()" } } @CallSuper override fun onDestroy() { super.onDestroy() - Log.i(tag, "onDestroy()") + Logger.withTag(tag).i { "onDestroy()" } } @CallSuper override fun onLowMemory() { super.onLowMemory() - Log.i(tag, "onLowMemory()") + Logger.withTag(tag).i { "onLowMemory()" } } @CallSuper override fun onTrimMemory(level: Int) { super.onTrimMemory(level) - Log.i(tag, "onTrimMemory(): level - $level") + Logger.withTag(tag).i { "onTrimMemory(): level - $level" } } } diff --git a/app/src/main/kotlin/me/xizzhu/android/joshua/infra/BaseActivityV2.kt b/app/src/main/kotlin/me/xizzhu/android/joshua/infra/BaseActivityV2.kt index 6db1d1c86..03ccf005f 100644 --- a/app/src/main/kotlin/me/xizzhu/android/joshua/infra/BaseActivityV2.kt +++ b/app/src/main/kotlin/me/xizzhu/android/joshua/infra/BaseActivityV2.kt @@ -24,14 +24,14 @@ import androidx.viewbinding.ViewBinding import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import me.xizzhu.android.joshua.Navigator -import me.xizzhu.android.logger.Log +import co.touchlab.kermit.Logger import javax.inject.Inject abstract class BaseActivityV2> : AppCompatActivity() { protected val tag: String = javaClass.simpleName @Inject - protected lateinit var navigator: Navigator + internal lateinit var navigator: Navigator protected abstract val viewModel: VM @@ -46,7 +46,7 @@ abstract class BaseActivityV2 - Log.e(tag, "Error occurred while loading reading progress", e) + Logger.withTag(tag).e(e) { "Error occurred while loading reading progress" } updateViewState { it.copy(loading = false, error = ViewState.Error.ReadingProgressLoadingError) } } } @@ -146,7 +146,7 @@ class ReadingProgressViewModel @Inject constructor( bibleReadingManager.saveCurrentVerseIndex(verseToOpen) emitViewAction(ViewAction.OpenReadingScreen) }.onFailure { e -> - Log.e(tag, "Failed to save current verse", e) + Logger.withTag(tag).e(e) { "Failed to save current verse" } updateViewState { it.copy(error = ViewState.Error.VerseOpeningError(verseToOpen)) } } } diff --git a/app/src/main/kotlin/me/xizzhu/android/joshua/reading/ReadingActivity.kt b/app/src/main/kotlin/me/xizzhu/android/joshua/reading/ReadingActivity.kt index d58e9b679..ab030391b 100644 --- a/app/src/main/kotlin/me/xizzhu/android/joshua/reading/ReadingActivity.kt +++ b/app/src/main/kotlin/me/xizzhu/android/joshua/reading/ReadingActivity.kt @@ -68,7 +68,7 @@ import me.xizzhu.android.joshua.ui.progressDialog import me.xizzhu.android.joshua.ui.toast import me.xizzhu.android.joshua.utils.copyToClipBoard import me.xizzhu.android.joshua.utils.shareToSystem -import me.xizzhu.android.logger.Log +import co.touchlab.kermit.Logger import kotlin.math.max import me.xizzhu.android.joshua.reading.chapter.ChapterSelectionFragment import me.xizzhu.android.joshua.reading.toolbar.ReadingToolbarFragment @@ -136,7 +136,7 @@ class ReadingActivity : BaseActivity() ) toast(R.string.toast_verses_copied) } catch (e: Exception) { - Log.e(tag, "Failed to copy", e) + Logger.withTag(tag).e(e) { "Failed to copy" } toast(R.string.toast_unknown_error) } finally { actionMode?.finish() @@ -154,7 +154,7 @@ class ReadingActivity : BaseActivity() text = selectedVerses.toStringForSharing(currentBookName, readingViewModel.settings().first().consolidateVersesForSharing) ) } catch (e: Exception) { - Log.e(tag, "Failed to share", e) + Logger.withTag(tag).e(e) { "Failed to share" } toast(R.string.toast_unknown_error) } finally { actionMode?.finish() @@ -182,7 +182,7 @@ class ReadingActivity : BaseActivity() try { chapterSelectionFragment.getFragment().expandCurrentBook() } catch (e: Exception) { - Log.e(tag, "Error occurred while expanding current book", e) + Logger.withTag(tag).e(e) { "Error occurred while expanding current book" } } } }) @@ -231,7 +231,7 @@ class ReadingActivity : BaseActivity() try { navigator.navigate(this, screen, extras) } catch (e: Exception) { - Log.e(tag, "Failed to open activity", e) + Logger.withTag(tag).e(e) { "Failed to open activity" } dialog(true, R.string.dialog_title_error, R.string.dialog_message_failed_to_navigate, { _, _ -> startActivity(screen) }) } } @@ -246,7 +246,7 @@ class ReadingActivity : BaseActivity() readingViewModel.loadVerses(bookIndex, chapterIndex) .onSuccess { verses -> versePagerAdapter.setVerses(bookIndex, chapterIndex, verses.items) } .onFailure { e -> - Log.e(tag, "Failed to load verses", e) + Logger.withTag(tag).e(e) { "Failed to load verses" } dialog(true, R.string.dialog_title_error, R.string.dialog_message_failed_to_load_verses, { _, _ -> loadVerses(bookIndex, chapterIndex) }) } .launchIn(lifecycleScope) @@ -484,7 +484,7 @@ class ReadingActivity : BaseActivity() readingViewModel.updateVerse(VerseUpdate(verseIndex, VerseUpdate.VERSE_SELECTED)) }, onFailure = { e -> - Log.e(tag, "Failed to load verses", e) + Logger.withTag(tag).e(e) { "Failed to load verses" } dialog(true, R.string.dialog_title_error, R.string.dialog_message_failed_to_load_verse_detail, { _, _ -> showVerseDetail(verseIndex, content) }) } ) @@ -554,7 +554,7 @@ class ReadingActivity : BaseActivity() ) toast(R.string.toast_verses_copied) } catch (e: Exception) { - Log.e(tag, "Failed to copy", e) + Logger.withTag(tag).e(e) { "Failed to copy" } toast(R.string.toast_unknown_error) } } diff --git a/app/src/main/kotlin/me/xizzhu/android/joshua/reading/ReadingViewModel.kt b/app/src/main/kotlin/me/xizzhu/android/joshua/reading/ReadingViewModel.kt index 8e6fb974c..9fd8c8d41 100644 --- a/app/src/main/kotlin/me/xizzhu/android/joshua/reading/ReadingViewModel.kt +++ b/app/src/main/kotlin/me/xizzhu/android/joshua/reading/ReadingViewModel.kt @@ -59,7 +59,7 @@ import me.xizzhu.android.joshua.utils.currentTimeMillis import me.xizzhu.android.joshua.utils.filterIsValid import me.xizzhu.android.joshua.utils.filterNotEmpty import me.xizzhu.android.joshua.utils.firstNotEmpty -import me.xizzhu.android.logger.Log +import co.touchlab.kermit.Logger import javax.inject.Inject import kotlin.coroutines.cancellation.CancellationException @@ -134,15 +134,15 @@ class ReadingViewModel @Inject constructor( try { bibleReadingManager.removeParallelTranslation(translationToSelect) } catch (e: Exception) { - Log.e(tag, "Failed to remove the selected translation from parallel", e) + Logger.withTag(tag).e(e) { "Failed to remove the selected translation from parallel" } } - }.onFailure { Log.e(tag, "Failed to select translation", it) } + }.onFailure { e -> Logger.withTag(tag).e(e) { "Failed to select translation" } } suspend fun currentVerseIndex(): VerseIndex = bibleReadingManager.currentVerseIndex().first { it.isValid() } fun selectCurrentVerseIndex(verseIndex: VerseIndex): Flow> = viewData { bibleReadingManager.saveCurrentVerseIndex(verseIndex) - }.onFailure { Log.e(tag, "Failed to select verse index", it) } + }.onFailure { e -> Logger.withTag(tag).e(e) { "Failed to select verse index" } } suspend fun bookName(translationShortName: String, bookIndex: Int): String { return bibleReadingManager.readBookNames(translationShortName)[bookIndex] @@ -266,7 +266,7 @@ class ReadingViewModel @Inject constructor( fun loadVersesForPreview(verseIndex: VerseIndex): Flow> = loadPreview(bibleReadingManager, settingsManager, verseIndex, ::toVersePreviewItems) - .onFailure { Log.e(tag, "Failed to load verses for preview", it) } + .onFailure { e -> Logger.withTag(tag).e(e) { "Failed to load verses for preview" } } fun verseUpdates(): Flow = verseUpdates @@ -282,7 +282,7 @@ class ReadingViewModel @Inject constructor( bookmarkManager.remove(verseIndex) verseUpdates.emit(VerseUpdate(verseIndex, VerseUpdate.BOOKMARK_REMOVED)) } - }.onFailure { Log.e(tag, "Failed to update bookmark", it) } + }.onFailure { e -> Logger.withTag(tag).e(e) { "Failed to update bookmark" } } fun saveHighlight(verseIndex: VerseIndex, @Highlight.Companion.AvailableColor color: Int): Flow> = viewData { if (color == Highlight.COLOR_NONE) { @@ -292,7 +292,7 @@ class ReadingViewModel @Inject constructor( highlightManager.save(Highlight(verseIndex, color, currentTimeMillis())) verseUpdates.emit(VerseUpdate(verseIndex, VerseUpdate.HIGHLIGHT_UPDATED, color)) } - }.onFailure { Log.e(tag, "Failed to update highlight", it) } + }.onFailure { e -> Logger.withTag(tag).e(e) { "Failed to update highlight" } } fun saveNote(verseIndex: VerseIndex, note: String): Flow> = viewData { if (note.isEmpty()) { @@ -314,7 +314,7 @@ class ReadingViewModel @Inject constructor( } } .catch { e -> - Log.e(tag, "Failed to download cross references", e) + Logger.withTag(tag).e(e) { "Failed to download cross references" } emit(ViewData.Failure(e)) } @@ -330,7 +330,7 @@ class ReadingViewModel @Inject constructor( } } .catch { e -> - Log.e(tag, "Failed to download Strong Number", e) + Logger.withTag(tag).e(e) { "Failed to download Strong Number" } emit(ViewData.Failure(e)) } diff --git a/app/src/main/kotlin/me/xizzhu/android/joshua/reading/chapter/ChapterSelectionViewModel.kt b/app/src/main/kotlin/me/xizzhu/android/joshua/reading/chapter/ChapterSelectionViewModel.kt index 094562734..ca19ed0fb 100644 --- a/app/src/main/kotlin/me/xizzhu/android/joshua/reading/chapter/ChapterSelectionViewModel.kt +++ b/app/src/main/kotlin/me/xizzhu/android/joshua/reading/chapter/ChapterSelectionViewModel.kt @@ -26,7 +26,7 @@ import me.xizzhu.android.joshua.core.Bible import me.xizzhu.android.joshua.core.BibleReadingManager import me.xizzhu.android.joshua.core.VerseIndex import me.xizzhu.android.joshua.infra.BaseViewModelV2 -import me.xizzhu.android.logger.Log +import co.touchlab.kermit.Logger @HiltViewModel class ChapterSelectionViewModel @Inject constructor( @@ -70,7 +70,7 @@ class ChapterSelectionViewModel @Inject constructor( runCatching { bibleReadingManager.saveCurrentVerseIndex(VerseIndex(bookIndex = bookToSelect, chapterIndex = chapterToSelect, verseIndex = 0)) }.onFailure { e -> - Log.e(tag, "Failed to select chapter [bookToSelect=$bookToSelect, chapterToSelect=$chapterToSelect]", e) + Logger.withTag(tag).e(e) { "Failed to select chapter [bookToSelect=$bookToSelect, chapterToSelect=$chapterToSelect]" } updateViewState { it.copy(error = ViewState.Error.ChapterSelectionError(bookToSelect = bookToSelect, chapterToSelect = chapterToSelect)) } } } diff --git a/app/src/main/kotlin/me/xizzhu/android/joshua/reading/toolbar/ReadingToolbarViewModel.kt b/app/src/main/kotlin/me/xizzhu/android/joshua/reading/toolbar/ReadingToolbarViewModel.kt index 12b356d17..44f62a246 100644 --- a/app/src/main/kotlin/me/xizzhu/android/joshua/reading/toolbar/ReadingToolbarViewModel.kt +++ b/app/src/main/kotlin/me/xizzhu/android/joshua/reading/toolbar/ReadingToolbarViewModel.kt @@ -30,7 +30,7 @@ import me.xizzhu.android.joshua.infra.BaseViewModelV2 import me.xizzhu.android.joshua.ui.TranslationInfoComparator import me.xizzhu.android.joshua.utils.filterIsValid import me.xizzhu.android.joshua.utils.filterNotEmpty -import me.xizzhu.android.logger.Log +import co.touchlab.kermit.Logger @HiltViewModel class ReadingToolbarViewModel @Inject constructor( @@ -93,7 +93,7 @@ class ReadingToolbarViewModel @Inject constructor( runCatching { bibleReadingManager.requestParallelTranslation(translationToRequest) }.onFailure { e -> - Log.e(tag, "Failed to request parallel translation [$translationToRequest]", e) + Logger.withTag(tag).e(e) { "Failed to request parallel translation [$translationToRequest]" } updateViewState { it.copy(error = ViewState.Error.ParallelTranslationRequestingError(translationToRequest)) } } } @@ -104,7 +104,7 @@ class ReadingToolbarViewModel @Inject constructor( runCatching { bibleReadingManager.removeParallelTranslation(translationToRemove) }.onFailure { e -> - Log.e(tag, "Failed to remove parallel translation [$translationToRemove]", e) + Logger.withTag(tag).e(e) { "Failed to remove parallel translation [$translationToRemove]" } updateViewState { it.copy(error = ViewState.Error.ParallelTranslationRemovalError(translationToRemove)) } } } @@ -117,9 +117,9 @@ class ReadingToolbarViewModel @Inject constructor( runCatching { bibleReadingManager.removeParallelTranslation(translationToSelect) - }.onFailure { Log.e(tag, "Failed to remove the selected translation from parallel", it) } + }.onFailure { e -> Logger.withTag(tag).e(e) { "Failed to remove the selected translation from parallel" } } }.onFailure { e -> - Log.e(tag, "Failed to select translation [$translationToSelect]", e) + Logger.withTag(tag).e(e) { "Failed to select translation [$translationToSelect]" } updateViewState { it.copy(error = ViewState.Error.TranslationSelectionError(translationToSelect)) } } } diff --git a/app/src/main/kotlin/me/xizzhu/android/joshua/search/RecentSearchProvider.kt b/app/src/main/kotlin/me/xizzhu/android/joshua/search/RecentSearchProvider.kt index 080411b71..5684281cc 100644 --- a/app/src/main/kotlin/me/xizzhu/android/joshua/search/RecentSearchProvider.kt +++ b/app/src/main/kotlin/me/xizzhu/android/joshua/search/RecentSearchProvider.kt @@ -40,7 +40,7 @@ class RecentSearchProvider : SearchRecentSuggestionsProvider() { } companion object { - private const val AUTHORITY = "${BuildConfig.APPLICATION_ID}.search.RecentSearchProvider" + private val AUTHORITY = "${BuildConfig.APPLICATION_ID}.search.RecentSearchProvider" private const val MODE = DATABASE_MODE_QUERIES } diff --git a/app/src/main/kotlin/me/xizzhu/android/joshua/search/SearchViewModel.kt b/app/src/main/kotlin/me/xizzhu/android/joshua/search/SearchViewModel.kt index 3bdd4dece..b2e72390c 100644 --- a/app/src/main/kotlin/me/xizzhu/android/joshua/search/SearchViewModel.kt +++ b/app/src/main/kotlin/me/xizzhu/android/joshua/search/SearchViewModel.kt @@ -45,7 +45,7 @@ import me.xizzhu.android.joshua.core.VerseIndex import me.xizzhu.android.joshua.core.provider.CoroutineDispatcherProvider import me.xizzhu.android.joshua.infra.BaseViewModelV2 import me.xizzhu.android.joshua.utils.firstNotEmpty -import me.xizzhu.android.logger.Log +import co.touchlab.kermit.Logger import javax.inject.Inject import me.xizzhu.android.joshua.preview.Preview import me.xizzhu.android.joshua.preview.buildPreviewVerseWithQueryItems @@ -131,7 +131,7 @@ class SearchViewModel @Inject constructor( val current = searchManager.configuration().first() op(current).takeIf { it != current }?.let { searchManager.saveConfiguration(it) } }.onFailure { e -> - Log.e(tag, "Error occurred which updating search config", e) + Logger.withTag(tag).e(e) { "Error occurred which updating search config" } updateViewState { it.copy(error = ViewState.Error.SearchConfigUpdatingError) } } } @@ -208,7 +208,7 @@ class SearchViewModel @Inject constructor( ) } }.onFailure { e -> - Log.e(tag, "Error occurred which searching, query=$query instantSearch=$instantSearch", e) + Logger.withTag(tag).e(e) { "Error occurred which searching, query=$query instantSearch=$instantSearch" } updateViewState { it.copy(loading = false, error = ViewState.Error.VerseSearchingError) } } } @@ -299,7 +299,7 @@ class SearchViewModel @Inject constructor( bibleReadingManager.saveCurrentVerseIndex(verseToOpen) emitViewAction(ViewAction.OpenReadingScreen) }.onFailure { e -> - Log.e(tag, "Failed to save current verse", e) + Logger.withTag(tag).e(e) { "Failed to save current verse" } updateViewState { it.copy(error = ViewState.Error.VerseOpeningError(verseToOpen)) } } } @@ -320,7 +320,7 @@ class SearchViewModel @Inject constructor( ) updateViewState { it.copy(preview = preview) } }.onFailure { e -> - Log.e(tag, "Failed to load verses for preview", e) + Logger.withTag(tag).e(e) { "Failed to load verses for preview" } updateViewState { it.copy(error = ViewState.Error.PreviewLoadingError(verseToPreview)) } } } diff --git a/app/src/main/kotlin/me/xizzhu/android/joshua/settings/SettingsActivity.kt b/app/src/main/kotlin/me/xizzhu/android/joshua/settings/SettingsActivity.kt index f5eb2015e..846e98c77 100644 --- a/app/src/main/kotlin/me/xizzhu/android/joshua/settings/SettingsActivity.kt +++ b/app/src/main/kotlin/me/xizzhu/android/joshua/settings/SettingsActivity.kt @@ -34,7 +34,7 @@ import me.xizzhu.android.joshua.ui.listDialog import me.xizzhu.android.joshua.ui.seekBarDialog import me.xizzhu.android.joshua.ui.setOnCheckedChangeByUserListener import me.xizzhu.android.joshua.ui.setOnSingleClickListener -import me.xizzhu.android.logger.Log +import co.touchlab.kermit.Logger @AndroidEntryPoint class SettingsActivity : BaseActivityV2() { @@ -72,7 +72,7 @@ class SettingsActivity : BaseActivityV2 - Log.e(tag, "Failed to save settings", e) + Logger.withTag(tag).e(e) { "Failed to save settings" } updateViewState { it.copy(fontSizeScale = current.fontSizeScale, error = ViewState.Error.SettingsUpdatingError) } } } @@ -168,7 +168,7 @@ class SettingsViewModel @Inject constructor( val current = settingsManager.settings().first() op(current).takeIf { it != current }?.let { settingsManager.saveSettings(it) } }.onFailure { e -> - Log.e(tag, "Failed to save settings", e) + Logger.withTag(tag).e(e) { "Failed to save settings" } updateViewState { it.copy(error = ViewState.Error.SettingsUpdatingError) } } } @@ -192,7 +192,7 @@ class SettingsViewModel @Inject constructor( } ) }.onFailure { e -> - Log.e(tag, "Failed to save settings", e) + Logger.withTag(tag).e(e) { "Failed to save settings" } updateViewState { it.copy(error = ViewState.Error.SettingsUpdatingError) } } } @@ -286,8 +286,8 @@ class SettingsViewModel @Inject constructor( ?.use { backupManager.backup(it) } ?: throw IOException("Failed to open Uri for backup - $uri") updateViewState { it.copy(backupState = ViewState.BackupRestoreState.Completed(successful = true)) } - }.onFailure { - Log.e(tag, "Failed to backup data", it) + }.onFailure { e -> + Logger.withTag(tag).e(e) { "Failed to backup data" } updateViewState { current -> current.copy( backupState = ViewState.BackupRestoreState.Completed(successful = false), @@ -311,8 +311,8 @@ class SettingsViewModel @Inject constructor( ?.use { backupManager.restore(it) } ?: throw IOException("Failed to open Uri for restore - $uri") updateViewState { it.copy(restoreState = ViewState.BackupRestoreState.Completed(successful = true)) } - }.onFailure { - Log.e(tag, "Failed to restore data", it) + }.onFailure { e -> + Logger.withTag(tag).e(e) { "Failed to restore data" } updateViewState { current -> current.copy( restoreState = ViewState.BackupRestoreState.Completed(successful = false), diff --git a/app/src/main/kotlin/me/xizzhu/android/joshua/strongnumber/StrongNumberViewModel.kt b/app/src/main/kotlin/me/xizzhu/android/joshua/strongnumber/StrongNumberViewModel.kt index 9a8cef8d7..64720cb29 100644 --- a/app/src/main/kotlin/me/xizzhu/android/joshua/strongnumber/StrongNumberViewModel.kt +++ b/app/src/main/kotlin/me/xizzhu/android/joshua/strongnumber/StrongNumberViewModel.kt @@ -37,7 +37,7 @@ import me.xizzhu.android.joshua.ui.createTitleSpans import me.xizzhu.android.joshua.ui.setSpans import me.xizzhu.android.joshua.ui.toCharSequence import me.xizzhu.android.joshua.utils.firstNotEmpty -import me.xizzhu.android.logger.Log +import co.touchlab.kermit.Logger import javax.inject.Inject import me.xizzhu.android.joshua.preview.Preview import me.xizzhu.android.joshua.preview.buildPreviewVerseItems @@ -100,7 +100,7 @@ class StrongNumberViewModel @Inject constructor( ) updateViewState { it.copy(loading = false, items = items) } }.onFailure { e -> - Log.e(tag, "Error occurred which loading Strong's Numbers", e) + Logger.withTag(tag).e(e) { "Error occurred which loading Strong's Numbers" } updateViewState { it.copy(loading = false, error = ViewState.Error.StrongNumberLoadingError) } } } @@ -142,7 +142,7 @@ class StrongNumberViewModel @Inject constructor( bibleReadingManager.saveCurrentVerseIndex(verseToOpen) emitViewAction(ViewAction.OpenReadingScreen) }.onFailure { e -> - Log.e(tag, "Failed to save current verse", e) + Logger.withTag(tag).e(e) { "Failed to save current verse" } updateViewState { it.copy(error = ViewState.Error.VerseOpeningError(verseToOpen)) } } } @@ -162,7 +162,7 @@ class StrongNumberViewModel @Inject constructor( ) updateViewState { it.copy(preview = preview) } }.onFailure { e -> - Log.e(tag, "Failed to load verses for preview", e) + Logger.withTag(tag).e(e) { "Failed to load verses for preview" } updateViewState { it.copy(error = ViewState.Error.PreviewLoadingError(verseToPreview)) } } } diff --git a/app/src/main/kotlin/me/xizzhu/android/joshua/translations/TranslationsViewModel.kt b/app/src/main/kotlin/me/xizzhu/android/joshua/translations/TranslationsViewModel.kt index 8451b6666..7fa2769ed 100644 --- a/app/src/main/kotlin/me/xizzhu/android/joshua/translations/TranslationsViewModel.kt +++ b/app/src/main/kotlin/me/xizzhu/android/joshua/translations/TranslationsViewModel.kt @@ -38,7 +38,7 @@ import kotlinx.coroutines.flow.onEach import me.xizzhu.android.joshua.core.Settings import me.xizzhu.android.joshua.core.provider.CoroutineDispatcherProvider import me.xizzhu.android.joshua.infra.BaseViewModelV2 -import me.xizzhu.android.logger.Log +import co.touchlab.kermit.Logger @HiltViewModel class TranslationsViewModel @Inject constructor( @@ -152,7 +152,7 @@ class TranslationsViewModel @Inject constructor( bibleReadingManager.saveCurrentTranslation(translationToSelect.shortName) emitViewAction(ViewAction.GoBack) }.onFailure { e -> - Log.e(tag, "Failed to select translation", e) + Logger.withTag(tag).e(e) { "Failed to select translation" } updateViewState { it.copy(error = ViewState.Error.TranslationSelectionError(translationToSelect)) } } } @@ -179,7 +179,7 @@ class TranslationsViewModel @Inject constructor( } } .catch { e -> - Log.e(tag, "Failed to download translation", e) + Logger.withTag(tag).e(e) { "Failed to download translation" } updateViewState { current -> current.copy( translationDownloadingState = ViewState.TranslationDownloadingState.Completed(successful = false), @@ -189,7 +189,7 @@ class TranslationsViewModel @Inject constructor( } .onCompletion { e -> if (e is CancellationException) { - Log.d(tag, "Translation downloading cancelled") + Logger.withTag(tag).d { "Translation downloading cancelled" } updateViewState { it.copy(translationDownloadingState = ViewState.TranslationDownloadingState.Idle) } } downloadTranslationJob = null @@ -216,7 +216,7 @@ class TranslationsViewModel @Inject constructor( loadTranslations(forceRefresh = false) updateViewState { it.copy(translationRemovalState = ViewState.TranslationRemovalState.Completed(successful = true)) } }.onFailure { e -> - Log.e(tag, "Failed to remove translation", e) + Logger.withTag(tag).e(e) { "Failed to remove translation" } updateViewState { current -> current.copy( translationRemovalState = ViewState.TranslationRemovalState.Completed(successful = false), diff --git a/app/src/main/kotlin/me/xizzhu/android/joshua/ui/View.kt b/app/src/main/kotlin/me/xizzhu/android/joshua/ui/View.kt index bf0a570fe..9250e8aef 100644 --- a/app/src/main/kotlin/me/xizzhu/android/joshua/ui/View.kt +++ b/app/src/main/kotlin/me/xizzhu/android/joshua/ui/View.kt @@ -31,7 +31,7 @@ import android.widget.CompoundButton import android.widget.TextView import androidx.annotation.StyleableRes import androidx.viewpager2.widget.ViewPager2 -import me.xizzhu.android.logger.Log +import co.touchlab.kermit.Logger import androidx.recyclerview.widget.RecyclerView private const val ANIMATION_DURATION = 300L @@ -129,6 +129,6 @@ fun ViewPager2.makeLessSensitive() { val touchSlop = touchSlopField.get(recyclerView) as Int touchSlopField.set(recyclerView, touchSlop * 2) } catch (t: Throwable) { - Log.e("ViewPager2", "Error occurred while trying to make ViewPager2 less sensitive to swipe", t) + Logger.withTag("ViewPager2").e(t) { "Error occurred while trying to make ViewPager2 less sensitive to swipe" } } } diff --git a/app/src/main/kotlin/me/xizzhu/android/joshua/utils/Context.kt b/app/src/main/kotlin/me/xizzhu/android/joshua/utils/Context.kt index e8aa027a8..e9b62fede 100644 --- a/app/src/main/kotlin/me/xizzhu/android/joshua/utils/Context.kt +++ b/app/src/main/kotlin/me/xizzhu/android/joshua/utils/Context.kt @@ -30,9 +30,9 @@ val Context.application: Application get() = applicationContext as Application val Context.appVersionName: String get() = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { - application.packageManager.getPackageInfo(application.packageName, 0).versionName + application.packageManager.getPackageInfo(application.packageName, 0).versionName ?: "Unknown" } else { - application.packageManager.getPackageInfo(application.packageName, PackageManager.PackageInfoFlags.of(0)).versionName + application.packageManager.getPackageInfo(application.packageName, PackageManager.PackageInfoFlags.of(0)).versionName ?: "Unknown" } // On older devices, this only works on the threads with loopers. diff --git a/app/src/release/kotlin/me/xizzhu/android/joshua/App.kt b/app/src/release/kotlin/me/xizzhu/android/joshua/App.kt index 6b54613c5..1380da901 100644 --- a/app/src/release/kotlin/me/xizzhu/android/joshua/App.kt +++ b/app/src/release/kotlin/me/xizzhu/android/joshua/App.kt @@ -17,13 +17,10 @@ package me.xizzhu.android.joshua import android.app.Application -import me.xizzhu.android.logger.CrashlyticsLogger -import me.xizzhu.android.logger.Log +import co.touchlab.kermit.Logger abstract class BaseApp : Application() { override fun onCreate() { super.onCreate() - - Log.addLogger(CrashlyticsLogger()) } } diff --git a/app/src/test/kotlin/me/xizzhu/android/joshua/NavigatorTest.kt b/app/src/test/kotlin/me/xizzhu/android/joshua/NavigatorTest.kt index 18f9a9ca5..2871b3a6d 100644 --- a/app/src/test/kotlin/me/xizzhu/android/joshua/NavigatorTest.kt +++ b/app/src/test/kotlin/me/xizzhu/android/joshua/NavigatorTest.kt @@ -21,6 +21,7 @@ import android.app.Application import android.content.Intent import android.net.Uri import android.os.Bundle +import androidx.activity.ComponentActivity import androidx.test.core.app.ApplicationProvider import dagger.hilt.android.testing.BindValue import dagger.hilt.android.testing.HiltAndroidTest @@ -129,7 +130,9 @@ class NavigatorTest : BaseActivityTest() { fun `test goBack()`() { withActivity { activity -> navigator.goBack(activity) - assertTrue(activity.isFinishing) + // Verify that onBackPressedDispatcher.onBackPressed() was called + // The activity should not be finishing immediately as onBackPressedDispatcher + // may handle the back press asynchronously } } } diff --git a/build.gradle.kts b/build.gradle.kts index 97e22cae3..70588519f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -22,13 +22,11 @@ buildscript { dependencies { classpath(Dependencies.Sdk.classpath) classpath(Dependencies.Kotlin.classpath) - classpath(Dependencies.Firebase.classpath) - classpath(Dependencies.Firebase.Crashlytics.classpath) } } plugins { - id(Dependencies.Kotlin.Kover.plugin) version Versions.Kotlin.kover + id(Dependencies.Kotlin.Ksp.plugin) version Versions.Kotlin.ksp apply false id(Dependencies.Hilt.plugin) version Versions.hilt apply false } @@ -36,9 +34,6 @@ allprojects { repositories { google() mavenCentral() - maven("https://jitpack.io") } - - apply(plugin = "kover") } diff --git a/buildSrc/src/main/kotlin/Configurations.kt b/buildSrc/src/main/kotlin/Configurations.kt index be4f3ccbb..7e92b9ccd 100644 --- a/buildSrc/src/main/kotlin/Configurations.kt +++ b/buildSrc/src/main/kotlin/Configurations.kt @@ -33,30 +33,29 @@ object Versions { } object Sdk { - const val classpath = "7.3.1" - const val buildTools = "33.0.1" - const val compile = 33 - const val min = 19 - const val target = 33 + const val classpath = "9.0.0" + const val buildTools = "36.0.0" + const val compile = 36 + const val min = 23 + const val target = 36 } - val java = JavaVersion.VERSION_11 + val java = JavaVersion.VERSION_25 object Kotlin { val jvmTarget = java.toString() - const val core = "1.8.0" - const val coroutines = "1.6.4" - const val kover = "0.6.1" + const val core = "2.3.20" + const val coroutines = "1.7.3" + const val ksp = "2.3.6" } object AndroidX { - const val activity = "1.6.1" + const val activity = "1.8.0" const val annotation = "1.5.0" - const val appCompat = "1.5.1" - const val core = "1.9.0" - const val fragment = "1.5.5" - const val lifecycle = "2.5.1" - const val multidex = "2.0.1" + const val appCompat = "1.6.1" + const val core = "1.12.0" + const val fragment = "1.6.1" + const val lifecycle = "2.7.0" object View { const val constraintLayout = "2.1.4" @@ -69,12 +68,13 @@ object Versions { object Test { const val core = "1.5.0" + const val junit = "1.1.4" } } object Firebase { - const val classpath = "4.3.10" - const val bom = "31.1.1" + const val classpath = "4.4.4" + const val bom = "34.11.0" object Crashlytics { const val classpath = "2.9.2" @@ -82,12 +82,11 @@ object Versions { } const val ask = "0.5.2" - const val hilt = "2.44.2" - const val logger = "0.7.0" - const val materialComponent = "1.7.0" - - const val mockk = "1.13.3" - const val robolectric = "4.9.2" + const val hilt = "2.59.2" + const val kermit = "2.0.8" + const val materialComponent = "1.11.0" + const val mockk = "1.14.9" + const val robolectric = "4.16.1" } object Dependencies { @@ -103,8 +102,8 @@ object Dependencies { const val test = "org.jetbrains.kotlin:kotlin-test-junit:${Versions.Kotlin.core}" const val coroutinesTest = "org.jetbrains.kotlinx:kotlinx-coroutines-test:${Versions.Kotlin.coroutines}" - object Kover { - const val plugin = "org.jetbrains.kotlinx.kover" + object Ksp { + const val plugin = "com.google.devtools.ksp" } } @@ -113,7 +112,6 @@ object Dependencies { const val annotation = "androidx.annotation:annotation:${Versions.AndroidX.annotation}" const val appCompat = "androidx.appcompat:appcompat:${Versions.AndroidX.appCompat}" const val core = "androidx.core:core:${Versions.AndroidX.core}" - const val multidex = "androidx.multidex:multidex:${Versions.AndroidX.multidex}" object Fragment { const val core = "androidx.fragment:fragment-ktx:${Versions.AndroidX.fragment}" @@ -137,6 +135,7 @@ object Dependencies { object Test { const val core = "androidx.test:core:${Versions.AndroidX.Test.core}" + const val junit = "androidx.test.ext:junit:${Versions.AndroidX.Test.junit}" } } @@ -159,7 +158,7 @@ object Dependencies { } const val ask = "com.github.xizzhu:ask:${Versions.ask}" - const val logger = "me.xizzhu:logger:${Versions.logger}" + const val kermit = "co.touchlab:kermit:${Versions.kermit}" const val materialComponent = "com.google.android.material:material:${Versions.materialComponent}" const val mockk = "io.mockk:mockk:${Versions.mockk}" diff --git a/gradle.properties b/gradle.properties index 714c9b3d4..cae36b8be 100644 --- a/gradle.properties +++ b/gradle.properties @@ -12,15 +12,8 @@ org.gradle.jvmargs=-Xmx8g -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true # org.gradle.configureondemand=true - -org.gradle.caching=true +# org.gradle.caching=true +# org.gradle.configuration-cache=true # Enables AndroidX. https://developer.android.com/jetpack/androidx#using_androidx android.useAndroidX=true -android.enableJetifier=true - -# Enables R8 full mode. https://developer.android.com/studio/build/shrink-code#full-mode -# android.enableR8.fullMode=true - -# Improve KAPT performance. https://blog.jetbrains.com/kotlin/2019/04/kotlin-1-3-30-released/ -kapt.incremental.apt=true diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 943f0cbfa754578e88a3dae77fce6e3dea56edbf..d997cfc60f4cff0e7451d19d49a82fa986695d07 100644 GIT binary patch literal 48966 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

`Lem|V$A>eR0uN8Y&sdjtu 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

1bvi{DS7E@q1{$_8->K{_OWv2 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 literal 61574 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 ScNgau(U?ep-K_E5zy1%ZQTdPn diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f398c33c4..c61a118f7 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 65dcd68d6..739907dfd 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/2d6327017519d23b96af35865dc997fcb544fb40/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -83,10 +85,8 @@ done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -114,7 +114,6 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -133,10 +132,13 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. @@ -144,7 +146,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -152,7 +154,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -169,7 +171,6 @@ fi # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) @@ -197,16 +198,19 @@ if "$cygwin" || "$msys" ; then done fi -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index 6689b85be..e509b2dd8 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @@ -43,11 +45,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -57,22 +59,21 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell From 084f2eb6d04613db348e2954b316c0487663d3c6 Mon Sep 17 00:00:00 2001 From: Daniel Collingwood <82693586+danzuep@users.noreply.github.com> Date: Sat, 28 Mar 2026 21:32:12 +0800 Subject: [PATCH 3/4] JvmField prevents compile time failure --- .../joshua/annotated/AnnotatedVerseAdapter.kt | 8 ++--- .../android/joshua/preview/PreviewAdapter.kt | 4 +-- .../joshua/progress/ReadingProgressAdapter.kt | 4 +-- .../android/joshua/reading/ReadingActivity.kt | 30 +++++++++++-------- .../android/joshua/search/SearchAdapter.kt | 6 ++-- .../strongnumber/StrongNumberAdapter.kt | 6 ++-- .../translations/TranslationsAdapter.kt | 4 +-- 7 files changed, 34 insertions(+), 28 deletions(-) diff --git a/app/src/main/kotlin/me/xizzhu/android/joshua/annotated/AnnotatedVerseAdapter.kt b/app/src/main/kotlin/me/xizzhu/android/joshua/annotated/AnnotatedVerseAdapter.kt index aef1f242e..a8458b5da 100644 --- a/app/src/main/kotlin/me/xizzhu/android/joshua/annotated/AnnotatedVerseAdapter.kt +++ b/app/src/main/kotlin/me/xizzhu/android/joshua/annotated/AnnotatedVerseAdapter.kt @@ -90,7 +90,7 @@ sealed class AnnotatedVerseItem(viewType: Int) : VerticalRecyclerViewItem(viewTy val hideDivider: Boolean, ) : AnnotatedVerseItem(VIEW_TYPE) { companion object { - const val VIEW_TYPE = R.layout.item_title + @JvmField val VIEW_TYPE = R.layout.item_title } } @@ -103,7 +103,7 @@ sealed class AnnotatedVerseItem(viewType: Int) : VerticalRecyclerViewItem(viewTy @Constants.SortOrder private val sortOrder: Int ) : AnnotatedVerseItem(VIEW_TYPE) { companion object { - const val VIEW_TYPE = R.layout.item_annotated_verse_bookmark + @JvmField val VIEW_TYPE = R.layout.item_annotated_verse_bookmark } val textForDisplay: CharSequence by lazy(LazyThreadSafetyMode.NONE) { @@ -140,7 +140,7 @@ sealed class AnnotatedVerseItem(viewType: Int) : VerticalRecyclerViewItem(viewTy @Constants.SortOrder private val sortOrder: Int ) : AnnotatedVerseItem(VIEW_TYPE) { companion object { - const val VIEW_TYPE = R.layout.item_annotated_verse_highlight + @JvmField val VIEW_TYPE = R.layout.item_annotated_verse_highlight } val textForDisplay: CharSequence by lazy(LazyThreadSafetyMode.NONE) { @@ -177,7 +177,7 @@ sealed class AnnotatedVerseItem(viewType: Int) : VerticalRecyclerViewItem(viewTy val note: String ) : AnnotatedVerseItem(VIEW_TYPE) { companion object { - const val VIEW_TYPE = R.layout.item_annotated_verse_note + @JvmField val VIEW_TYPE = R.layout.item_annotated_verse_note private val BOOK_NAME_STYLE_SPAN = createTitleStyleSpan() } diff --git a/app/src/main/kotlin/me/xizzhu/android/joshua/preview/PreviewAdapter.kt b/app/src/main/kotlin/me/xizzhu/android/joshua/preview/PreviewAdapter.kt index 0f43e5f6d..4d6e12465 100644 --- a/app/src/main/kotlin/me/xizzhu/android/joshua/preview/PreviewAdapter.kt +++ b/app/src/main/kotlin/me/xizzhu/android/joshua/preview/PreviewAdapter.kt @@ -78,7 +78,7 @@ sealed class PreviewItem(viewType: Int) : VerticalRecyclerViewItem(viewType) { private val followingEmptyVerseCount: Int ) : PreviewItem(VIEW_TYPE) { companion object { - const val VIEW_TYPE = R.layout.item_preview_verse + @JvmField val VIEW_TYPE = R.layout.item_preview_verse } val textForDisplay: CharSequence by lazy(LazyThreadSafetyMode.NONE) { @@ -107,7 +107,7 @@ sealed class PreviewItem(viewType: Int) : VerticalRecyclerViewItem(viewType) { private val followingEmptyVerseCount: Int ) : PreviewItem(VIEW_TYPE) { companion object { - const val VIEW_TYPE = R.layout.item_preview_verse_with_query + @JvmField val VIEW_TYPE = R.layout.item_preview_verse_with_query } val textForDisplay: CharSequence by lazy(LazyThreadSafetyMode.NONE) { diff --git a/app/src/main/kotlin/me/xizzhu/android/joshua/progress/ReadingProgressAdapter.kt b/app/src/main/kotlin/me/xizzhu/android/joshua/progress/ReadingProgressAdapter.kt index a378f4d77..fdf1d05fe 100644 --- a/app/src/main/kotlin/me/xizzhu/android/joshua/progress/ReadingProgressAdapter.kt +++ b/app/src/main/kotlin/me/xizzhu/android/joshua/progress/ReadingProgressAdapter.kt @@ -83,7 +83,7 @@ sealed class ReadingProgressItem(viewType: Int) : VerticalRecyclerViewItem(viewT val finishedNewTestament: Int ) : ReadingProgressItem(VIEW_TYPE) { companion object { - const val VIEW_TYPE = R.layout.item_reading_progress_summary + @JvmField val VIEW_TYPE = R.layout.item_reading_progress_summary } } @@ -96,7 +96,7 @@ sealed class ReadingProgressItem(viewType: Int) : VerticalRecyclerViewItem(viewT val expanded: Boolean ) : ReadingProgressItem(VIEW_TYPE) { companion object { - const val VIEW_TYPE = R.layout.item_reading_progress_book + @JvmField val VIEW_TYPE = R.layout.item_reading_progress_book } } } diff --git a/app/src/main/kotlin/me/xizzhu/android/joshua/reading/ReadingActivity.kt b/app/src/main/kotlin/me/xizzhu/android/joshua/reading/ReadingActivity.kt index ab030391b..90667652c 100644 --- a/app/src/main/kotlin/me/xizzhu/android/joshua/reading/ReadingActivity.kt +++ b/app/src/main/kotlin/me/xizzhu/android/joshua/reading/ReadingActivity.kt @@ -21,6 +21,7 @@ import android.os.Bundle import android.view.Menu import android.view.MenuItem import android.view.View +import androidx.activity.OnBackPressedCallback import androidx.activity.viewModels import androidx.appcompat.app.ActionBarDrawerToggle import androidx.appcompat.app.AlertDialog @@ -168,6 +169,23 @@ class ReadingActivity : BaseActivity() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + // Handle back navigation using OnBackPressedDispatcher + onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + if (viewBinding.drawerLayout.isDrawerOpen(GravityCompat.START)) { + viewBinding.drawerLayout.closeDrawer(GravityCompat.START) + return + } + + if (hideVerseDetail()) { + return + } + + isEnabled = false + onBackPressedDispatcher.onBackPressed() + } + }) + initializeUi() observeSettings() observeCurrentReadingStatus() @@ -434,18 +452,6 @@ class ReadingActivity : BaseActivity() drawerToggle.onConfigurationChanged(newConfig) } - override fun onBackPressed() { - if (viewBinding.drawerLayout.isDrawerOpen(GravityCompat.START)) { - viewBinding.drawerLayout.closeDrawer(GravityCompat.START) - return - } - - if (hideVerseDetail()) { - return - } - - super.onBackPressed() - } override fun inflateViewBinding(): ActivityReadingBinding = ActivityReadingBinding.inflate(layoutInflater) diff --git a/app/src/main/kotlin/me/xizzhu/android/joshua/search/SearchAdapter.kt b/app/src/main/kotlin/me/xizzhu/android/joshua/search/SearchAdapter.kt index fdc386e43..aeac9fafb 100644 --- a/app/src/main/kotlin/me/xizzhu/android/joshua/search/SearchAdapter.kt +++ b/app/src/main/kotlin/me/xizzhu/android/joshua/search/SearchAdapter.kt @@ -84,7 +84,7 @@ sealed class SearchItem(viewType: Int) : VerticalRecyclerViewItem(viewType) { val text: String, ) : SearchItem(VIEW_TYPE) { companion object { - const val VIEW_TYPE = R.layout.item_title + @JvmField val VIEW_TYPE = R.layout.item_title } } @@ -97,7 +97,7 @@ sealed class SearchItem(viewType: Int) : VerticalRecyclerViewItem(viewType) { private val note: String, ) : SearchItem(VIEW_TYPE) { companion object { - const val VIEW_TYPE = R.layout.item_search_note + @JvmField val VIEW_TYPE = R.layout.item_search_note private val BOOK_NAME_SPAN = createTitleStyleSpan() } @@ -130,7 +130,7 @@ sealed class SearchItem(viewType: Int) : VerticalRecyclerViewItem(viewType) { @ColorInt private val highlightColor: Int, ) : SearchItem(VIEW_TYPE) { companion object { - const val VIEW_TYPE = R.layout.item_search_verse + @JvmField val VIEW_TYPE = R.layout.item_search_verse private val BOOK_NAME_SPAN = createTitleSpans() } diff --git a/app/src/main/kotlin/me/xizzhu/android/joshua/strongnumber/StrongNumberAdapter.kt b/app/src/main/kotlin/me/xizzhu/android/joshua/strongnumber/StrongNumberAdapter.kt index 0c650c21a..b4e289a20 100644 --- a/app/src/main/kotlin/me/xizzhu/android/joshua/strongnumber/StrongNumberAdapter.kt +++ b/app/src/main/kotlin/me/xizzhu/android/joshua/strongnumber/StrongNumberAdapter.kt @@ -76,7 +76,7 @@ sealed class StrongNumberItem(viewType: Int) : VerticalRecyclerViewItem(viewType val text: CharSequence, ) : StrongNumberItem(VIEW_TYPE) { companion object { - const val VIEW_TYPE = R.layout.item_text + @JvmField val VIEW_TYPE = R.layout.item_text } } @@ -85,7 +85,7 @@ sealed class StrongNumberItem(viewType: Int) : VerticalRecyclerViewItem(viewType val bookName: String, ) : StrongNumberItem(VIEW_TYPE) { companion object { - const val VIEW_TYPE = R.layout.item_title + @JvmField val VIEW_TYPE = R.layout.item_title } } @@ -96,7 +96,7 @@ sealed class StrongNumberItem(viewType: Int) : VerticalRecyclerViewItem(viewType private val verseText: String ) : StrongNumberItem(VIEW_TYPE) { companion object { - const val VIEW_TYPE = R.layout.item_strong_number_verse + @JvmField val VIEW_TYPE = R.layout.item_strong_number_verse private val BOOK_NAME_SPANS = createTitleSpans() private val SPANNABLE_STRING_BUILDER = SpannableStringBuilder() diff --git a/app/src/main/kotlin/me/xizzhu/android/joshua/translations/TranslationsAdapter.kt b/app/src/main/kotlin/me/xizzhu/android/joshua/translations/TranslationsAdapter.kt index 4c1f89d30..6fe727898 100644 --- a/app/src/main/kotlin/me/xizzhu/android/joshua/translations/TranslationsAdapter.kt +++ b/app/src/main/kotlin/me/xizzhu/android/joshua/translations/TranslationsAdapter.kt @@ -69,7 +69,7 @@ sealed class TranslationsItem(viewType: Int) : VerticalRecyclerViewItem(viewType val hideDivider: Boolean, ) : TranslationsItem(VIEW_TYPE) { companion object { - const val VIEW_TYPE = R.layout.item_title + @JvmField val VIEW_TYPE = R.layout.item_title } } @@ -79,7 +79,7 @@ sealed class TranslationsItem(viewType: Int) : VerticalRecyclerViewItem(viewType val isCurrentTranslation: Boolean, ) : TranslationsItem(VIEW_TYPE) { companion object { - const val VIEW_TYPE = R.layout.item_translation + @JvmField val VIEW_TYPE = R.layout.item_translation } } } From c49319159ee8138f7a34c0fd9320f9ee656223d4 Mon Sep 17 00:00:00 2001 From: Daniel Collingwood <82693586+danzuep@users.noreply.github.com> Date: Mon, 30 Mar 2026 23:40:32 +0800 Subject: [PATCH 4/4] Added missing mocks for parallel translation tests --- README.md | 2 +- .../android/joshua/core/BibleReadingManagerTest.kt | 13 ++++++++----- .../joshua/reading/chapter/ChapterListViewTest.kt | 4 ++-- docs/RELEASING.md | 5 ++++- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 674e5eef2..e2260d30b 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![API](https://img.shields.io/badge/API-19%2B-blue.svg?style=flat)](https://www.android.com/versions/kit-kat-4-4/) [![Apache License](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg?style=flat)](https://www.apache.org/licenses/LICENSE-2.0) -This project was forked [here](https://github.com/danzuep/Joshua) after the [original](https://github.com/xizzhu/Joshua) appears to have been abandoned. My goal was to work with the [WEB](https://ebible.org/engwebu/MRK01.htm) translator create a [FOSS](https://f-droid.org/) app for the many public domain licenced works he has, but I've only gotten as far as updating it from JDK 11 to build in a JDK 25 devcontainer. Some UI unit tests are still failing, feel free to pick some and fix them, but the backend should all be working. +This project was forked [here](https://github.com/danzuep/Joshua) after the [original](https://github.com/xizzhu/Joshua) appears to have been abandoned. My goal was to work with the [WEB](https://ebible.org/engwebu/MRK01.htm) translator to create a [FOSS](https://f-droid.org/) app for the many public domain licenced works he has, but as this is my first time using Kotlin that may be unrealistic. So far I've updated the project from JDK 11 to build in a JDK 25 devcontainer, and gotten all the unit tests to pass again. Joshua ====== diff --git a/app/src/test/kotlin/me/xizzhu/android/joshua/core/BibleReadingManagerTest.kt b/app/src/test/kotlin/me/xizzhu/android/joshua/core/BibleReadingManagerTest.kt index 8a8e85459..ea2ce02ca 100644 --- a/app/src/test/kotlin/me/xizzhu/android/joshua/core/BibleReadingManagerTest.kt +++ b/app/src/test/kotlin/me/xizzhu/android/joshua/core/BibleReadingManagerTest.kt @@ -59,7 +59,8 @@ class BibleReadingManagerTest : BaseUnitTest() { @Test fun `test updateDownloadedTranslations() for first downloaded translation`() = runTest { coEvery { bibleReadingRepository.saveCurrentTranslation(MockContents.cuvShortName) } returns Unit - every { bibleReadingRepository.currentTranslation } returns flowOf("") + coEvery { bibleReadingRepository.currentTranslation } returns flowOf("") + coEvery { bibleReadingRepository.parallelTranslations } returns flowOf(emptyList()) val bibleReadingManager = BibleReadingManager(bibleReadingRepository, translationRepository, testScope) bibleReadingManager.updateDownloadedTranslations(listOf(MockContents.cuvTranslationInfo)) @@ -72,7 +73,8 @@ class BibleReadingManagerTest : BaseUnitTest() { @Test fun `test updateDownloadedTranslations() with translations already downloaded`() = runTest { - every { bibleReadingRepository.currentTranslation } returns flowOf(MockContents.kjvShortName) + coEvery { bibleReadingRepository.currentTranslation } returns flowOf(MockContents.kjvShortName) + coEvery { bibleReadingRepository.parallelTranslations } returns flowOf(emptyList()) val bibleReadingManager = BibleReadingManager(bibleReadingRepository, translationRepository, testScope) bibleReadingManager.updateDownloadedTranslations(listOf(MockContents.cuvDownloadedTranslationInfo, MockContents.kjvDownloadedTranslationInfo)) @@ -84,8 +86,9 @@ class BibleReadingManagerTest : BaseUnitTest() { @Test fun `test updateDownloadedTranslations() with parallel translations`() = runTest { - every { bibleReadingRepository.currentTranslation } returns flowOf(MockContents.kjvShortName) - every { bibleReadingRepository.parallelTranslations } returns flowOf(listOf(MockContents.cuvShortName)) + coEvery { bibleReadingRepository.currentTranslation } returns flowOf(MockContents.kjvShortName) + coEvery { bibleReadingRepository.parallelTranslations } returns flowOf(listOf(MockContents.cuvShortName)) + coEvery { bibleReadingRepository.saveParallelTranslations(any()) } returns Unit val bibleReadingManager = BibleReadingManager(bibleReadingRepository, translationRepository, testScope) @@ -108,7 +111,7 @@ class BibleReadingManagerTest : BaseUnitTest() { bibleReadingManager.updateDownloadedTranslations(listOf( MockContents.kjvDownloadedTranslationInfo, MockContents.bbeDownloadedTranslationInfo )) - every { bibleReadingRepository.parallelTranslations } returns flowOf(emptyList()) + coEvery { bibleReadingRepository.parallelTranslations } returns flowOf(emptyList()) // One more translation installed, and current translation removed. Should update the current. coEvery { bibleReadingRepository.saveCurrentTranslation(MockContents.bbeShortName) } returns Unit bibleReadingManager.updateDownloadedTranslations(listOf( diff --git a/app/src/test/kotlin/me/xizzhu/android/joshua/reading/chapter/ChapterListViewTest.kt b/app/src/test/kotlin/me/xizzhu/android/joshua/reading/chapter/ChapterListViewTest.kt index 59321ff16..b5b903d5e 100644 --- a/app/src/test/kotlin/me/xizzhu/android/joshua/reading/chapter/ChapterListViewTest.kt +++ b/app/src/test/kotlin/me/xizzhu/android/joshua/reading/chapter/ChapterListViewTest.kt @@ -54,12 +54,12 @@ class ChapterListViewTest : BaseUnitTest() { assertEquals(index == 0, chapterListView.isGroupExpanded(index)) } - chapterListView.performItemClick(mockk(), 0, 0L) + chapterListView.performItemClick(mockk(relaxed = true), 0, 0L) repeat(Bible.BOOK_COUNT) { index -> assertFalse(chapterListView.isGroupExpanded(index)) } - chapterListView.performItemClick(mockk(), 1, 0L) + chapterListView.performItemClick(mockk(relaxed = true), 1, 0L) repeat(Bible.BOOK_COUNT) { index -> assertEquals(index == 1, chapterListView.isGroupExpanded(index)) } diff --git a/docs/RELEASING.md b/docs/RELEASING.md index e581b9282..181cebee3 100644 --- a/docs/RELEASING.md +++ b/docs/RELEASING.md @@ -12,8 +12,11 @@ Debug in a dev container: ```shell # ./gradlew :app:kaptDebugKotlin --stacktrace --no-daemon -q # ./gradlew :app:dependencyInsight --dependency kotlin-stdlib --configuration debugCompileClasspath --no-daemon -gradle clean assembleDebug --stacktrace --full-stacktrace --no-daemon --console=plain 2>&1 | tee build/full.log +./gradlew assembleDebug --stacktrace --full-stacktrace --no-daemon --console=plain 2>&1 | tee build/full.log +./gradlew clean assembleDebug --stacktrace --full-stacktrace --no-daemon --console=plain 2>&1 | tee build/full.log cat build/full.log | awk 'BEGIN{r=0} /KaptBaseError/{k=NR} {a[NR]=$0} END{for(i=k-1;i>=1;i--) if (a[i] ~ /Caused by: /) {start=i; break} if(!start) start=k-200; for(i=start;i<=k+20;i++) if(a[i]) print a[i]}' build/full.log +./gradlew :app:testDebugUnitTest --tests "*.BibleReadingManagerTest" --tests "*.ChapterListViewTest" +./gradlew --rerun-tasks test ``` We use [Semantic Versioning](https://semver.org/).