diff --git a/.github/workflows/static-sonarqube.yml b/.github/workflows/static-sonarqube.yml new file mode 100755 index 00000000..f4f67424 --- /dev/null +++ b/.github/workflows/static-sonarqube.yml @@ -0,0 +1,74 @@ +name: static-sonarqube + +on: + push: + branches: + - "*" + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + name: Build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 1 + submodules: true + + - name: local.properties + env: + LOCAL_PROPERTIES: ${{ secrets.LOCAL_PROPERTIES }} + run: | + echo "$LOCAL_PROPERTIES" | base64 -d > local.properties + + - name: local.properties.cloudLib + env: + LOCAL_PROPERTIES: ${{ secrets.LOCAL_PROPERTIES_CLOUDLIB }} + run: | + echo "$LOCAL_PROPERTIES" | base64 -d > QuoteUnquote.cloudLib/local.properties + ls -al QuoteUnquote.cloudLib/local.properties + + - name: local.properties.utilsLib + env: + LOCAL_PROPERTIES: ${{ secrets.LOCAL_PROPERTIES_UTILSLIB }} + run: | + echo "$LOCAL_PROPERTIES" | base64 -d > QuoteUnquote.utilsLib/local.properties + ls -al QuoteUnquote.utilsLib/local.properties + + - name: set up jdk + uses: actions/setup-java@v4 + with: + distribution: 'zulu' + java-version: 17 + + - name: Cache SonarCloud packages + uses: actions/cache@v4 + with: + path: ~/.sonar/cache + key: ${{ runner.os }}-sonar + restore-keys: ${{ runner.os }}-sonar + + - name: Cache Gradle packages + uses: actions/cache@v4 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} + restore-keys: ${{ runner.os }}-gradle + + - name: compileFdroidDebugKotlin + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + run: | + ./gradlew :app:compileFdroidDebugKotlin :app:compileFdroidDebugJavaWithJavac + + - name: sonar + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + run: | + ./gradlew app:sonar --info diff --git a/.idea/androidTestResultsUserPreferences.xml b/.idea/androidTestResultsUserPreferences.xml index fb508698..d670621c 100644 --- a/.idea/androidTestResultsUserPreferences.xml +++ b/.idea/androidTestResultsUserPreferences.xml @@ -341,6 +341,19 @@ + + + + + + + diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index 95b35e4b..920dabfb 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -1,9 +1,16 @@ + + + + - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index b3bebd26..1f07edd7 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,3 @@ - - + diff --git a/.idea/runConfigurations/_app_androidTest.xml b/.idea/runConfigurations/_app_androidTest.xml index 37e91ab6..5e02adcb 100755 --- a/.idea/runConfigurations/_app_androidTest.xml +++ b/.idea/runConfigurations/_app_androidTest.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/.idea/runConfigurations/_app_androidTest_espresso___Fdroid_SourceSet.xml b/.idea/runConfigurations/_app_androidTest_espresso___Fdroid_SourceSet.xml index c95522ab..7974419f 100755 --- a/.idea/runConfigurations/_app_androidTest_espresso___Fdroid_SourceSet.xml +++ b/.idea/runConfigurations/_app_androidTest_espresso___Fdroid_SourceSet.xml @@ -1,6 +1,5 @@ - \ No newline at end of file diff --git a/.idea/runConfigurations/_app_androidTest_uiautomator___Fdroid_SourceSet.xml b/.idea/runConfigurations/_app_androidTest_uiautomator___Fdroid_SourceSet.xml index d867d30e..5d642b35 100755 --- a/.idea/runConfigurations/_app_androidTest_uiautomator___Fdroid_SourceSet.xml +++ b/.idea/runConfigurations/_app_androidTest_uiautomator___Fdroid_SourceSet.xml @@ -1,6 +1,5 @@ - \ No newline at end of file diff --git a/QuoteUnquote.cloudLib b/QuoteUnquote.cloudLib index a0332a10..9a0df87a 160000 --- a/QuoteUnquote.cloudLib +++ b/QuoteUnquote.cloudLib @@ -1 +1 @@ -Subproject commit a0332a109abd7c05df7622c35c06c3a55a479b43 +Subproject commit 9a0df87aff43c58931736380f925b014f0c9a313 diff --git a/QuoteUnquote.utilsLib b/QuoteUnquote.utilsLib index aa81228e..dafb1b65 160000 --- a/QuoteUnquote.utilsLib +++ b/QuoteUnquote.utilsLib @@ -1 +1 @@ -Subproject commit aa81228e4b13ae9936f2374cf9ee1307bbf39556 +Subproject commit dafb1b65c4ea7632852590cbd9365b2aaf8c1b71 diff --git a/README.md b/README.md index 4aec8e16..06d259d5 100755 --- a/README.md +++ b/README.md @@ -9,9 +9,9 @@ | | ci | codecov | codacy | sonarcloud | deployment | |------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | :app | codecov.yml | codecov.yml | [![Codacy Badge](https://app.codacy.com/project/badge/Grade/0d6227a494f747439d748802ca595999)](https://www.codacy.com/gh/jameshnsears/QuoteUnquote/dashboard?utm_source=github.com&utm_medium=referral&utm_content=jameshnsears/QuoteUnquote&utm_campaign=Badge_Grade) | | | -| [:cloudLib](https://github.com/jameshnsears/QuoteUnquote.cloudLib) | [![coverage](https://github.com/jameshnsears/QuoteUnquote.cloudLib/actions/workflows/coverage.yml/badge.svg)](https://github.com/jameshnsears/QuoteUnquote.cloudLib/actions/workflows/coverage.yml) | [![codecov](https://codecov.io/gh/jameshnsears/QuoteUnquote.cloudLib/branch/main/graph/badge.svg?token=hjNc1SbSgT)](https://codecov.io/gh/jameshnsears/QuoteUnquote.cloudLib) | [![Codacy Badge](https://app.codacy.com/project/badge/Grade/78d7a9a166b9420b9dc47991ef7cb028)](https://www.codacy.com/gh/jameshnsears/QuoteUnquote.cloudLib/dashboard?utm_source=github.com&utm_medium=referral&utm_content=jameshnsears/QuoteUnquote.cloudLib&utm_campaign=Badge_Grade) | [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=jameshnsears_QuoteUnquote.cloudLib&metric=alert_status)](https://sonarcloud.io/dashboard?id=jameshnsears_QuoteUnquote.cloudLib) | | | +| [:cloudLib](https://github.com/jameshnsears/QuoteUnquote.cloudLib) | [![coverage](https://github.com/jameshnsears/QuoteUnquote.cloudLib/actions/workflows/coverage.yml/badge.svg)](https://github.com/jameshnsears/QuoteUnquote.cloudLib/actions/workflows/coverage.yml) | [![codecov](https://codecov.io/gh/jameshnsears/QuoteUnquote.cloudLib/branch/main/graph/badge.svg?token=hjNc1SbSgT)](https://codecov.io/gh/jameshnsears/QuoteUnquote.cloudLib) | [![Codacy Badge](https://app.codacy.com/project/badge/Grade/78d7a9a166b9420b9dc47991ef7cb028)](https://www.codacy.com/gh/jameshnsears/QuoteUnquote.cloudLib/dashboard?utm_source=github.com&utm_medium=referral&utm_content=jameshnsears/QuoteUnquote.cloudLib&utm_campaign=Badge_Grade) | [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=jameshnsears_QuoteUnquote.cloudLib&metric=alert_status)](https://sonarcloud.io/dashboard?id=jameshnsears_QuoteUnquote.cloudLib) | | | | [functions](https://github.com/jameshnsears/QuoteUnquote.cloudLib.functions) | [![coverage](https://github.com/jameshnsears/QuoteUnquote.cloudLib.functions/actions/workflows/coverage.yml/badge.svg)](https://github.com/jameshnsears/QuoteUnquote.cloudLib.functions/actions/workflows/coverage.yml) | [![codecov](https://codecov.io/gh/jameshnsears/QuoteUnquote.cloudLib.functions/branch/main/graph/badge.svg?token=jc55AxH2ry)](https://codecov.io/gh/jameshnsears/QuoteUnquote.cloudLib.functions) | [![Codacy Badge](https://app.codacy.com/project/badge/Grade/5c0ebcf94aac443a8637460cf1a4068b)](https://www.codacy.com/gh/jameshnsears/QuoteUnquote.cloudLib.functions/dashboard?utm_source=github.com&utm_medium=referral&utm_content=jameshnsears/QuoteUnquote.cloudLib.functions&utm_campaign=Badge_Grade) | [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=jameshnsears_QuoteUnquote.cloudLib.functions&metric=alert_status)](https://sonarcloud.io/dashboard?id=jameshnsears_QuoteUnquote.cloudLib.functions) | [![deploy-gcp](https://github.com/jameshnsears/QuoteUnquote.cloudLib.functions/workflows/deploy-gcp/badge.svg)](https://github.com/jameshnsears/QuoteUnquote.cloudLib.functions/actions?query=workflow%3Adeploy-gcp) | -| [:utilsLib](https://github.com/jameshnsears/QuoteUnquote.utilsLib) | [![coverage](https://github.com/jameshnsears/QuoteUnquote.utilsLib/actions/workflows/coverage.yml/badge.svg)](https://github.com/jameshnsears/QuoteUnquote.utilsLib/actions/workflows/coverage.yml) | [![codecov](https://codecov.io/gh/jameshnsears/QuoteUnquote.utilsLib/branch/main/graph/badge.svg?token=UmWdOTiqB7)](https://codecov.io/gh/jameshnsears/QuoteUnquote.utilsLib) | [![Codacy Badge](https://app.codacy.com/project/badge/Grade/e9cd947f7acf4a5cb090d49a09a7df3f)](https://www.codacy.com/gh/jameshnsears/QuoteUnquote.utilsLib/dashboard?utm_source=github.com&utm_medium=referral&utm_content=jameshnsears/QuoteUnquote.utilsLib&utm_campaign=Badge_Grade) | [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=jameshnsears_QuoteUnquote.utilsLib&metric=alert_status)](https://sonarcloud.io/dashboard?id=jameshnsears_QuoteUnquote.utilsLib) | | | +| [:utilsLib](https://github.com/jameshnsears/QuoteUnquote.utilsLib) | [![coverage](https://github.com/jameshnsears/QuoteUnquote.utilsLib/actions/workflows/coverage.yml/badge.svg)](https://github.com/jameshnsears/QuoteUnquote.utilsLib/actions/workflows/coverage.yml) | [![codecov](https://codecov.io/gh/jameshnsears/QuoteUnquote.utilsLib/branch/main/graph/badge.svg?token=UmWdOTiqB7)](https://codecov.io/gh/jameshnsears/QuoteUnquote.utilsLib) | [![Codacy Badge](https://app.codacy.com/project/badge/Grade/e9cd947f7acf4a5cb090d49a09a7df3f)](https://www.codacy.com/gh/jameshnsears/QuoteUnquote.utilsLib/dashboard?utm_source=github.com&utm_medium=referral&utm_content=jameshnsears/QuoteUnquote.utilsLib&utm_campaign=Badge_Grade) | [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=jameshnsears_QuoteUnquote.utilsLib&metric=alert_status)](https://sonarcloud.io/dashboard?id=jameshnsears_QuoteUnquote.utilsLib) | | | ### 1.1. codecov.yml @@ -23,10 +23,9 @@ ## 2. Build Instructions -After cloning extract .gpg files - BuildConfig / GitHub Action Secrets values. +After cloning I extract .gpg files (BuildConfig, GitHub Action Secrets values) to create local.properties -The app can be built on Windows 11 but the ./bin folder contains bash scripts (that work with git -bash; some require gh cli). +The app can be built on Windows 11 but the ./bin folder contains bash scripts (that work with git bash; some require gh cli). ### 2.1. CLI @@ -71,12 +70,12 @@ After a clone... PyCharm > Open > QuoteUnquote.cloudLib.functions File > Settings > Project: - > set Intepreter > New Virtualenv Environment + > set Interpreter > New Virtualenv Environment Virtualenv Terminal > > python -m pip install -r requirements-test.txt > python -m pip install -r src/requirements.txt run a Run/Debug Configuration - > setting Python Intepreter to Virtualenv Environment + > setting Python Interpreter to Virtualenv Environment ``` diff --git a/app/build.gradle b/app/build.gradle index a05388c5..6cd7541d 100755 --- a/app/build.gradle +++ b/app/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.firebase.crashlytics' apply plugin: 'kotlin-android' apply plugin: 'com.diffplug.spotless' -apply plugin: "org.jetbrains.kotlin.plugin.compose" +apply plugin: 'org.jetbrains.kotlin.plugin.compose' apply from: '../jacoco.gradle' apply from: '../ktlint.gradle' @@ -47,9 +47,9 @@ android { applicationId "com.github.jameshnsears.quoteunquote" // changelog version | min sdk | target sdk - versionCode 1822435 + versionCode 1832435 // semantic versioning - versionName "4.47.0" + versionName "4.48.0" vectorDrawables.useSupportLibrary = true @@ -75,7 +75,7 @@ android { } composeOptions { - kotlinCompilerExtensionVersion '1.5.1' + kotlinCompilerExtensionVersion '1.5.15' } packagingOptions { @@ -221,7 +221,7 @@ android { dependencies { androidTestImplementation 'androidx.arch.core:core-testing:2.2.0' - androidTestImplementation 'androidx.compose.ui:ui-test-junit4-android:1.7.5' + androidTestImplementation 'androidx.compose.ui:ui-test-junit4-android:1.7.6' androidTestImplementation 'androidx.room:room-testing:2.6.1' androidTestImplementation 'androidx.test:core:1.6.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1' @@ -230,14 +230,14 @@ dependencies { androidTestImplementation 'androidx.test:rules:1.6.1' androidTestImplementation 'androidx.test:runner:1.6.2' androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.3.0' - androidTestImplementation 'io.mockk:mockk-android:1.13.13' - androidTestImplementation 'org.jetbrains.kotlin:kotlin-test-junit:2.0.21' + androidTestImplementation 'io.mockk:mockk-android:1.13.14' + androidTestImplementation 'org.jetbrains.kotlin:kotlin-test-junit:2.1.0' annotationProcessor 'androidx.room:room-compiler:2.6.1' debugImplementation 'androidx.compose.ui:ui-tooling-preview' debugImplementation 'androidx.fragment:fragment-testing:1.8.5' debugImplementation 'androidx.test:core-ktx:1.6.1' debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.14' - googleplayImplementation platform('com.google.firebase:firebase-bom:33.5.1') + googleplayImplementation platform('com.google.firebase:firebase-bom:33.7.0') implementation 'androidx.activity:activity-compose' implementation 'androidx.activity:activity-ktx:1.9.3' implementation 'androidx.appcompat:appcompat:1.7.0' @@ -249,7 +249,7 @@ dependencies { implementation 'androidx.constraintlayout:constraintlayout:2.2.0' implementation 'androidx.core:core-ktx' implementation 'androidx.core:core-ktx:1.15.0' - implementation 'androidx.databinding:databinding-runtime:8.7.2' + implementation 'androidx.databinding:databinding-runtime:8.7.3' implementation 'androidx.lifecycle:lifecycle-runtime-ktx' implementation 'androidx.multidex:multidex:2.0.1' implementation 'androidx.room:room-guava:2.6.1' @@ -260,17 +260,17 @@ dependencies { implementation 'com.github.skydoves:colorpickerpreference:2.0.6' implementation 'com.google.android.material:material:1.12.0' implementation 'com.google.code.gson:gson:2.11.0' - implementation 'com.google.guava:guava:33.3.1-jre' + implementation 'com.google.guava:guava:33.4.0-jre' implementation 'com.jakewharton.rxbinding2:rxbinding:2.2.0' implementation 'com.jakewharton.timber:timber:5.0.1' implementation 'com.squareup.okhttp3:okhttp:4.12.0' implementation fileTree(include: ['*.jar'], dir: 'libs') implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' implementation 'io.reactivex.rxjava2:rxjava:2.2.21' - implementation 'net.pwall.json:json-kotlin-schema:0.50' + implementation 'net.pwall.json:json-kotlin-schema:0.52' implementation 'org.apache.commons:commons-csv:1.12.0' - implementation 'org.jsoup:jsoup:1.18.1' - implementation platform('androidx.compose:compose-bom:2024.10.01') + implementation 'org.jsoup:jsoup:1.18.3' + implementation platform('androidx.compose:compose-bom:2024.12.01') implementation project(path: ':cloudLib') implementation project(path: ':utilsLib') testImplementation 'androidx.arch.core:core-testing:2.2.0' @@ -278,12 +278,12 @@ dependencies { testImplementation 'androidx.test:core-ktx:1.6.1' testImplementation 'androidx.test.ext:junit:1.2.1' testImplementation 'androidx.test:rules:1.6.1' - testImplementation 'ch.qos.logback:logback-classic:1.5.12' - testImplementation 'com.google.guava:guava:33.3.1-jre' + testImplementation 'ch.qos.logback:logback-classic:1.5.15' + testImplementation 'com.google.guava:guava:33.4.0-jre' testImplementation 'io.mockk:mockk:1.13.13' testImplementation 'junit:junit:4.13.2' - testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.9.0' - testImplementation 'org.robolectric:robolectric:4.13' + testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.10.1' + testImplementation 'org.robolectric:robolectric:4.14.1' } repositories { diff --git a/app/schemas/com.github.jameshnsears.quoteunquote.database.quotation.AbstractQuotationDatabase/48.json b/app/schemas/com.github.jameshnsears.quoteunquote.database.quotation.AbstractQuotationDatabase/49.json similarity index 99% rename from app/schemas/com.github.jameshnsears.quoteunquote.database.quotation.AbstractQuotationDatabase/48.json rename to app/schemas/com.github.jameshnsears.quoteunquote.database.quotation.AbstractQuotationDatabase/49.json index f95b144a..4e70183c 100644 --- a/app/schemas/com.github.jameshnsears.quoteunquote.database.quotation.AbstractQuotationDatabase/48.json +++ b/app/schemas/com.github.jameshnsears.quoteunquote.database.quotation.AbstractQuotationDatabase/49.json @@ -1,7 +1,7 @@ { "formatVersion": 1, "database": { - "version": 48, + "version": 49, "identityHash": "4576f076a1896260b13b26d1a0d40a61", "entities": [ { diff --git a/app/sonar-project.properties b/app/sonar-project.properties deleted file mode 100755 index 67f8f3f6..00000000 --- a/app/sonar-project.properties +++ /dev/null @@ -1,15 +0,0 @@ -sonar.projectKey=jameshnsears_QuoteUnquote -sonar.projectName=QuoteUnquote -sonar.organization=jameshnsears-github -sonar.projectVersion=HEAD -sonar.sources=src/main/java -sonar.tests=src/androidTest/java -sonar.java.binaries=build/intermediates/javac/debug/classes -sonar.android.lint.report=build/reports/lint-results.xml -sonar.junit.reportPaths=build/test-results/testDebugUnitTest -sonar.coverage.jacoco.xmlReportPaths=build/reports/jacoco-combined.xml -sonar.java.source=11 -sonar.java.target=11 -sonar.sourceEncoding=UTF-8 -sonar.exclusions=src/test/** -sonar.verbose=true \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/github/jameshnsears/quoteunquote/cloud/transfer/backup/TransferBackupSettingsTest.kt b/app/src/androidTest/kotlin/com/github/jameshnsears/quoteunquote/cloud/transfer/backup/TransferBackupSettingsTest.kt index ae3d67ed..5cf1fb34 100755 --- a/app/src/androidTest/kotlin/com/github/jameshnsears/quoteunquote/cloud/transfer/backup/TransferBackupSettingsTest.kt +++ b/app/src/androidTest/kotlin/com/github/jameshnsears/quoteunquote/cloud/transfer/backup/TransferBackupSettingsTest.kt @@ -100,6 +100,8 @@ class TransferBackupSettingsTest : GsonTestHelper() { 0, 23, 1, + false, + false, ) private fun expectedAppearance() = Appearance( diff --git a/app/src/androidTest/kotlin/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/content/files/csv/FilesCsvInPlaceEditDialogDouble.kt b/app/src/androidTest/kotlin/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/content/files/csv/FilesCsvInPlaceEditDialogDouble.kt index 44a234fb..987043f8 100644 --- a/app/src/androidTest/kotlin/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/content/files/csv/FilesCsvInPlaceEditDialogDouble.kt +++ b/app/src/androidTest/kotlin/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/content/files/csv/FilesCsvInPlaceEditDialogDouble.kt @@ -8,7 +8,7 @@ import com.github.jameshnsears.quoteunquote.database.DatabaseRepositoryDouble import com.github.jameshnsears.quoteunquote.database.quotation.QuotationEntity import com.github.jameshnsears.quoteunquote.utils.ContentSelection -class FilesCsvInPlaceEditDialogDouble() : ContentCsvInPlaceEditDialog() { +class FilesCsvInPlaceEditDialogDouble : ContentCsvInPlaceEditDialog() { private var databaseRepositoryDouble: DatabaseRepositoryDouble = DatabaseRepositoryDouble.getInstance(ApplicationProvider.getApplicationContext()) diff --git a/app/src/androidTest/kotlin/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/content/files/csv/FilesCsvInPlaceEditDialogTest.kt b/app/src/androidTest/kotlin/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/content/files/csv/FilesCsvInPlaceEditDialogTest.kt index 83d2c048..18b5119c 100644 --- a/app/src/androidTest/kotlin/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/content/files/csv/FilesCsvInPlaceEditDialogTest.kt +++ b/app/src/androidTest/kotlin/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/content/files/csv/FilesCsvInPlaceEditDialogTest.kt @@ -37,7 +37,7 @@ class FilesCsvInPlaceEditDialogTest : QuoteUnquoteModelUtility() { ) scenario.onFragment { contentCsvInPlaceEditDialog -> - assertTrue(contentCsvInPlaceEditDialog.quoteUnquoteModel.allQuotations.size == 20267) + assertTrue(contentCsvInPlaceEditDialog.quoteUnquoteModel.allQuotations.size == 19971) } composeRule.onNodeWithText("Save").assertExists().performClick() diff --git a/app/src/androidTest/kotlin/com/github/jameshnsears/quoteunquote/utils/notification/NotificationsCustomisableIntervalAlarmTest.kt b/app/src/androidTest/kotlin/com/github/jameshnsears/quoteunquote/utils/notification/NotificationsCustomisableIntervalAlarmTest.kt index 0cc85f60..bb0d601a 100755 --- a/app/src/androidTest/kotlin/com/github/jameshnsears/quoteunquote/utils/notification/NotificationsCustomisableIntervalAlarmTest.kt +++ b/app/src/androidTest/kotlin/com/github/jameshnsears/quoteunquote/utils/notification/NotificationsCustomisableIntervalAlarmTest.kt @@ -32,7 +32,7 @@ class NotificationsCustomisableIntervalAlarmTest : QuoteUnquoteModelUtility() { notificationsPreferences.customisableIntervalHours = hours } - class AlarmMock(context: Context, val current: Int) : NotificationsCustomisableIntervalAlarm( + class AlarmMock(context: Context, val current: Int) : NotificationCustomisableIntervalAlarm( context, WidgetIdHelper.WIDGET_ID_01, ) { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b60e7a8a..a57e6f1c 100755 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,9 +1,12 @@ - + - + @@ -55,14 +58,24 @@ + android:exported="false"> + + + + + + + + + + diff --git a/app/src/main/assets/quotations.db.prod b/app/src/main/assets/quotations.db.prod index 2f308bb1..60ed7561 100644 Binary files a/app/src/main/assets/quotations.db.prod and b/app/src/main/assets/quotations.db.prod differ diff --git a/app/src/main/java/com/github/jameshnsears/quoteunquote/QuoteUnquoteModel.java b/app/src/main/java/com/github/jameshnsears/quoteunquote/QuoteUnquoteModel.java index a01bc485..51377932 100755 --- a/app/src/main/java/com/github/jameshnsears/quoteunquote/QuoteUnquoteModel.java +++ b/app/src/main/java/com/github/jameshnsears/quoteunquote/QuoteUnquoteModel.java @@ -56,9 +56,9 @@ public QuoteUnquoteModel(int widgetId, @NonNull final Context widgetContext) { if (widgetId != -1) { QuotationsPreferences quotationsPreferences = new QuotationsPreferences(widgetId, context); if (quotationsPreferences.getDatabaseInternal()) { - databaseRepository.useInternalDatabase = true; + DatabaseRepository.useInternalDatabase = true; } else { - databaseRepository.useInternalDatabase = false; + DatabaseRepository.useInternalDatabase = false; } } } diff --git a/app/src/main/java/com/github/jameshnsears/quoteunquote/QuoteUnquoteWidget.java b/app/src/main/java/com/github/jameshnsears/quoteunquote/QuoteUnquoteWidget.java index 1e9c28ce..351fc545 100755 --- a/app/src/main/java/com/github/jameshnsears/quoteunquote/QuoteUnquoteWidget.java +++ b/app/src/main/java/com/github/jameshnsears/quoteunquote/QuoteUnquoteWidget.java @@ -31,6 +31,7 @@ import com.github.jameshnsears.quoteunquote.configure.fragment.appearance.AppearancePreferences; import com.github.jameshnsears.quoteunquote.configure.fragment.notifications.NotificationsPreferences; import com.github.jameshnsears.quoteunquote.configure.fragment.quotations.QuotationsPreferences; +import com.github.jameshnsears.quoteunquote.database.DatabaseRepository; import com.github.jameshnsears.quoteunquote.database.quotation.QuotationEntity; import com.github.jameshnsears.quoteunquote.listview.ListViewService; import com.github.jameshnsears.quoteunquote.scraper.ScraperData; @@ -39,10 +40,11 @@ import com.github.jameshnsears.quoteunquote.utils.IntentFactoryHelper; import com.github.jameshnsears.quoteunquote.utils.notification.NotificationContent; import com.github.jameshnsears.quoteunquote.utils.notification.NotificationCoordinator; +import com.github.jameshnsears.quoteunquote.utils.notification.NotificationCustomisableIntervalAlarm; +import com.github.jameshnsears.quoteunquote.utils.notification.NotificationDailyAlarm; import com.github.jameshnsears.quoteunquote.utils.notification.NotificationEvent; import com.github.jameshnsears.quoteunquote.utils.notification.NotificationHelper; -import com.github.jameshnsears.quoteunquote.utils.notification.NotificationsCustomisableIntervalAlarm; -import com.github.jameshnsears.quoteunquote.utils.notification.NotificationsDailyAlarm; +import com.github.jameshnsears.quoteunquote.utils.notification.NotificationTextToSpeechService; import com.github.jameshnsears.quoteunquote.utils.preference.PreferencesFacade; import com.github.jameshnsears.quoteunquote.utils.scraper.ScraperAlarm; import com.google.common.util.concurrent.ThreadFactoryBuilder; @@ -56,17 +58,24 @@ public class QuoteUnquoteWidget extends AppWidgetProvider { @Nullable public static ContentSelection currentContentSelection = ContentSelection.ALL; + @Nullable public static String currentAuthorSelection; + @Nullable public static int notificationPermissionDeniedCount = 0; + @Nullable private static ExecutorService executorService; + private static volatile boolean receiversRegistered; + @Nullable private static NotificationHelper notificationHelper; + @Nullable public QuoteUnquoteModel quoteUnquoteModel; + @Nullable private NotificationCoordinator notificationCoordinator; @@ -110,7 +119,7 @@ public static ExecutorService getExecutorService() { return executorService; } - public static void stopExecutorService() { + public static void executorServiceStop() { if (executorService != null) { Runtime.getRuntime().addShutdownHook(new Thread(() -> { executorService.shutdown(); @@ -160,7 +169,9 @@ public void onEnabled(@NonNull final Context context) { quotationsPreferences.setContentLocalCode(CloudTransferHelper.getLocalCode()); } - startDatabaseConnectivity(-1, context); + databaseConnectivityStart(-1, context); + + textToSpeechServiceSpeak(-1, context, null); } @Override @@ -242,7 +253,7 @@ private NotificationHelper getNotificationHelper(@NonNull Context context) { return notificationHelper; } - private NotificationCoordinator getNotificationCoordinator(@NonNull Context context) { + private NotificationCoordinator getNotificationCoordinator() { if (notificationCoordinator == null) { notificationCoordinator = new NotificationCoordinator(); } @@ -314,8 +325,8 @@ public void onReceive(@NonNull final Context context, @NonNull final Intent inte final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); try { - final NotificationsDailyAlarm notificationsDailyAlarm = new NotificationsDailyAlarm(context, widgetId); - final NotificationsCustomisableIntervalAlarm notificationsCustomisableIntervalAlarm = new NotificationsCustomisableIntervalAlarm(context, widgetId); + final NotificationDailyAlarm notificationDailyAlarm = new NotificationDailyAlarm(context, widgetId); + final NotificationCustomisableIntervalAlarm notificationsCustomisableIntervalAlarm = new NotificationCustomisableIntervalAlarm(context, widgetId); final ScraperAlarm scraperAlarm = new ScraperAlarm(context, widgetId); switch (intent.getAction()) { @@ -328,7 +339,7 @@ public void onReceive(@NonNull final Context context, @NonNull final Intent inte break; case Intent.ACTION_USER_PRESENT: - startDatabaseConnectivity(widgetId, context); + databaseConnectivityStart(widgetId, context); onReceiveDeviceUnlock(context, appWidgetManager); break; @@ -344,26 +355,19 @@ public void onReceive(@NonNull final Context context, @NonNull final Intent inte onReceiveNotificationDismissed(context, intent); break; - /* - # this now no longer works on API 34: - adb shell - am broadcast -a android.intent.action.BOOT_COMPLETED - - adb reboot - */ case Intent.ACTION_BOOT_COMPLETED: case Intent.ACTION_REBOOT: case IntentFactoryHelper.ACTIVITY_FINISHED_CONFIGURATION: onReceiveActivityFinishedConfiguration( context, widgetId, - notificationsDailyAlarm, + notificationDailyAlarm, notificationsCustomisableIntervalAlarm, scraperAlarm); break; case IntentFactoryHelper.DAILY_ALARM: - onReceiveDailyAlarm(context, widgetId, notificationsDailyAlarm); + onReceiveDailyAlarm(context, widgetId, notificationDailyAlarm); break; case IntentFactoryHelper.CUSTOMISABLE_INTERVAL_ALARM: @@ -476,11 +480,11 @@ private void onReceiveActionAppwidgetEnabled(@NonNull final Context context, int[] widgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, QuoteUnquoteWidget.class)); for (final int widgetId : widgetIds) { Timber.d("setDailyAlarm: %d", widgetId); - NotificationsDailyAlarm notificationsDailyAlarm = new NotificationsDailyAlarm(context, widgetId); - notificationsDailyAlarm.setAlarm(); + NotificationDailyAlarm notificationDailyAlarm = new NotificationDailyAlarm(context, widgetId); + notificationDailyAlarm.setAlarm(); Timber.d("setCustomisableIntervalAlarm: %d", widgetId); - NotificationsCustomisableIntervalAlarm notificationsCustomisableIntervalAlarm = new NotificationsCustomisableIntervalAlarm(context, widgetId); + NotificationCustomisableIntervalAlarm notificationsCustomisableIntervalAlarm = new NotificationCustomisableIntervalAlarm(context, widgetId); notificationsCustomisableIntervalAlarm.setAlarm(); Timber.d("scraperAlarm: %d", widgetId); @@ -523,11 +527,11 @@ private void onReceiveAllWidgetInstancesFavouriteNotification( setAutoCloudBackupAlarm(context, widgetId); } - private void startDatabaseConnectivity(int widgetId, @NonNull Context context) { + private void databaseConnectivityStart(int widgetId, @NonNull Context context) { setQuoteUnquoteModel(new QuoteUnquoteModel(widgetId, context)); } - public void stopDatabaseConnectivity() { + public void databaseConnectivityStop() { quoteUnquoteModel = null; } @@ -571,7 +575,7 @@ private void onReceiveToolbarPressedFavourite( updateWidgetFavourite(context, widgetId, digest, appWidgetManager); - if (getNotificationCoordinator(context).isNotificationShowingQuotation(digest)) { + if (getNotificationCoordinator().isNotificationShowingQuotation(digest)) { updateNotificationFavourite( context, widgetId, @@ -690,16 +694,16 @@ private void onReceiveToolbarPressedNext( private void onReceiveDailyAlarm( @NonNull final Context context, final int widgetId, - @NonNull final NotificationsDailyAlarm notificationsDailyAlarm) { + @NonNull final NotificationDailyAlarm notificationDailyAlarm) { // reschedule, as recurring - notificationsDailyAlarm.setAlarm(); + notificationDailyAlarm.setAlarm(); scheduleEvent(context, widgetId, NotificationEvent.EVENT_DAILY); } private void onReceiveCustomisableIntervalAlarm( @NonNull final Context context, final int widgetId, - @NonNull final NotificationsCustomisableIntervalAlarm notificationsCustomisableIntervalAlarm) { + @NonNull final NotificationCustomisableIntervalAlarm notificationsCustomisableIntervalAlarm) { Timber.d("customisableIntervalAlarm"); notificationsCustomisableIntervalAlarm.setAlarm(); scheduleEvent(context, widgetId, NotificationEvent.CUSTOMISABLE_INTERVAL); @@ -796,9 +800,9 @@ private void scheduleEvent( QuotationEntity currentQuotation = getQuoteUnquoteModel(widgetId, context).getCurrentQuotation(widgetId); - int notificationId = getNotificationCoordinator(context).createNotificationId(currentQuotation.digest); + int notificationId = getNotificationCoordinator().createNotificationId(currentQuotation.digest); - getNotificationCoordinator(context).dismissNotification(context, getNotificationHelper(context), notificationId); + getNotificationCoordinator().dismissNotification(context, getNotificationHelper(context), notificationId); displayNotification(context, widgetId, notificationEvent); } @@ -814,7 +818,7 @@ private void displayNotification( if (currentQuotation != null) { NotificationsPreferences notificationsPreferences = new NotificationsPreferences(widgetId, context); - int notificationId = getNotificationCoordinator(context).createNotificationId(currentQuotation.digest); + int notificationId = getNotificationCoordinator().createNotificationId(currentQuotation.digest); NotificationContent notificationContent = new NotificationContent( context, @@ -829,7 +833,39 @@ private void displayNotification( displayNotificationInCorrectChannel(context, notificationContent, notificationEvent); - getNotificationCoordinator(context).rememberNotification(notificationEvent, notificationId, currentQuotation.digest); + textToSpeechServiceSpeak(widgetId, context, notificationContent); + + getNotificationCoordinator().rememberNotification(notificationEvent, notificationId, currentQuotation.digest); + } + } + + private void textToSpeechServiceSpeak(int widgetId, + Context context, + NotificationContent notificationContent) { + if (notificationContent != null) { + NotificationsPreferences notificationsPreferences = new NotificationsPreferences(widgetId, context); + + if (notificationsPreferences.getEventTtsUk() || notificationsPreferences.getEventTtsSystem()) { + Intent serviceIntent = new Intent(context, NotificationTextToSpeechService.class); + serviceIntent.putExtra("textToSpeak", notificationContent.getQuotation()); + + serviceIntent.putExtra("textToSpeakSource", notificationContent.getAuthor()); + serviceIntent.putExtra("excludeSource", notificationsPreferences.getExcludeSourceFromNotification()); + + if (notificationsPreferences.getEventTtsUk()) { + serviceIntent.putExtra("localeTts", "UK"); + } else { + serviceIntent.putExtra("localeTts", "SYSTEM"); + } + + context.startService(serviceIntent); + } + } + } + + private void textToSpeechServiceStop(Context context) { + if (NotificationTextToSpeechService.Companion.isRunning()) { + context.stopService(new Intent(context, NotificationTextToSpeechService.class)); } } @@ -853,7 +889,7 @@ private void displayNotificationInCorrectChannel( break; case NotificationEvent.TOOLBAR_PRESSED_FAVOURITE: - switch (getNotificationCoordinator(context).getNotificationChannelId(notificationContent.getNotificationId())) { + switch (getNotificationCoordinator().getNotificationChannelId(notificationContent.getNotificationId())) { case NotificationEvent.DEVICE_UNLOCK: getNotificationHelper(context).displayNotificationDeviceUnlock(notificationContent); break; @@ -890,7 +926,7 @@ private void onReceiveNotificationNext( onReceiveToolbarPressedNextRandom(context, widgetId, appWidgetManager); } - getNotificationCoordinator(context).dismissNotification(context, getNotificationHelper(context), notificationId); + getNotificationCoordinator().dismissNotification(context, getNotificationHelper(context), notificationId); displayNotification(context, widgetId, notificationEvent); } @@ -899,9 +935,9 @@ private void onReceiveNotificationDismissed( @NonNull Context context, @NonNull final Intent intent) { final int notificationId = intent.getExtras().getInt("notificationId"); - getNotificationCoordinator(context).dismissNotification(context, getNotificationHelper(context), notificationId); + getNotificationCoordinator().dismissNotification(context, getNotificationHelper(context), notificationId); - getNotificationCoordinator(context).forgetNotification(notificationId); + getNotificationCoordinator().forgetNotification(notificationId); } private void onReceiveNotificationFavourite( @@ -957,7 +993,7 @@ private String markNotificationAsFavourite( private void updateNotificationFavourite( @NonNull Context context, int widgetId, @NonNull String widgetDigest) { - if (getNotificationCoordinator(context).isNotificationShowingQuotation(widgetDigest)) { + if (getNotificationCoordinator().isNotificationShowingQuotation(widgetDigest)) { NotificationsPreferences notificationsPreferences = new NotificationsPreferences(widgetId, context); @@ -972,7 +1008,7 @@ private void updateNotificationFavourite( widgetDigest, getQuoteUnquoteModel(widgetId, context).isFavourite(quotationEntity.digest), notificationsPreferences.getEventNextSequential(), - getNotificationCoordinator(context).createNotificationId(quotationEntity.digest), + getNotificationCoordinator().createNotificationId(quotationEntity.digest), NotificationEvent.TOOLBAR_PRESSED_FAVOURITE); displayNotificationInCorrectChannel(context, notificationContent, NotificationEvent.TOOLBAR_PRESSED_FAVOURITE); @@ -982,8 +1018,8 @@ private void updateNotificationFavourite( private void onReceiveActivityFinishedConfiguration( @NonNull final Context context, final int widgetId, - @NonNull final NotificationsDailyAlarm notificationsDailyAlarm, - @NonNull final NotificationsCustomisableIntervalAlarm notificationsCustomisableIntervalAlarm, + @NonNull final NotificationDailyAlarm notificationDailyAlarm, + @NonNull final NotificationCustomisableIntervalAlarm notificationsCustomisableIntervalAlarm, @NonNull final ScraperAlarm scraperAlarm) { if (getQuoteUnquoteModel(widgetId, context).getCurrentQuotation(widgetId) == null) { @@ -996,13 +1032,13 @@ private void onReceiveActivityFinishedConfiguration( } manageAlarms(context, widgetId, - notificationsDailyAlarm, notificationsCustomisableIntervalAlarm, scraperAlarm); + notificationDailyAlarm, notificationsCustomisableIntervalAlarm, scraperAlarm); } private void manageAlarms( @NonNull Context context, int widgetId, - @NonNull NotificationsDailyAlarm notificationsDailyAlarm, - @NonNull NotificationsCustomisableIntervalAlarm notificationsCustomisableIntervalAlarm, + @NonNull NotificationDailyAlarm notificationDailyAlarm, + @NonNull NotificationCustomisableIntervalAlarm notificationsCustomisableIntervalAlarm, @NonNull ScraperAlarm scraperAlarm) { QuotationsPreferences quotationsPreferences = new QuotationsPreferences(widgetId, context); @@ -1014,9 +1050,9 @@ private void manageAlarms( NotificationsPreferences notificationsPreferences = new NotificationsPreferences(widgetId, context); if (notificationsPreferences.getEventDaily()) { - notificationsDailyAlarm.setAlarm(); + notificationDailyAlarm.setAlarm(); } else { - notificationsDailyAlarm.resetAlarm(); + notificationDailyAlarm.resetAlarm(); } if (notificationsPreferences.getCustomisableInterval()) { @@ -1226,10 +1262,10 @@ public void onDeleted( getQuoteUnquoteModel(widgetId, context).delete(widgetId); PreferencesFacade.delete(context, widgetId); - final NotificationsDailyAlarm notificationsDailyAlarm = new NotificationsDailyAlarm(context, widgetId); - notificationsDailyAlarm.resetAlarm(); + final NotificationDailyAlarm notificationDailyAlarm = new NotificationDailyAlarm(context, widgetId); + notificationDailyAlarm.resetAlarm(); - final NotificationsCustomisableIntervalAlarm notificationsCustomisableIntervalAlarm = new NotificationsCustomisableIntervalAlarm(context, widgetId); + final NotificationCustomisableIntervalAlarm notificationsCustomisableIntervalAlarm = new NotificationCustomisableIntervalAlarm(context, widgetId); notificationsCustomisableIntervalAlarm.resetAlarm(); final ScraperAlarm scraperAlarm = new ScraperAlarm(context, widgetId); @@ -1258,8 +1294,9 @@ public void onDisabled(@NonNull final Context context) { context.stopService(new Intent(context, CloudServiceRestore.class)); } } finally { - stopDatabaseConnectivity(); - stopExecutorService(); + databaseConnectivityStop(); + executorServiceStop(); + textToSpeechServiceStop(context); } } @@ -1270,9 +1307,9 @@ public synchronized QuoteUnquoteModel getQuoteUnquoteModel( quoteUnquoteModel = new QuoteUnquoteModel(widgetId, context); } else { if (getQuotationsPreferences(context, widgetId).getDatabaseInternal()) { - quoteUnquoteModel.databaseRepository.useInternalDatabase = true; + DatabaseRepository.useInternalDatabase = true; } else { - quoteUnquoteModel.databaseRepository.useInternalDatabase = false; + DatabaseRepository.useInternalDatabase = false; } } diff --git a/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/FragmentCommon.java b/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/FragmentCommon.java index e2fb9194..a281bfbc 100755 --- a/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/FragmentCommon.java +++ b/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/FragmentCommon.java @@ -27,7 +27,7 @@ public void makeButtonAlpha(@NonNull final Button button, final boolean enable) } public void rememberScreen(final Screen screen, Context applicationContext) { - new QuotationsPreferences(widgetId, applicationContext).setScreen(screen.name); + new QuotationsPreferences(widgetId, applicationContext).setScreen(screen.screenName); } public enum Screen { @@ -43,15 +43,15 @@ public enum Screen { Sync("Sync"); - public final String name; + public final String screenName; - Screen(String name) { - this.name = name; + Screen(String screenName) { + this.screenName = screenName; } public static Screen fromString(String name) { for (Screen screen : Screen.values()) { - if (screen.name.equalsIgnoreCase(name)) { + if (screen.screenName.equalsIgnoreCase(name)) { return screen; } } diff --git a/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/appearance/AppearanceFragment.java b/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/appearance/AppearanceFragment.java index f4c81eab..b925f6ae 100755 --- a/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/appearance/AppearanceFragment.java +++ b/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/appearance/AppearanceFragment.java @@ -88,7 +88,7 @@ public void onPageSelected(int position) { String screen = new QuotationsPreferences(widgetId, getContext()).getScreen(); - if (screen.equals(Screen.AppearanceToolbar.name)) { + if (screen.equals(Screen.AppearanceToolbar.screenName)) { fragmentAppearanceBinding.viewPager2Appearance.setCurrentItem(1); } else { fragmentAppearanceBinding.viewPager2Appearance.setCurrentItem(0); diff --git a/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/appearance/tabs/style/AppearanceStyleFragment.java b/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/appearance/tabs/style/AppearanceStyleFragment.java index 90f0d90d..b9b54626 100755 --- a/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/appearance/tabs/style/AppearanceStyleFragment.java +++ b/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/appearance/tabs/style/AppearanceStyleFragment.java @@ -49,12 +49,6 @@ public class AppearanceStyleFragment extends FragmentCommon { @Nullable public AppearancePreferences appearancePreferences; - @Override - public void onResume() { - super.onResume(); - rememberScreen(Screen.AppearanceStyle, getContext()); - } - public AppearanceStyleFragment() { // dark mode support } @@ -70,6 +64,12 @@ public static AppearanceStyleFragment newInstance(final int widgetId) { return fragment; } + @Override + public void onResume() { + super.onResume(); + rememberScreen(Screen.AppearanceStyle, getContext()); + } + @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); diff --git a/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/appearance/tabs/toolbar/AppearanceToolbarFragment.java b/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/appearance/tabs/toolbar/AppearanceToolbarFragment.java index 88d4f295..a1696074 100755 --- a/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/appearance/tabs/toolbar/AppearanceToolbarFragment.java +++ b/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/appearance/tabs/toolbar/AppearanceToolbarFragment.java @@ -26,12 +26,6 @@ public class AppearanceToolbarFragment extends FragmentCommon { @Nullable public AppearancePreferences appearancePreferences; - @Override - public void onResume() { - super.onResume(); - rememberScreen(Screen.AppearanceToolbar, getContext()); - } - public AppearanceToolbarFragment() { // dark mode support } @@ -47,6 +41,12 @@ public static AppearanceToolbarFragment newInstance(final int widgetId) { return fragment; } + @Override + public void onResume() { + super.onResume(); + rememberScreen(Screen.AppearanceToolbar, getContext()); + } + @Override @NonNull public View onCreateView( diff --git a/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/notifications/NotificationsFragment.java b/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/notifications/NotificationsFragment.java index 24e87399..c3ac3fc1 100755 --- a/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/notifications/NotificationsFragment.java +++ b/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/notifications/NotificationsFragment.java @@ -65,6 +65,9 @@ public class NotificationsFragment extends FragmentCommon { notificationsPreferences.setEventDisplayWidget(false); notificationsPreferences.setEventDisplayWidgetAndNotification(true); fragmentNotificationsBinding.switchExcludeSourceFromNotification.setEnabled(true); + fragmentNotificationsBinding.switchTtsUk.setEnabled(true); + fragmentNotificationsBinding.switchTtsSystem.setEnabled(true); + fragmentNotificationsBinding.textViewNotificationSizeWarningInfo.setEnabled(true); fragmentNotificationsBinding.textViewNotificationSizeWarning1.setEnabled(true); } @@ -91,14 +94,6 @@ public class NotificationsFragment extends FragmentCommon { } ); - @Override - public void onResume() { - super.onResume(); - rememberScreen(Screen.Notifications, getContext()); - - handleSpecialPermissionForExactAlarm(); - } - public NotificationsFragment() { // dark mode support } @@ -114,6 +109,14 @@ public static NotificationsFragment newInstance(final int widgetId) { return fragment; } + @Override + public void onResume() { + super.onResume(); + rememberScreen(Screen.Notifications, getContext()); + + handleSpecialPermissionForExactAlarm(); + } + @Override @NonNull public View onCreateView( @@ -165,6 +168,15 @@ public void onViewCreated( createListenerSpecificTime(); createListenerDaily(); + + createListenerTtsUk(); + createListenerTtsSystem(); + + /* + ensureTtsSwitchesAligned() + + only one TTS can be enabled + */ } private void handleSpecialPermissionForExactAlarm() { @@ -271,15 +283,31 @@ private void setDisplay() { if (fragmentNotificationsBinding.radioButtonWhereAsNotification.isChecked()) { fragmentNotificationsBinding.switchExcludeSourceFromNotification.setEnabled(true); + fragmentNotificationsBinding.switchTtsUk.setEnabled(true); + fragmentNotificationsBinding.switchTtsSystem.setEnabled(true); + fragmentNotificationsBinding.textViewNotificationSizeWarningInfo.setEnabled(true); fragmentNotificationsBinding.textViewNotificationSizeWarning1.setEnabled(true); } else { fragmentNotificationsBinding.switchExcludeSourceFromNotification.setEnabled(false); + fragmentNotificationsBinding.switchTtsUk.setEnabled(false); + fragmentNotificationsBinding.switchTtsSystem.setEnabled(false); + fragmentNotificationsBinding.textViewNotificationSizeWarningInfo.setEnabled(false); fragmentNotificationsBinding.textViewNotificationSizeWarning1.setEnabled(false); } + if (notificationsPreferences.getEventTtsUk()) { + fragmentNotificationsBinding.switchTtsUk.setChecked(true); + fragmentNotificationsBinding.switchTtsSystem.setChecked(false); + } + + if (notificationsPreferences.getEventTtsSystem()) { + fragmentNotificationsBinding.switchTtsUk.setChecked(false); + fragmentNotificationsBinding.switchTtsSystem.setChecked(true); + } + fragmentNotificationsBinding.switchExcludeSourceFromNotification.setChecked(notificationsPreferences.getExcludeSourceFromNotification()); } @@ -314,6 +342,9 @@ private void createListenerDisplayRadioGroup() { notificationsPreferences.setEventDisplayWidgetAndNotification(false); fragmentNotificationsBinding.switchExcludeSourceFromNotification.setEnabled(false); + fragmentNotificationsBinding.switchTtsUk.setEnabled(false); + fragmentNotificationsBinding.switchTtsSystem.setEnabled(false); + fragmentNotificationsBinding.textViewNotificationSizeWarningInfo.setEnabled(false); fragmentNotificationsBinding.textViewNotificationSizeWarning1.setEnabled(false); break; @@ -334,6 +365,9 @@ private void createListenerDisplayRadioGroup() { notificationsPreferences.setEventDisplayWidget(false); notificationsPreferences.setEventDisplayWidgetAndNotification(true); fragmentNotificationsBinding.switchExcludeSourceFromNotification.setEnabled(true); + fragmentNotificationsBinding.switchTtsUk.setEnabled(true); + fragmentNotificationsBinding.switchTtsSystem.setEnabled(true); + fragmentNotificationsBinding.textViewNotificationSizeWarningInfo.setEnabled(true); fragmentNotificationsBinding.textViewNotificationSizeWarning1.setEnabled(true); break; @@ -376,6 +410,26 @@ private void createListenerDaily() { }); } + private void createListenerTtsUk() { + fragmentNotificationsBinding.switchTtsUk.setOnCheckedChangeListener((buttonView, isChecked) -> { + notificationsPreferences.setEventTtsSystem(false); + fragmentNotificationsBinding.switchTtsSystem.setChecked(false); + + notificationsPreferences.setEventTtsUk(isChecked); + fragmentNotificationsBinding.switchTtsUk.setChecked(isChecked); + }); + } + + private void createListenerTtsSystem() { + fragmentNotificationsBinding.switchTtsSystem.setOnCheckedChangeListener((buttonView, isChecked) -> { + notificationsPreferences.setEventTtsUk(false); + fragmentNotificationsBinding.switchTtsUk.setChecked(false); + + notificationsPreferences.setEventTtsSystem(isChecked); + fragmentNotificationsBinding.switchTtsSystem.setChecked(isChecked); + }); + } + private void createListenerDailyCommon(boolean isChecked) { if (notificationsPreferences.getEventDaily() != isChecked) { notificationsPreferences.setEventDaily(isChecked); diff --git a/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/notifications/NotificationsPreferences.java b/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/notifications/NotificationsPreferences.java index d66d1ba1..dbb971af 100755 --- a/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/notifications/NotificationsPreferences.java +++ b/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/notifications/NotificationsPreferences.java @@ -21,6 +21,27 @@ public class NotificationsPreferences extends PreferencesFacade { public static final String EVENT_CUSTOMISABLE_INTERVAL_HOUR_TO = "EVENT_CUSTOMISABLE_INTERVAL_HOUR_TO"; public static final String EVENT_CUSTOMISABLE_INTERVAL_HOURS = "EVENT_CUSTOMISABLE_INTERVAL_HOURS"; + public static final String EVENT_TTS_UK = "EVENT_TTS_UK"; + public static final String EVENT_TTS_SYSTEM = "EVENT_TTS_SYSTEM"; + + public boolean getEventTtsUk() { + return this.preferenceHelper.getPreferenceBoolean(this.getPreferenceKey(NotificationsPreferences.EVENT_TTS_UK), false); + } + + public void setEventTtsUk(boolean value) { + this.preferenceHelper.setPreference(this.getPreferenceKey(NotificationsPreferences.EVENT_TTS_UK), value); + } + + public boolean getEventTtsSystem() { + return this.preferenceHelper.getPreferenceBoolean(this.getPreferenceKey(NotificationsPreferences.EVENT_TTS_SYSTEM), false); + } + + public void setEventTtsSystem(boolean value) { + this.preferenceHelper.setPreference(this.getPreferenceKey(NotificationsPreferences.EVENT_TTS_SYSTEM), value); + } + + ////////////////// + public NotificationsPreferences(int widgetId, @NonNull Context applicationContext) { super(widgetId, applicationContext); } diff --git a/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/QuotationsFragment.java b/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/QuotationsFragment.java index e0a64db1..6ff75e78 100755 --- a/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/QuotationsFragment.java +++ b/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/QuotationsFragment.java @@ -106,9 +106,9 @@ public void onPageSelected(int position) { String screen = new QuotationsPreferences(widgetId, getContext()).getScreen(); - if (screen.equals(Screen.ContentInternal.name) - || screen.equals(Screen.ContentFiles.name) - || screen.equals(Screen.ContentWeb.name) + if (screen.equals(Screen.ContentInternal.screenName) + || screen.equals(Screen.ContentFiles.screenName) + || screen.equals(Screen.ContentWeb.screenName) ) { fragmentQuotationsBinding.viewPager2Quotations.setCurrentItem(1); } else { diff --git a/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/QuotationsPreferences.java b/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/QuotationsPreferences.java index 3dc42cab..d40eb134 100755 --- a/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/QuotationsPreferences.java +++ b/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/QuotationsPreferences.java @@ -36,6 +36,14 @@ public class QuotationsPreferences extends PreferencesFacade { public static final String DATABASE_EXTERNAL_CONTENT = "DATABASE_EXTERNAL_CONTENT"; + public QuotationsPreferences(@NonNull Context applicationContext) { + super(0, applicationContext); + } + + public QuotationsPreferences(int widgetId, @NonNull Context applicationContext) { + super(widgetId, applicationContext); + } + @NonNull public String getScreen() { return this.preferenceHelper.getPreferenceString(this.getPreferenceKey(SCREEN)); @@ -45,14 +53,6 @@ public void setScreen(@NonNull String value) { this.preferenceHelper.setPreference(this.getPreferenceKey(SCREEN), value); } - public QuotationsPreferences(@NonNull Context applicationContext) { - super(0, applicationContext); - } - - public QuotationsPreferences(int widgetId, @NonNull Context applicationContext) { - super(widgetId, applicationContext); - } - @NonNull public boolean getDatabaseWebKeepLatestOnly() { return this.preferenceHelper.getPreferenceBoolean(this.getPreferenceKey(QuotationsPreferences.DATABASE_WEB_KEEP_LATEST_ONLY), true); diff --git a/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/content/QuotationsContentFragment.java b/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/content/QuotationsContentFragment.java index 48fc8d91..d1ce4160 100755 --- a/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/content/QuotationsContentFragment.java +++ b/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/content/QuotationsContentFragment.java @@ -105,10 +105,10 @@ public void onTabReselected(TabLayout.Tab tab) { String screen = new QuotationsPreferences(widgetId, getContext()).getScreen(); - if (screen.equals(Screen.ContentFiles.name)) { + if (screen.equals(Screen.ContentFiles.screenName)) { fragmentQuotationsTabDatabaseBinding.tabDatabase.getTabAt(1).select(); - } else if (screen.equals(Screen.ContentWeb.name)) { + } else if (screen.equals(Screen.ContentWeb.screenName)) { fragmentQuotationsTabDatabaseBinding.tabDatabase.getTabAt(2).select(); } else { diff --git a/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/content/internal/ContentInternalFragment.java b/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/content/internal/ContentInternalFragment.java index 86cca6fc..e9239b24 100755 --- a/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/content/internal/ContentInternalFragment.java +++ b/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/content/internal/ContentInternalFragment.java @@ -19,8 +19,9 @@ public class ContentInternalFragment extends ContentFragment { @Nullable public FragmentQuotationsTabDatabaseTabInternalBinding fragmentQuotationsTabDatabaseTabInternalBinding; - @Nullable - public QuotationsPreferences quotationsPreferences; + public ContentInternalFragment(int widgetId) { + super(widgetId); + } @Override public void onResume() { @@ -28,10 +29,6 @@ public void onResume() { rememberScreen(Screen.ContentInternal, getContext()); } - public ContentInternalFragment(int widgetId) { - super(widgetId); - } - @Override @NonNull public View onCreateView( diff --git a/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/content/web/ContentWebFragment.java b/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/content/web/ContentWebFragment.java index 43d93aa7..e9e3ad9b 100755 --- a/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/content/web/ContentWebFragment.java +++ b/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/content/web/ContentWebFragment.java @@ -26,8 +26,9 @@ public class ContentWebFragment extends ContentFragment { @Nullable public FragmentQuotationsTabDatabaseTabWebBinding fragmentQuotationsTabDatabaseTabWebBinding; - @Nullable - public QuotationsPreferences quotationsPreferences; + public ContentWebFragment(int widgetId) { + super(widgetId); + } @Override public void onResume() { @@ -35,10 +36,6 @@ public void onResume() { rememberScreen(Screen.ContentWeb, getContext()); } - public ContentWebFragment(int widgetId) { - super(widgetId); - } - @Override @NonNull public View onCreateView( @@ -185,7 +182,7 @@ private void createListenerButtonImportWebPage() { String xpathQuotation = getWebXpathQuotation(); String xpathSource = getWebXpathSource(); - if ("".equals(url) || "".equals(xpathQuotation) | "".equals(xpathSource) + if ("".equals(url) || "".equals(xpathQuotation) || "".equals(xpathSource) || 10 > url.length()) { useInternalDatabase(); diff --git a/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/filter/QuotationsFilterFragment.java b/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/filter/QuotationsFilterFragment.java index 165bf80c..29d8e149 100755 --- a/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/filter/QuotationsFilterFragment.java +++ b/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/filter/QuotationsFilterFragment.java @@ -75,12 +75,6 @@ public class QuotationsFilterFragment extends FragmentCommon { @NonNull private ActivityResultLauncher activityExportSource = activityExport(); - @Override - public void onResume() { - super.onResume(); - rememberScreen(Screen.QuotationsFilter, getContext()); - } - public QuotationsFilterFragment() { } @@ -111,6 +105,12 @@ public static void ensureFragmentContentSearchConsistency( } } + @Override + public void onResume() { + super.onResume(); + rememberScreen(Screen.QuotationsFilter, getContext()); + } + @Override public void onCreate(@NonNull final Bundle savedInstanceState) { super.onCreate(savedInstanceState); diff --git a/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/filter/browse/adapter/BrowseAdapter.java b/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/filter/browse/adapter/BrowseAdapter.java index 3d21a0a5..0834a597 100644 --- a/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/filter/browse/adapter/BrowseAdapter.java +++ b/app/src/main/java/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/filter/browse/adapter/BrowseAdapter.java @@ -32,7 +32,7 @@ public BrowseAdapter(final int widgetId, DIALOG dialogType) { BrowseAdapter.widgetId = widgetId; browseDataList = new CopyOnWriteArrayList<>(browseDataItems); - this.dialogType = dialogType; + BrowseAdapter.dialogType = dialogType; } @Override diff --git a/app/src/main/java/com/github/jameshnsears/quoteunquote/database/quotation/AbstractQuotationDatabase.java b/app/src/main/java/com/github/jameshnsears/quoteunquote/database/quotation/AbstractQuotationDatabase.java index 821227b8..6b5b0792 100755 --- a/app/src/main/java/com/github/jameshnsears/quoteunquote/database/quotation/AbstractQuotationDatabase.java +++ b/app/src/main/java/com/github/jameshnsears/quoteunquote/database/quotation/AbstractQuotationDatabase.java @@ -10,7 +10,7 @@ import com.github.jameshnsears.quoteunquote.BuildConfig; -@Database(entities = {QuotationEntity.class}, version = 48) +@Database(entities = {QuotationEntity.class}, version = 49) public abstract class AbstractQuotationDatabase extends RoomDatabase { @Nullable public static AbstractQuotationDatabase quotationDatabase; diff --git a/app/src/main/java/com/github/jameshnsears/quoteunquote/utils/notification/NotificationsCustomisableIntervalAlarm.java b/app/src/main/java/com/github/jameshnsears/quoteunquote/utils/notification/NotificationCustomisableIntervalAlarm.java similarity index 96% rename from app/src/main/java/com/github/jameshnsears/quoteunquote/utils/notification/NotificationsCustomisableIntervalAlarm.java rename to app/src/main/java/com/github/jameshnsears/quoteunquote/utils/notification/NotificationCustomisableIntervalAlarm.java index c125afb3..3da3e22f 100755 --- a/app/src/main/java/com/github/jameshnsears/quoteunquote/utils/notification/NotificationsCustomisableIntervalAlarm.java +++ b/app/src/main/java/com/github/jameshnsears/quoteunquote/utils/notification/NotificationCustomisableIntervalAlarm.java @@ -15,11 +15,11 @@ import timber.log.Timber; -public class NotificationsCustomisableIntervalAlarm extends NotificationsDailyAlarm { +public class NotificationCustomisableIntervalAlarm extends NotificationDailyAlarm { int nextAlarmHour; boolean nextAlarmDay; - public NotificationsCustomisableIntervalAlarm( + public NotificationCustomisableIntervalAlarm( @NonNull Context widgetContext, int theWidgetId) { super(widgetContext, theWidgetId); } diff --git a/app/src/main/java/com/github/jameshnsears/quoteunquote/utils/notification/NotificationsDailyAlarm.java b/app/src/main/java/com/github/jameshnsears/quoteunquote/utils/notification/NotificationDailyAlarm.java similarity index 97% rename from app/src/main/java/com/github/jameshnsears/quoteunquote/utils/notification/NotificationsDailyAlarm.java rename to app/src/main/java/com/github/jameshnsears/quoteunquote/utils/notification/NotificationDailyAlarm.java index 543b06ea..bd3fce06 100755 --- a/app/src/main/java/com/github/jameshnsears/quoteunquote/utils/notification/NotificationsDailyAlarm.java +++ b/app/src/main/java/com/github/jameshnsears/quoteunquote/utils/notification/NotificationDailyAlarm.java @@ -17,14 +17,14 @@ import timber.log.Timber; -public class NotificationsDailyAlarm { +public class NotificationDailyAlarm { @Nullable protected final NotificationsPreferences notificationsPreferences; @NonNull protected final Context context; protected final int widgetId; - public NotificationsDailyAlarm( + public NotificationDailyAlarm( @NonNull final Context widgetContext, final int theWidgetId) { this.context = widgetContext; this.widgetId = theWidgetId; diff --git a/app/src/main/java/com/github/jameshnsears/quoteunquote/utils/preference/PreferencesFacade.java b/app/src/main/java/com/github/jameshnsears/quoteunquote/utils/preference/PreferencesFacade.java index 35101939..3ebd0674 100755 --- a/app/src/main/java/com/github/jameshnsears/quoteunquote/utils/preference/PreferencesFacade.java +++ b/app/src/main/java/com/github/jameshnsears/quoteunquote/utils/preference/PreferencesFacade.java @@ -19,11 +19,11 @@ public class PreferencesFacade { protected int widgetId; - public PreferencesFacade(@NonNull Context applicationContext) { + public PreferencesFacade(Context applicationContext) { init(applicationContext); } - public PreferencesFacade(int theWidgetId, @NonNull Context applicationContext) { + public PreferencesFacade(int theWidgetId, Context applicationContext) { widgetId = theWidgetId; init(applicationContext); } diff --git a/app/src/main/kotlin/com/github/jameshnsears/quoteunquote/cloud/transfer/backup/TransferBackupSettings.kt b/app/src/main/kotlin/com/github/jameshnsears/quoteunquote/cloud/transfer/backup/TransferBackupSettings.kt index 0f1c962e..0b1056f5 100755 --- a/app/src/main/kotlin/com/github/jameshnsears/quoteunquote/cloud/transfer/backup/TransferBackupSettings.kt +++ b/app/src/main/kotlin/com/github/jameshnsears/quoteunquote/cloud/transfer/backup/TransferBackupSettings.kt @@ -139,6 +139,8 @@ open class TransferBackupSettings(val context: Context) { notificationsPreferences.customisableIntervalHourFrom, notificationsPreferences.customisableIntervalHourTo, notificationsPreferences.customisableIntervalHours, + notificationsPreferences.eventTtsSystem, + notificationsPreferences.eventTtsUk, ) } } diff --git a/app/src/main/kotlin/com/github/jameshnsears/quoteunquote/cloud/transfer/backup/restore/TransferRestore.kt b/app/src/main/kotlin/com/github/jameshnsears/quoteunquote/cloud/transfer/backup/restore/TransferRestore.kt index e7b77f9d..688fc68a 100755 --- a/app/src/main/kotlin/com/github/jameshnsears/quoteunquote/cloud/transfer/backup/restore/TransferRestore.kt +++ b/app/src/main/kotlin/com/github/jameshnsears/quoteunquote/cloud/transfer/backup/restore/TransferRestore.kt @@ -253,34 +253,29 @@ class TransferRestore : TransferCommon() { context, ) + notificationsPreferences.eventTtsUk = schedule.eventEventTtsUk + notificationsPreferences.eventTtsSystem = schedule.eventEventTtsSystem + notificationsPreferences.eventDaily = schedule.eventDaily notificationsPreferences.eventDailyTimeHour = schedule.eventDailyHour notificationsPreferences.eventDailyTimeMinute = schedule.eventDailyMinute - if (schedule.eventEventCustomisableInterval != null) { - notificationsPreferences.customisableInterval = schedule.eventEventCustomisableInterval - } - - if (schedule.eventEventCustomisableIntervalHourFrom != null) { - Timber.d("from = %d", schedule.eventEventCustomisableIntervalHourFrom) - notificationsPreferences.customisableIntervalHourFrom = - schedule.eventEventCustomisableIntervalHourFrom - } + notificationsPreferences.customisableInterval = schedule.eventEventCustomisableInterval - if (schedule.eventEventCustomisableIntervalHourTo != null) { - Timber.d("to = %d", schedule.eventEventCustomisableIntervalHourTo) - notificationsPreferences.customisableIntervalHourTo = - schedule.eventEventCustomisableIntervalHourTo - } + Timber.d("from = %d", schedule.eventEventCustomisableIntervalHourFrom) + notificationsPreferences.customisableIntervalHourFrom = + schedule.eventEventCustomisableIntervalHourFrom - if (schedule.eventEventCustomisableIntervalHours != null) { - Timber.d("hours = %d", schedule.eventEventCustomisableIntervalHours) + Timber.d("to = %d", schedule.eventEventCustomisableIntervalHourTo) + notificationsPreferences.customisableIntervalHourTo = + schedule.eventEventCustomisableIntervalHourTo - notificationsPreferences.customisableIntervalHours = - schedule.eventEventCustomisableIntervalHours - } + Timber.d("hours = %d", schedule.eventEventCustomisableIntervalHours) + notificationsPreferences.customisableIntervalHours = + schedule.eventEventCustomisableIntervalHours - notificationsPreferences.setEventDisplayWidgetAndNotification(schedule.eventDisplayWidgetAndNotification) + notificationsPreferences.eventDisplayWidgetAndNotification = + schedule.eventDisplayWidgetAndNotification if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { val alarmManager: AlarmManager = context.getSystemService()!! @@ -290,7 +285,7 @@ class TransferRestore : TransferCommon() { } if (!NotificationManagerCompat.from(context).areNotificationsEnabled()) { - notificationsPreferences.setEventDisplayWidgetAndNotification(false) + notificationsPreferences.eventDisplayWidgetAndNotification = false } } diff --git a/app/src/main/kotlin/com/github/jameshnsears/quoteunquote/configure/fragment/appearance/tabs/style/AppearanceTextFamilySpinnerAdapter.kt b/app/src/main/kotlin/com/github/jameshnsears/quoteunquote/configure/fragment/appearance/tabs/style/AppearanceTextFamilySpinnerAdapter.kt index 4e4d04f7..d1fc9d7f 100755 --- a/app/src/main/kotlin/com/github/jameshnsears/quoteunquote/configure/fragment/appearance/tabs/style/AppearanceTextFamilySpinnerAdapter.kt +++ b/app/src/main/kotlin/com/github/jameshnsears/quoteunquote/configure/fragment/appearance/tabs/style/AppearanceTextFamilySpinnerAdapter.kt @@ -50,7 +50,7 @@ class AppearanceTextFamilySpinnerAdapter(private val context: Context) : BaseAda ) } - view = view?.findViewById(android.R.id.text1) as TextView + view = view?.findViewById(android.R.id.text1)!! view.text = getItem(position) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { diff --git a/app/src/main/kotlin/com/github/jameshnsears/quoteunquote/configure/fragment/appearance/tabs/style/AppearanceTextStyleSpinnerAdapter.kt b/app/src/main/kotlin/com/github/jameshnsears/quoteunquote/configure/fragment/appearance/tabs/style/AppearanceTextStyleSpinnerAdapter.kt index cd3024ad..26552a00 100755 --- a/app/src/main/kotlin/com/github/jameshnsears/quoteunquote/configure/fragment/appearance/tabs/style/AppearanceTextStyleSpinnerAdapter.kt +++ b/app/src/main/kotlin/com/github/jameshnsears/quoteunquote/configure/fragment/appearance/tabs/style/AppearanceTextStyleSpinnerAdapter.kt @@ -51,7 +51,7 @@ class AppearanceTextStyleSpinnerAdapter(private val context: Context) : BaseAdap ) } - view = view?.findViewById(android.R.id.text1) as TextView + view = view?.findViewById(android.R.id.text1)!! view.text = getItem(position) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { diff --git a/app/src/main/kotlin/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/content/files/ContentFilesFragment.kt b/app/src/main/kotlin/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/content/files/ContentFilesFragment.kt index 9f54c0e5..a9a20e0c 100644 --- a/app/src/main/kotlin/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/content/files/ContentFilesFragment.kt +++ b/app/src/main/kotlin/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/content/files/ContentFilesFragment.kt @@ -35,8 +35,6 @@ class ContentFilesFragment(widgetId: Int) : ContentFragment(widgetId) { private val fragmentQuotationsTabDatabaseTabCsvBinding get() = _binding!! - var quotationsPreferences: QuotationsPreferences? = null - private var storageAccessFrameworkActivityImportCSV: ActivityResultLauncher? = null private var storageAccessFrameworkActivityExportCsv: ActivityResultLauncher? = null diff --git a/app/src/main/kotlin/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/content/files/csv/FilesCsvInPlaceEditComposable.kt b/app/src/main/kotlin/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/content/files/csv/FilesCsvInPlaceEditComposable.kt index 5660a641..fdb0654f 100644 --- a/app/src/main/kotlin/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/content/files/csv/FilesCsvInPlaceEditComposable.kt +++ b/app/src/main/kotlin/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/content/files/csv/FilesCsvInPlaceEditComposable.kt @@ -95,7 +95,7 @@ fun InPlaceEditList( .height(320.dp) .padding(top = 4.dp, bottom = 14.dp), ) { - LazyColumn() { + LazyColumn { itemsIndexed(list) { index, quotation -> val isSelected = selectedItemIndex == index diff --git a/app/src/main/kotlin/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/content/files/csv/FilestCsvInPlaceEditDialog.kt b/app/src/main/kotlin/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/content/files/csv/FilestCsvInPlaceEditDialog.kt index 60f5119b..748f451b 100644 --- a/app/src/main/kotlin/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/content/files/csv/FilestCsvInPlaceEditDialog.kt +++ b/app/src/main/kotlin/com/github/jameshnsears/quoteunquote/configure/fragment/quotations/tabs/content/files/csv/FilestCsvInPlaceEditDialog.kt @@ -16,7 +16,7 @@ interface OnDialogDismissedListener { fun onDialogDismissed() } -open class ContentCsvInPlaceEditDialog() : DialogFragment() { +open class ContentCsvInPlaceEditDialog : DialogFragment() { private var listener: OnDialogDismissedListener? = null fun setListener(listener: OnDialogDismissedListener) { diff --git a/app/src/main/kotlin/com/github/jameshnsears/quoteunquote/utils/notification/NotificationTextToSpeechService.kt b/app/src/main/kotlin/com/github/jameshnsears/quoteunquote/utils/notification/NotificationTextToSpeechService.kt new file mode 100644 index 00000000..f75f13e7 --- /dev/null +++ b/app/src/main/kotlin/com/github/jameshnsears/quoteunquote/utils/notification/NotificationTextToSpeechService.kt @@ -0,0 +1,85 @@ +package com.github.jameshnsears.quoteunquote.utils.notification + +import android.app.Service +import android.content.Intent +import android.os.IBinder +import android.speech.tts.TextToSpeech +import timber.log.Timber +import java.util.Locale +import java.util.concurrent.ConcurrentLinkedQueue + +class NotificationTextToSpeechService : Service(), TextToSpeech.OnInitListener { + companion object { + var isRunning = false + var localeTts = Locale.UK + } + + private var tts: TextToSpeech? = null + private var isTtsInitialized = false + private val textQueue = ConcurrentLinkedQueue() + + override fun onCreate() { + super.onCreate() + tts = TextToSpeech(this, this) + } + + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + localeTts = when (intent?.getStringExtra("localeTts") ?: "UK") { + "UK" -> Locale.UK + else -> Locale.getDefault() + } + Timber.d("TTS: localeTts: $localeTts") + + var textToSpeak = intent?.getStringExtra("textToSpeak") ?: "" + + if (intent?.getBooleanExtra("excludeSource", false) == false) { + textToSpeak += intent.getStringExtra("textToSpeakSource") + } + + Timber.d("TTS: textToSpeak: $textToSpeak") + textQueue.add(textToSpeak) + + processTextQueue() + + return START_NOT_STICKY + } + + private fun processTextQueue() { + if (isTtsInitialized && tts != null && textQueue.isNotEmpty()) { + val text = textQueue.poll() ?: return + + tts?.speak( + text, + TextToSpeech.QUEUE_FLUSH, + null, + "utteranceId-${System.currentTimeMillis()}", + ) + } + } + + override fun onInit(status: Int) { + if (status == TextToSpeech.SUCCESS) { + isTtsInitialized = true + Timber.d("TTS: init success") + + val result = tts?.setLanguage(localeTts) + + if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) { + Timber.e("TTS: init fail: language not supported") + } else { + processTextQueue() + } + } else { + Timber.e("TTS: init fail") + } + } + + override fun onDestroy() { + tts?.shutdown() + + isRunning = false + super.onDestroy() + } + + override fun onBind(intent: Intent?): IBinder? = null +} diff --git a/app/src/main/res/drawable/example_appwidget_preview.png b/app/src/main/res/drawable/example_appwidget_preview.png index b11876ca..81ef5d11 100644 Binary files a/app/src/main/res/drawable/example_appwidget_preview.png and b/app/src/main/res/drawable/example_appwidget_preview.png differ diff --git a/app/src/main/res/layout/activity_instructions.xml b/app/src/main/res/layout/activity_instructions.xml index c3dd82e2..d8db9fad 100755 --- a/app/src/main/res/layout/activity_instructions.xml +++ b/app/src/main/res/layout/activity_instructions.xml @@ -50,7 +50,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" - android:padding="10dp"> + android:padding="12dp"> + android:padding="12dp"> + android:padding="12dp"> diff --git a/app/src/main/res/layout/fragment_appearance_tab_style.xml b/app/src/main/res/layout/fragment_appearance_tab_style.xml index 4a992945..472ae43a 100755 --- a/app/src/main/res/layout/fragment_appearance_tab_style.xml +++ b/app/src/main/res/layout/fragment_appearance_tab_style.xml @@ -27,7 +27,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" - android:padding="10dp"> + android:padding="12dp"> + android:paddingEnd="10dp" + android:paddingBottom="3dp"> @@ -243,10 +244,10 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" - android:paddingStart="10dp" + android:paddingStart="12dp" android:paddingTop="5dp" android:paddingEnd="10dp" - android:paddingBottom="5dp"> + android:paddingBottom="9dp">