diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index a1eddc3db27c73fee7338e3e5b43a95e1ce9b785..40678861fa4ab18dbc55081a40ef52294c2152eb 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -2,9 +2,9 @@ * @thunderbird/mobile-android-reviewers # Release Engineering -/.github/ @thunderbird/build-release -/docs/ci/ @thunderbird/build-release +/.github/ @thunderbird/build-release +/docs/release/ @thunderbird/build-release /scripts/ci/ @thunderbird/build-release # CODEOWNERS protection -/.github/CODEOWNERS @kewisch +/.github/CODEOWNERS @Herbal7ea diff --git a/.github/workflows/fluidscan.yml b/.github/workflows/fluidscan.yml index da2511fa683b49468ccb98c6f23a59dae8d12dd4..1012ab38a44b0e704392fb8d6596661cffb67fb8 100644 --- a/.github/workflows/fluidscan.yml +++ b/.github/workflows/fluidscan.yml @@ -27,7 +27,7 @@ jobs: bash scripts/ci/run-fluidattacks-scanner.sh - name: "Upload scan results" - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 with: name: SARIF scan results path: fluidscan-results.sarif @@ -35,6 +35,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v4.30.8 + uses: github/codeql-action/upload-sarif@0499de31b99561a6d14a36a5f662c2a54f91beee # v4.31.2 with: sarif_file: fluidscan-results.sarif diff --git a/.github/workflows/pulls-opened.yml b/.github/workflows/pulls-opened.yml index 225c80971a9a971fd99f46789a20dc2214dc0e9b..c9b2c6904b08eb85b1717fe4afe775139780e641 100644 --- a/.github/workflows/pulls-opened.yml +++ b/.github/workflows/pulls-opened.yml @@ -36,7 +36,8 @@ jobs: Original Issue/Pull request: Regression caused by (issue #): User impact if declined: - Testing completed (on daily, etc.): + Testing completed (on daily, beta, etc.): + Introduces or modifies localizable strings (yes/no): Risk to taking this patch (and alternatives if risky): run: | if gh pr view "$PR_NUMBER" --repo "$GITHUB_REPOSITORY" --json comments \ diff --git a/.github/workflows/quality-codeql.yml b/.github/workflows/quality-codeql.yml index a42934f8051b4d9e0d49685624033b8e9bc028cb..407d9c07f50ad7cb1663b068db2a4a5d0d262e63 100644 --- a/.github/workflows/quality-codeql.yml +++ b/.github/workflows/quality-codeql.yml @@ -43,7 +43,7 @@ jobs: disable-cache: 'true' - name: Initialize CodeQL - uses: github/codeql-action/init@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v4.30.8 + uses: github/codeql-action/init@0499de31b99561a6d14a36a5f662c2a54f91beee # v4.31.2 with: languages: ${{ matrix.language }} build-mode: ${{ matrix.build-mode }} @@ -53,6 +53,6 @@ jobs: run: ./gradlew assemble --no-daemon - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v4.30.8 + uses: github/codeql-action/analyze@0499de31b99561a6d14a36a5f662c2a54f91beee # v4.31.2 with: category: "/language:${{ matrix.language }}" diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index f202cadd6aec7f83d7e6d7455a51285a80ffb962..aa7c0dac09baef82197eb26df66dae0ca135c5f3 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -54,7 +54,7 @@ jobs: # Upload the results as artifacts. - name: "Upload artifact" - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 with: name: SARIF file path: results.sarif @@ -62,6 +62,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v4.30.8 + uses: github/codeql-action/upload-sarif@0499de31b99561a6d14a36a5f662c2a54f91beee # v4.31.2 with: sarif_file: results.sarif diff --git a/.github/workflows/shippable_builds.yml b/.github/workflows/shippable_builds.yml index 27790f89162b60acf761df448146aa4511c450f6..dd0c33f512015b0e103dbf2062f1dcc8c37e2f7e 100644 --- a/.github/workflows/shippable_builds.yml +++ b/.github/workflows/shippable_builds.yml @@ -543,7 +543,7 @@ jobs: ls -l ${UPLOAD_PATH}/ - name: Upload unsigned - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 env: UPLOAD_PATH: "uploads" with: @@ -563,7 +563,7 @@ jobs: env: RELEASE_TYPE: ${{ needs.dump_config.outputs.releaseType }} steps: - - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 with: name: unsigned-${{ matrix.appName }}-${{ matrix.packageFormat }}-${{ matrix.packageFlavor }} path: uploads/ @@ -592,7 +592,7 @@ jobs: rm -f uploads/*.jks - name: Upload signed - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 with: name: signed-${{ matrix.appName }}-${{ matrix.packageFormat }}-${{ matrix.packageFlavor }} if-no-files-found: error @@ -684,7 +684,7 @@ jobs: ref: ${{ steps.shanotes.outputs.app_sha }} - name: Download Artifacts - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 with: name: signed-${{ matrix.appName }}-${{ matrix.packageFormat }}-${{ matrix.packageFlavor }} path: "uploads/" @@ -755,7 +755,7 @@ jobs: - name: Publish to GitHub Releases id: publish_gh if: ${{ contains(matrix.releaseTarget, 'github') }} - uses: softprops/action-gh-release@6da8fa9354ddfdc4aeace5fc48d7f679b5214090 # v2.4.1 + uses: softprops/action-gh-release@5be0e66d93ac7ed76da52eca8bb058f665c3a5fe # v2.4.2 with: token: ${{ steps.app-token.outputs.token || github.token }} target_commitish: ${{ steps.shanotes.outputs.app_sha }} diff --git a/.gitignore b/.gitignore index 8fe66b93a4aa97c02de013e6436e41d8b93cc770..467acf470d9a506d6fe3d56c23384136a0edb494 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,5 @@ captures/ # Screenshots adb-screenshots/ +# Extracted eml files +eml-files/ diff --git a/README.md b/README.md index 3d1d2109e871ccd46b90f4f98a26b7a291b39845..9c95d309fda7e9a95c7a5eb83e29aef7e051f8b8 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Get it on Google Play Get it on F-Droid -Get it on Obtanium +Get it on Obtainium [![Latest release](https://img.shields.io/github/release/thunderbird/thunderbird-android.svg?style=for-the-badge&filter=THUNDERBIRD_*&logo=thunderbird)](https://github.com/thunderbird/thunderbird-android/releases/latest) [![Latest beta release](https://img.shields.io/github/release/thunderbird/thunderbird-android.svg?include_prereleases&style=for-the-badge&label=beta&filter=THUNDERBIRD_*b*&logo=thunderbird)](https://github.com/thunderbird/thunderbird-android/releases) @@ -18,7 +18,7 @@ Thunderbird for Android can be downloaded from a couple of sources: - Thunderbird Beta on [Google Play](https://play.google.com/store/apps/details?id=net.thunderbird.android.beta&referrer=utm_campaign%3Dandroid_metadata%26utm_medium%3Dweb%26utm_source%3Dgithub.com%26utm_content%3Dlink) or [F-Droid](https://f-droid.org/packages/net.thunderbird.android.beta) - [Github Releases](https://github.com/thunderbird/thunderbird-android/releases) - [FFUpdater](https://f-droid.org/packages/de.marmaro.krt.ffupdater/) allows installing the latest versions from ftp.mozilla.org -- [Obtanium](https://obtainium.imranr.dev/) requires app-specific configuration from the [Complex Obtanium Apps list](https://apps.obtainium.imranr.dev/) +- [Obtainium](https://obtainium.imranr.dev/) requires app-specific configuration from the [Complex Obtainium Apps list](https://apps.obtainium.imranr.dev/) By using Thunderbird for Android Beta, you have early access to current development and are able to try new features earlier. diff --git a/app-common/build.gradle.kts b/app-common/build.gradle.kts index 4bcba76fb7c1dc7d59737feb130e6e27f16bb91c..373e8e396a0c9b0c8dee7757ba3ac634635314bc 100644 --- a/app-common/build.gradle.kts +++ b/app-common/build.gradle.kts @@ -31,17 +31,25 @@ dependencies { implementation(projects.core.configstore.implBackend) implementation(projects.core.featureflag) + implementation(projects.core.file) + + implementation(projects.core.ui.setting.api) + implementation(projects.core.ui.setting.implDialog) implementation(projects.core.ui.legacy.theme2.common) implementation(projects.feature.account.avatar.api) implementation(projects.feature.account.avatar.impl) implementation(projects.feature.account.setup) implementation(projects.feature.mail.account.api) + implementation(projects.feature.mail.message.composer) implementation(projects.feature.migration.provider) implementation(projects.feature.notification.api) implementation(projects.feature.notification.impl) implementation(projects.feature.widget.messageList) + implementation(projects.feature.mail.message.export.api) + implementation(projects.feature.mail.message.export.implEml) + implementation(projects.mail.protocols.imap) implementation(projects.backend.imap) diff --git a/app-common/src/main/kotlin/net/thunderbird/app/common/core/AppCommonCoreModule.kt b/app-common/src/main/kotlin/net/thunderbird/app/common/core/AppCommonCoreModule.kt index a1d7430af48a50eedba2da230ebc798c0cb98551..cfe25354936acca69e5c4734b7125374b5977c9b 100644 --- a/app-common/src/main/kotlin/net/thunderbird/app/common/core/AppCommonCoreModule.kt +++ b/app-common/src/main/kotlin/net/thunderbird/app/common/core/AppCommonCoreModule.kt @@ -1,7 +1,13 @@ package net.thunderbird.app.common.core +import android.content.Context import net.thunderbird.app.common.core.configstore.appCommonCoreConfigStoreModule import net.thunderbird.app.common.core.logging.appCommonCoreLogger +import net.thunderbird.app.common.core.ui.appCommonCoreUiModule +import net.thunderbird.core.file.AndroidFileSystemManager +import net.thunderbird.core.file.DefaultFileManager +import net.thunderbird.core.file.FileManager +import net.thunderbird.core.file.FileSystemManager import org.koin.core.module.Module import org.koin.dsl.module @@ -9,5 +15,18 @@ val appCommonCoreModule: Module = module { includes( appCommonCoreConfigStoreModule, appCommonCoreLogger, + appCommonCoreUiModule, ) + + single { + AndroidFileSystemManager( + contentResolver = get().contentResolver, + ) + } + + single { + DefaultFileManager( + fileSystemManager = get(), + ) + } } diff --git a/app-common/src/main/kotlin/net/thunderbird/app/common/core/logging/LoggerModule.kt b/app-common/src/main/kotlin/net/thunderbird/app/common/core/logging/LoggerModule.kt index e31b9f2c0b95d9edbe686bffa610375659138379..3bb495a636c1067391c2fec932402130e4ebe8bd 100644 --- a/app-common/src/main/kotlin/net/thunderbird/app/common/core/logging/LoggerModule.kt +++ b/app-common/src/main/kotlin/net/thunderbird/app/common/core/logging/LoggerModule.kt @@ -13,7 +13,6 @@ import net.thunderbird.core.logging.LogSink import net.thunderbird.core.logging.Logger import net.thunderbird.core.logging.composite.CompositeLogSink import net.thunderbird.core.logging.console.ConsoleLogSink -import net.thunderbird.core.logging.file.AndroidFileSystemManager import net.thunderbird.core.logging.file.FileLogSink import org.koin.core.qualifier.named import org.koin.dsl.bind @@ -46,10 +45,16 @@ val appCommonCoreLogger = module { ) } + // Setup for sync debug logger + // Define this list lazily to avoid eager initialization at app startup + single>(qualifier = named(SYNC_DEBUG_LOG), createdAtStart = false) { + listOf(get(named(SYNC_DEBUG_LOG))) + } + single(named(SYNC_DEBUG_LOG)) { CompositeLogSink( logLevelProvider = get(), - sinks = getList(), + sinks = get>(named(SYNC_DEBUG_LOG)), ) } @@ -58,7 +63,7 @@ val appCommonCoreLogger = module { level = LogLevel.DEBUG, fileName = "thunderbird-sync-debug", fileLocation = get().filesDir.path, - fileSystemManager = AndroidFileSystemManager(get().contentResolver), + fileManager = get(), ) } diff --git a/app-common/src/main/kotlin/net/thunderbird/app/common/core/ui/AppCommonCoreUiModule.kt b/app-common/src/main/kotlin/net/thunderbird/app/common/core/ui/AppCommonCoreUiModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..b60b28c1ecd7692387adcf09310a60f339cf4d36 --- /dev/null +++ b/app-common/src/main/kotlin/net/thunderbird/app/common/core/ui/AppCommonCoreUiModule.kt @@ -0,0 +1,9 @@ +package net.thunderbird.app.common.core.ui + +import net.thunderbird.core.ui.setting.SettingViewProvider +import net.thunderbird.core.ui.setting.dialog.DialogSettingViewProvider +import org.koin.dsl.module + +val appCommonCoreUiModule = module { + single { DialogSettingViewProvider() } +} diff --git a/app-common/src/main/kotlin/net/thunderbird/app/common/feature/AppCommonFeatureModule.kt b/app-common/src/main/kotlin/net/thunderbird/app/common/feature/AppCommonFeatureModule.kt index f43927d52155fa830f6d4eade7479f7c8fbee616..3d8411b57ff72bb6daacd15daa140d91f53afa88 100644 --- a/app-common/src/main/kotlin/net/thunderbird/app/common/feature/AppCommonFeatureModule.kt +++ b/app-common/src/main/kotlin/net/thunderbird/app/common/feature/AppCommonFeatureModule.kt @@ -3,6 +3,7 @@ package net.thunderbird.app.common.feature import app.k9mail.feature.launcher.FeatureLauncherExternalContract import app.k9mail.feature.launcher.di.featureLauncherModule import net.thunderbird.app.common.feature.mail.appCommonFeatureMailModule +import net.thunderbird.feature.mail.message.composer.inject.featureMessageComposerModule import net.thunderbird.feature.navigation.drawer.api.NavigationDrawerExternalContract import net.thunderbird.feature.notification.impl.inject.featureNotificationModule import org.koin.android.ext.koin.androidContext @@ -11,6 +12,7 @@ import org.koin.dsl.module internal val appCommonFeatureModule = module { includes(featureLauncherModule) includes(featureNotificationModule) + includes(featureMessageComposerModule) includes(appCommonFeatureMailModule) factory { diff --git a/app-common/src/main/kotlin/net/thunderbird/app/common/feature/mail/FeatureMailModule.kt b/app-common/src/main/kotlin/net/thunderbird/app/common/feature/mail/FeatureMailModule.kt index 5ccb4b8b5b9702349d0a8c46415dd9126dbaab5a..c6ee5c3a1f9fdd78bb9029bddd710f2711f5e5d9 100644 --- a/app-common/src/main/kotlin/net/thunderbird/app/common/feature/mail/FeatureMailModule.kt +++ b/app-common/src/main/kotlin/net/thunderbird/app/common/feature/mail/FeatureMailModule.kt @@ -2,6 +2,7 @@ package net.thunderbird.app.common.feature.mail import com.fsck.k9.mailstore.DefaultSpecialFolderUpdater import com.fsck.k9.mailstore.LegacyAccountDtoSpecialFolderUpdaterFactory +import net.thunderbird.app.common.feature.mail.message.mailMessageModule import net.thunderbird.backend.api.BackendFactory import net.thunderbird.backend.api.BackendStorageFactory import net.thunderbird.backend.api.folder.RemoteFolderCreator @@ -13,6 +14,8 @@ import org.koin.dsl.module internal val appCommonFeatureMailModule = module { + includes(mailMessageModule) + single> { BaseAccountBackendStorageFactory( legacyFactory = get(), diff --git a/app-common/src/main/kotlin/net/thunderbird/app/common/feature/mail/message/MailMessageModule.kt b/app-common/src/main/kotlin/net/thunderbird/app/common/feature/mail/message/MailMessageModule.kt new file mode 100644 index 0000000000000000000000000000000000000000..d25b1eb3d33b896aee8d1c27b46e72e5c1fd7efe --- /dev/null +++ b/app-common/src/main/kotlin/net/thunderbird/app/common/feature/mail/message/MailMessageModule.kt @@ -0,0 +1,17 @@ +package net.thunderbird.app.common.feature.mail.message + +import net.thunderbird.feature.mail.message.export.DefaultMessageFileNameSuggester +import net.thunderbird.feature.mail.message.export.MessageExporter +import net.thunderbird.feature.mail.message.export.MessageFileNameSuggester +import net.thunderbird.feature.mail.message.export.eml.EmlMessageExporter +import org.koin.dsl.module + +internal val mailMessageModule = module { + single { DefaultMessageFileNameSuggester() } + + single { + EmlMessageExporter( + fileManager = get(), + ) + } +} diff --git a/app-common/src/main/res/values-am/strings.xml b/app-common/src/main/res/values-am/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-am/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-ar/strings.xml b/app-common/src/main/res/values-ar/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-ar/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-ast/strings.xml b/app-common/src/main/res/values-ast/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-ast/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-az/strings.xml b/app-common/src/main/res/values-az/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-az/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-be/strings.xml b/app-common/src/main/res/values-be/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-be/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-bg/strings.xml b/app-common/src/main/res/values-bg/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-bg/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-bn/strings.xml b/app-common/src/main/res/values-bn/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-bn/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-br/strings.xml b/app-common/src/main/res/values-br/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-br/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-bs/strings.xml b/app-common/src/main/res/values-bs/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-bs/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-ca/strings.xml b/app-common/src/main/res/values-ca/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-ca/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-co/strings.xml b/app-common/src/main/res/values-co/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-co/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-cs/strings.xml b/app-common/src/main/res/values-cs/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-cs/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-cy/strings.xml b/app-common/src/main/res/values-cy/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-cy/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-da/strings.xml b/app-common/src/main/res/values-da/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-da/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-de/strings.xml b/app-common/src/main/res/values-de/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-de/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-el/strings.xml b/app-common/src/main/res/values-el/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-el/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-en-rGB/strings.xml b/app-common/src/main/res/values-en-rGB/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-en-rGB/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-enm/strings.xml b/app-common/src/main/res/values-enm/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-enm/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-eo/strings.xml b/app-common/src/main/res/values-eo/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-eo/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-es/strings.xml b/app-common/src/main/res/values-es/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-es/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-et/strings.xml b/app-common/src/main/res/values-et/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-et/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-eu/strings.xml b/app-common/src/main/res/values-eu/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-eu/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-fa/strings.xml b/app-common/src/main/res/values-fa/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-fa/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-fi/strings.xml b/app-common/src/main/res/values-fi/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-fi/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-fr/strings.xml b/app-common/src/main/res/values-fr/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-fr/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-fy/strings.xml b/app-common/src/main/res/values-fy/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-fy/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-ga/strings.xml b/app-common/src/main/res/values-ga/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-ga/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-gd/strings.xml b/app-common/src/main/res/values-gd/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-gd/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-gl/strings.xml b/app-common/src/main/res/values-gl/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-gl/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-gu/strings.xml b/app-common/src/main/res/values-gu/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-gu/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-hi/strings.xml b/app-common/src/main/res/values-hi/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-hi/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-hr/strings.xml b/app-common/src/main/res/values-hr/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-hr/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-ht/strings.xml b/app-common/src/main/res/values-ht/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-ht/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-hu/strings.xml b/app-common/src/main/res/values-hu/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-hu/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-hy/strings.xml b/app-common/src/main/res/values-hy/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-hy/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-in/strings.xml b/app-common/src/main/res/values-in/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-in/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-is/strings.xml b/app-common/src/main/res/values-is/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-is/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-it/strings.xml b/app-common/src/main/res/values-it/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-it/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-iw/strings.xml b/app-common/src/main/res/values-iw/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-iw/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-ja/strings.xml b/app-common/src/main/res/values-ja/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-ja/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-ka/strings.xml b/app-common/src/main/res/values-ka/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-ka/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-kab/strings.xml b/app-common/src/main/res/values-kab/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-kab/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-kk/strings.xml b/app-common/src/main/res/values-kk/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-kk/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-kn/strings.xml b/app-common/src/main/res/values-kn/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-kn/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-ko/strings.xml b/app-common/src/main/res/values-ko/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-ko/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-lt/strings.xml b/app-common/src/main/res/values-lt/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-lt/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-lv/strings.xml b/app-common/src/main/res/values-lv/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-lv/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-ml/strings.xml b/app-common/src/main/res/values-ml/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-ml/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-mnw/strings.xml b/app-common/src/main/res/values-mnw/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-mnw/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-nb-rNO/strings.xml b/app-common/src/main/res/values-nb-rNO/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-nb-rNO/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-nl/strings.xml b/app-common/src/main/res/values-nl/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-nl/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-nn/strings.xml b/app-common/src/main/res/values-nn/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-nn/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-pl/strings.xml b/app-common/src/main/res/values-pl/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-pl/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-pt-rBR/strings.xml b/app-common/src/main/res/values-pt-rBR/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-pt-rBR/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-pt-rPT/strings.xml b/app-common/src/main/res/values-pt-rPT/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-pt-rPT/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-pt/strings.xml b/app-common/src/main/res/values-pt/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-pt/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-ro/strings.xml b/app-common/src/main/res/values-ro/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-ro/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-ru/strings.xml b/app-common/src/main/res/values-ru/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-ru/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-sk/strings.xml b/app-common/src/main/res/values-sk/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-sk/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-sl/strings.xml b/app-common/src/main/res/values-sl/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-sl/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-sq/strings.xml b/app-common/src/main/res/values-sq/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-sq/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-sr/strings.xml b/app-common/src/main/res/values-sr/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-sr/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-sv/strings.xml b/app-common/src/main/res/values-sv/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-sv/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-sw/strings.xml b/app-common/src/main/res/values-sw/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-sw/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-ta/strings.xml b/app-common/src/main/res/values-ta/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-ta/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-th/strings.xml b/app-common/src/main/res/values-th/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-th/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-tr/strings.xml b/app-common/src/main/res/values-tr/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-tr/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-uk/strings.xml b/app-common/src/main/res/values-uk/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-uk/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-vi/strings.xml b/app-common/src/main/res/values-vi/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-vi/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-zh-rCN/strings.xml b/app-common/src/main/res/values-zh-rCN/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-zh-rCN/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-common/src/main/res/values-zh-rTW/strings.xml b/app-common/src/main/res/values-zh-rTW/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-common/src/main/res/values-zh-rTW/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-k9mail/badging/fossRelease-badging.txt b/app-k9mail/badging/fossRelease-badging.txt index 256b1fbce6c26316e69f03def5cd6d90fbe5e222..9bd213c40008bd6a23699d2cd016e471d42579f1 100644 --- a/app-k9mail/badging/fossRelease-badging.txt +++ b/app-k9mail/badging/fossRelease-badging.txt @@ -74,7 +74,7 @@ native-code: 'arm64-v8a' 'armeabi-v7a' 'x86' 'x86_64' other-activities other-receivers other-services -package: name='com.fsck.k9' platformBuildVersionName='15' platformBuildVersionCode='35' compileSdkVersion='35' compileSdkVersionCodename='15' +package: name='com.fsck.k9' platformBuildVersionName='16' platformBuildVersionCode='36' compileSdkVersion='36' compileSdkVersionCodename='16' property: name='android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE' value='This service is used to maintain a continuous connection to an IMAP server to be able to provide instant notifications to the user when a new email arrives. Firebase Cloud Messaging is not suitable for this task, neither are mechanisms like AndroidX WorkManager. Other foreground service types aren't a good fit for this use case.' provides-component:'app-widget' supports-any-density: 'true' diff --git a/app-k9mail/badging/fullRelease-badging.txt b/app-k9mail/badging/fullRelease-badging.txt index 5a5c447d6190318b63c693d93f6b5f2f55c4dd6a..3f1917df6f47db09404a1c28c0b2abcceb260ea6 100644 --- a/app-k9mail/badging/fullRelease-badging.txt +++ b/app-k9mail/badging/fullRelease-badging.txt @@ -74,7 +74,7 @@ native-code: 'arm64-v8a' 'armeabi-v7a' 'x86' 'x86_64' other-activities other-receivers other-services -package: name='com.fsck.k9' platformBuildVersionName='15' platformBuildVersionCode='35' compileSdkVersion='35' compileSdkVersionCodename='15' +package: name='com.fsck.k9' platformBuildVersionName='16' platformBuildVersionCode='36' compileSdkVersion='36' compileSdkVersionCodename='16' property: name='android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE' value='This service is used to maintain a continuous connection to an IMAP server to be able to provide instant notifications to the user when a new email arrives. Firebase Cloud Messaging is not suitable for this task, neither are mechanisms like AndroidX WorkManager. Other foreground service types aren't a good fit for this use case.' provides-component:'app-widget' supports-any-density: 'true' diff --git a/app-k9mail/build.gradle.kts b/app-k9mail/build.gradle.kts index a88dde97156aa66dc6f86b8823550b6020228d16..4c34f726d458a478fd961e34fbf03a903edf2169 100644 --- a/app-k9mail/build.gradle.kts +++ b/app-k9mail/build.gradle.kts @@ -18,7 +18,7 @@ android { testApplicationId = "com.fsck.k9.tests" versionCode = 39021 - versionName = "14.0" + versionName = "15.0" versionNameSuffix = "b1" buildConfigField("String", "CLIENT_INFO_APP_NAME", "\"K-9 Mail\"") diff --git a/app-k9mail/dependencies/fossReleaseRuntimeClasspath.txt b/app-k9mail/dependencies/fossReleaseRuntimeClasspath.txt index fd3ba8c643ac118858cd69e505158db8dab3182c..4b169cff440746dfd3814a66e25bf2583d4bfb2a 100644 --- a/app-k9mail/dependencies/fossReleaseRuntimeClasspath.txt +++ b/app-k9mail/dependencies/fossReleaseRuntimeClasspath.txt @@ -37,12 +37,12 @@ androidx.compose.material:material-icons-extended-android:1.7.8 androidx.compose.material:material-icons-extended:1.7.8 androidx.compose.material:material-ripple-android:1.8.3 androidx.compose.material:material-ripple:1.8.3 -androidx.compose.runtime:runtime-android:1.9.0 -androidx.compose.runtime:runtime-annotation-android:1.9.0 -androidx.compose.runtime:runtime-annotation:1.9.0 -androidx.compose.runtime:runtime-saveable-android:1.9.0 -androidx.compose.runtime:runtime-saveable:1.9.0 -androidx.compose.runtime:runtime:1.9.0 +androidx.compose.runtime:runtime-android:1.9.4 +androidx.compose.runtime:runtime-annotation-android:1.9.4 +androidx.compose.runtime:runtime-annotation:1.9.4 +androidx.compose.runtime:runtime-saveable-android:1.9.4 +androidx.compose.runtime:runtime-saveable:1.9.4 +androidx.compose.runtime:runtime:1.9.4 androidx.compose.ui:ui-android:1.9.0 androidx.compose.ui:ui-geometry-android:1.9.0 androidx.compose.ui:ui-geometry:1.9.0 @@ -63,11 +63,11 @@ androidx.concurrent:concurrent-futures:1.1.0 androidx.constraintlayout:constraintlayout-core:1.1.1 androidx.constraintlayout:constraintlayout:2.2.1 androidx.coordinatorlayout:coordinatorlayout:1.3.0 -androidx.core:core-ktx:1.16.0 +androidx.core:core-ktx:1.17.0 androidx.core:core-remoteviews:1.1.0 androidx.core:core-splashscreen:1.0.1 androidx.core:core-viewtree:1.0.0 -androidx.core:core:1.16.0 +androidx.core:core:1.17.0 androidx.cursoradapter:cursoradapter:1.0.0 androidx.customview:customview-poolingcontainer:1.0.0 androidx.customview:customview:1.1.0 @@ -100,28 +100,28 @@ androidx.glance:glance:1.1.1 androidx.graphics:graphics-path:1.0.1 androidx.interpolator:interpolator:1.0.0 androidx.legacy:legacy-support-core-utils:1.0.0 -androidx.lifecycle:lifecycle-common-java8:2.9.3 -androidx.lifecycle:lifecycle-common-jvm:2.9.3 -androidx.lifecycle:lifecycle-common:2.9.3 -androidx.lifecycle:lifecycle-livedata-core-ktx:2.9.3 -androidx.lifecycle:lifecycle-livedata-core:2.9.3 -androidx.lifecycle:lifecycle-livedata-ktx:2.9.3 -androidx.lifecycle:lifecycle-livedata:2.9.3 -androidx.lifecycle:lifecycle-process:2.9.3 -androidx.lifecycle:lifecycle-runtime-android:2.9.3 -androidx.lifecycle:lifecycle-runtime-compose-android:2.9.3 -androidx.lifecycle:lifecycle-runtime-compose:2.9.3 -androidx.lifecycle:lifecycle-runtime-ktx-android:2.9.3 -androidx.lifecycle:lifecycle-runtime-ktx:2.9.3 -androidx.lifecycle:lifecycle-runtime:2.9.3 -androidx.lifecycle:lifecycle-service:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-android:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-compose-android:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-compose:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-ktx:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-savedstate-android:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-savedstate:2.9.3 -androidx.lifecycle:lifecycle-viewmodel:2.9.3 +androidx.lifecycle:lifecycle-common-java8:2.9.4 +androidx.lifecycle:lifecycle-common-jvm:2.9.4 +androidx.lifecycle:lifecycle-common:2.9.4 +androidx.lifecycle:lifecycle-livedata-core-ktx:2.9.4 +androidx.lifecycle:lifecycle-livedata-core:2.9.4 +androidx.lifecycle:lifecycle-livedata-ktx:2.9.4 +androidx.lifecycle:lifecycle-livedata:2.9.4 +androidx.lifecycle:lifecycle-process:2.9.4 +androidx.lifecycle:lifecycle-runtime-android:2.9.4 +androidx.lifecycle:lifecycle-runtime-compose-android:2.9.4 +androidx.lifecycle:lifecycle-runtime-compose:2.9.4 +androidx.lifecycle:lifecycle-runtime-ktx-android:2.9.4 +androidx.lifecycle:lifecycle-runtime-ktx:2.9.4 +androidx.lifecycle:lifecycle-runtime:2.9.4 +androidx.lifecycle:lifecycle-service:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-android:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-compose-android:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-compose:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-ktx:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-savedstate-android:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-savedstate:2.9.4 +androidx.lifecycle:lifecycle-viewmodel:2.9.4 androidx.loader:loader:1.0.0 androidx.localbroadcastmanager:localbroadcastmanager:1.1.0 androidx.navigation:navigation-common-android:2.9.3 @@ -140,11 +140,11 @@ androidx.resourceinspection:resourceinspection-annotation:1.0.1 androidx.room:room-common:2.6.1 androidx.room:room-ktx:2.6.1 androidx.room:room-runtime:2.6.1 -androidx.savedstate:savedstate-android:1.3.1 -androidx.savedstate:savedstate-compose-android:1.3.1 -androidx.savedstate:savedstate-compose:1.3.1 -androidx.savedstate:savedstate-ktx:1.3.1 -androidx.savedstate:savedstate:1.3.1 +androidx.savedstate:savedstate-android:1.3.3 +androidx.savedstate:savedstate-compose-android:1.3.3 +androidx.savedstate:savedstate-compose:1.3.3 +androidx.savedstate:savedstate-ktx:1.3.3 +androidx.savedstate:savedstate:1.3.3 androidx.slidingpanelayout:slidingpanelayout:1.2.0 androidx.sqlite:sqlite-framework:2.4.0 androidx.sqlite:sqlite:2.4.0 @@ -172,15 +172,17 @@ co.touchlab:stately-concurrent-collections:2.1.0 co.touchlab:stately-strict-jvm:2.1.0 co.touchlab:stately-strict:2.1.0 com.beetstra.jutf7:jutf7:1.0.0 +com.eygraber:uri-kmp-android:0.0.21 +com.eygraber:uri-kmp:0.0.21 com.github.ByteHamster:SearchPreference:2.7.3 com.github.bumptech.glide:annotations:4.16.0 com.github.bumptech.glide:disklrucache:4.16.0 com.github.bumptech.glide:gifdecoder:4.16.0 com.github.bumptech.glide:glide:4.16.0 -com.github.skydoves:landscapist-android:2.5.1 -com.github.skydoves:landscapist-coil3-android:2.5.1 -com.github.skydoves:landscapist-coil3:2.5.1 -com.github.skydoves:landscapist:2.5.1 +com.github.skydoves:landscapist-android:2.6.1 +com.github.skydoves:landscapist-coil3-android:2.6.1 +com.github.skydoves:landscapist-coil3:2.6.1 +com.github.skydoves:landscapist:2.6.1 com.google.android.flexbox:flexbox:3.0.0 com.google.android.material:material:1.12.0 com.google.errorprone:error_prone_annotations:2.15.0 @@ -193,10 +195,10 @@ com.mikepenz:fastadapter-extensions-swipe:5.7.0 com.mikepenz:fastadapter-extensions-utils:5.7.0 com.mikepenz:fastadapter:5.7.0 com.squareup.moshi:moshi:1.15.2 -com.squareup.okhttp3:okhttp-android:5.1.0 -com.squareup.okhttp3:okhttp:5.1.0 -com.squareup.okio:okio-jvm:3.16.0 -com.squareup.okio:okio:3.16.0 +com.squareup.okhttp3:okhttp-android:5.2.1 +com.squareup.okhttp3:okhttp:5.2.1 +com.squareup.okio:okio-jvm:3.16.2 +com.squareup.okio:okio:3.16.2 com.takisoft.colorpicker:colorpicker:1.0.0 com.takisoft.datetimepicker:datetimepicker:1.0.2 com.takisoft.preferencex:preferencex-colorpicker:1.1.0 @@ -206,16 +208,16 @@ commons-io:commons-io:2.20.0 de.cketti.library.changelog:ckchangelog-core:2.0.0-beta02 de.cketti.safecontentresolver:safe-content-resolver-v21:1.0.0 de.hdodenhof:circleimageview:3.1.0 -io.coil-kt.coil3:coil-android:3.2.0 -io.coil-kt.coil3:coil-core-android:3.2.0 -io.coil-kt.coil3:coil-core:3.2.0 -io.coil-kt.coil3:coil-gif:3.2.0 -io.coil-kt.coil3:coil-network-core-android:3.2.0 -io.coil-kt.coil3:coil-network-core:3.2.0 -io.coil-kt.coil3:coil-network-okhttp-jvm:3.2.0 -io.coil-kt.coil3:coil-network-okhttp:3.2.0 -io.coil-kt.coil3:coil-video:3.2.0 -io.coil-kt.coil3:coil:3.2.0 +io.coil-kt.coil3:coil-android:3.3.0 +io.coil-kt.coil3:coil-core-android:3.3.0 +io.coil-kt.coil3:coil-core:3.3.0 +io.coil-kt.coil3:coil-gif:3.3.0 +io.coil-kt.coil3:coil-network-core-android:3.3.0 +io.coil-kt.coil3:coil-network-core:3.3.0 +io.coil-kt.coil3:coil-network-okhttp-jvm:3.3.0 +io.coil-kt.coil3:coil-network-okhttp:3.3.0 +io.coil-kt.coil3:coil-video:3.3.0 +io.coil-kt.coil3:coil:3.3.0 io.insert-koin:koin-android:4.1.1 io.insert-koin:koin-androidx-compose:4.1.1 io.insert-koin:koin-bom:4.1.1 @@ -236,14 +238,14 @@ org.apache.httpcomponents.core5:httpcore5-h2:5.3.6 org.apache.httpcomponents.core5:httpcore5:5.3.6 org.apache.james:apache-mime4j-core:0.8.13 org.apache.james:apache-mime4j-dom:0.8.13 -org.jetbrains.androidx.lifecycle:lifecycle-common:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-runtime:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.9.4 +org.jetbrains.androidx.lifecycle:lifecycle-common:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-runtime:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.9.6 org.jetbrains.androidx.savedstate:savedstate-compose:1.3.4 -org.jetbrains.androidx.savedstate:savedstate:1.3.4 +org.jetbrains.androidx.savedstate:savedstate:1.3.6 org.jetbrains.compose.animation:animation-core:1.9.0 org.jetbrains.compose.animation:animation:1.9.0 org.jetbrains.compose.annotation-internal:annotation:1.9.0 @@ -255,7 +257,7 @@ org.jetbrains.compose.components:components-ui-tooling-preview:1.9.0 org.jetbrains.compose.foundation:foundation-layout:1.9.0 org.jetbrains.compose.foundation:foundation:1.9.0 org.jetbrains.compose.runtime:runtime-saveable:1.9.0 -org.jetbrains.compose.runtime:runtime:1.9.0 +org.jetbrains.compose.runtime:runtime:1.9.3 org.jetbrains.compose.ui:ui-geometry:1.9.0 org.jetbrains.compose.ui:ui-graphics:1.9.0 org.jetbrains.compose.ui:ui-text:1.9.0 @@ -263,12 +265,12 @@ org.jetbrains.compose.ui:ui-tooling-preview:1.9.0 org.jetbrains.compose.ui:ui-unit:1.9.0 org.jetbrains.compose.ui:ui-util:1.9.0 org.jetbrains.compose.ui:ui:1.9.0 -org.jetbrains.kotlin:kotlin-bom:2.2.20 -org.jetbrains.kotlin:kotlin-parcelize-runtime:2.2.20 -org.jetbrains.kotlin:kotlin-stdlib-common:2.2.20 -org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.2.20 -org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.2.20 -org.jetbrains.kotlin:kotlin-stdlib:2.2.20 +org.jetbrains.kotlin:kotlin-bom:2.2.21 +org.jetbrains.kotlin:kotlin-parcelize-runtime:2.2.21 +org.jetbrains.kotlin:kotlin-stdlib-common:2.2.21 +org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.2.21 +org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.2.21 +org.jetbrains.kotlin:kotlin-stdlib:2.2.21 org.jetbrains.kotlinx:kotlinx-collections-immutable-jvm:0.4.0 org.jetbrains.kotlinx:kotlinx-collections-immutable:0.4.0 org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2 diff --git a/app-k9mail/dependencies/fullReleaseRuntimeClasspath.txt b/app-k9mail/dependencies/fullReleaseRuntimeClasspath.txt index de8d7e2c9c38af03533ec56341c492b7c3c5a680..a82688e3165cdc3c5dd0f0175da4763994023de5 100644 --- a/app-k9mail/dependencies/fullReleaseRuntimeClasspath.txt +++ b/app-k9mail/dependencies/fullReleaseRuntimeClasspath.txt @@ -37,12 +37,12 @@ androidx.compose.material:material-icons-extended-android:1.7.8 androidx.compose.material:material-icons-extended:1.7.8 androidx.compose.material:material-ripple-android:1.8.3 androidx.compose.material:material-ripple:1.8.3 -androidx.compose.runtime:runtime-android:1.9.0 -androidx.compose.runtime:runtime-annotation-android:1.9.0 -androidx.compose.runtime:runtime-annotation:1.9.0 -androidx.compose.runtime:runtime-saveable-android:1.9.0 -androidx.compose.runtime:runtime-saveable:1.9.0 -androidx.compose.runtime:runtime:1.9.0 +androidx.compose.runtime:runtime-android:1.9.4 +androidx.compose.runtime:runtime-annotation-android:1.9.4 +androidx.compose.runtime:runtime-annotation:1.9.4 +androidx.compose.runtime:runtime-saveable-android:1.9.4 +androidx.compose.runtime:runtime-saveable:1.9.4 +androidx.compose.runtime:runtime:1.9.4 androidx.compose.ui:ui-android:1.9.0 androidx.compose.ui:ui-geometry-android:1.9.0 androidx.compose.ui:ui-geometry:1.9.0 @@ -63,11 +63,11 @@ androidx.concurrent:concurrent-futures:1.1.0 androidx.constraintlayout:constraintlayout-core:1.1.1 androidx.constraintlayout:constraintlayout:2.2.1 androidx.coordinatorlayout:coordinatorlayout:1.3.0 -androidx.core:core-ktx:1.16.0 +androidx.core:core-ktx:1.17.0 androidx.core:core-remoteviews:1.1.0 androidx.core:core-splashscreen:1.0.1 androidx.core:core-viewtree:1.0.0 -androidx.core:core:1.16.0 +androidx.core:core:1.17.0 androidx.cursoradapter:cursoradapter:1.0.0 androidx.customview:customview-poolingcontainer:1.0.0 androidx.customview:customview:1.1.0 @@ -100,28 +100,28 @@ androidx.glance:glance:1.1.1 androidx.graphics:graphics-path:1.0.1 androidx.interpolator:interpolator:1.0.0 androidx.legacy:legacy-support-core-utils:1.0.0 -androidx.lifecycle:lifecycle-common-java8:2.9.3 -androidx.lifecycle:lifecycle-common-jvm:2.9.3 -androidx.lifecycle:lifecycle-common:2.9.3 -androidx.lifecycle:lifecycle-livedata-core-ktx:2.9.3 -androidx.lifecycle:lifecycle-livedata-core:2.9.3 -androidx.lifecycle:lifecycle-livedata-ktx:2.9.3 -androidx.lifecycle:lifecycle-livedata:2.9.3 -androidx.lifecycle:lifecycle-process:2.9.3 -androidx.lifecycle:lifecycle-runtime-android:2.9.3 -androidx.lifecycle:lifecycle-runtime-compose-android:2.9.3 -androidx.lifecycle:lifecycle-runtime-compose:2.9.3 -androidx.lifecycle:lifecycle-runtime-ktx-android:2.9.3 -androidx.lifecycle:lifecycle-runtime-ktx:2.9.3 -androidx.lifecycle:lifecycle-runtime:2.9.3 -androidx.lifecycle:lifecycle-service:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-android:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-compose-android:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-compose:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-ktx:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-savedstate-android:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-savedstate:2.9.3 -androidx.lifecycle:lifecycle-viewmodel:2.9.3 +androidx.lifecycle:lifecycle-common-java8:2.9.4 +androidx.lifecycle:lifecycle-common-jvm:2.9.4 +androidx.lifecycle:lifecycle-common:2.9.4 +androidx.lifecycle:lifecycle-livedata-core-ktx:2.9.4 +androidx.lifecycle:lifecycle-livedata-core:2.9.4 +androidx.lifecycle:lifecycle-livedata-ktx:2.9.4 +androidx.lifecycle:lifecycle-livedata:2.9.4 +androidx.lifecycle:lifecycle-process:2.9.4 +androidx.lifecycle:lifecycle-runtime-android:2.9.4 +androidx.lifecycle:lifecycle-runtime-compose-android:2.9.4 +androidx.lifecycle:lifecycle-runtime-compose:2.9.4 +androidx.lifecycle:lifecycle-runtime-ktx-android:2.9.4 +androidx.lifecycle:lifecycle-runtime-ktx:2.9.4 +androidx.lifecycle:lifecycle-runtime:2.9.4 +androidx.lifecycle:lifecycle-service:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-android:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-compose-android:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-compose:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-ktx:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-savedstate-android:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-savedstate:2.9.4 +androidx.lifecycle:lifecycle-viewmodel:2.9.4 androidx.loader:loader:1.0.0 androidx.localbroadcastmanager:localbroadcastmanager:1.1.0 androidx.navigation:navigation-common-android:2.9.3 @@ -140,11 +140,11 @@ androidx.resourceinspection:resourceinspection-annotation:1.0.1 androidx.room:room-common:2.6.1 androidx.room:room-ktx:2.6.1 androidx.room:room-runtime:2.6.1 -androidx.savedstate:savedstate-android:1.3.1 -androidx.savedstate:savedstate-compose-android:1.3.1 -androidx.savedstate:savedstate-compose:1.3.1 -androidx.savedstate:savedstate-ktx:1.3.1 -androidx.savedstate:savedstate:1.3.1 +androidx.savedstate:savedstate-android:1.3.3 +androidx.savedstate:savedstate-compose-android:1.3.3 +androidx.savedstate:savedstate-compose:1.3.3 +androidx.savedstate:savedstate-ktx:1.3.3 +androidx.savedstate:savedstate:1.3.3 androidx.slidingpanelayout:slidingpanelayout:1.2.0 androidx.sqlite:sqlite-framework:2.4.0 androidx.sqlite:sqlite:2.4.0 @@ -174,15 +174,17 @@ co.touchlab:stately-strict:2.1.0 com.android.billingclient:billing-ktx:7.1.1 com.android.billingclient:billing:7.1.1 com.beetstra.jutf7:jutf7:1.0.0 +com.eygraber:uri-kmp-android:0.0.21 +com.eygraber:uri-kmp:0.0.21 com.github.ByteHamster:SearchPreference:2.7.3 com.github.bumptech.glide:annotations:4.16.0 com.github.bumptech.glide:disklrucache:4.16.0 com.github.bumptech.glide:gifdecoder:4.16.0 com.github.bumptech.glide:glide:4.16.0 -com.github.skydoves:landscapist-android:2.5.1 -com.github.skydoves:landscapist-coil3-android:2.5.1 -com.github.skydoves:landscapist-coil3:2.5.1 -com.github.skydoves:landscapist:2.5.1 +com.github.skydoves:landscapist-android:2.6.1 +com.github.skydoves:landscapist-coil3-android:2.6.1 +com.github.skydoves:landscapist-coil3:2.6.1 +com.github.skydoves:landscapist:2.6.1 com.google.android.datatransport:transport-api:3.0.0 com.google.android.datatransport:transport-backend-cct:3.1.8 com.google.android.datatransport:transport-runtime:3.1.8 @@ -206,10 +208,10 @@ com.mikepenz:fastadapter-extensions-swipe:5.7.0 com.mikepenz:fastadapter-extensions-utils:5.7.0 com.mikepenz:fastadapter:5.7.0 com.squareup.moshi:moshi:1.15.2 -com.squareup.okhttp3:okhttp-android:5.1.0 -com.squareup.okhttp3:okhttp:5.1.0 -com.squareup.okio:okio-jvm:3.16.0 -com.squareup.okio:okio:3.16.0 +com.squareup.okhttp3:okhttp-android:5.2.1 +com.squareup.okhttp3:okhttp:5.2.1 +com.squareup.okio:okio-jvm:3.16.2 +com.squareup.okio:okio:3.16.2 com.takisoft.colorpicker:colorpicker:1.0.0 com.takisoft.datetimepicker:datetimepicker:1.0.2 com.takisoft.preferencex:preferencex-colorpicker:1.1.0 @@ -219,16 +221,16 @@ commons-io:commons-io:2.20.0 de.cketti.library.changelog:ckchangelog-core:2.0.0-beta02 de.cketti.safecontentresolver:safe-content-resolver-v21:1.0.0 de.hdodenhof:circleimageview:3.1.0 -io.coil-kt.coil3:coil-android:3.2.0 -io.coil-kt.coil3:coil-core-android:3.2.0 -io.coil-kt.coil3:coil-core:3.2.0 -io.coil-kt.coil3:coil-gif:3.2.0 -io.coil-kt.coil3:coil-network-core-android:3.2.0 -io.coil-kt.coil3:coil-network-core:3.2.0 -io.coil-kt.coil3:coil-network-okhttp-jvm:3.2.0 -io.coil-kt.coil3:coil-network-okhttp:3.2.0 -io.coil-kt.coil3:coil-video:3.2.0 -io.coil-kt.coil3:coil:3.2.0 +io.coil-kt.coil3:coil-android:3.3.0 +io.coil-kt.coil3:coil-core-android:3.3.0 +io.coil-kt.coil3:coil-core:3.3.0 +io.coil-kt.coil3:coil-gif:3.3.0 +io.coil-kt.coil3:coil-network-core-android:3.3.0 +io.coil-kt.coil3:coil-network-core:3.3.0 +io.coil-kt.coil3:coil-network-okhttp-jvm:3.3.0 +io.coil-kt.coil3:coil-network-okhttp:3.3.0 +io.coil-kt.coil3:coil-video:3.3.0 +io.coil-kt.coil3:coil:3.3.0 io.insert-koin:koin-android:4.1.1 io.insert-koin:koin-androidx-compose:4.1.1 io.insert-koin:koin-bom:4.1.1 @@ -250,14 +252,14 @@ org.apache.httpcomponents.core5:httpcore5-h2:5.3.6 org.apache.httpcomponents.core5:httpcore5:5.3.6 org.apache.james:apache-mime4j-core:0.8.13 org.apache.james:apache-mime4j-dom:0.8.13 -org.jetbrains.androidx.lifecycle:lifecycle-common:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-runtime:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.9.4 +org.jetbrains.androidx.lifecycle:lifecycle-common:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-runtime:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.9.6 org.jetbrains.androidx.savedstate:savedstate-compose:1.3.4 -org.jetbrains.androidx.savedstate:savedstate:1.3.4 +org.jetbrains.androidx.savedstate:savedstate:1.3.6 org.jetbrains.compose.animation:animation-core:1.9.0 org.jetbrains.compose.animation:animation:1.9.0 org.jetbrains.compose.annotation-internal:annotation:1.9.0 @@ -269,7 +271,7 @@ org.jetbrains.compose.components:components-ui-tooling-preview:1.9.0 org.jetbrains.compose.foundation:foundation-layout:1.9.0 org.jetbrains.compose.foundation:foundation:1.9.0 org.jetbrains.compose.runtime:runtime-saveable:1.9.0 -org.jetbrains.compose.runtime:runtime:1.9.0 +org.jetbrains.compose.runtime:runtime:1.9.3 org.jetbrains.compose.ui:ui-geometry:1.9.0 org.jetbrains.compose.ui:ui-graphics:1.9.0 org.jetbrains.compose.ui:ui-text:1.9.0 @@ -277,12 +279,12 @@ org.jetbrains.compose.ui:ui-tooling-preview:1.9.0 org.jetbrains.compose.ui:ui-unit:1.9.0 org.jetbrains.compose.ui:ui-util:1.9.0 org.jetbrains.compose.ui:ui:1.9.0 -org.jetbrains.kotlin:kotlin-bom:2.2.20 -org.jetbrains.kotlin:kotlin-parcelize-runtime:2.2.20 -org.jetbrains.kotlin:kotlin-stdlib-common:2.2.20 -org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.2.20 -org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.2.20 -org.jetbrains.kotlin:kotlin-stdlib:2.2.20 +org.jetbrains.kotlin:kotlin-bom:2.2.21 +org.jetbrains.kotlin:kotlin-parcelize-runtime:2.2.21 +org.jetbrains.kotlin:kotlin-stdlib-common:2.2.21 +org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.2.21 +org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.2.21 +org.jetbrains.kotlin:kotlin-stdlib:2.2.21 org.jetbrains.kotlinx:kotlinx-collections-immutable-jvm:0.4.0 org.jetbrains.kotlinx:kotlinx-collections-immutable:0.4.0 org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2 diff --git a/app-k9mail/src/debug/kotlin/app/k9mail/featureflag/K9FeatureFlagFactory.kt b/app-k9mail/src/debug/kotlin/app/k9mail/featureflag/K9FeatureFlagFactory.kt index c9c81aae4ed35779fa55b88996d1c72c9a6e2120..433ae8ba14bd2fc115f7259a6279e6fea74d690c 100644 --- a/app-k9mail/src/debug/kotlin/app/k9mail/featureflag/K9FeatureFlagFactory.kt +++ b/app-k9mail/src/debug/kotlin/app/k9mail/featureflag/K9FeatureFlagFactory.kt @@ -1,10 +1,12 @@ package app.k9mail.featureflag import com.fsck.k9.ui.messagelist.MessageListFeatureFlags +import com.fsck.k9.ui.messageview.MessageViewFeatureFlags import net.thunderbird.core.featureflag.FeatureFlag import net.thunderbird.core.featureflag.FeatureFlagFactory import net.thunderbird.core.featureflag.FeatureFlagKey import net.thunderbird.core.featureflag.toFeatureFlagKey +import net.thunderbird.feature.account.settings.AccountSettingsFeatureFlags class K9FeatureFlagFactory : FeatureFlagFactory { override fun createFeatureCatalog(): List { @@ -18,6 +20,8 @@ class K9FeatureFlagFactory : FeatureFlagFactory { FeatureFlag(FeatureFlagKey.DisplayInAppNotifications, enabled = false), FeatureFlag(FeatureFlagKey.UseNotificationSenderForSystemNotifications, enabled = false), FeatureFlag(MessageListFeatureFlags.UseComposeForMessageListItems, enabled = false), + FeatureFlag(MessageViewFeatureFlags.ActionExportEml, enabled = true), + FeatureFlag(AccountSettingsFeatureFlags.EnableAvatarCustomization, enabled = false), ) } } diff --git a/app-k9mail/src/main/kotlin/app/k9mail/provider/K9AppNotificationIconProvider.kt b/app-k9mail/src/main/kotlin/app/k9mail/provider/K9AppNotificationIconProvider.kt new file mode 100644 index 0000000000000000000000000000000000000000..6d53a01af18f376caac2b8a18a7ed3c13449f699 --- /dev/null +++ b/app-k9mail/src/main/kotlin/app/k9mail/provider/K9AppNotificationIconProvider.kt @@ -0,0 +1,10 @@ +package app.k9mail.provider + +import app.k9mail.core.android.common.provider.NotificationIconResourceProvider +import app.k9mail.core.ui.legacy.theme2.k9mail.R + +class K9AppNotificationIconProvider : NotificationIconResourceProvider { + override val pushNotificationIcon: Int + + get() = R.drawable.ic_logo_k9_white +} diff --git a/app-k9mail/src/main/kotlin/app/k9mail/provider/ProviderModule.kt b/app-k9mail/src/main/kotlin/app/k9mail/provider/ProviderModule.kt index 07e236989f7277b1ae5782f49445621d1c174da6..303aca7908bede05c99b5b963bff36e900d9807a 100644 --- a/app-k9mail/src/main/kotlin/app/k9mail/provider/ProviderModule.kt +++ b/app-k9mail/src/main/kotlin/app/k9mail/provider/ProviderModule.kt @@ -1,5 +1,6 @@ package app.k9mail.provider +import app.k9mail.core.android.common.provider.NotificationIconResourceProvider import com.fsck.k9.preferences.FilePrefixProvider import net.thunderbird.core.common.provider.AppNameProvider import net.thunderbird.core.common.provider.BrandNameProvider @@ -17,4 +18,8 @@ internal val providerModule = module { single { K9ThemeProvider() } single { K9FeatureThemeProvider() } + + single { + K9AppNotificationIconProvider() + } } diff --git a/app-k9mail/src/main/res/values-ht/strings.xml b/app-k9mail/src/main/res/values-ht/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-k9mail/src/main/res/values-ht/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-k9mail/src/main/res/values-kn/strings.xml b/app-k9mail/src/main/res/values-kn/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-k9mail/src/main/res/values-kn/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-k9mail/src/main/res/values-mnw/strings.xml b/app-k9mail/src/main/res/values-mnw/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..a29a9fcf41394188c44e093f470c62cf9ed2d5a2 --- /dev/null +++ b/app-k9mail/src/main/res/values-mnw/strings.xml @@ -0,0 +1,4 @@ + + + တိုက်လိက် ခေ-၉ + diff --git a/app-k9mail/src/release/kotlin/app/k9mail/featureflag/K9FeatureFlagFactory.kt b/app-k9mail/src/release/kotlin/app/k9mail/featureflag/K9FeatureFlagFactory.kt index 22ce98a94aa2a48ab7d6cfec24c85d199ee048c4..e8058409a7600e67647e083ce70cc60389e60d74 100644 --- a/app-k9mail/src/release/kotlin/app/k9mail/featureflag/K9FeatureFlagFactory.kt +++ b/app-k9mail/src/release/kotlin/app/k9mail/featureflag/K9FeatureFlagFactory.kt @@ -1,15 +1,16 @@ package app.k9mail.featureflag import com.fsck.k9.ui.messagelist.MessageListFeatureFlags +import com.fsck.k9.ui.messageview.MessageViewFeatureFlags import net.thunderbird.core.featureflag.FeatureFlag import net.thunderbird.core.featureflag.FeatureFlagFactory import net.thunderbird.core.featureflag.FeatureFlagKey import net.thunderbird.core.featureflag.toFeatureFlagKey +import net.thunderbird.feature.account.settings.AccountSettingsFeatureFlags /** * Feature flags for K-9 Mail (release) */ - class K9FeatureFlagFactory : FeatureFlagFactory { override fun createFeatureCatalog(): List { return listOf( @@ -22,6 +23,8 @@ class K9FeatureFlagFactory : FeatureFlagFactory { FeatureFlag(FeatureFlagKey.DisplayInAppNotifications, enabled = false), FeatureFlag(FeatureFlagKey.UseNotificationSenderForSystemNotifications, enabled = false), FeatureFlag(MessageListFeatureFlags.UseComposeForMessageListItems, enabled = false), + FeatureFlag(MessageViewFeatureFlags.ActionExportEml, enabled = false), + FeatureFlag(AccountSettingsFeatureFlags.EnableAvatarCustomization, enabled = false), ) } } diff --git a/app-k9mail/src/test/kotlin/app/k9mail/K9AppNotificationIconProviderTest.kt b/app-k9mail/src/test/kotlin/app/k9mail/K9AppNotificationIconProviderTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..ab59d1077bb28d3ac6604248058af75d4c5b7ffb --- /dev/null +++ b/app-k9mail/src/test/kotlin/app/k9mail/K9AppNotificationIconProviderTest.kt @@ -0,0 +1,17 @@ +package app.k9mail + +import app.k9mail.provider.K9AppNotificationIconProvider +import assertk.assertThat +import assertk.assertions.isEqualTo +import kotlin.test.Test + +class K9AppNotificationIconProviderTest { + @Test + fun `provides correct K9 notification icon`() { + val provider = K9AppNotificationIconProvider() + val icon = provider.pushNotificationIcon + + assertThat(icon) + .isEqualTo(app.k9mail.core.ui.legacy.theme2.k9mail.R.drawable.ic_logo_k9_white) + } +} diff --git a/app-metadata/com.fsck.k9/eo/title.txt b/app-metadata/com.fsck.k9/eo/title.txt new file mode 100644 index 0000000000000000000000000000000000000000..680b102e340ed933acb961205a382a958c24a064 --- /dev/null +++ b/app-metadata/com.fsck.k9/eo/title.txt @@ -0,0 +1 @@ +K-9 Retpoŝtilo diff --git a/app-metadata/com.fsck.k9/mnw/title.txt b/app-metadata/com.fsck.k9/mnw/title.txt new file mode 100644 index 0000000000000000000000000000000000000000..30118793d75a86b87ab46c1a8f83f08ca1b57067 --- /dev/null +++ b/app-metadata/com.fsck.k9/mnw/title.txt @@ -0,0 +1 @@ +တိုက်လိက် K-၉ diff --git a/app-metadata/com.fsck.k9/nn/full_description.txt b/app-metadata/com.fsck.k9/nn/full_description.txt index 056a77367ce40bbcea50e07dd58e804a87e1c357..21d470c486f4edc953b200af2e5266b190156c29 100644 --- a/app-metadata/com.fsck.k9/nn/full_description.txt +++ b/app-metadata/com.fsck.k9/nn/full_description.txt @@ -6,15 +6,15 @@ K-9 Mail er ein e-post klient med 100% open kjeldekode, som verker med omtrent k * Samla innboks * Personvern-vennleg (ingen sporing i det heile, kontaktar kun e-posttilbydaren din) * Automatisk bakkgrunnssynkronisering eller dyttenotifikasjonar -* Lokal og tenar-side søk +* Søk lokalt og på tenaren * OpenPGP e-post kryptering (PGP/MIME) Installer appen OpenKeychain: Easy PGP for å enkryptere/dekryptere e-postane dine med hjelp av OpenPGP. -Kundestønad +Støtte -Om du har problem med K-9 Mail, spør om hjelp på vårt kundestønadsforum. +Om du har problemar med K-9 Mail, kan du spørje om hjelp på vårt støtteforum. Vil du hjelpa? diff --git a/app-metadata/net.thunderbird.android.beta/eo/short_description.txt b/app-metadata/net.thunderbird.android.beta/eo/short_description.txt new file mode 100644 index 0000000000000000000000000000000000000000..61c36826a2a18ba2dbf6e6d09cbee362c3aff819 --- /dev/null +++ b/app-metadata/net.thunderbird.android.beta/eo/short_description.txt @@ -0,0 +1 @@ +Thunderbird estas plene malfermitkoda, privateco-gardanta retpoŝtilo. diff --git a/app-metadata/net.thunderbird.android.beta/eo/title.txt b/app-metadata/net.thunderbird.android.beta/eo/title.txt new file mode 100644 index 0000000000000000000000000000000000000000..2929797d77155da0b0863e0da957fc5f15fe6215 --- /dev/null +++ b/app-metadata/net.thunderbird.android.beta/eo/title.txt @@ -0,0 +1 @@ +Thunderbird Beta por Testantoj diff --git a/app-metadata/net.thunderbird.android.beta/hi-IN/short_description.txt b/app-metadata/net.thunderbird.android.beta/hi-IN/short_description.txt new file mode 100644 index 0000000000000000000000000000000000000000..5f81c3818d6ce387b7b5c4f52e7d4539826d7449 --- /dev/null +++ b/app-metadata/net.thunderbird.android.beta/hi-IN/short_description.txt @@ -0,0 +1 @@ +थंडरबर्ड एक 100% खुला स्रोत, गोपनीयता केंद्रित ईमेल ऐप है। diff --git a/app-metadata/net.thunderbird.android.beta/hi-IN/title.txt b/app-metadata/net.thunderbird.android.beta/hi-IN/title.txt new file mode 100644 index 0000000000000000000000000000000000000000..f14db2a509aef2af2bf1e963857093acce5c143a --- /dev/null +++ b/app-metadata/net.thunderbird.android.beta/hi-IN/title.txt @@ -0,0 +1 @@ +परीक्षकों के लिये थंडरबर्ड बीटा diff --git a/app-metadata/net.thunderbird.android.beta/is-IS/title.txt b/app-metadata/net.thunderbird.android.beta/is-IS/title.txt new file mode 100644 index 0000000000000000000000000000000000000000..86c491a80106ace1cb874f6507966bdeaa938d96 --- /dev/null +++ b/app-metadata/net.thunderbird.android.beta/is-IS/title.txt @@ -0,0 +1 @@ +Thunderbird Beta til prófana diff --git a/app-metadata/net.thunderbird.android.beta/mnw/title.txt b/app-metadata/net.thunderbird.android.beta/mnw/title.txt new file mode 100644 index 0000000000000000000000000000000000000000..f5d270823f316725c67656086ec1a60c95048ba8 --- /dev/null +++ b/app-metadata/net.thunderbird.android.beta/mnw/title.txt @@ -0,0 +1 @@ +Thunderbird Beta သွက်ရဲစမ်ၜတ် diff --git a/app-metadata/net.thunderbird.android.beta/pt-BR/full_description.txt b/app-metadata/net.thunderbird.android.beta/pt-BR/full_description.txt index c503983a74a8a8fd6af74d564047243fbe3bf27f..785c48374301fbc475253712327ee6a69474ab17 100644 --- a/app-metadata/net.thunderbird.android.beta/pt-BR/full_description.txt +++ b/app-metadata/net.thunderbird.android.beta/pt-BR/full_description.txt @@ -1,43 +1,25 @@ -Ajude a tornar a próxima versão do Thunderbird a melhor possível baixando o Thunderbird Beta e tendo acesso antecipado aos recursos mais recentes e correções de bugs antes do lançamento oficial. Seus testes e feedback são importantes, então, por favor, reporte bugs, problemas e compartilhe suas opiniões conosco! +Ajude a tornar a próxima versão do Thunderbird a melhor possível baixando o Thunderbird Beta e tendo acesso antecipado aos recursos mais recentes e correções de bugs antes do lançamento oficial. Seus testes e feedback são importantes, então por favor reporte bugs, problemas e compartilhe suas opiniões conosco! -Encontre nosso rastreador de bugs, código-fonte e wiki em https://github.com/thunderbird/thunderbird-android. +Encontre nosso rastreador de bugs, código-fonte e wiki em https://github.com/thunderbird/thunderbird-android +. -Estamos sempre felizes em receber novos desenvolvedores, designers, documentadores, tradutores, revisores de bugs e amigos. Visite https://thunderbird.net/participate para começar. +Estamos sempre felizes em receber novos desenvolvedores, designers, redatores de documentação, tradutores, triadores de bugs e amigos. Visite https://thunderbird.net/participate + para começar. -O Thunderbird é um poderoso aplicativo de e-mail focado em privacidade. Gerencie facilmente várias contas de e-mail em um único aplicativo, com a opção de Caixa de Entrada Unificada para máxima produtividade. Construído com tecnologia de código aberto e apoiado por uma equipe dedicada de desenvolvedores, junto a uma comunidade global de voluntários, o Thunderbird nunca trata seus dados privados como produto. É financiado exclusivamente por contribuições dos usuários, então você nunca verá anúncios misturados aos seus e-mails. +O Thunderbird é um poderoso aplicativo de e-mail focado em privacidade. Gerencie múltiplas contas de e-mail em um único app, com a opção de Caixa de Entrada Unificada para máxima produtividade. Construído com tecnologia open source e apoiado por uma equipe dedicada de desenvolvedores junto a uma comunidade global de voluntários, o Thunderbird nunca trata seus dados privados como produto. Suportado apenas por contribuições financeiras dos nossos usuários, para que você nunca mais veja anúncios misturados aos seus e-mails. -O que você pode fazer +O que você pode fazer -Diga adeus a múltiplos apps e webmail. Use um único aplicativo, com a Caixa de Entrada Unificada opcional, para agilizar seu dia. +
  • Abandone múltiplos apps e webmails. Use um único app, com a opção de Caixa de Entrada Unificada, para otimizar seu dia.
  • Desfrute de um cliente de e-mail que respeita sua privacidade e nunca coleta ou vende seus dados pessoais. Conectamos você diretamente ao seu provedor de e-mail. Só isso!
  • Eleve sua privacidade usando criptografia de e-mail OpenPGP (PGP/MIME) com o app “OpenKeychain”, para criptografar e descriptografar suas mensagens.
  • Escolha sincronizar seu e-mail instantaneamente, em intervalos definidos ou sob demanda. A forma como você verifica seu e-mail é você quem decide!
  • Encontre suas mensagens importantes usando busca local e no servidor.
-Aproveite um cliente de e-mail que respeita sua privacidade e nunca coleta ou vende seus dados pessoais. Conectamos você diretamente ao seu provedor de e-mail. Só isso! +Compatibilidade -Leve sua privacidade a outro nível usando criptografia de e-mails OpenPGP (PGP/MIME) com o app OpenKeychain, para criptografar e descriptografar suas mensagens. +
  • O Thunderbird funciona com os protocolos IMAP e POP3, suportando uma ampla variedade de provedores de e-mail, incluindo Gmail, Outlook, Yahoo Mail, iCloud e mais.
-Escolha sincronizar seus e-mails instantaneamente, em intervalos definidos ou sob demanda. Você decide como quer checar seu e-mail! +Por que usar o Thunderbird -Encontre suas mensagens importantes usando pesquisa local ou no servidor. +
  • Nome de confiança em e-mails por mais de 20 anos – agora no Android.
  • O Thunderbird é totalmente financiado por contribuições voluntárias dos nossos usuários. Não coletamos seus dados pessoais. Você nunca é o produto.
  • Desenvolvido por uma equipe tão focada em eficiência quanto você. Queremos que você gaste o mínimo de tempo usando o app, obtendo o máximo em retorno.
  • Com colaboradores de todo o mundo, o Thunderbird para Android foi traduzido para mais de 20 idiomas.
  • Suportado pela MZLA Technologies Corporation, uma subsidiária integral da Mozilla Foundation.
-Compatibilidade +Open Source e Comunidade -O Thunderbird funciona com os protocolos IMAP e POP3, suportando uma ampla gama de provedores de e-mail, incluindo Gmail, Outlook, Yahoo Mail, iCloud e outros. - -Por que usar o Thunderbird - -Um nome de confiança em e-mails por mais de 20 anos – agora disponível para Android. - -O Thunderbird é totalmente financiado por contribuições voluntárias dos usuários. Não mineramos seus dados pessoais. Você nunca é o produto. - -Criado por uma equipe tão focada em eficiência quanto você. Queremos que você passe o mínimo de tempo usando o app, aproveitando o máximo dele. - -Com colaboradores de todo o mundo, o Thunderbird para Android foi traduzido para mais de 20 idiomas. - -Suportado pela MZLA Technologies Corporation, subsidiária integral da Mozilla Foundation. - -Código aberto e comunidade - -O Thunderbird é gratuito e de código aberto, o que significa que seu código está disponível para ver, modificar, usar e compartilhar livremente. Sua licença garante que ele será sempre gratuito. Você pode pensar no Thunderbird como um presente de milhares de colaboradores para você. - -Desenvolvemos de forma aberta, com atualizações regulares e transparentes em nosso blog e listas de discussão. - -Nosso suporte aos usuários é alimentado por nossa comunidade global. Encontre as respostas que precisa ou participe como colaborador – seja respondendo perguntas, traduzindo o app ou divulgando o Thunderbird para amigos e familiares. +
  • O Thunderbird é gratuito e open source, o que significa que seu código está disponível para ser visto, modificado, usado e compartilhado livremente. Sua licença também garante que ele será gratuito para sempre. Você pode pensar no Thunderbird como um presente de milhares de colaboradores para você.
  • Desenvolvemos de forma aberta com atualizações regulares e transparentes em nosso blog e listas de discussão.
  • Nosso suporte ao usuário é impulsionado por nossa comunidade global. Encontre as respostas que precisa ou participe como colaborador – seja respondendo perguntas, traduzindo o app ou divulgando o Thunderbird para amigos e familiares.
diff --git a/app-metadata/net.thunderbird.android/eo/short_description.txt b/app-metadata/net.thunderbird.android/eo/short_description.txt new file mode 100644 index 0000000000000000000000000000000000000000..61c36826a2a18ba2dbf6e6d09cbee362c3aff819 --- /dev/null +++ b/app-metadata/net.thunderbird.android/eo/short_description.txt @@ -0,0 +1 @@ +Thunderbird estas plene malfermitkoda, privateco-gardanta retpoŝtilo. diff --git a/app-metadata/net.thunderbird.android/eo/title.txt b/app-metadata/net.thunderbird.android/eo/title.txt new file mode 100644 index 0000000000000000000000000000000000000000..a5d89e240c9c0610e3666c2511d3ae8a2965aaa2 --- /dev/null +++ b/app-metadata/net.thunderbird.android/eo/title.txt @@ -0,0 +1 @@ +Thunderbird: Libera retpoŝtilo diff --git a/app-metadata/net.thunderbird.android/es-ES/title.txt b/app-metadata/net.thunderbird.android/es-ES/title.txt index 4ac6ef767441241a4833066ea07649bd09b31ef2..2092e4080c996708f9f2ec718f55c6c5acc3064a 100644 --- a/app-metadata/net.thunderbird.android/es-ES/title.txt +++ b/app-metadata/net.thunderbird.android/es-ES/title.txt @@ -1 +1 @@ -Thunderbird para Android +Thunderbird; libera tu correo diff --git a/app-metadata/net.thunderbird.android/hi-IN/short_description.txt b/app-metadata/net.thunderbird.android/hi-IN/short_description.txt new file mode 100644 index 0000000000000000000000000000000000000000..5f81c3818d6ce387b7b5c4f52e7d4539826d7449 --- /dev/null +++ b/app-metadata/net.thunderbird.android/hi-IN/short_description.txt @@ -0,0 +1 @@ +थंडरबर्ड एक 100% खुला स्रोत, गोपनीयता केंद्रित ईमेल ऐप है। diff --git a/app-metadata/net.thunderbird.android/hi-IN/title.txt b/app-metadata/net.thunderbird.android/hi-IN/title.txt new file mode 100644 index 0000000000000000000000000000000000000000..3efeabc574566b5239aa1d3a1b8b36bca872d747 --- /dev/null +++ b/app-metadata/net.thunderbird.android/hi-IN/title.txt @@ -0,0 +1 @@ +थंडरबर्ड - इन्बॉक्स मुक्त करें diff --git a/app-metadata/net.thunderbird.android/mnw/title.txt b/app-metadata/net.thunderbird.android/mnw/title.txt new file mode 100644 index 0000000000000000000000000000000000000000..5fa191052dc86947d6370df806d2e059d09c9553 --- /dev/null +++ b/app-metadata/net.thunderbird.android/mnw/title.txt @@ -0,0 +1 @@ +ဂစေံလလဳ: သၠးကဠာလိက်မၞး diff --git a/app-metadata/net.thunderbird.android/pt-BR/short_description.txt b/app-metadata/net.thunderbird.android/pt-BR/short_description.txt index 3c71ae90d58f246b4bcc26a78114788b84a7b460..927c151c825ebb4f3b8265e4227f347f659c8e48 100644 --- a/app-metadata/net.thunderbird.android/pt-BR/short_description.txt +++ b/app-metadata/net.thunderbird.android/pt-BR/short_description.txt @@ -1 +1 @@ -Thunderbird é um aplicativo de email, totalmente de código aberto e com foco na privacidade. +Thunderbird é um app de e-mail 100% open source e focado em privacidade. diff --git a/app-metadata/net.thunderbird.android/th/short_description.txt b/app-metadata/net.thunderbird.android/th/short_description.txt new file mode 100644 index 0000000000000000000000000000000000000000..9e2a87e42dbdfdb4b81f7e7f73faa2380baa41f9 --- /dev/null +++ b/app-metadata/net.thunderbird.android/th/short_description.txt @@ -0,0 +1 @@ +Thunderbird is a 100% open source, privacy focused email app. diff --git a/app-thunderbird/badging/fossBeta-badging.txt b/app-thunderbird/badging/fossBeta-badging.txt index ed8e7c15b50b7348cf116c667e6266d1aaa3ac3b..3bd2f8bf53a9552426194479cac626697090433f 100644 --- a/app-thunderbird/badging/fossBeta-badging.txt +++ b/app-thunderbird/badging/fossBeta-badging.txt @@ -74,7 +74,7 @@ native-code: 'arm64-v8a' 'armeabi-v7a' 'x86' 'x86_64' other-activities other-receivers other-services -package: name='net.thunderbird.android.beta' platformBuildVersionName='15' platformBuildVersionCode='35' compileSdkVersion='35' compileSdkVersionCodename='15' +package: name='net.thunderbird.android.beta' platformBuildVersionName='16' platformBuildVersionCode='36' compileSdkVersion='36' compileSdkVersionCodename='16' property: name='android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE' value='This service is used to maintain a continuous connection to an IMAP server to be able to provide instant notifications to the user when a new email arrives. Firebase Cloud Messaging is not suitable for this task, neither are mechanisms like AndroidX WorkManager. Other foreground service types aren't a good fit for this use case.' provides-component:'app-widget' supports-any-density: 'true' diff --git a/app-thunderbird/badging/fossDaily-badging.txt b/app-thunderbird/badging/fossDaily-badging.txt index 64163be6089062e0ecc24ff6eb65390747f8caac..e55ca6989f45358b96e5c92939476f0734e87315 100644 --- a/app-thunderbird/badging/fossDaily-badging.txt +++ b/app-thunderbird/badging/fossDaily-badging.txt @@ -74,7 +74,7 @@ native-code: 'arm64-v8a' 'armeabi-v7a' 'x86' 'x86_64' other-activities other-receivers other-services -package: name='net.thunderbird.android.daily' platformBuildVersionName='15' platformBuildVersionCode='35' compileSdkVersion='35' compileSdkVersionCodename='15' +package: name='net.thunderbird.android.daily' platformBuildVersionName='16' platformBuildVersionCode='36' compileSdkVersion='36' compileSdkVersionCodename='16' property: name='android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE' value='This service is used to maintain a continuous connection to an IMAP server to be able to provide instant notifications to the user when a new email arrives. Firebase Cloud Messaging is not suitable for this task, neither are mechanisms like AndroidX WorkManager. Other foreground service types aren't a good fit for this use case.' provides-component:'app-widget' supports-any-density: 'true' diff --git a/app-thunderbird/badging/fossRelease-badging.txt b/app-thunderbird/badging/fossRelease-badging.txt index fef671d676432da16478b6c06c106227352b5d32..b538d2886b6de8a718cc09ed605fbbb0ada23e78 100644 --- a/app-thunderbird/badging/fossRelease-badging.txt +++ b/app-thunderbird/badging/fossRelease-badging.txt @@ -74,7 +74,7 @@ native-code: 'arm64-v8a' 'armeabi-v7a' 'x86' 'x86_64' other-activities other-receivers other-services -package: name='net.thunderbird.android' platformBuildVersionName='15' platformBuildVersionCode='35' compileSdkVersion='35' compileSdkVersionCodename='15' +package: name='net.thunderbird.android' platformBuildVersionName='16' platformBuildVersionCode='36' compileSdkVersion='36' compileSdkVersionCodename='16' property: name='android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE' value='This service is used to maintain a continuous connection to an IMAP server to be able to provide instant notifications to the user when a new email arrives. Firebase Cloud Messaging is not suitable for this task, neither are mechanisms like AndroidX WorkManager. Other foreground service types aren't a good fit for this use case.' provides-component:'app-widget' supports-any-density: 'true' diff --git a/app-thunderbird/badging/fullBeta-badging.txt b/app-thunderbird/badging/fullBeta-badging.txt index 17ff54616b411bcdbeeef4225b7820aad5628065..1e4a87bcac8f9b4f57063b361f5da9a19ab13eec 100644 --- a/app-thunderbird/badging/fullBeta-badging.txt +++ b/app-thunderbird/badging/fullBeta-badging.txt @@ -74,7 +74,7 @@ native-code: 'arm64-v8a' 'armeabi-v7a' 'x86' 'x86_64' other-activities other-receivers other-services -package: name='net.thunderbird.android.beta' platformBuildVersionName='15' platformBuildVersionCode='35' compileSdkVersion='35' compileSdkVersionCodename='15' +package: name='net.thunderbird.android.beta' platformBuildVersionName='16' platformBuildVersionCode='36' compileSdkVersion='36' compileSdkVersionCodename='16' property: name='android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE' value='This service is used to maintain a continuous connection to an IMAP server to be able to provide instant notifications to the user when a new email arrives. Firebase Cloud Messaging is not suitable for this task, neither are mechanisms like AndroidX WorkManager. Other foreground service types aren't a good fit for this use case.' provides-component:'app-widget' supports-any-density: 'true' diff --git a/app-thunderbird/badging/fullDaily-badging.txt b/app-thunderbird/badging/fullDaily-badging.txt index d8582ea705e603c80abbf476ab5b6deb877a1cf4..ed9d025abd262cfaf247ce3a7552c693831479ab 100644 --- a/app-thunderbird/badging/fullDaily-badging.txt +++ b/app-thunderbird/badging/fullDaily-badging.txt @@ -74,7 +74,7 @@ native-code: 'arm64-v8a' 'armeabi-v7a' 'x86' 'x86_64' other-activities other-receivers other-services -package: name='net.thunderbird.android.daily' platformBuildVersionName='15' platformBuildVersionCode='35' compileSdkVersion='35' compileSdkVersionCodename='15' +package: name='net.thunderbird.android.daily' platformBuildVersionName='16' platformBuildVersionCode='36' compileSdkVersion='36' compileSdkVersionCodename='16' property: name='android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE' value='This service is used to maintain a continuous connection to an IMAP server to be able to provide instant notifications to the user when a new email arrives. Firebase Cloud Messaging is not suitable for this task, neither are mechanisms like AndroidX WorkManager. Other foreground service types aren't a good fit for this use case.' provides-component:'app-widget' supports-any-density: 'true' diff --git a/app-thunderbird/badging/fullRelease-badging.txt b/app-thunderbird/badging/fullRelease-badging.txt index 1fee8f8c3eddb962844ccbb104b7d9933dfcdc77..17ed8e73680ed3cfcf3480d47783e06d426fce98 100644 --- a/app-thunderbird/badging/fullRelease-badging.txt +++ b/app-thunderbird/badging/fullRelease-badging.txt @@ -74,7 +74,7 @@ native-code: 'arm64-v8a' 'armeabi-v7a' 'x86' 'x86_64' other-activities other-receivers other-services -package: name='net.thunderbird.android' platformBuildVersionName='15' platformBuildVersionCode='35' compileSdkVersion='35' compileSdkVersionCodename='15' +package: name='net.thunderbird.android' platformBuildVersionName='16' platformBuildVersionCode='36' compileSdkVersion='36' compileSdkVersionCodename='16' property: name='android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE' value='This service is used to maintain a continuous connection to an IMAP server to be able to provide instant notifications to the user when a new email arrives. Firebase Cloud Messaging is not suitable for this task, neither are mechanisms like AndroidX WorkManager. Other foreground service types aren't a good fit for this use case.' provides-component:'app-widget' supports-any-density: 'true' diff --git a/app-thunderbird/build.gradle.kts b/app-thunderbird/build.gradle.kts index dcfb01958727f2555373995ed2a3c51dcbd0a577..28c30495a06157585a12d76a6213b87ec9d54e2e 100644 --- a/app-thunderbird/build.gradle.kts +++ b/app-thunderbird/build.gradle.kts @@ -18,7 +18,7 @@ android { testApplicationId = "net.thunderbird.android.tests" versionCode = 34 - versionName = "14.0" + versionName = "15.0" buildConfigField("String", "CLIENT_INFO_APP_NAME", "\"Thunderbird for Android\"") } @@ -121,7 +121,7 @@ android { signingConfig = signingConfigs.getByType(SigningType.TB_BETA) applicationIdSuffix = ".beta" - versionNameSuffix = "b3" + versionNameSuffix = "b1" isMinifyEnabled = true isShrinkResources = true @@ -172,7 +172,6 @@ android { } } - @Suppress("UnstableApiUsage") bundle { language { // Don't split by language. Otherwise our in-app language switcher won't work. @@ -253,7 +252,6 @@ dependencies { implementation(projects.feature.migration.launcher.thunderbird) // TODO remove once OAuth ids have been moved from TBD to TBA - "betaImplementation"(libs.appauth) releaseImplementation(libs.appauth) // Required for DependencyInjectionTest diff --git a/app-thunderbird/dependencies/fossBetaRuntimeClasspath.txt b/app-thunderbird/dependencies/fossBetaRuntimeClasspath.txt index 6f18d9b53d85c91d2492f0eaf5270eaa4b3c0e5e..c4067960d1fec0acd939225cbbb01417b30213d2 100644 --- a/app-thunderbird/dependencies/fossBetaRuntimeClasspath.txt +++ b/app-thunderbird/dependencies/fossBetaRuntimeClasspath.txt @@ -42,12 +42,12 @@ androidx.compose.material:material-icons-extended-android:1.7.8 androidx.compose.material:material-icons-extended:1.7.8 androidx.compose.material:material-ripple-android:1.8.3 androidx.compose.material:material-ripple:1.8.3 -androidx.compose.runtime:runtime-android:1.9.0 -androidx.compose.runtime:runtime-annotation-android:1.9.0 -androidx.compose.runtime:runtime-annotation:1.9.0 -androidx.compose.runtime:runtime-saveable-android:1.9.0 -androidx.compose.runtime:runtime-saveable:1.9.0 -androidx.compose.runtime:runtime:1.9.0 +androidx.compose.runtime:runtime-android:1.9.4 +androidx.compose.runtime:runtime-annotation-android:1.9.4 +androidx.compose.runtime:runtime-annotation:1.9.4 +androidx.compose.runtime:runtime-saveable-android:1.9.4 +androidx.compose.runtime:runtime-saveable:1.9.4 +androidx.compose.runtime:runtime:1.9.4 androidx.compose.ui:ui-android:1.9.0 androidx.compose.ui:ui-geometry-android:1.9.0 androidx.compose.ui:ui-geometry:1.9.0 @@ -68,11 +68,11 @@ androidx.concurrent:concurrent-futures:1.1.0 androidx.constraintlayout:constraintlayout-core:1.1.1 androidx.constraintlayout:constraintlayout:2.2.1 androidx.coordinatorlayout:coordinatorlayout:1.3.0 -androidx.core:core-ktx:1.16.0 +androidx.core:core-ktx:1.17.0 androidx.core:core-remoteviews:1.1.0 androidx.core:core-splashscreen:1.0.1 androidx.core:core-viewtree:1.0.0 -androidx.core:core:1.16.0 +androidx.core:core:1.17.0 androidx.cursoradapter:cursoradapter:1.0.0 androidx.customview:customview-poolingcontainer:1.0.0 androidx.customview:customview:1.1.0 @@ -105,28 +105,28 @@ androidx.glance:glance:1.1.1 androidx.graphics:graphics-path:1.0.1 androidx.interpolator:interpolator:1.0.0 androidx.legacy:legacy-support-core-utils:1.0.0 -androidx.lifecycle:lifecycle-common-java8:2.9.3 -androidx.lifecycle:lifecycle-common-jvm:2.9.3 -androidx.lifecycle:lifecycle-common:2.9.3 -androidx.lifecycle:lifecycle-livedata-core-ktx:2.9.3 -androidx.lifecycle:lifecycle-livedata-core:2.9.3 -androidx.lifecycle:lifecycle-livedata-ktx:2.9.3 -androidx.lifecycle:lifecycle-livedata:2.9.3 -androidx.lifecycle:lifecycle-process:2.9.3 -androidx.lifecycle:lifecycle-runtime-android:2.9.3 -androidx.lifecycle:lifecycle-runtime-compose-android:2.9.3 -androidx.lifecycle:lifecycle-runtime-compose:2.9.3 -androidx.lifecycle:lifecycle-runtime-ktx-android:2.9.3 -androidx.lifecycle:lifecycle-runtime-ktx:2.9.3 -androidx.lifecycle:lifecycle-runtime:2.9.3 -androidx.lifecycle:lifecycle-service:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-android:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-compose-android:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-compose:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-ktx:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-savedstate-android:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-savedstate:2.9.3 -androidx.lifecycle:lifecycle-viewmodel:2.9.3 +androidx.lifecycle:lifecycle-common-java8:2.9.4 +androidx.lifecycle:lifecycle-common-jvm:2.9.4 +androidx.lifecycle:lifecycle-common:2.9.4 +androidx.lifecycle:lifecycle-livedata-core-ktx:2.9.4 +androidx.lifecycle:lifecycle-livedata-core:2.9.4 +androidx.lifecycle:lifecycle-livedata-ktx:2.9.4 +androidx.lifecycle:lifecycle-livedata:2.9.4 +androidx.lifecycle:lifecycle-process:2.9.4 +androidx.lifecycle:lifecycle-runtime-android:2.9.4 +androidx.lifecycle:lifecycle-runtime-compose-android:2.9.4 +androidx.lifecycle:lifecycle-runtime-compose:2.9.4 +androidx.lifecycle:lifecycle-runtime-ktx-android:2.9.4 +androidx.lifecycle:lifecycle-runtime-ktx:2.9.4 +androidx.lifecycle:lifecycle-runtime:2.9.4 +androidx.lifecycle:lifecycle-service:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-android:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-compose-android:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-compose:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-ktx:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-savedstate-android:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-savedstate:2.9.4 +androidx.lifecycle:lifecycle-viewmodel:2.9.4 androidx.loader:loader:1.0.0 androidx.localbroadcastmanager:localbroadcastmanager:1.1.0 androidx.navigation:navigation-common-android:2.9.3 @@ -145,11 +145,11 @@ androidx.resourceinspection:resourceinspection-annotation:1.0.1 androidx.room:room-common:2.6.1 androidx.room:room-ktx:2.6.1 androidx.room:room-runtime:2.6.1 -androidx.savedstate:savedstate-android:1.3.1 -androidx.savedstate:savedstate-compose-android:1.3.1 -androidx.savedstate:savedstate-compose:1.3.1 -androidx.savedstate:savedstate-ktx:1.3.1 -androidx.savedstate:savedstate:1.3.1 +androidx.savedstate:savedstate-android:1.3.3 +androidx.savedstate:savedstate-compose-android:1.3.3 +androidx.savedstate:savedstate-compose:1.3.3 +androidx.savedstate:savedstate-ktx:1.3.3 +androidx.savedstate:savedstate:1.3.3 androidx.slidingpanelayout:slidingpanelayout:1.2.0 androidx.sqlite:sqlite-framework:2.4.0 androidx.sqlite:sqlite:2.4.0 @@ -177,15 +177,17 @@ co.touchlab:stately-concurrent-collections:2.1.0 co.touchlab:stately-strict-jvm:2.1.0 co.touchlab:stately-strict:2.1.0 com.beetstra.jutf7:jutf7:1.0.0 +com.eygraber:uri-kmp-android:0.0.21 +com.eygraber:uri-kmp:0.0.21 com.github.ByteHamster:SearchPreference:2.7.3 com.github.bumptech.glide:annotations:4.16.0 com.github.bumptech.glide:disklrucache:4.16.0 com.github.bumptech.glide:gifdecoder:4.16.0 com.github.bumptech.glide:glide:4.16.0 -com.github.skydoves:landscapist-android:2.5.1 -com.github.skydoves:landscapist-coil3-android:2.5.1 -com.github.skydoves:landscapist-coil3:2.5.1 -com.github.skydoves:landscapist:2.5.1 +com.github.skydoves:landscapist-android:2.6.1 +com.github.skydoves:landscapist-coil3-android:2.6.1 +com.github.skydoves:landscapist-coil3:2.6.1 +com.github.skydoves:landscapist:2.6.1 com.google.android.flexbox:flexbox:3.0.0 com.google.android.material:material:1.12.0 com.google.auto.value:auto-value-annotations:1.6.3 @@ -200,10 +202,10 @@ com.mikepenz:fastadapter-extensions-swipe:5.7.0 com.mikepenz:fastadapter-extensions-utils:5.7.0 com.mikepenz:fastadapter:5.7.0 com.squareup.moshi:moshi:1.15.2 -com.squareup.okhttp3:okhttp-android:5.1.0 -com.squareup.okhttp3:okhttp:5.1.0 -com.squareup.okio:okio-jvm:3.16.0 -com.squareup.okio:okio:3.16.0 +com.squareup.okhttp3:okhttp-android:5.2.1 +com.squareup.okhttp3:okhttp:5.2.1 +com.squareup.okio:okio-jvm:3.16.2 +com.squareup.okio:okio:3.16.2 com.takisoft.colorpicker:colorpicker:1.0.0 com.takisoft.datetimepicker:datetimepicker:1.0.2 com.takisoft.preferencex:preferencex-colorpicker:1.1.0 @@ -213,16 +215,16 @@ commons-io:commons-io:2.20.0 de.cketti.library.changelog:ckchangelog-core:2.0.0-beta02 de.cketti.safecontentresolver:safe-content-resolver-v21:1.0.0 de.hdodenhof:circleimageview:3.1.0 -io.coil-kt.coil3:coil-android:3.2.0 -io.coil-kt.coil3:coil-core-android:3.2.0 -io.coil-kt.coil3:coil-core:3.2.0 -io.coil-kt.coil3:coil-gif:3.2.0 -io.coil-kt.coil3:coil-network-core-android:3.2.0 -io.coil-kt.coil3:coil-network-core:3.2.0 -io.coil-kt.coil3:coil-network-okhttp-jvm:3.2.0 -io.coil-kt.coil3:coil-network-okhttp:3.2.0 -io.coil-kt.coil3:coil-video:3.2.0 -io.coil-kt.coil3:coil:3.2.0 +io.coil-kt.coil3:coil-android:3.3.0 +io.coil-kt.coil3:coil-core-android:3.3.0 +io.coil-kt.coil3:coil-core:3.3.0 +io.coil-kt.coil3:coil-gif:3.3.0 +io.coil-kt.coil3:coil-network-core-android:3.3.0 +io.coil-kt.coil3:coil-network-core:3.3.0 +io.coil-kt.coil3:coil-network-okhttp-jvm:3.3.0 +io.coil-kt.coil3:coil-network-okhttp:3.3.0 +io.coil-kt.coil3:coil-video:3.3.0 +io.coil-kt.coil3:coil:3.3.0 io.insert-koin:koin-android:4.1.1 io.insert-koin:koin-androidx-compose:4.1.1 io.insert-koin:koin-bom:4.1.1 @@ -243,14 +245,14 @@ org.apache.httpcomponents.core5:httpcore5-h2:5.3.6 org.apache.httpcomponents.core5:httpcore5:5.3.6 org.apache.james:apache-mime4j-core:0.8.13 org.apache.james:apache-mime4j-dom:0.8.13 -org.jetbrains.androidx.lifecycle:lifecycle-common:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-runtime:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.9.4 +org.jetbrains.androidx.lifecycle:lifecycle-common:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-runtime:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.9.6 org.jetbrains.androidx.savedstate:savedstate-compose:1.3.4 -org.jetbrains.androidx.savedstate:savedstate:1.3.4 +org.jetbrains.androidx.savedstate:savedstate:1.3.6 org.jetbrains.compose.animation:animation-core:1.9.0 org.jetbrains.compose.animation:animation:1.9.0 org.jetbrains.compose.annotation-internal:annotation:1.9.0 @@ -262,7 +264,7 @@ org.jetbrains.compose.components:components-ui-tooling-preview:1.9.0 org.jetbrains.compose.foundation:foundation-layout:1.9.0 org.jetbrains.compose.foundation:foundation:1.9.0 org.jetbrains.compose.runtime:runtime-saveable:1.9.0 -org.jetbrains.compose.runtime:runtime:1.9.0 +org.jetbrains.compose.runtime:runtime:1.9.3 org.jetbrains.compose.ui:ui-geometry:1.9.0 org.jetbrains.compose.ui:ui-graphics:1.9.0 org.jetbrains.compose.ui:ui-text:1.9.0 @@ -270,12 +272,12 @@ org.jetbrains.compose.ui:ui-tooling-preview:1.9.0 org.jetbrains.compose.ui:ui-unit:1.9.0 org.jetbrains.compose.ui:ui-util:1.9.0 org.jetbrains.compose.ui:ui:1.9.0 -org.jetbrains.kotlin:kotlin-bom:2.2.20 -org.jetbrains.kotlin:kotlin-parcelize-runtime:2.2.20 -org.jetbrains.kotlin:kotlin-stdlib-common:2.2.20 -org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.2.20 -org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.2.20 -org.jetbrains.kotlin:kotlin-stdlib:2.2.20 +org.jetbrains.kotlin:kotlin-bom:2.2.21 +org.jetbrains.kotlin:kotlin-parcelize-runtime:2.2.21 +org.jetbrains.kotlin:kotlin-stdlib-common:2.2.21 +org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.2.21 +org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.2.21 +org.jetbrains.kotlin:kotlin-stdlib:2.2.21 org.jetbrains.kotlinx:kotlinx-collections-immutable-jvm:0.4.0 org.jetbrains.kotlinx:kotlinx-collections-immutable:0.4.0 org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2 diff --git a/app-thunderbird/dependencies/fossDailyRuntimeClasspath.txt b/app-thunderbird/dependencies/fossDailyRuntimeClasspath.txt index 6f18d9b53d85c91d2492f0eaf5270eaa4b3c0e5e..c4067960d1fec0acd939225cbbb01417b30213d2 100644 --- a/app-thunderbird/dependencies/fossDailyRuntimeClasspath.txt +++ b/app-thunderbird/dependencies/fossDailyRuntimeClasspath.txt @@ -42,12 +42,12 @@ androidx.compose.material:material-icons-extended-android:1.7.8 androidx.compose.material:material-icons-extended:1.7.8 androidx.compose.material:material-ripple-android:1.8.3 androidx.compose.material:material-ripple:1.8.3 -androidx.compose.runtime:runtime-android:1.9.0 -androidx.compose.runtime:runtime-annotation-android:1.9.0 -androidx.compose.runtime:runtime-annotation:1.9.0 -androidx.compose.runtime:runtime-saveable-android:1.9.0 -androidx.compose.runtime:runtime-saveable:1.9.0 -androidx.compose.runtime:runtime:1.9.0 +androidx.compose.runtime:runtime-android:1.9.4 +androidx.compose.runtime:runtime-annotation-android:1.9.4 +androidx.compose.runtime:runtime-annotation:1.9.4 +androidx.compose.runtime:runtime-saveable-android:1.9.4 +androidx.compose.runtime:runtime-saveable:1.9.4 +androidx.compose.runtime:runtime:1.9.4 androidx.compose.ui:ui-android:1.9.0 androidx.compose.ui:ui-geometry-android:1.9.0 androidx.compose.ui:ui-geometry:1.9.0 @@ -68,11 +68,11 @@ androidx.concurrent:concurrent-futures:1.1.0 androidx.constraintlayout:constraintlayout-core:1.1.1 androidx.constraintlayout:constraintlayout:2.2.1 androidx.coordinatorlayout:coordinatorlayout:1.3.0 -androidx.core:core-ktx:1.16.0 +androidx.core:core-ktx:1.17.0 androidx.core:core-remoteviews:1.1.0 androidx.core:core-splashscreen:1.0.1 androidx.core:core-viewtree:1.0.0 -androidx.core:core:1.16.0 +androidx.core:core:1.17.0 androidx.cursoradapter:cursoradapter:1.0.0 androidx.customview:customview-poolingcontainer:1.0.0 androidx.customview:customview:1.1.0 @@ -105,28 +105,28 @@ androidx.glance:glance:1.1.1 androidx.graphics:graphics-path:1.0.1 androidx.interpolator:interpolator:1.0.0 androidx.legacy:legacy-support-core-utils:1.0.0 -androidx.lifecycle:lifecycle-common-java8:2.9.3 -androidx.lifecycle:lifecycle-common-jvm:2.9.3 -androidx.lifecycle:lifecycle-common:2.9.3 -androidx.lifecycle:lifecycle-livedata-core-ktx:2.9.3 -androidx.lifecycle:lifecycle-livedata-core:2.9.3 -androidx.lifecycle:lifecycle-livedata-ktx:2.9.3 -androidx.lifecycle:lifecycle-livedata:2.9.3 -androidx.lifecycle:lifecycle-process:2.9.3 -androidx.lifecycle:lifecycle-runtime-android:2.9.3 -androidx.lifecycle:lifecycle-runtime-compose-android:2.9.3 -androidx.lifecycle:lifecycle-runtime-compose:2.9.3 -androidx.lifecycle:lifecycle-runtime-ktx-android:2.9.3 -androidx.lifecycle:lifecycle-runtime-ktx:2.9.3 -androidx.lifecycle:lifecycle-runtime:2.9.3 -androidx.lifecycle:lifecycle-service:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-android:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-compose-android:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-compose:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-ktx:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-savedstate-android:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-savedstate:2.9.3 -androidx.lifecycle:lifecycle-viewmodel:2.9.3 +androidx.lifecycle:lifecycle-common-java8:2.9.4 +androidx.lifecycle:lifecycle-common-jvm:2.9.4 +androidx.lifecycle:lifecycle-common:2.9.4 +androidx.lifecycle:lifecycle-livedata-core-ktx:2.9.4 +androidx.lifecycle:lifecycle-livedata-core:2.9.4 +androidx.lifecycle:lifecycle-livedata-ktx:2.9.4 +androidx.lifecycle:lifecycle-livedata:2.9.4 +androidx.lifecycle:lifecycle-process:2.9.4 +androidx.lifecycle:lifecycle-runtime-android:2.9.4 +androidx.lifecycle:lifecycle-runtime-compose-android:2.9.4 +androidx.lifecycle:lifecycle-runtime-compose:2.9.4 +androidx.lifecycle:lifecycle-runtime-ktx-android:2.9.4 +androidx.lifecycle:lifecycle-runtime-ktx:2.9.4 +androidx.lifecycle:lifecycle-runtime:2.9.4 +androidx.lifecycle:lifecycle-service:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-android:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-compose-android:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-compose:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-ktx:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-savedstate-android:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-savedstate:2.9.4 +androidx.lifecycle:lifecycle-viewmodel:2.9.4 androidx.loader:loader:1.0.0 androidx.localbroadcastmanager:localbroadcastmanager:1.1.0 androidx.navigation:navigation-common-android:2.9.3 @@ -145,11 +145,11 @@ androidx.resourceinspection:resourceinspection-annotation:1.0.1 androidx.room:room-common:2.6.1 androidx.room:room-ktx:2.6.1 androidx.room:room-runtime:2.6.1 -androidx.savedstate:savedstate-android:1.3.1 -androidx.savedstate:savedstate-compose-android:1.3.1 -androidx.savedstate:savedstate-compose:1.3.1 -androidx.savedstate:savedstate-ktx:1.3.1 -androidx.savedstate:savedstate:1.3.1 +androidx.savedstate:savedstate-android:1.3.3 +androidx.savedstate:savedstate-compose-android:1.3.3 +androidx.savedstate:savedstate-compose:1.3.3 +androidx.savedstate:savedstate-ktx:1.3.3 +androidx.savedstate:savedstate:1.3.3 androidx.slidingpanelayout:slidingpanelayout:1.2.0 androidx.sqlite:sqlite-framework:2.4.0 androidx.sqlite:sqlite:2.4.0 @@ -177,15 +177,17 @@ co.touchlab:stately-concurrent-collections:2.1.0 co.touchlab:stately-strict-jvm:2.1.0 co.touchlab:stately-strict:2.1.0 com.beetstra.jutf7:jutf7:1.0.0 +com.eygraber:uri-kmp-android:0.0.21 +com.eygraber:uri-kmp:0.0.21 com.github.ByteHamster:SearchPreference:2.7.3 com.github.bumptech.glide:annotations:4.16.0 com.github.bumptech.glide:disklrucache:4.16.0 com.github.bumptech.glide:gifdecoder:4.16.0 com.github.bumptech.glide:glide:4.16.0 -com.github.skydoves:landscapist-android:2.5.1 -com.github.skydoves:landscapist-coil3-android:2.5.1 -com.github.skydoves:landscapist-coil3:2.5.1 -com.github.skydoves:landscapist:2.5.1 +com.github.skydoves:landscapist-android:2.6.1 +com.github.skydoves:landscapist-coil3-android:2.6.1 +com.github.skydoves:landscapist-coil3:2.6.1 +com.github.skydoves:landscapist:2.6.1 com.google.android.flexbox:flexbox:3.0.0 com.google.android.material:material:1.12.0 com.google.auto.value:auto-value-annotations:1.6.3 @@ -200,10 +202,10 @@ com.mikepenz:fastadapter-extensions-swipe:5.7.0 com.mikepenz:fastadapter-extensions-utils:5.7.0 com.mikepenz:fastadapter:5.7.0 com.squareup.moshi:moshi:1.15.2 -com.squareup.okhttp3:okhttp-android:5.1.0 -com.squareup.okhttp3:okhttp:5.1.0 -com.squareup.okio:okio-jvm:3.16.0 -com.squareup.okio:okio:3.16.0 +com.squareup.okhttp3:okhttp-android:5.2.1 +com.squareup.okhttp3:okhttp:5.2.1 +com.squareup.okio:okio-jvm:3.16.2 +com.squareup.okio:okio:3.16.2 com.takisoft.colorpicker:colorpicker:1.0.0 com.takisoft.datetimepicker:datetimepicker:1.0.2 com.takisoft.preferencex:preferencex-colorpicker:1.1.0 @@ -213,16 +215,16 @@ commons-io:commons-io:2.20.0 de.cketti.library.changelog:ckchangelog-core:2.0.0-beta02 de.cketti.safecontentresolver:safe-content-resolver-v21:1.0.0 de.hdodenhof:circleimageview:3.1.0 -io.coil-kt.coil3:coil-android:3.2.0 -io.coil-kt.coil3:coil-core-android:3.2.0 -io.coil-kt.coil3:coil-core:3.2.0 -io.coil-kt.coil3:coil-gif:3.2.0 -io.coil-kt.coil3:coil-network-core-android:3.2.0 -io.coil-kt.coil3:coil-network-core:3.2.0 -io.coil-kt.coil3:coil-network-okhttp-jvm:3.2.0 -io.coil-kt.coil3:coil-network-okhttp:3.2.0 -io.coil-kt.coil3:coil-video:3.2.0 -io.coil-kt.coil3:coil:3.2.0 +io.coil-kt.coil3:coil-android:3.3.0 +io.coil-kt.coil3:coil-core-android:3.3.0 +io.coil-kt.coil3:coil-core:3.3.0 +io.coil-kt.coil3:coil-gif:3.3.0 +io.coil-kt.coil3:coil-network-core-android:3.3.0 +io.coil-kt.coil3:coil-network-core:3.3.0 +io.coil-kt.coil3:coil-network-okhttp-jvm:3.3.0 +io.coil-kt.coil3:coil-network-okhttp:3.3.0 +io.coil-kt.coil3:coil-video:3.3.0 +io.coil-kt.coil3:coil:3.3.0 io.insert-koin:koin-android:4.1.1 io.insert-koin:koin-androidx-compose:4.1.1 io.insert-koin:koin-bom:4.1.1 @@ -243,14 +245,14 @@ org.apache.httpcomponents.core5:httpcore5-h2:5.3.6 org.apache.httpcomponents.core5:httpcore5:5.3.6 org.apache.james:apache-mime4j-core:0.8.13 org.apache.james:apache-mime4j-dom:0.8.13 -org.jetbrains.androidx.lifecycle:lifecycle-common:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-runtime:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.9.4 +org.jetbrains.androidx.lifecycle:lifecycle-common:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-runtime:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.9.6 org.jetbrains.androidx.savedstate:savedstate-compose:1.3.4 -org.jetbrains.androidx.savedstate:savedstate:1.3.4 +org.jetbrains.androidx.savedstate:savedstate:1.3.6 org.jetbrains.compose.animation:animation-core:1.9.0 org.jetbrains.compose.animation:animation:1.9.0 org.jetbrains.compose.annotation-internal:annotation:1.9.0 @@ -262,7 +264,7 @@ org.jetbrains.compose.components:components-ui-tooling-preview:1.9.0 org.jetbrains.compose.foundation:foundation-layout:1.9.0 org.jetbrains.compose.foundation:foundation:1.9.0 org.jetbrains.compose.runtime:runtime-saveable:1.9.0 -org.jetbrains.compose.runtime:runtime:1.9.0 +org.jetbrains.compose.runtime:runtime:1.9.3 org.jetbrains.compose.ui:ui-geometry:1.9.0 org.jetbrains.compose.ui:ui-graphics:1.9.0 org.jetbrains.compose.ui:ui-text:1.9.0 @@ -270,12 +272,12 @@ org.jetbrains.compose.ui:ui-tooling-preview:1.9.0 org.jetbrains.compose.ui:ui-unit:1.9.0 org.jetbrains.compose.ui:ui-util:1.9.0 org.jetbrains.compose.ui:ui:1.9.0 -org.jetbrains.kotlin:kotlin-bom:2.2.20 -org.jetbrains.kotlin:kotlin-parcelize-runtime:2.2.20 -org.jetbrains.kotlin:kotlin-stdlib-common:2.2.20 -org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.2.20 -org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.2.20 -org.jetbrains.kotlin:kotlin-stdlib:2.2.20 +org.jetbrains.kotlin:kotlin-bom:2.2.21 +org.jetbrains.kotlin:kotlin-parcelize-runtime:2.2.21 +org.jetbrains.kotlin:kotlin-stdlib-common:2.2.21 +org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.2.21 +org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.2.21 +org.jetbrains.kotlin:kotlin-stdlib:2.2.21 org.jetbrains.kotlinx:kotlinx-collections-immutable-jvm:0.4.0 org.jetbrains.kotlinx:kotlinx-collections-immutable:0.4.0 org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2 diff --git a/app-thunderbird/dependencies/fossReleaseRuntimeClasspath.txt b/app-thunderbird/dependencies/fossReleaseRuntimeClasspath.txt index 6f18d9b53d85c91d2492f0eaf5270eaa4b3c0e5e..c4067960d1fec0acd939225cbbb01417b30213d2 100644 --- a/app-thunderbird/dependencies/fossReleaseRuntimeClasspath.txt +++ b/app-thunderbird/dependencies/fossReleaseRuntimeClasspath.txt @@ -42,12 +42,12 @@ androidx.compose.material:material-icons-extended-android:1.7.8 androidx.compose.material:material-icons-extended:1.7.8 androidx.compose.material:material-ripple-android:1.8.3 androidx.compose.material:material-ripple:1.8.3 -androidx.compose.runtime:runtime-android:1.9.0 -androidx.compose.runtime:runtime-annotation-android:1.9.0 -androidx.compose.runtime:runtime-annotation:1.9.0 -androidx.compose.runtime:runtime-saveable-android:1.9.0 -androidx.compose.runtime:runtime-saveable:1.9.0 -androidx.compose.runtime:runtime:1.9.0 +androidx.compose.runtime:runtime-android:1.9.4 +androidx.compose.runtime:runtime-annotation-android:1.9.4 +androidx.compose.runtime:runtime-annotation:1.9.4 +androidx.compose.runtime:runtime-saveable-android:1.9.4 +androidx.compose.runtime:runtime-saveable:1.9.4 +androidx.compose.runtime:runtime:1.9.4 androidx.compose.ui:ui-android:1.9.0 androidx.compose.ui:ui-geometry-android:1.9.0 androidx.compose.ui:ui-geometry:1.9.0 @@ -68,11 +68,11 @@ androidx.concurrent:concurrent-futures:1.1.0 androidx.constraintlayout:constraintlayout-core:1.1.1 androidx.constraintlayout:constraintlayout:2.2.1 androidx.coordinatorlayout:coordinatorlayout:1.3.0 -androidx.core:core-ktx:1.16.0 +androidx.core:core-ktx:1.17.0 androidx.core:core-remoteviews:1.1.0 androidx.core:core-splashscreen:1.0.1 androidx.core:core-viewtree:1.0.0 -androidx.core:core:1.16.0 +androidx.core:core:1.17.0 androidx.cursoradapter:cursoradapter:1.0.0 androidx.customview:customview-poolingcontainer:1.0.0 androidx.customview:customview:1.1.0 @@ -105,28 +105,28 @@ androidx.glance:glance:1.1.1 androidx.graphics:graphics-path:1.0.1 androidx.interpolator:interpolator:1.0.0 androidx.legacy:legacy-support-core-utils:1.0.0 -androidx.lifecycle:lifecycle-common-java8:2.9.3 -androidx.lifecycle:lifecycle-common-jvm:2.9.3 -androidx.lifecycle:lifecycle-common:2.9.3 -androidx.lifecycle:lifecycle-livedata-core-ktx:2.9.3 -androidx.lifecycle:lifecycle-livedata-core:2.9.3 -androidx.lifecycle:lifecycle-livedata-ktx:2.9.3 -androidx.lifecycle:lifecycle-livedata:2.9.3 -androidx.lifecycle:lifecycle-process:2.9.3 -androidx.lifecycle:lifecycle-runtime-android:2.9.3 -androidx.lifecycle:lifecycle-runtime-compose-android:2.9.3 -androidx.lifecycle:lifecycle-runtime-compose:2.9.3 -androidx.lifecycle:lifecycle-runtime-ktx-android:2.9.3 -androidx.lifecycle:lifecycle-runtime-ktx:2.9.3 -androidx.lifecycle:lifecycle-runtime:2.9.3 -androidx.lifecycle:lifecycle-service:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-android:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-compose-android:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-compose:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-ktx:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-savedstate-android:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-savedstate:2.9.3 -androidx.lifecycle:lifecycle-viewmodel:2.9.3 +androidx.lifecycle:lifecycle-common-java8:2.9.4 +androidx.lifecycle:lifecycle-common-jvm:2.9.4 +androidx.lifecycle:lifecycle-common:2.9.4 +androidx.lifecycle:lifecycle-livedata-core-ktx:2.9.4 +androidx.lifecycle:lifecycle-livedata-core:2.9.4 +androidx.lifecycle:lifecycle-livedata-ktx:2.9.4 +androidx.lifecycle:lifecycle-livedata:2.9.4 +androidx.lifecycle:lifecycle-process:2.9.4 +androidx.lifecycle:lifecycle-runtime-android:2.9.4 +androidx.lifecycle:lifecycle-runtime-compose-android:2.9.4 +androidx.lifecycle:lifecycle-runtime-compose:2.9.4 +androidx.lifecycle:lifecycle-runtime-ktx-android:2.9.4 +androidx.lifecycle:lifecycle-runtime-ktx:2.9.4 +androidx.lifecycle:lifecycle-runtime:2.9.4 +androidx.lifecycle:lifecycle-service:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-android:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-compose-android:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-compose:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-ktx:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-savedstate-android:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-savedstate:2.9.4 +androidx.lifecycle:lifecycle-viewmodel:2.9.4 androidx.loader:loader:1.0.0 androidx.localbroadcastmanager:localbroadcastmanager:1.1.0 androidx.navigation:navigation-common-android:2.9.3 @@ -145,11 +145,11 @@ androidx.resourceinspection:resourceinspection-annotation:1.0.1 androidx.room:room-common:2.6.1 androidx.room:room-ktx:2.6.1 androidx.room:room-runtime:2.6.1 -androidx.savedstate:savedstate-android:1.3.1 -androidx.savedstate:savedstate-compose-android:1.3.1 -androidx.savedstate:savedstate-compose:1.3.1 -androidx.savedstate:savedstate-ktx:1.3.1 -androidx.savedstate:savedstate:1.3.1 +androidx.savedstate:savedstate-android:1.3.3 +androidx.savedstate:savedstate-compose-android:1.3.3 +androidx.savedstate:savedstate-compose:1.3.3 +androidx.savedstate:savedstate-ktx:1.3.3 +androidx.savedstate:savedstate:1.3.3 androidx.slidingpanelayout:slidingpanelayout:1.2.0 androidx.sqlite:sqlite-framework:2.4.0 androidx.sqlite:sqlite:2.4.0 @@ -177,15 +177,17 @@ co.touchlab:stately-concurrent-collections:2.1.0 co.touchlab:stately-strict-jvm:2.1.0 co.touchlab:stately-strict:2.1.0 com.beetstra.jutf7:jutf7:1.0.0 +com.eygraber:uri-kmp-android:0.0.21 +com.eygraber:uri-kmp:0.0.21 com.github.ByteHamster:SearchPreference:2.7.3 com.github.bumptech.glide:annotations:4.16.0 com.github.bumptech.glide:disklrucache:4.16.0 com.github.bumptech.glide:gifdecoder:4.16.0 com.github.bumptech.glide:glide:4.16.0 -com.github.skydoves:landscapist-android:2.5.1 -com.github.skydoves:landscapist-coil3-android:2.5.1 -com.github.skydoves:landscapist-coil3:2.5.1 -com.github.skydoves:landscapist:2.5.1 +com.github.skydoves:landscapist-android:2.6.1 +com.github.skydoves:landscapist-coil3-android:2.6.1 +com.github.skydoves:landscapist-coil3:2.6.1 +com.github.skydoves:landscapist:2.6.1 com.google.android.flexbox:flexbox:3.0.0 com.google.android.material:material:1.12.0 com.google.auto.value:auto-value-annotations:1.6.3 @@ -200,10 +202,10 @@ com.mikepenz:fastadapter-extensions-swipe:5.7.0 com.mikepenz:fastadapter-extensions-utils:5.7.0 com.mikepenz:fastadapter:5.7.0 com.squareup.moshi:moshi:1.15.2 -com.squareup.okhttp3:okhttp-android:5.1.0 -com.squareup.okhttp3:okhttp:5.1.0 -com.squareup.okio:okio-jvm:3.16.0 -com.squareup.okio:okio:3.16.0 +com.squareup.okhttp3:okhttp-android:5.2.1 +com.squareup.okhttp3:okhttp:5.2.1 +com.squareup.okio:okio-jvm:3.16.2 +com.squareup.okio:okio:3.16.2 com.takisoft.colorpicker:colorpicker:1.0.0 com.takisoft.datetimepicker:datetimepicker:1.0.2 com.takisoft.preferencex:preferencex-colorpicker:1.1.0 @@ -213,16 +215,16 @@ commons-io:commons-io:2.20.0 de.cketti.library.changelog:ckchangelog-core:2.0.0-beta02 de.cketti.safecontentresolver:safe-content-resolver-v21:1.0.0 de.hdodenhof:circleimageview:3.1.0 -io.coil-kt.coil3:coil-android:3.2.0 -io.coil-kt.coil3:coil-core-android:3.2.0 -io.coil-kt.coil3:coil-core:3.2.0 -io.coil-kt.coil3:coil-gif:3.2.0 -io.coil-kt.coil3:coil-network-core-android:3.2.0 -io.coil-kt.coil3:coil-network-core:3.2.0 -io.coil-kt.coil3:coil-network-okhttp-jvm:3.2.0 -io.coil-kt.coil3:coil-network-okhttp:3.2.0 -io.coil-kt.coil3:coil-video:3.2.0 -io.coil-kt.coil3:coil:3.2.0 +io.coil-kt.coil3:coil-android:3.3.0 +io.coil-kt.coil3:coil-core-android:3.3.0 +io.coil-kt.coil3:coil-core:3.3.0 +io.coil-kt.coil3:coil-gif:3.3.0 +io.coil-kt.coil3:coil-network-core-android:3.3.0 +io.coil-kt.coil3:coil-network-core:3.3.0 +io.coil-kt.coil3:coil-network-okhttp-jvm:3.3.0 +io.coil-kt.coil3:coil-network-okhttp:3.3.0 +io.coil-kt.coil3:coil-video:3.3.0 +io.coil-kt.coil3:coil:3.3.0 io.insert-koin:koin-android:4.1.1 io.insert-koin:koin-androidx-compose:4.1.1 io.insert-koin:koin-bom:4.1.1 @@ -243,14 +245,14 @@ org.apache.httpcomponents.core5:httpcore5-h2:5.3.6 org.apache.httpcomponents.core5:httpcore5:5.3.6 org.apache.james:apache-mime4j-core:0.8.13 org.apache.james:apache-mime4j-dom:0.8.13 -org.jetbrains.androidx.lifecycle:lifecycle-common:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-runtime:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.9.4 +org.jetbrains.androidx.lifecycle:lifecycle-common:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-runtime:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.9.6 org.jetbrains.androidx.savedstate:savedstate-compose:1.3.4 -org.jetbrains.androidx.savedstate:savedstate:1.3.4 +org.jetbrains.androidx.savedstate:savedstate:1.3.6 org.jetbrains.compose.animation:animation-core:1.9.0 org.jetbrains.compose.animation:animation:1.9.0 org.jetbrains.compose.annotation-internal:annotation:1.9.0 @@ -262,7 +264,7 @@ org.jetbrains.compose.components:components-ui-tooling-preview:1.9.0 org.jetbrains.compose.foundation:foundation-layout:1.9.0 org.jetbrains.compose.foundation:foundation:1.9.0 org.jetbrains.compose.runtime:runtime-saveable:1.9.0 -org.jetbrains.compose.runtime:runtime:1.9.0 +org.jetbrains.compose.runtime:runtime:1.9.3 org.jetbrains.compose.ui:ui-geometry:1.9.0 org.jetbrains.compose.ui:ui-graphics:1.9.0 org.jetbrains.compose.ui:ui-text:1.9.0 @@ -270,12 +272,12 @@ org.jetbrains.compose.ui:ui-tooling-preview:1.9.0 org.jetbrains.compose.ui:ui-unit:1.9.0 org.jetbrains.compose.ui:ui-util:1.9.0 org.jetbrains.compose.ui:ui:1.9.0 -org.jetbrains.kotlin:kotlin-bom:2.2.20 -org.jetbrains.kotlin:kotlin-parcelize-runtime:2.2.20 -org.jetbrains.kotlin:kotlin-stdlib-common:2.2.20 -org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.2.20 -org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.2.20 -org.jetbrains.kotlin:kotlin-stdlib:2.2.20 +org.jetbrains.kotlin:kotlin-bom:2.2.21 +org.jetbrains.kotlin:kotlin-parcelize-runtime:2.2.21 +org.jetbrains.kotlin:kotlin-stdlib-common:2.2.21 +org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.2.21 +org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.2.21 +org.jetbrains.kotlin:kotlin-stdlib:2.2.21 org.jetbrains.kotlinx:kotlinx-collections-immutable-jvm:0.4.0 org.jetbrains.kotlinx:kotlinx-collections-immutable:0.4.0 org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2 diff --git a/app-thunderbird/dependencies/fullBetaRuntimeClasspath.txt b/app-thunderbird/dependencies/fullBetaRuntimeClasspath.txt index d4540eedfc8fdcc29dbb8c2174278ce695d51d52..2a6a5724b904be1487cb4bcd76f86c5c1d5de4e3 100644 --- a/app-thunderbird/dependencies/fullBetaRuntimeClasspath.txt +++ b/app-thunderbird/dependencies/fullBetaRuntimeClasspath.txt @@ -42,12 +42,12 @@ androidx.compose.material:material-icons-extended-android:1.7.8 androidx.compose.material:material-icons-extended:1.7.8 androidx.compose.material:material-ripple-android:1.8.3 androidx.compose.material:material-ripple:1.8.3 -androidx.compose.runtime:runtime-android:1.9.0 -androidx.compose.runtime:runtime-annotation-android:1.9.0 -androidx.compose.runtime:runtime-annotation:1.9.0 -androidx.compose.runtime:runtime-saveable-android:1.9.0 -androidx.compose.runtime:runtime-saveable:1.9.0 -androidx.compose.runtime:runtime:1.9.0 +androidx.compose.runtime:runtime-android:1.9.4 +androidx.compose.runtime:runtime-annotation-android:1.9.4 +androidx.compose.runtime:runtime-annotation:1.9.4 +androidx.compose.runtime:runtime-saveable-android:1.9.4 +androidx.compose.runtime:runtime-saveable:1.9.4 +androidx.compose.runtime:runtime:1.9.4 androidx.compose.ui:ui-android:1.9.0 androidx.compose.ui:ui-geometry-android:1.9.0 androidx.compose.ui:ui-geometry:1.9.0 @@ -68,11 +68,11 @@ androidx.concurrent:concurrent-futures:1.1.0 androidx.constraintlayout:constraintlayout-core:1.1.1 androidx.constraintlayout:constraintlayout:2.2.1 androidx.coordinatorlayout:coordinatorlayout:1.3.0 -androidx.core:core-ktx:1.16.0 +androidx.core:core-ktx:1.17.0 androidx.core:core-remoteviews:1.1.0 androidx.core:core-splashscreen:1.0.1 androidx.core:core-viewtree:1.0.0 -androidx.core:core:1.16.0 +androidx.core:core:1.17.0 androidx.cursoradapter:cursoradapter:1.0.0 androidx.customview:customview-poolingcontainer:1.0.0 androidx.customview:customview:1.1.0 @@ -105,28 +105,28 @@ androidx.glance:glance:1.1.1 androidx.graphics:graphics-path:1.0.1 androidx.interpolator:interpolator:1.0.0 androidx.legacy:legacy-support-core-utils:1.0.0 -androidx.lifecycle:lifecycle-common-java8:2.9.3 -androidx.lifecycle:lifecycle-common-jvm:2.9.3 -androidx.lifecycle:lifecycle-common:2.9.3 -androidx.lifecycle:lifecycle-livedata-core-ktx:2.9.3 -androidx.lifecycle:lifecycle-livedata-core:2.9.3 -androidx.lifecycle:lifecycle-livedata-ktx:2.9.3 -androidx.lifecycle:lifecycle-livedata:2.9.3 -androidx.lifecycle:lifecycle-process:2.9.3 -androidx.lifecycle:lifecycle-runtime-android:2.9.3 -androidx.lifecycle:lifecycle-runtime-compose-android:2.9.3 -androidx.lifecycle:lifecycle-runtime-compose:2.9.3 -androidx.lifecycle:lifecycle-runtime-ktx-android:2.9.3 -androidx.lifecycle:lifecycle-runtime-ktx:2.9.3 -androidx.lifecycle:lifecycle-runtime:2.9.3 -androidx.lifecycle:lifecycle-service:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-android:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-compose-android:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-compose:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-ktx:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-savedstate-android:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-savedstate:2.9.3 -androidx.lifecycle:lifecycle-viewmodel:2.9.3 +androidx.lifecycle:lifecycle-common-java8:2.9.4 +androidx.lifecycle:lifecycle-common-jvm:2.9.4 +androidx.lifecycle:lifecycle-common:2.9.4 +androidx.lifecycle:lifecycle-livedata-core-ktx:2.9.4 +androidx.lifecycle:lifecycle-livedata-core:2.9.4 +androidx.lifecycle:lifecycle-livedata-ktx:2.9.4 +androidx.lifecycle:lifecycle-livedata:2.9.4 +androidx.lifecycle:lifecycle-process:2.9.4 +androidx.lifecycle:lifecycle-runtime-android:2.9.4 +androidx.lifecycle:lifecycle-runtime-compose-android:2.9.4 +androidx.lifecycle:lifecycle-runtime-compose:2.9.4 +androidx.lifecycle:lifecycle-runtime-ktx-android:2.9.4 +androidx.lifecycle:lifecycle-runtime-ktx:2.9.4 +androidx.lifecycle:lifecycle-runtime:2.9.4 +androidx.lifecycle:lifecycle-service:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-android:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-compose-android:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-compose:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-ktx:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-savedstate-android:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-savedstate:2.9.4 +androidx.lifecycle:lifecycle-viewmodel:2.9.4 androidx.loader:loader:1.0.0 androidx.localbroadcastmanager:localbroadcastmanager:1.1.0 androidx.navigation:navigation-common-android:2.9.3 @@ -145,11 +145,11 @@ androidx.resourceinspection:resourceinspection-annotation:1.0.1 androidx.room:room-common:2.6.1 androidx.room:room-ktx:2.6.1 androidx.room:room-runtime:2.6.1 -androidx.savedstate:savedstate-android:1.3.1 -androidx.savedstate:savedstate-compose-android:1.3.1 -androidx.savedstate:savedstate-compose:1.3.1 -androidx.savedstate:savedstate-ktx:1.3.1 -androidx.savedstate:savedstate:1.3.1 +androidx.savedstate:savedstate-android:1.3.3 +androidx.savedstate:savedstate-compose-android:1.3.3 +androidx.savedstate:savedstate-compose:1.3.3 +androidx.savedstate:savedstate-ktx:1.3.3 +androidx.savedstate:savedstate:1.3.3 androidx.slidingpanelayout:slidingpanelayout:1.2.0 androidx.sqlite:sqlite-framework:2.4.0 androidx.sqlite:sqlite:2.4.0 @@ -179,15 +179,17 @@ co.touchlab:stately-strict:2.1.0 com.android.billingclient:billing-ktx:7.1.1 com.android.billingclient:billing:7.1.1 com.beetstra.jutf7:jutf7:1.0.0 +com.eygraber:uri-kmp-android:0.0.21 +com.eygraber:uri-kmp:0.0.21 com.github.ByteHamster:SearchPreference:2.7.3 com.github.bumptech.glide:annotations:4.16.0 com.github.bumptech.glide:disklrucache:4.16.0 com.github.bumptech.glide:gifdecoder:4.16.0 com.github.bumptech.glide:glide:4.16.0 -com.github.skydoves:landscapist-android:2.5.1 -com.github.skydoves:landscapist-coil3-android:2.5.1 -com.github.skydoves:landscapist-coil3:2.5.1 -com.github.skydoves:landscapist:2.5.1 +com.github.skydoves:landscapist-android:2.6.1 +com.github.skydoves:landscapist-coil3-android:2.6.1 +com.github.skydoves:landscapist-coil3:2.6.1 +com.github.skydoves:landscapist:2.6.1 com.google.android.datatransport:transport-api:3.0.0 com.google.android.datatransport:transport-backend-cct:3.1.8 com.google.android.datatransport:transport-runtime:3.1.8 @@ -213,10 +215,10 @@ com.mikepenz:fastadapter-extensions-swipe:5.7.0 com.mikepenz:fastadapter-extensions-utils:5.7.0 com.mikepenz:fastadapter:5.7.0 com.squareup.moshi:moshi:1.15.2 -com.squareup.okhttp3:okhttp-android:5.1.0 -com.squareup.okhttp3:okhttp:5.1.0 -com.squareup.okio:okio-jvm:3.16.0 -com.squareup.okio:okio:3.16.0 +com.squareup.okhttp3:okhttp-android:5.2.1 +com.squareup.okhttp3:okhttp:5.2.1 +com.squareup.okio:okio-jvm:3.16.2 +com.squareup.okio:okio:3.16.2 com.takisoft.colorpicker:colorpicker:1.0.0 com.takisoft.datetimepicker:datetimepicker:1.0.2 com.takisoft.preferencex:preferencex-colorpicker:1.1.0 @@ -226,16 +228,16 @@ commons-io:commons-io:2.20.0 de.cketti.library.changelog:ckchangelog-core:2.0.0-beta02 de.cketti.safecontentresolver:safe-content-resolver-v21:1.0.0 de.hdodenhof:circleimageview:3.1.0 -io.coil-kt.coil3:coil-android:3.2.0 -io.coil-kt.coil3:coil-core-android:3.2.0 -io.coil-kt.coil3:coil-core:3.2.0 -io.coil-kt.coil3:coil-gif:3.2.0 -io.coil-kt.coil3:coil-network-core-android:3.2.0 -io.coil-kt.coil3:coil-network-core:3.2.0 -io.coil-kt.coil3:coil-network-okhttp-jvm:3.2.0 -io.coil-kt.coil3:coil-network-okhttp:3.2.0 -io.coil-kt.coil3:coil-video:3.2.0 -io.coil-kt.coil3:coil:3.2.0 +io.coil-kt.coil3:coil-android:3.3.0 +io.coil-kt.coil3:coil-core-android:3.3.0 +io.coil-kt.coil3:coil-core:3.3.0 +io.coil-kt.coil3:coil-gif:3.3.0 +io.coil-kt.coil3:coil-network-core-android:3.3.0 +io.coil-kt.coil3:coil-network-core:3.3.0 +io.coil-kt.coil3:coil-network-okhttp-jvm:3.3.0 +io.coil-kt.coil3:coil-network-okhttp:3.3.0 +io.coil-kt.coil3:coil-video:3.3.0 +io.coil-kt.coil3:coil:3.3.0 io.insert-koin:koin-android:4.1.1 io.insert-koin:koin-androidx-compose:4.1.1 io.insert-koin:koin-bom:4.1.1 @@ -257,14 +259,14 @@ org.apache.httpcomponents.core5:httpcore5-h2:5.3.6 org.apache.httpcomponents.core5:httpcore5:5.3.6 org.apache.james:apache-mime4j-core:0.8.13 org.apache.james:apache-mime4j-dom:0.8.13 -org.jetbrains.androidx.lifecycle:lifecycle-common:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-runtime:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.9.4 +org.jetbrains.androidx.lifecycle:lifecycle-common:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-runtime:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.9.6 org.jetbrains.androidx.savedstate:savedstate-compose:1.3.4 -org.jetbrains.androidx.savedstate:savedstate:1.3.4 +org.jetbrains.androidx.savedstate:savedstate:1.3.6 org.jetbrains.compose.animation:animation-core:1.9.0 org.jetbrains.compose.animation:animation:1.9.0 org.jetbrains.compose.annotation-internal:annotation:1.9.0 @@ -276,7 +278,7 @@ org.jetbrains.compose.components:components-ui-tooling-preview:1.9.0 org.jetbrains.compose.foundation:foundation-layout:1.9.0 org.jetbrains.compose.foundation:foundation:1.9.0 org.jetbrains.compose.runtime:runtime-saveable:1.9.0 -org.jetbrains.compose.runtime:runtime:1.9.0 +org.jetbrains.compose.runtime:runtime:1.9.3 org.jetbrains.compose.ui:ui-geometry:1.9.0 org.jetbrains.compose.ui:ui-graphics:1.9.0 org.jetbrains.compose.ui:ui-text:1.9.0 @@ -284,12 +286,12 @@ org.jetbrains.compose.ui:ui-tooling-preview:1.9.0 org.jetbrains.compose.ui:ui-unit:1.9.0 org.jetbrains.compose.ui:ui-util:1.9.0 org.jetbrains.compose.ui:ui:1.9.0 -org.jetbrains.kotlin:kotlin-bom:2.2.20 -org.jetbrains.kotlin:kotlin-parcelize-runtime:2.2.20 -org.jetbrains.kotlin:kotlin-stdlib-common:2.2.20 -org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.2.20 -org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.2.20 -org.jetbrains.kotlin:kotlin-stdlib:2.2.20 +org.jetbrains.kotlin:kotlin-bom:2.2.21 +org.jetbrains.kotlin:kotlin-parcelize-runtime:2.2.21 +org.jetbrains.kotlin:kotlin-stdlib-common:2.2.21 +org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.2.21 +org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.2.21 +org.jetbrains.kotlin:kotlin-stdlib:2.2.21 org.jetbrains.kotlinx:kotlinx-collections-immutable-jvm:0.4.0 org.jetbrains.kotlinx:kotlinx-collections-immutable:0.4.0 org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2 diff --git a/app-thunderbird/dependencies/fullDailyRuntimeClasspath.txt b/app-thunderbird/dependencies/fullDailyRuntimeClasspath.txt index d4540eedfc8fdcc29dbb8c2174278ce695d51d52..2a6a5724b904be1487cb4bcd76f86c5c1d5de4e3 100644 --- a/app-thunderbird/dependencies/fullDailyRuntimeClasspath.txt +++ b/app-thunderbird/dependencies/fullDailyRuntimeClasspath.txt @@ -42,12 +42,12 @@ androidx.compose.material:material-icons-extended-android:1.7.8 androidx.compose.material:material-icons-extended:1.7.8 androidx.compose.material:material-ripple-android:1.8.3 androidx.compose.material:material-ripple:1.8.3 -androidx.compose.runtime:runtime-android:1.9.0 -androidx.compose.runtime:runtime-annotation-android:1.9.0 -androidx.compose.runtime:runtime-annotation:1.9.0 -androidx.compose.runtime:runtime-saveable-android:1.9.0 -androidx.compose.runtime:runtime-saveable:1.9.0 -androidx.compose.runtime:runtime:1.9.0 +androidx.compose.runtime:runtime-android:1.9.4 +androidx.compose.runtime:runtime-annotation-android:1.9.4 +androidx.compose.runtime:runtime-annotation:1.9.4 +androidx.compose.runtime:runtime-saveable-android:1.9.4 +androidx.compose.runtime:runtime-saveable:1.9.4 +androidx.compose.runtime:runtime:1.9.4 androidx.compose.ui:ui-android:1.9.0 androidx.compose.ui:ui-geometry-android:1.9.0 androidx.compose.ui:ui-geometry:1.9.0 @@ -68,11 +68,11 @@ androidx.concurrent:concurrent-futures:1.1.0 androidx.constraintlayout:constraintlayout-core:1.1.1 androidx.constraintlayout:constraintlayout:2.2.1 androidx.coordinatorlayout:coordinatorlayout:1.3.0 -androidx.core:core-ktx:1.16.0 +androidx.core:core-ktx:1.17.0 androidx.core:core-remoteviews:1.1.0 androidx.core:core-splashscreen:1.0.1 androidx.core:core-viewtree:1.0.0 -androidx.core:core:1.16.0 +androidx.core:core:1.17.0 androidx.cursoradapter:cursoradapter:1.0.0 androidx.customview:customview-poolingcontainer:1.0.0 androidx.customview:customview:1.1.0 @@ -105,28 +105,28 @@ androidx.glance:glance:1.1.1 androidx.graphics:graphics-path:1.0.1 androidx.interpolator:interpolator:1.0.0 androidx.legacy:legacy-support-core-utils:1.0.0 -androidx.lifecycle:lifecycle-common-java8:2.9.3 -androidx.lifecycle:lifecycle-common-jvm:2.9.3 -androidx.lifecycle:lifecycle-common:2.9.3 -androidx.lifecycle:lifecycle-livedata-core-ktx:2.9.3 -androidx.lifecycle:lifecycle-livedata-core:2.9.3 -androidx.lifecycle:lifecycle-livedata-ktx:2.9.3 -androidx.lifecycle:lifecycle-livedata:2.9.3 -androidx.lifecycle:lifecycle-process:2.9.3 -androidx.lifecycle:lifecycle-runtime-android:2.9.3 -androidx.lifecycle:lifecycle-runtime-compose-android:2.9.3 -androidx.lifecycle:lifecycle-runtime-compose:2.9.3 -androidx.lifecycle:lifecycle-runtime-ktx-android:2.9.3 -androidx.lifecycle:lifecycle-runtime-ktx:2.9.3 -androidx.lifecycle:lifecycle-runtime:2.9.3 -androidx.lifecycle:lifecycle-service:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-android:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-compose-android:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-compose:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-ktx:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-savedstate-android:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-savedstate:2.9.3 -androidx.lifecycle:lifecycle-viewmodel:2.9.3 +androidx.lifecycle:lifecycle-common-java8:2.9.4 +androidx.lifecycle:lifecycle-common-jvm:2.9.4 +androidx.lifecycle:lifecycle-common:2.9.4 +androidx.lifecycle:lifecycle-livedata-core-ktx:2.9.4 +androidx.lifecycle:lifecycle-livedata-core:2.9.4 +androidx.lifecycle:lifecycle-livedata-ktx:2.9.4 +androidx.lifecycle:lifecycle-livedata:2.9.4 +androidx.lifecycle:lifecycle-process:2.9.4 +androidx.lifecycle:lifecycle-runtime-android:2.9.4 +androidx.lifecycle:lifecycle-runtime-compose-android:2.9.4 +androidx.lifecycle:lifecycle-runtime-compose:2.9.4 +androidx.lifecycle:lifecycle-runtime-ktx-android:2.9.4 +androidx.lifecycle:lifecycle-runtime-ktx:2.9.4 +androidx.lifecycle:lifecycle-runtime:2.9.4 +androidx.lifecycle:lifecycle-service:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-android:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-compose-android:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-compose:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-ktx:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-savedstate-android:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-savedstate:2.9.4 +androidx.lifecycle:lifecycle-viewmodel:2.9.4 androidx.loader:loader:1.0.0 androidx.localbroadcastmanager:localbroadcastmanager:1.1.0 androidx.navigation:navigation-common-android:2.9.3 @@ -145,11 +145,11 @@ androidx.resourceinspection:resourceinspection-annotation:1.0.1 androidx.room:room-common:2.6.1 androidx.room:room-ktx:2.6.1 androidx.room:room-runtime:2.6.1 -androidx.savedstate:savedstate-android:1.3.1 -androidx.savedstate:savedstate-compose-android:1.3.1 -androidx.savedstate:savedstate-compose:1.3.1 -androidx.savedstate:savedstate-ktx:1.3.1 -androidx.savedstate:savedstate:1.3.1 +androidx.savedstate:savedstate-android:1.3.3 +androidx.savedstate:savedstate-compose-android:1.3.3 +androidx.savedstate:savedstate-compose:1.3.3 +androidx.savedstate:savedstate-ktx:1.3.3 +androidx.savedstate:savedstate:1.3.3 androidx.slidingpanelayout:slidingpanelayout:1.2.0 androidx.sqlite:sqlite-framework:2.4.0 androidx.sqlite:sqlite:2.4.0 @@ -179,15 +179,17 @@ co.touchlab:stately-strict:2.1.0 com.android.billingclient:billing-ktx:7.1.1 com.android.billingclient:billing:7.1.1 com.beetstra.jutf7:jutf7:1.0.0 +com.eygraber:uri-kmp-android:0.0.21 +com.eygraber:uri-kmp:0.0.21 com.github.ByteHamster:SearchPreference:2.7.3 com.github.bumptech.glide:annotations:4.16.0 com.github.bumptech.glide:disklrucache:4.16.0 com.github.bumptech.glide:gifdecoder:4.16.0 com.github.bumptech.glide:glide:4.16.0 -com.github.skydoves:landscapist-android:2.5.1 -com.github.skydoves:landscapist-coil3-android:2.5.1 -com.github.skydoves:landscapist-coil3:2.5.1 -com.github.skydoves:landscapist:2.5.1 +com.github.skydoves:landscapist-android:2.6.1 +com.github.skydoves:landscapist-coil3-android:2.6.1 +com.github.skydoves:landscapist-coil3:2.6.1 +com.github.skydoves:landscapist:2.6.1 com.google.android.datatransport:transport-api:3.0.0 com.google.android.datatransport:transport-backend-cct:3.1.8 com.google.android.datatransport:transport-runtime:3.1.8 @@ -213,10 +215,10 @@ com.mikepenz:fastadapter-extensions-swipe:5.7.0 com.mikepenz:fastadapter-extensions-utils:5.7.0 com.mikepenz:fastadapter:5.7.0 com.squareup.moshi:moshi:1.15.2 -com.squareup.okhttp3:okhttp-android:5.1.0 -com.squareup.okhttp3:okhttp:5.1.0 -com.squareup.okio:okio-jvm:3.16.0 -com.squareup.okio:okio:3.16.0 +com.squareup.okhttp3:okhttp-android:5.2.1 +com.squareup.okhttp3:okhttp:5.2.1 +com.squareup.okio:okio-jvm:3.16.2 +com.squareup.okio:okio:3.16.2 com.takisoft.colorpicker:colorpicker:1.0.0 com.takisoft.datetimepicker:datetimepicker:1.0.2 com.takisoft.preferencex:preferencex-colorpicker:1.1.0 @@ -226,16 +228,16 @@ commons-io:commons-io:2.20.0 de.cketti.library.changelog:ckchangelog-core:2.0.0-beta02 de.cketti.safecontentresolver:safe-content-resolver-v21:1.0.0 de.hdodenhof:circleimageview:3.1.0 -io.coil-kt.coil3:coil-android:3.2.0 -io.coil-kt.coil3:coil-core-android:3.2.0 -io.coil-kt.coil3:coil-core:3.2.0 -io.coil-kt.coil3:coil-gif:3.2.0 -io.coil-kt.coil3:coil-network-core-android:3.2.0 -io.coil-kt.coil3:coil-network-core:3.2.0 -io.coil-kt.coil3:coil-network-okhttp-jvm:3.2.0 -io.coil-kt.coil3:coil-network-okhttp:3.2.0 -io.coil-kt.coil3:coil-video:3.2.0 -io.coil-kt.coil3:coil:3.2.0 +io.coil-kt.coil3:coil-android:3.3.0 +io.coil-kt.coil3:coil-core-android:3.3.0 +io.coil-kt.coil3:coil-core:3.3.0 +io.coil-kt.coil3:coil-gif:3.3.0 +io.coil-kt.coil3:coil-network-core-android:3.3.0 +io.coil-kt.coil3:coil-network-core:3.3.0 +io.coil-kt.coil3:coil-network-okhttp-jvm:3.3.0 +io.coil-kt.coil3:coil-network-okhttp:3.3.0 +io.coil-kt.coil3:coil-video:3.3.0 +io.coil-kt.coil3:coil:3.3.0 io.insert-koin:koin-android:4.1.1 io.insert-koin:koin-androidx-compose:4.1.1 io.insert-koin:koin-bom:4.1.1 @@ -257,14 +259,14 @@ org.apache.httpcomponents.core5:httpcore5-h2:5.3.6 org.apache.httpcomponents.core5:httpcore5:5.3.6 org.apache.james:apache-mime4j-core:0.8.13 org.apache.james:apache-mime4j-dom:0.8.13 -org.jetbrains.androidx.lifecycle:lifecycle-common:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-runtime:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.9.4 +org.jetbrains.androidx.lifecycle:lifecycle-common:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-runtime:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.9.6 org.jetbrains.androidx.savedstate:savedstate-compose:1.3.4 -org.jetbrains.androidx.savedstate:savedstate:1.3.4 +org.jetbrains.androidx.savedstate:savedstate:1.3.6 org.jetbrains.compose.animation:animation-core:1.9.0 org.jetbrains.compose.animation:animation:1.9.0 org.jetbrains.compose.annotation-internal:annotation:1.9.0 @@ -276,7 +278,7 @@ org.jetbrains.compose.components:components-ui-tooling-preview:1.9.0 org.jetbrains.compose.foundation:foundation-layout:1.9.0 org.jetbrains.compose.foundation:foundation:1.9.0 org.jetbrains.compose.runtime:runtime-saveable:1.9.0 -org.jetbrains.compose.runtime:runtime:1.9.0 +org.jetbrains.compose.runtime:runtime:1.9.3 org.jetbrains.compose.ui:ui-geometry:1.9.0 org.jetbrains.compose.ui:ui-graphics:1.9.0 org.jetbrains.compose.ui:ui-text:1.9.0 @@ -284,12 +286,12 @@ org.jetbrains.compose.ui:ui-tooling-preview:1.9.0 org.jetbrains.compose.ui:ui-unit:1.9.0 org.jetbrains.compose.ui:ui-util:1.9.0 org.jetbrains.compose.ui:ui:1.9.0 -org.jetbrains.kotlin:kotlin-bom:2.2.20 -org.jetbrains.kotlin:kotlin-parcelize-runtime:2.2.20 -org.jetbrains.kotlin:kotlin-stdlib-common:2.2.20 -org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.2.20 -org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.2.20 -org.jetbrains.kotlin:kotlin-stdlib:2.2.20 +org.jetbrains.kotlin:kotlin-bom:2.2.21 +org.jetbrains.kotlin:kotlin-parcelize-runtime:2.2.21 +org.jetbrains.kotlin:kotlin-stdlib-common:2.2.21 +org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.2.21 +org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.2.21 +org.jetbrains.kotlin:kotlin-stdlib:2.2.21 org.jetbrains.kotlinx:kotlinx-collections-immutable-jvm:0.4.0 org.jetbrains.kotlinx:kotlinx-collections-immutable:0.4.0 org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2 diff --git a/app-thunderbird/dependencies/fullReleaseRuntimeClasspath.txt b/app-thunderbird/dependencies/fullReleaseRuntimeClasspath.txt index d4540eedfc8fdcc29dbb8c2174278ce695d51d52..2a6a5724b904be1487cb4bcd76f86c5c1d5de4e3 100644 --- a/app-thunderbird/dependencies/fullReleaseRuntimeClasspath.txt +++ b/app-thunderbird/dependencies/fullReleaseRuntimeClasspath.txt @@ -42,12 +42,12 @@ androidx.compose.material:material-icons-extended-android:1.7.8 androidx.compose.material:material-icons-extended:1.7.8 androidx.compose.material:material-ripple-android:1.8.3 androidx.compose.material:material-ripple:1.8.3 -androidx.compose.runtime:runtime-android:1.9.0 -androidx.compose.runtime:runtime-annotation-android:1.9.0 -androidx.compose.runtime:runtime-annotation:1.9.0 -androidx.compose.runtime:runtime-saveable-android:1.9.0 -androidx.compose.runtime:runtime-saveable:1.9.0 -androidx.compose.runtime:runtime:1.9.0 +androidx.compose.runtime:runtime-android:1.9.4 +androidx.compose.runtime:runtime-annotation-android:1.9.4 +androidx.compose.runtime:runtime-annotation:1.9.4 +androidx.compose.runtime:runtime-saveable-android:1.9.4 +androidx.compose.runtime:runtime-saveable:1.9.4 +androidx.compose.runtime:runtime:1.9.4 androidx.compose.ui:ui-android:1.9.0 androidx.compose.ui:ui-geometry-android:1.9.0 androidx.compose.ui:ui-geometry:1.9.0 @@ -68,11 +68,11 @@ androidx.concurrent:concurrent-futures:1.1.0 androidx.constraintlayout:constraintlayout-core:1.1.1 androidx.constraintlayout:constraintlayout:2.2.1 androidx.coordinatorlayout:coordinatorlayout:1.3.0 -androidx.core:core-ktx:1.16.0 +androidx.core:core-ktx:1.17.0 androidx.core:core-remoteviews:1.1.0 androidx.core:core-splashscreen:1.0.1 androidx.core:core-viewtree:1.0.0 -androidx.core:core:1.16.0 +androidx.core:core:1.17.0 androidx.cursoradapter:cursoradapter:1.0.0 androidx.customview:customview-poolingcontainer:1.0.0 androidx.customview:customview:1.1.0 @@ -105,28 +105,28 @@ androidx.glance:glance:1.1.1 androidx.graphics:graphics-path:1.0.1 androidx.interpolator:interpolator:1.0.0 androidx.legacy:legacy-support-core-utils:1.0.0 -androidx.lifecycle:lifecycle-common-java8:2.9.3 -androidx.lifecycle:lifecycle-common-jvm:2.9.3 -androidx.lifecycle:lifecycle-common:2.9.3 -androidx.lifecycle:lifecycle-livedata-core-ktx:2.9.3 -androidx.lifecycle:lifecycle-livedata-core:2.9.3 -androidx.lifecycle:lifecycle-livedata-ktx:2.9.3 -androidx.lifecycle:lifecycle-livedata:2.9.3 -androidx.lifecycle:lifecycle-process:2.9.3 -androidx.lifecycle:lifecycle-runtime-android:2.9.3 -androidx.lifecycle:lifecycle-runtime-compose-android:2.9.3 -androidx.lifecycle:lifecycle-runtime-compose:2.9.3 -androidx.lifecycle:lifecycle-runtime-ktx-android:2.9.3 -androidx.lifecycle:lifecycle-runtime-ktx:2.9.3 -androidx.lifecycle:lifecycle-runtime:2.9.3 -androidx.lifecycle:lifecycle-service:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-android:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-compose-android:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-compose:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-ktx:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-savedstate-android:2.9.3 -androidx.lifecycle:lifecycle-viewmodel-savedstate:2.9.3 -androidx.lifecycle:lifecycle-viewmodel:2.9.3 +androidx.lifecycle:lifecycle-common-java8:2.9.4 +androidx.lifecycle:lifecycle-common-jvm:2.9.4 +androidx.lifecycle:lifecycle-common:2.9.4 +androidx.lifecycle:lifecycle-livedata-core-ktx:2.9.4 +androidx.lifecycle:lifecycle-livedata-core:2.9.4 +androidx.lifecycle:lifecycle-livedata-ktx:2.9.4 +androidx.lifecycle:lifecycle-livedata:2.9.4 +androidx.lifecycle:lifecycle-process:2.9.4 +androidx.lifecycle:lifecycle-runtime-android:2.9.4 +androidx.lifecycle:lifecycle-runtime-compose-android:2.9.4 +androidx.lifecycle:lifecycle-runtime-compose:2.9.4 +androidx.lifecycle:lifecycle-runtime-ktx-android:2.9.4 +androidx.lifecycle:lifecycle-runtime-ktx:2.9.4 +androidx.lifecycle:lifecycle-runtime:2.9.4 +androidx.lifecycle:lifecycle-service:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-android:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-compose-android:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-compose:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-ktx:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-savedstate-android:2.9.4 +androidx.lifecycle:lifecycle-viewmodel-savedstate:2.9.4 +androidx.lifecycle:lifecycle-viewmodel:2.9.4 androidx.loader:loader:1.0.0 androidx.localbroadcastmanager:localbroadcastmanager:1.1.0 androidx.navigation:navigation-common-android:2.9.3 @@ -145,11 +145,11 @@ androidx.resourceinspection:resourceinspection-annotation:1.0.1 androidx.room:room-common:2.6.1 androidx.room:room-ktx:2.6.1 androidx.room:room-runtime:2.6.1 -androidx.savedstate:savedstate-android:1.3.1 -androidx.savedstate:savedstate-compose-android:1.3.1 -androidx.savedstate:savedstate-compose:1.3.1 -androidx.savedstate:savedstate-ktx:1.3.1 -androidx.savedstate:savedstate:1.3.1 +androidx.savedstate:savedstate-android:1.3.3 +androidx.savedstate:savedstate-compose-android:1.3.3 +androidx.savedstate:savedstate-compose:1.3.3 +androidx.savedstate:savedstate-ktx:1.3.3 +androidx.savedstate:savedstate:1.3.3 androidx.slidingpanelayout:slidingpanelayout:1.2.0 androidx.sqlite:sqlite-framework:2.4.0 androidx.sqlite:sqlite:2.4.0 @@ -179,15 +179,17 @@ co.touchlab:stately-strict:2.1.0 com.android.billingclient:billing-ktx:7.1.1 com.android.billingclient:billing:7.1.1 com.beetstra.jutf7:jutf7:1.0.0 +com.eygraber:uri-kmp-android:0.0.21 +com.eygraber:uri-kmp:0.0.21 com.github.ByteHamster:SearchPreference:2.7.3 com.github.bumptech.glide:annotations:4.16.0 com.github.bumptech.glide:disklrucache:4.16.0 com.github.bumptech.glide:gifdecoder:4.16.0 com.github.bumptech.glide:glide:4.16.0 -com.github.skydoves:landscapist-android:2.5.1 -com.github.skydoves:landscapist-coil3-android:2.5.1 -com.github.skydoves:landscapist-coil3:2.5.1 -com.github.skydoves:landscapist:2.5.1 +com.github.skydoves:landscapist-android:2.6.1 +com.github.skydoves:landscapist-coil3-android:2.6.1 +com.github.skydoves:landscapist-coil3:2.6.1 +com.github.skydoves:landscapist:2.6.1 com.google.android.datatransport:transport-api:3.0.0 com.google.android.datatransport:transport-backend-cct:3.1.8 com.google.android.datatransport:transport-runtime:3.1.8 @@ -213,10 +215,10 @@ com.mikepenz:fastadapter-extensions-swipe:5.7.0 com.mikepenz:fastadapter-extensions-utils:5.7.0 com.mikepenz:fastadapter:5.7.0 com.squareup.moshi:moshi:1.15.2 -com.squareup.okhttp3:okhttp-android:5.1.0 -com.squareup.okhttp3:okhttp:5.1.0 -com.squareup.okio:okio-jvm:3.16.0 -com.squareup.okio:okio:3.16.0 +com.squareup.okhttp3:okhttp-android:5.2.1 +com.squareup.okhttp3:okhttp:5.2.1 +com.squareup.okio:okio-jvm:3.16.2 +com.squareup.okio:okio:3.16.2 com.takisoft.colorpicker:colorpicker:1.0.0 com.takisoft.datetimepicker:datetimepicker:1.0.2 com.takisoft.preferencex:preferencex-colorpicker:1.1.0 @@ -226,16 +228,16 @@ commons-io:commons-io:2.20.0 de.cketti.library.changelog:ckchangelog-core:2.0.0-beta02 de.cketti.safecontentresolver:safe-content-resolver-v21:1.0.0 de.hdodenhof:circleimageview:3.1.0 -io.coil-kt.coil3:coil-android:3.2.0 -io.coil-kt.coil3:coil-core-android:3.2.0 -io.coil-kt.coil3:coil-core:3.2.0 -io.coil-kt.coil3:coil-gif:3.2.0 -io.coil-kt.coil3:coil-network-core-android:3.2.0 -io.coil-kt.coil3:coil-network-core:3.2.0 -io.coil-kt.coil3:coil-network-okhttp-jvm:3.2.0 -io.coil-kt.coil3:coil-network-okhttp:3.2.0 -io.coil-kt.coil3:coil-video:3.2.0 -io.coil-kt.coil3:coil:3.2.0 +io.coil-kt.coil3:coil-android:3.3.0 +io.coil-kt.coil3:coil-core-android:3.3.0 +io.coil-kt.coil3:coil-core:3.3.0 +io.coil-kt.coil3:coil-gif:3.3.0 +io.coil-kt.coil3:coil-network-core-android:3.3.0 +io.coil-kt.coil3:coil-network-core:3.3.0 +io.coil-kt.coil3:coil-network-okhttp-jvm:3.3.0 +io.coil-kt.coil3:coil-network-okhttp:3.3.0 +io.coil-kt.coil3:coil-video:3.3.0 +io.coil-kt.coil3:coil:3.3.0 io.insert-koin:koin-android:4.1.1 io.insert-koin:koin-androidx-compose:4.1.1 io.insert-koin:koin-bom:4.1.1 @@ -257,14 +259,14 @@ org.apache.httpcomponents.core5:httpcore5-h2:5.3.6 org.apache.httpcomponents.core5:httpcore5:5.3.6 org.apache.james:apache-mime4j-core:0.8.13 org.apache.james:apache-mime4j-dom:0.8.13 -org.jetbrains.androidx.lifecycle:lifecycle-common:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-runtime:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.9.4 -org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.9.4 +org.jetbrains.androidx.lifecycle:lifecycle-common:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-runtime:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.9.6 +org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.9.6 org.jetbrains.androidx.savedstate:savedstate-compose:1.3.4 -org.jetbrains.androidx.savedstate:savedstate:1.3.4 +org.jetbrains.androidx.savedstate:savedstate:1.3.6 org.jetbrains.compose.animation:animation-core:1.9.0 org.jetbrains.compose.animation:animation:1.9.0 org.jetbrains.compose.annotation-internal:annotation:1.9.0 @@ -276,7 +278,7 @@ org.jetbrains.compose.components:components-ui-tooling-preview:1.9.0 org.jetbrains.compose.foundation:foundation-layout:1.9.0 org.jetbrains.compose.foundation:foundation:1.9.0 org.jetbrains.compose.runtime:runtime-saveable:1.9.0 -org.jetbrains.compose.runtime:runtime:1.9.0 +org.jetbrains.compose.runtime:runtime:1.9.3 org.jetbrains.compose.ui:ui-geometry:1.9.0 org.jetbrains.compose.ui:ui-graphics:1.9.0 org.jetbrains.compose.ui:ui-text:1.9.0 @@ -284,12 +286,12 @@ org.jetbrains.compose.ui:ui-tooling-preview:1.9.0 org.jetbrains.compose.ui:ui-unit:1.9.0 org.jetbrains.compose.ui:ui-util:1.9.0 org.jetbrains.compose.ui:ui:1.9.0 -org.jetbrains.kotlin:kotlin-bom:2.2.20 -org.jetbrains.kotlin:kotlin-parcelize-runtime:2.2.20 -org.jetbrains.kotlin:kotlin-stdlib-common:2.2.20 -org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.2.20 -org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.2.20 -org.jetbrains.kotlin:kotlin-stdlib:2.2.20 +org.jetbrains.kotlin:kotlin-bom:2.2.21 +org.jetbrains.kotlin:kotlin-parcelize-runtime:2.2.21 +org.jetbrains.kotlin:kotlin-stdlib-common:2.2.21 +org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.2.21 +org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.2.21 +org.jetbrains.kotlin:kotlin-stdlib:2.2.21 org.jetbrains.kotlinx:kotlinx-collections-immutable-jvm:0.4.0 org.jetbrains.kotlinx:kotlinx-collections-immutable:0.4.0 org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2 diff --git a/app-thunderbird/src/beta/kotlin/net/thunderbird/android/featureflag/TbFeatureFlagFactory.kt b/app-thunderbird/src/beta/kotlin/net/thunderbird/android/featureflag/TbFeatureFlagFactory.kt index 6fce270d82e4a66119a8dbb57f086fe16a396572..a1852ca5a9d8c3a2dd15e5e3566780c395429cdf 100644 --- a/app-thunderbird/src/beta/kotlin/net/thunderbird/android/featureflag/TbFeatureFlagFactory.kt +++ b/app-thunderbird/src/beta/kotlin/net/thunderbird/android/featureflag/TbFeatureFlagFactory.kt @@ -1,10 +1,12 @@ package net.thunderbird.android.featureflag import com.fsck.k9.ui.messagelist.MessageListFeatureFlags +import com.fsck.k9.ui.messageview.MessageViewFeatureFlags import net.thunderbird.core.featureflag.FeatureFlag import net.thunderbird.core.featureflag.FeatureFlagFactory import net.thunderbird.core.featureflag.FeatureFlagKey import net.thunderbird.core.featureflag.toFeatureFlagKey +import net.thunderbird.feature.account.settings.AccountSettingsFeatureFlags /** * Feature flags for Thunderbird Beta @@ -18,9 +20,11 @@ class TbFeatureFlagFactory : FeatureFlagFactory { FeatureFlag("email_notification_default".toFeatureFlagKey(), enabled = true), FeatureFlag("enable_dropdown_drawer".toFeatureFlagKey(), enabled = true), FeatureFlag("enable_dropdown_drawer_ui".toFeatureFlagKey(), enabled = true), - FeatureFlag(FeatureFlagKey.DisplayInAppNotifications, enabled = false), + FeatureFlag(FeatureFlagKey.DisplayInAppNotifications, enabled = true), FeatureFlag(FeatureFlagKey.UseNotificationSenderForSystemNotifications, enabled = false), FeatureFlag(MessageListFeatureFlags.UseComposeForMessageListItems, enabled = false), + FeatureFlag(MessageViewFeatureFlags.ActionExportEml, enabled = false), + FeatureFlag(AccountSettingsFeatureFlags.EnableAvatarCustomization, enabled = false), ) } } diff --git a/app-thunderbird/src/daily/AndroidManifest.xml b/app-thunderbird/src/daily/AndroidManifest.xml index 689e9c615a44160357f6b334b6d42064f2fe809d..17d3572fff3d03070a4ea6aac501dd20d9d5f6b6 100644 --- a/app-thunderbird/src/daily/AndroidManifest.xml +++ b/app-thunderbird/src/daily/AndroidManifest.xml @@ -4,7 +4,9 @@ xmlns:tools="http://schemas.android.com/tools" > - + diff --git a/app-thunderbird/src/daily/kotlin/net/thunderbird/android/featureflag/TbFeatureFlagFactory.kt b/app-thunderbird/src/daily/kotlin/net/thunderbird/android/featureflag/TbFeatureFlagFactory.kt index 51cc37abb64acadb71e7889f9f32d9e72771a374..51a6f461fccb59a7164badb71802ecab3cf398c4 100644 --- a/app-thunderbird/src/daily/kotlin/net/thunderbird/android/featureflag/TbFeatureFlagFactory.kt +++ b/app-thunderbird/src/daily/kotlin/net/thunderbird/android/featureflag/TbFeatureFlagFactory.kt @@ -1,10 +1,12 @@ package net.thunderbird.android.featureflag import com.fsck.k9.ui.messagelist.MessageListFeatureFlags +import com.fsck.k9.ui.messageview.MessageViewFeatureFlags import net.thunderbird.core.featureflag.FeatureFlag import net.thunderbird.core.featureflag.FeatureFlagFactory import net.thunderbird.core.featureflag.FeatureFlagKey import net.thunderbird.core.featureflag.toFeatureFlagKey +import net.thunderbird.feature.account.settings.AccountSettingsFeatureFlags /** * Feature flags for Thunderbird Daily @@ -21,6 +23,8 @@ class TbFeatureFlagFactory : FeatureFlagFactory { FeatureFlag(FeatureFlagKey.DisplayInAppNotifications, enabled = true), FeatureFlag(FeatureFlagKey.UseNotificationSenderForSystemNotifications, enabled = false), FeatureFlag(MessageListFeatureFlags.UseComposeForMessageListItems, enabled = false), + FeatureFlag(MessageViewFeatureFlags.ActionExportEml, enabled = true), + FeatureFlag(AccountSettingsFeatureFlags.EnableAvatarCustomization, enabled = false), ) } } diff --git a/app-thunderbird/src/debug/AndroidManifest.xml b/app-thunderbird/src/debug/AndroidManifest.xml index 689e9c615a44160357f6b334b6d42064f2fe809d..17d3572fff3d03070a4ea6aac501dd20d9d5f6b6 100644 --- a/app-thunderbird/src/debug/AndroidManifest.xml +++ b/app-thunderbird/src/debug/AndroidManifest.xml @@ -4,7 +4,9 @@ xmlns:tools="http://schemas.android.com/tools" > - + diff --git a/app-thunderbird/src/debug/kotlin/net/thunderbird/android/featureflag/TbFeatureFlagFactory.kt b/app-thunderbird/src/debug/kotlin/net/thunderbird/android/featureflag/TbFeatureFlagFactory.kt index 174a8ee9751803942416e9379be8bf427749ef59..88a2b9890051bc3afed84da19f50962f9226d397 100644 --- a/app-thunderbird/src/debug/kotlin/net/thunderbird/android/featureflag/TbFeatureFlagFactory.kt +++ b/app-thunderbird/src/debug/kotlin/net/thunderbird/android/featureflag/TbFeatureFlagFactory.kt @@ -1,10 +1,12 @@ package net.thunderbird.android.featureflag import com.fsck.k9.ui.messagelist.MessageListFeatureFlags +import com.fsck.k9.ui.messageview.MessageViewFeatureFlags import net.thunderbird.core.featureflag.FeatureFlag import net.thunderbird.core.featureflag.FeatureFlagFactory import net.thunderbird.core.featureflag.FeatureFlagKey import net.thunderbird.core.featureflag.toFeatureFlagKey +import net.thunderbird.feature.account.settings.AccountSettingsFeatureFlags /** * Feature flags for Thunderbird Debug @@ -21,6 +23,8 @@ class TbFeatureFlagFactory : FeatureFlagFactory { FeatureFlag(FeatureFlagKey.DisplayInAppNotifications, enabled = true), FeatureFlag(FeatureFlagKey.UseNotificationSenderForSystemNotifications, enabled = true), FeatureFlag(MessageListFeatureFlags.UseComposeForMessageListItems, enabled = false), + FeatureFlag(MessageViewFeatureFlags.ActionExportEml, enabled = true), + FeatureFlag(AccountSettingsFeatureFlags.EnableAvatarCustomization, enabled = false), ) } } diff --git a/app-thunderbird/src/main/kotlin/net/thunderbird/android/provider/ProviderModule.kt b/app-thunderbird/src/main/kotlin/net/thunderbird/android/provider/ProviderModule.kt index cf7d989eefd8ed83bb97d6d5e63bf3cf0ec48828..cd46613fe834430ca2936f1b192e9a2598c401fb 100644 --- a/app-thunderbird/src/main/kotlin/net/thunderbird/android/provider/ProviderModule.kt +++ b/app-thunderbird/src/main/kotlin/net/thunderbird/android/provider/ProviderModule.kt @@ -1,5 +1,6 @@ package net.thunderbird.android.provider +import app.k9mail.core.android.common.provider.NotificationIconResourceProvider import com.fsck.k9.preferences.FilePrefixProvider import net.thunderbird.core.common.provider.AppNameProvider import net.thunderbird.core.common.provider.BrandNameProvider @@ -17,4 +18,8 @@ internal val providerModule = module { single { TbThemeProvider() } single { TbFeatureThemeProvider() } + + single { + TbAppIconNotificationProvider() + } } diff --git a/app-thunderbird/src/main/kotlin/net/thunderbird/android/provider/TbAppIconNotificationProvider.kt b/app-thunderbird/src/main/kotlin/net/thunderbird/android/provider/TbAppIconNotificationProvider.kt new file mode 100644 index 0000000000000000000000000000000000000000..6cbaba6179eac49af6a25dc6b3936c32afc26a6a --- /dev/null +++ b/app-thunderbird/src/main/kotlin/net/thunderbird/android/provider/TbAppIconNotificationProvider.kt @@ -0,0 +1,8 @@ +package net.thunderbird.android.provider + +import app.k9mail.core.android.common.provider.NotificationIconResourceProvider + +class TbAppIconNotificationProvider : NotificationIconResourceProvider { + override val pushNotificationIcon: Int + get() = app.k9mail.core.ui.legacy.theme2.thunderbird.R.drawable.ic_logo_thunderbird_white +} diff --git a/app-thunderbird/src/main/res/values-ht/strings.xml b/app-thunderbird/src/main/res/values-ht/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-thunderbird/src/main/res/values-ht/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-thunderbird/src/main/res/values-kn/strings.xml b/app-thunderbird/src/main/res/values-kn/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-thunderbird/src/main/res/values-kn/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-thunderbird/src/main/res/values-mnw/strings.xml b/app-thunderbird/src/main/res/values-mnw/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/app-thunderbird/src/main/res/values-mnw/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-thunderbird/src/release/kotlin/net/thunderbird/android/featureflag/TbFeatureFlagFactory.kt b/app-thunderbird/src/release/kotlin/net/thunderbird/android/featureflag/TbFeatureFlagFactory.kt index d5dce4a7658aa10a31e34ec4cc381d581aa3bc12..295060007a2efae581b7862f174cf750116069bd 100644 --- a/app-thunderbird/src/release/kotlin/net/thunderbird/android/featureflag/TbFeatureFlagFactory.kt +++ b/app-thunderbird/src/release/kotlin/net/thunderbird/android/featureflag/TbFeatureFlagFactory.kt @@ -1,10 +1,12 @@ package net.thunderbird.android.featureflag import com.fsck.k9.ui.messagelist.MessageListFeatureFlags +import com.fsck.k9.ui.messageview.MessageViewFeatureFlags import net.thunderbird.core.featureflag.FeatureFlag import net.thunderbird.core.featureflag.FeatureFlagFactory import net.thunderbird.core.featureflag.FeatureFlagKey import net.thunderbird.core.featureflag.toFeatureFlagKey +import net.thunderbird.feature.account.settings.AccountSettingsFeatureFlags /** * Feature flags for Thunderbird (release) @@ -21,6 +23,8 @@ class TbFeatureFlagFactory : FeatureFlagFactory { FeatureFlag(FeatureFlagKey.DisplayInAppNotifications, enabled = false), FeatureFlag(FeatureFlagKey.UseNotificationSenderForSystemNotifications, enabled = false), FeatureFlag(MessageListFeatureFlags.UseComposeForMessageListItems, enabled = false), + FeatureFlag(MessageViewFeatureFlags.ActionExportEml, enabled = false), + FeatureFlag(AccountSettingsFeatureFlags.EnableAvatarCustomization, enabled = false), ) } } diff --git a/app-thunderbird/src/test/kotlin/net/thunderbird/android/TbAppIconNotificationProviderTest.kt b/app-thunderbird/src/test/kotlin/net/thunderbird/android/TbAppIconNotificationProviderTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..86dd8c284d01a44b91e52e460315b85e51583506 --- /dev/null +++ b/app-thunderbird/src/test/kotlin/net/thunderbird/android/TbAppIconNotificationProviderTest.kt @@ -0,0 +1,17 @@ +package net.thunderbird.android + +import assertk.assertThat +import assertk.assertions.isEqualTo +import net.thunderbird.android.provider.TbAppIconNotificationProvider +import org.junit.Test + +class TbAppIconNotificationProviderTest { + @Test + fun `provides correct Thunderbird notification icon`() { + val provider = TbAppIconNotificationProvider() + val icon = provider.pushNotificationIcon + + assertThat(icon) + .isEqualTo(app.k9mail.core.ui.legacy.theme2.thunderbird.R.drawable.ic_logo_thunderbird_white) + } +} diff --git a/build-plugin/build.gradle.kts b/build-plugin/build.gradle.kts index e3bd34c04ffa93082f7660cccb2056b63fa1080a..3aa0e61daffb1ef727983d090a7f93006625139d 100644 --- a/build-plugin/build.gradle.kts +++ b/build-plugin/build.gradle.kts @@ -30,6 +30,12 @@ dependencies { implementation(platform(libs.kotlin.gradle.bom)) } +kotlin { + compilerOptions { + allWarningsAsErrors = true + } +} + fun plugin(provider: Provider) = with(provider.get()) { "$pluginId:$pluginId.gradle.plugin:$version" } diff --git a/build-plugin/src/main/kotlin/AndroidExtension.kt b/build-plugin/src/main/kotlin/AndroidExtension.kt index 81395391ec03f9ba01da4560b6b962bdae116abc..b0a1e6d731299797e7f39b741011f6971b029eb9 100644 --- a/build-plugin/src/main/kotlin/AndroidExtension.kt +++ b/build-plugin/src/main/kotlin/AndroidExtension.kt @@ -28,12 +28,6 @@ internal fun CommonExtension<*, *, *, *, *, *>.configureSharedConfig(project: Pr checkReleaseBuilds = System.getenv("CI_CHECK_RELEASE_BUILDS")?.toBoolean() ?: true } - testOptions { - unitTests { - isIncludeAndroidResources = true - } - } - packaging { resources { excludes += listOf( diff --git a/build-plugin/src/main/kotlin/ThunderbirdProjectConfig.kt b/build-plugin/src/main/kotlin/ThunderbirdProjectConfig.kt index 6739d8c99fd375d2d902139830b38b76f1f93033..cf9f38ee9dc2d6a559a51ba27b376df8dfdbf9ad 100644 --- a/build-plugin/src/main/kotlin/ThunderbirdProjectConfig.kt +++ b/build-plugin/src/main/kotlin/ThunderbirdProjectConfig.kt @@ -8,7 +8,7 @@ object ThunderbirdProjectConfig { // Only needed for application const val sdkTarget = 35 - const val sdkCompile = 35 + const val sdkCompile = 36 } object Compiler { diff --git a/build-plugin/src/main/kotlin/thunderbird.app.android.gradle.kts b/build-plugin/src/main/kotlin/thunderbird.app.android.gradle.kts index 5f1a2681635fae1b6839209daec73e6cb1a2c843..7f27a1f4332fe5d651a7c401146909a3e4df2efe 100644 --- a/build-plugin/src/main/kotlin/thunderbird.app.android.gradle.kts +++ b/build-plugin/src/main/kotlin/thunderbird.app.android.gradle.kts @@ -20,16 +20,18 @@ android { isCoreLibraryDesugaringEnabled = true } - kotlinOptions { - jvmTarget = ThunderbirdProjectConfig.Compiler.javaCompatibility.toString() - } - dependenciesInfo { includeInApk = false includeInBundle = false } } +kotlin { + compilerOptions { + jvmTarget = ThunderbirdProjectConfig.Compiler.jvmTarget + } +} + dependencies { coreLibraryDesugaring(libs.android.desugar.nio) diff --git a/build-plugin/src/main/kotlin/thunderbird.library.android.compose.gradle.kts b/build-plugin/src/main/kotlin/thunderbird.library.android.compose.gradle.kts index c1e6087f2c1783abc2ffce9baebff51ddd31499a..efcf8538d796d17a71da609f09248e5bd4ba6307 100644 --- a/build-plugin/src/main/kotlin/thunderbird.library.android.compose.gradle.kts +++ b/build-plugin/src/main/kotlin/thunderbird.library.android.compose.gradle.kts @@ -1,3 +1,5 @@ +import com.android.build.api.variant.HostTestBuilder + plugins { id("thunderbird.library.android") id("org.jetbrains.kotlin.plugin.compose") @@ -12,7 +14,7 @@ android { androidComponents { beforeVariants(selector().withBuildType("release")) { variantBuilder -> - variantBuilder.enableUnitTest = false + variantBuilder.hostTests[HostTestBuilder.UNIT_TEST_TYPE]?.enable = false variantBuilder.enableAndroidTest = false } } diff --git a/build-plugin/src/main/kotlin/thunderbird.library.android.gradle.kts b/build-plugin/src/main/kotlin/thunderbird.library.android.gradle.kts index 75a1077b660de9719b71ef20c435b48fec626448..7a16e7bf6f03afe9ba05103ec83d8ce936792f36 100644 --- a/build-plugin/src/main/kotlin/thunderbird.library.android.gradle.kts +++ b/build-plugin/src/main/kotlin/thunderbird.library.android.gradle.kts @@ -11,19 +11,12 @@ android { buildFeatures { buildConfig = false } - - kotlinOptions { - jvmTarget = ThunderbirdProjectConfig.Compiler.javaCompatibility.toString() - } - - testOptions { - unitTests { - isIncludeAndroidResources = true - } - } } kotlin { + compilerOptions { + jvmTarget.set(ThunderbirdProjectConfig.Compiler.jvmTarget) + } sourceSets.all { compilerOptions { freeCompilerArgs.add("-Xwhen-guards") diff --git a/cli/resource-mover-cli/src/main/kotlin/net/thunderbird/cli/resource/mover/ResourceMoverCli.kt b/cli/resource-mover-cli/src/main/kotlin/net/thunderbird/cli/resource/mover/ResourceMoverCli.kt index bc0dd1a08fef9f4514590e6f0fd9f15a315e0888..86271d74a342704edb282341c849b2cab3038873 100644 --- a/cli/resource-mover-cli/src/main/kotlin/net/thunderbird/cli/resource/mover/ResourceMoverCli.kt +++ b/cli/resource-mover-cli/src/main/kotlin/net/thunderbird/cli/resource/mover/ResourceMoverCli.kt @@ -12,15 +12,16 @@ class ResourceMoverCli( name = "resource-mover", ) { private val from: String by option( - help = "Source module path", + help = "Source module path.", ).required() private val to: String by option( - help = "Target module path", + help = "Target module path. If the target module is a KMP module, ensure the " + + "commonMain/composeResources, otherwise the CLI won't be able to detect it automatically.", ).required() private val keys: List by option( - help = "Keys to move", + help = "Keys to move. When multiple separate by ','.", ).split(",").required() override fun help(context: Context): String = "Move string resources from one file to another" diff --git a/cli/resource-mover-cli/src/main/kotlin/net/thunderbird/cli/resource/mover/StringResourceMover.kt b/cli/resource-mover-cli/src/main/kotlin/net/thunderbird/cli/resource/mover/StringResourceMover.kt index ddfb264488a730d2534f6095d749493fcadef3e5..1ab7859e9598614b48d414a2f1e7cee3d1560023 100644 --- a/cli/resource-mover-cli/src/main/kotlin/net/thunderbird/cli/resource/mover/StringResourceMover.kt +++ b/cli/resource-mover-cli/src/main/kotlin/net/thunderbird/cli/resource/mover/StringResourceMover.kt @@ -7,8 +7,16 @@ import kotlin.system.exitProcess class StringResourceMover { fun moveKeys(source: String, target: String, keys: List) { - val sourcePath = File(source + RESOURCE_PATH) - val targetPath = File(target + RESOURCE_PATH) + fun File.isComposeResource(): Boolean = File(this, COMPOSE_RESOURCE_PATH).exists() + + val sourceDir = File(source) + val sourceBaseResourcePath = if (sourceDir.isComposeResource()) COMPOSE_RESOURCE_PATH else RESOURCE_PATH + val sourcePath = File(source + sourceBaseResourcePath) + + val targetDir = File(target) + val isTargetComposeResources = targetDir.isComposeResource() + val targetBaseResourcePath = if (isTargetComposeResources) COMPOSE_RESOURCE_PATH else RESOURCE_PATH + val targetPath = File(target + targetBaseResourcePath) if (!sourcePath.exists()) { println("\nSource path does not exist: $sourcePath\n") @@ -18,11 +26,11 @@ class StringResourceMover { println("\nMoving keys $keys") println(" from \"$sourcePath\" -> \"$targetPath\"\n") for (key in keys) { - moveKey(sourcePath, targetPath, key) + moveKey(sourcePath, targetPath, key, isTargetComposeResources) } } - private fun moveKey(sourcePath: File, targetPath: File, key: String) { + private fun moveKey(sourcePath: File, targetPath: File, key: String, isTargetComposeResources: Boolean) { println("\nMoving key: $key\n") sourcePath.walk() @@ -30,22 +38,30 @@ class StringResourceMover { .forEach { sourceDir -> val sourceFile = sourceDir.resolve(STRING_RESOURCE_FILE_NAME) if (sourceFile.exists()) { - moveKeyDeclaration(sourceFile, targetPath, key) + moveKeyDeclaration(sourceFile, targetPath, key, isTargetComposeResources) } } } - private fun moveKeyDeclaration(sourceFile: File, targetPath: File, key: String) { + private fun moveKeyDeclaration(sourceFile: File, targetPath: File, key: String, isTargetComposeResources: Boolean) { if (containsKey(sourceFile, key)) { println("\nFound key in file: ${sourceFile.path}\n") - val targetFile = getOrCreateTargetFile(targetPath, sourceFile) - val keyDeclaration = extractKeyDeclaration(sourceFile, key) + val targetFile = getOrCreateTargetFile(targetPath, sourceFile, isTargetComposeResources) + val originalKeyDeclaration = extractKeyDeclaration(sourceFile, key) + val keyDeclaration = originalKeyDeclaration.let { keyDeclaration -> + if (isTargetComposeResources && keyDeclaration.contains(")(.*?)()""".toRegex() + keyDeclaration.replace(regex, "$2") + } else { + keyDeclaration + } + } println(" Key declaration: $keyDeclaration") copyKeyToTarget(targetFile, keyDeclaration, key) - deleteKeyFromSource(sourceFile, keyDeclaration) + deleteKeyFromSource(sourceFile, originalKeyDeclaration) if (isSourceFileEmpty(sourceFile)) { println(" Source file is empty: ${sourceFile.path} -> deleting it.") @@ -134,7 +150,7 @@ class StringResourceMover { return sourceContent.contains(STRING_CLOSING_TAG).not() && sourceContent.contains(PLURALS_CLOSING_TAG).not() } - private fun getOrCreateTargetFile(targetPath: File, sourceFile: File): File { + private fun getOrCreateTargetFile(targetPath: File, sourceFile: File, isTargetComposeResources: Boolean): File { val targetFilePath = targetPath.resolve(sourceFile.parentFile.name) val targetFile = File(targetFilePath, sourceFile.name) val targetDirectory = targetFile.parentFile @@ -145,20 +161,22 @@ class StringResourceMover { } if (!targetFile.exists()) { - createTargetFile(targetFile) + createTargetFile(targetFile, isTargetComposeResources) } return targetFile } - private fun createTargetFile(targetFile: File) { + private fun createTargetFile(targetFile: File, isTargetComposeResources: Boolean) { val isNewFileCreated: Boolean = targetFile.createNewFile() if (!isNewFileCreated) { printError("Target file could not be created: ${targetFile.path}") exitProcess(-1) } - targetFile.writeText(TARGET_FILE_CONTENT) + targetFile.writeText( + if (isTargetComposeResources) TARGET_FILE_CONTENT_COMPOSE_RESOURCE else TARGET_FILE_CONTENT, + ) println("Target file ${targetFile.path} created") } @@ -168,6 +186,7 @@ class StringResourceMover { private companion object { const val RESOURCE_PATH = "/src/main/res/" + const val COMPOSE_RESOURCE_PATH = "/src/commonMain/composeResources/" const val KEY_PLACEHOLDER = "{KEY}" const val KEY_PATTERN = """name="$KEY_PLACEHOLDER"""" const val VALUES_PATH = "values" @@ -182,5 +201,12 @@ class StringResourceMover { """.trimIndent() + + val TARGET_FILE_CONTENT_COMPOSE_RESOURCE = """ + + + + + """.trimIndent() } } diff --git a/config/lint/lint.xml b/config/lint/lint.xml index b17c6187f6aba9e7b7130402ec27322960dda056..ae75933115da02d804772d621dbe353cf30443ba 100644 --- a/config/lint/lint.xml +++ b/config/lint/lint.xml @@ -6,7 +6,6 @@ - diff --git a/core/android/account/src/main/kotlin/net/thunderbird/core/android/account/AccountDefaultsProvider.kt b/core/android/account/src/main/kotlin/net/thunderbird/core/android/account/AccountDefaultsProvider.kt index b7dc95b1a197fb6695e1da5ad3e9df03f2dc949f..33e86b187e044b877e11832f41cee879ffa44209 100644 --- a/core/android/account/src/main/kotlin/net/thunderbird/core/android/account/AccountDefaultsProvider.kt +++ b/core/android/account/src/main/kotlin/net/thunderbird/core/android/account/AccountDefaultsProvider.kt @@ -41,7 +41,7 @@ interface AccountDefaultsProvider { const val DEFAULT_STRIP_SIGNATURE = true - const val DEFAULT_SYNC_INTERVAL = 60 + const val DEFAULT_SYNC_INTERVAL = 15 /** * Specifies how many messages will be shown in a folder by default. This number is set diff --git a/core/android/common/src/main/kotlin/app/k9mail/core/android/common/contact/ContactRepository.kt b/core/android/common/src/main/kotlin/app/k9mail/core/android/common/contact/ContactRepository.kt index ef97d63a055bb3180fad2c4e554ec2daefa48896..a03105d31c108619ccec5d115776be46bb7d96de 100644 --- a/core/android/common/src/main/kotlin/app/k9mail/core/android/common/contact/ContactRepository.kt +++ b/core/android/common/src/main/kotlin/app/k9mail/core/android/common/contact/ContactRepository.kt @@ -1,7 +1,9 @@ package app.k9mail.core.android.common.contact +import android.net.Uri import net.thunderbird.core.common.cache.Cache import net.thunderbird.core.common.mail.EmailAddress +import net.thunderbird.core.common.mail.toEmailAddressOrNull interface ContactRepository { @@ -10,6 +12,8 @@ interface ContactRepository { fun hasContactFor(emailAddress: EmailAddress): Boolean fun hasAnyContactFor(emailAddresses: List): Boolean + + fun getPhotoUri(emailAddress: String): Uri? } interface CachingRepository { @@ -42,6 +46,12 @@ internal class CachingContactRepository( override fun hasAnyContactFor(emailAddresses: List): Boolean = emailAddresses.any { emailAddress -> hasContactFor(emailAddress) } + override fun getPhotoUri(emailAddress: String): Uri? { + return emailAddress.toEmailAddressOrNull()?.let { emailAddress -> + getContactFor(emailAddress)?.photoUri + } + } + override fun clearCache() { cache.clear() } diff --git a/core/android/common/src/main/kotlin/app/k9mail/core/android/common/provider/NotificationIconResourceProvider.kt b/core/android/common/src/main/kotlin/app/k9mail/core/android/common/provider/NotificationIconResourceProvider.kt new file mode 100644 index 0000000000000000000000000000000000000000..014283ae9f0c2a32591afdecaad31744326428fa --- /dev/null +++ b/core/android/common/src/main/kotlin/app/k9mail/core/android/common/provider/NotificationIconResourceProvider.kt @@ -0,0 +1,5 @@ +package app.k9mail.core.android.common.provider + +interface NotificationIconResourceProvider { + val pushNotificationIcon: Int +} diff --git a/core/android/common/src/test/kotlin/app/k9mail/core/android/common/CoreCommonAndroidModuleKtTest.kt b/core/android/common/src/test/kotlin/app/k9mail/core/android/common/CoreCommonAndroidModuleKtTest.kt index 97a34d1222250e0307e6b750d373f691d2461063..00826960e84bfc39c4e0a1fd21e068f0c1d72eef 100644 --- a/core/android/common/src/test/kotlin/app/k9mail/core/android/common/CoreCommonAndroidModuleKtTest.kt +++ b/core/android/common/src/test/kotlin/app/k9mail/core/android/common/CoreCommonAndroidModuleKtTest.kt @@ -2,10 +2,12 @@ package app.k9mail.core.android.common import android.content.Context import org.junit.Test +import org.koin.core.annotation.KoinExperimentalAPI import org.koin.test.verify.verify internal class CoreCommonAndroidModuleKtTest { + @OptIn(KoinExperimentalAPI::class) @Test fun `should have a valid di module`() { coreCommonAndroidModule.verify( diff --git a/core/android/common/src/test/kotlin/app/k9mail/core/android/common/contact/CachingContactRepositoryTest.kt b/core/android/common/src/test/kotlin/app/k9mail/core/android/common/contact/CachingContactRepositoryTest.kt index a4eed9a1e6f016d6cfd7d99ee38925e68882893b..3854450ef7c2800f7501dd1d7cabcfe1179a038a 100644 --- a/core/android/common/src/test/kotlin/app/k9mail/core/android/common/contact/CachingContactRepositoryTest.kt +++ b/core/android/common/src/test/kotlin/app/k9mail/core/android/common/contact/CachingContactRepositoryTest.kt @@ -1,5 +1,6 @@ package app.k9mail.core.android.common.contact +import android.net.Uri import assertk.assertThat import assertk.assertions.isEqualTo import assertk.assertions.isFalse @@ -140,4 +141,53 @@ internal class CachingContactRepositoryTest { assertThat(cache[CONTACT_EMAIL_ADDRESS]).isNull() } + + @Test + fun `getPhotoUri() returns null when email is invalid`() { + val result = testSubject.getPhotoUri("invalid-email") + + assertThat(result).isNull() + } + + @Test + fun `getPhotoUri() returns null when no contact found for valid email`() { + dataSource.stub { on { getContactFor(CONTACT_EMAIL_ADDRESS) } doReturn null } + + val result = testSubject.getPhotoUri(CONTACT_EMAIL_ADDRESS.address) + + assertThat(result).isNull() + } + + @Test + fun `getPhotoUri() returns contact photo uri when contact exists`() { + dataSource.stub { on { getContactFor(CONTACT_EMAIL_ADDRESS) } doReturn CONTACT } + + val result = testSubject.getPhotoUri(CONTACT_EMAIL_ADDRESS.address) + + assertThat(result).isEqualTo(CONTACT.photoUri) + } + + @Test + fun `getPhotoUri() returns cached photo uri when contact already cached`() { + cache[CONTACT_EMAIL_ADDRESS] = CONTACT + + val result = testSubject.getPhotoUri(CONTACT_EMAIL_ADDRESS.address) + + assertThat(result).isEqualTo(CONTACT.photoUri) + } + + @Test + fun `getPhotoUri() caches result after first fetch`() { + dataSource.stub { + on { getContactFor(CONTACT_EMAIL_ADDRESS) } doReturnConsecutively listOf( + CONTACT, + CONTACT.copy(photoUri = Uri.parse("content://other/photo")), + ) + } + + val result1 = testSubject.getPhotoUri(CONTACT_EMAIL_ADDRESS.address) + val result2 = testSubject.getPhotoUri(CONTACT_EMAIL_ADDRESS.address) + + assertThat(result1).isEqualTo(result2) + } } diff --git a/core/android/common/src/test/kotlin/app/k9mail/core/android/common/contact/ContactKoinModuleKtTest.kt b/core/android/common/src/test/kotlin/app/k9mail/core/android/common/contact/ContactKoinModuleKtTest.kt index 8b9442979bf587e6c48a2c50c726520293374152..f72ad5acf59aab91ee5177852de4a45b4021528c 100644 --- a/core/android/common/src/test/kotlin/app/k9mail/core/android/common/contact/ContactKoinModuleKtTest.kt +++ b/core/android/common/src/test/kotlin/app/k9mail/core/android/common/contact/ContactKoinModuleKtTest.kt @@ -1,10 +1,12 @@ package app.k9mail.core.android.common.contact import org.junit.Test +import org.koin.core.annotation.KoinExperimentalAPI import org.koin.test.verify.verify internal class ContactKoinModuleKtTest { + @OptIn(KoinExperimentalAPI::class) @Test fun `should have a valid di module`() { contactModule.verify() diff --git a/core/common/src/commonMain/kotlin/net/thunderbird/core/common/collections/PriorityQueue.kt b/core/common/src/commonMain/kotlin/net/thunderbird/core/common/collections/PriorityQueue.kt new file mode 100644 index 0000000000000000000000000000000000000000..3caf595dd73b49dd5635e7e5cd6e55c26808b82f --- /dev/null +++ b/core/common/src/commonMain/kotlin/net/thunderbird/core/common/collections/PriorityQueue.kt @@ -0,0 +1,177 @@ +package net.thunderbird.core.common.collections + +/** + * An unbounded priority queue based on a binary heap. + * + * The elements of the priority queue are ordered according to the provided [Comparator]. + * The head of this queue is the *least* element with respect to the specified ordering. + * If multiple elements are tied for least value, the head is one of those elements — ties + * are broken arbitrarily. + * + * The queue does not permit `null` elements. + * + * This class and its iterator implement all of the *optional* methods of the [Collection] and + * [Iterator] interfaces. The iterator returned by the `iterator()` method is *not* guaranteed + * to traverse the elements of the priority queue in any particular order. + * If you need ordered traversal, consider draining the queue into a list, for example: + * + * ```kotlin + * val list = mutableListOf() + * while (queue.isNotEmpty()) { + * list.add(queue.poll()) + * } + * ``` + * + * This implementation is not thread-safe. + * + * @param T The type of elements held in this collection. + * @param comparator The comparator that will be used to order this priority queue. + * @param elements An optional list of initial elements to be added to the queue. + */ +class PriorityQueue( + private val comparator: Comparator, + elements: List = emptyList(), +) : AbstractQueue() { + private val heap = elements.toMutableList() + + init { + if (heap.isNotEmpty()) { + heapify() + } + } + + override val size: Int get() = heap.size + override fun isEmpty(): Boolean = heap.isEmpty() + + override fun iterator(): MutableIterator = HeapIterator() + + override fun offer(element: T): Boolean { + heap.add(element) + siftUp(heap.lastIndex) + return true + } + + override fun poll(): T? { + if (heap.isEmpty()) { + return null + } + val result = heap.first() + val last = heap.removeAt(heap.lastIndex) + if (heap.isNotEmpty()) { + heap[0] = last + siftDown(0) + } + return result + } + + override fun peek(): T? = heap.firstOrNull() + + private fun siftUp(index: Int) { + var childIndex = index + fun parentIndex(childIndex: Int) = (childIndex - 1) / 2 + + while (childIndex > 0 && comparator.compare(heap[childIndex], heap[parentIndex(childIndex)]) < 0) { + swap(childIndex, parentIndex(childIndex)) + childIndex = parentIndex(childIndex) + } + } + + private fun siftDown(index: Int) { + var parentIndex = index + fun leftChildIndex(parentIndex: Int) = (parentIndex * 2) + 1 + val half = heap.size / 2 + while (parentIndex < half) { + var childIndex = leftChildIndex(parentIndex) + val rightChildIndex = childIndex + 1 + if (rightChildIndex < heap.size && + comparator.compare(heap[childIndex], heap[rightChildIndex]) > 0 + ) { + childIndex = rightChildIndex + } + + if (comparator.compare(heap[parentIndex], heap[childIndex]) <= 0) { + break + } + + swap(parentIndex, childIndex) + parentIndex = childIndex + } + } + + private fun heapify() { + for (index in ((heap.lastIndex - 1) / 2) downTo 0) { + siftDown(index) + } + } + + private fun swap(first: Int, second: Int) { + val temp = heap[first] + heap[first] = heap[second] + heap[second] = temp + } + + private fun removeAt(i: Int) { + val lastIndex = heap.lastIndex + if (i == lastIndex) { + heap.removeAt(lastIndex) + return + } + val moved = heap.removeAt(lastIndex) + heap[i] = moved + siftDown(i) + siftUp(i) + } + + private inner class HeapIterator : MutableIterator { + private var index = 0 + private var lastReturned = -1 + + override fun hasNext(): Boolean = index < heap.size + + override fun next(): T { + if (!hasNext()) throw NoSuchElementException("Queue is empty") + lastReturned = index++ + return heap[lastReturned] + } + + override fun remove() { + require(lastReturned >= 0) { "next() has not been called" } + removeAt(lastReturned) + index = lastReturned-- + } + } +} + +/** + * Creates a [PriorityQueue] that orders its elements according to their natural-order, + * resulting in a min-priority queue (the smallest element is at the head). + * + * The elements must be [Comparable]. + * + * @param T the type of elements in the priority queue. + * @param elements an optional [Iterable] of initial elements to be added to the queue. + * @return a [PriorityQueue] containing the specified elements, ordered by their natural ascending order. + */ +inline fun minPriorityQueueOf( + elements: Iterable = emptyList(), +): PriorityQueue where T : Comparable = PriorityQueue( + comparator = { a, b -> a.compareTo(b) }, + elements = elements.toList(), +) + +/** + * Creates a [PriorityQueue] that orders its elements according to their reverse-order, + * resulting in a max-priority queue (the largest element is at the head). + * + * The elements must be [Comparable]. + * + * @param T the type of elements in the priority queue. + * @param elements an optional [Iterable] of initial elements to be added to the queue. + * @return a [PriorityQueue] containing the specified elements, ordered by their natural descending order. + */ +inline fun maxPriorityQueueOf( + elements: Iterable = emptyList(), +): PriorityQueue where T : Comparable = PriorityQueue( + comparator = { a, b -> b.compareTo(a) }, + elements = elements.toList(), +) diff --git a/core/common/src/commonMain/kotlin/net/thunderbird/core/common/collections/Queue.kt b/core/common/src/commonMain/kotlin/net/thunderbird/core/common/collections/Queue.kt new file mode 100644 index 0000000000000000000000000000000000000000..6874d0f2a3fdac2e1c04a95e4fa4a0e63c81a3ee --- /dev/null +++ b/core/common/src/commonMain/kotlin/net/thunderbird/core/common/collections/Queue.kt @@ -0,0 +1,96 @@ +package net.thunderbird.core.common.collections + +/** + * A collection designed for holding elements prior to processing. + * Besides basic [Collection] operations, queues provide additional insertion, extraction, and inspection operations. + * + * Queues typically, but do not necessarily, order elements in a FIFO (first-in-first-out) manner. + */ +interface Queue : Collection { + /** + * Inserts the specified element into this queue. + * + * @return `true` if the element was added to this queue. + * @throws IllegalStateException if the element cannot be added at this time due to capacity restrictions. + */ + fun add(element: T): Boolean + + /** + * Inserts the specified element into this queue. + * + * @return `true` if the element was added to this queue, else `false`. + */ + fun offer(element: T): Boolean + + /** + * Retrieves and removes the head of this queue. + * + * @return the head of this queue. + * @throws NoSuchElementException if this queue is empty. + */ + fun remove(): T + + /** + * @return Retrieves and removes the head of this queue, or returns `null` if this queue is empty. + */ + fun poll(): T? + + /** + * Retrieves, but does not remove, the head of this queue. + * + * @return the head of this queue. + * @throws NoSuchElementException if this queue is empty. + */ + fun element(): T + + /** + * @return Retrieves, but does not remove, the head of this queue, or returns `null` if this queue is empty. + */ + fun peek(): T? +} + +abstract class AbstractQueue : AbstractMutableCollection(), Queue { + + override fun element(): T { + val head = peek() + if (head != null) { + return head + } else { + error("Collection empty") + } + } + + override fun add(element: T): Boolean { + if (offer(element)) { + return true + } else { + error("Collection full") + } + } + + override fun addAll(elements: Collection): Boolean { + require(elements != this) { "Collection can't addAll itself" } + var modified = false + for (element in elements) { + if (add(element)) { + modified = true + } + } + return modified + } + + override fun remove(): T { + val head = poll() + if (head != null) { + return head + } else { + throw NoSuchElementException("Queue is empty") + } + } + + override fun clear() { + while (!isEmpty()) { + remove() + } + } +} diff --git a/core/common/src/commonMain/kotlin/net/thunderbird/core/common/domain/usecase/validation/ValidationError.kt b/core/common/src/commonMain/kotlin/net/thunderbird/core/common/domain/usecase/validation/ValidationError.kt deleted file mode 100644 index 2cd21eebf5bd7f81f3fbcc9ac5b61c1fb5970ca5..0000000000000000000000000000000000000000 --- a/core/common/src/commonMain/kotlin/net/thunderbird/core/common/domain/usecase/validation/ValidationError.kt +++ /dev/null @@ -1,3 +0,0 @@ -package net.thunderbird.core.common.domain.usecase.validation - -interface ValidationError diff --git a/core/common/src/commonMain/kotlin/net/thunderbird/core/common/domain/usecase/validation/ValidationResult.kt b/core/common/src/commonMain/kotlin/net/thunderbird/core/common/domain/usecase/validation/ValidationResult.kt deleted file mode 100644 index 8a80cf163ad108569266484f937f480edf510879..0000000000000000000000000000000000000000 --- a/core/common/src/commonMain/kotlin/net/thunderbird/core/common/domain/usecase/validation/ValidationResult.kt +++ /dev/null @@ -1,7 +0,0 @@ -package net.thunderbird.core.common.domain.usecase.validation - -sealed interface ValidationResult { - data object Success : ValidationResult - - data class Failure(val error: ValidationError) : ValidationResult -} diff --git a/core/common/src/commonTest/kotlin/net/thunderbird/core/common/collections/PriorityQueueTests.kt b/core/common/src/commonTest/kotlin/net/thunderbird/core/common/collections/PriorityQueueTests.kt new file mode 100644 index 0000000000000000000000000000000000000000..ba368905586449f9d4a995543bfbb366ad4cd7c6 --- /dev/null +++ b/core/common/src/commonTest/kotlin/net/thunderbird/core/common/collections/PriorityQueueTests.kt @@ -0,0 +1,272 @@ +package net.thunderbird.core.common.collections + +import assertk.assertThat +import assertk.assertions.isEqualTo +import assertk.assertions.isFalse +import assertk.assertions.isNull +import assertk.assertions.isTrue +import kotlin.test.Test + +class PriorityQueueTests { + @Test + fun `minPriorityQueueOf - isEmpty returns true for new queue`() { + // Arrange + val queue = minPriorityQueueOf() + + // Act + val isEmpty = queue.isEmpty() + + // Assert + assertThat(isEmpty).isTrue() + } + + @Test + fun `isEmpty returns false for non-empty queue`() { + // Arrange + val queue = minPriorityQueueOf() + queue.add(1) + + // Act + val isEmpty = queue.isEmpty() + + // Assert + assertThat(isEmpty).isFalse() + } + + @Test + fun `minPriorityQueueOf - size returns correct number of elements`() { + // Arrange + val queue = minPriorityQueueOf() + + // Pre-Act Assert + assertThat(queue.size).isEqualTo(0) + + // Act + queue.add("A") + + // Assert + assertThat(queue.size).isEqualTo(1) + + // Act (Phase 2) + queue.add("B") + + // Assert (Phase 2) + assertThat(queue.size).isEqualTo(2) + + // Act (Phase 3) + queue.poll() + + // Assert (Phase 3) + assertThat(queue.size).isEqualTo(1) + } + + @Test + fun `minPriorityQueueOf - poll returns null for empty queue`() { + // Arrange + val queue = minPriorityQueueOf() + + // Act + val element = queue.poll() + + // Assert + assertThat(element).isNull() + } + + @Test + fun `minPriorityQueueOf - peek returns null for empty queue`() { + // Arrange + val queue = minPriorityQueueOf() + + // Act + val element = queue.peek() + + // Assert + assertThat(element).isNull() + } + + @Test + fun `minPriorityQueueOf - peek returns the smallest element without removing it`() { + // Arrange + val queue = minPriorityQueueOf() + queue.add('C') + queue.add('A') + queue.add('B') + + // Act + val element1 = queue.peek() + val element2 = queue.peek() + + // Assert + assertThat(queue.size).isEqualTo(3) + assertThat(element1).isEqualTo('A') + assertThat(element2).isEqualTo('A') // Subsequent peeks return the same element + assertThat(queue.size).isEqualTo(3) + } + + @Test + fun `minPriorityQueueOf - add and poll elements in natural order`() { + // Arrange + val queue = minPriorityQueueOf() + queue.add(5) + queue.add(1) + queue.add(10) + queue.add(3) + + // Act & Assert + assertThat(queue.poll()).isEqualTo(1) + assertThat(queue.poll()).isEqualTo(3) + assertThat(queue.poll()).isEqualTo(5) + assertThat(queue.poll()).isEqualTo(10) + assertThat(queue.poll()).isNull() + } + + @Test + fun `minPriorityQueueOf - clear removes all elements from the queue`() { + // Arrange + val queue = minPriorityQueueOf() + queue.add(10) + queue.add(20) + queue.add(5) + + // Act + queue.clear() + + // Assert + assertThat(queue.isEmpty()).isTrue() + assertThat(queue.size).isEqualTo(0) + assertThat(queue.peek()).isNull() + assertThat(queue.poll()).isNull() + } + + // maxPriorityQueueOf tests + @Test + fun `maxPriorityQueueOf - isEmpty returns true for new queue`() { + // Arrange + val queue = maxPriorityQueueOf() + + // Act + val isEmpty = queue.isEmpty() + + // Assert + assertThat(isEmpty).isTrue() + } + + @Test + fun `maxPriorityQueueOf - isEmpty returns false for non-empty queue`() { + // Arrange + val queue = maxPriorityQueueOf() + queue.add(1) + + // Act + val isEmpty = queue.isEmpty() + + // Assert + assertThat(isEmpty).isFalse() + } + + @Test + fun `maxPriorityQueueOf - size returns correct number of elements`() { + // Arrange + val queue = maxPriorityQueueOf() + + // Pre-Act Assert + assertThat(queue.size).isEqualTo(0) + + // Act + queue.add("A") + + // Assert + assertThat(queue.size).isEqualTo(1) + + // Act (Phase 2) + queue.add("B") + + // Assert (Phase 2) + assertThat(queue.size).isEqualTo(2) + + // Act (Phase 3) + queue.poll() + + // Assert (Phase 3) + assertThat(queue.size).isEqualTo(1) + } + + @Test + fun `maxPriorityQueueOf - poll returns null for empty queue`() { + // Arrange + val queue = maxPriorityQueueOf() + + // Act + val element = queue.poll() + + // Assert + assertThat(element).isNull() + } + + @Test + fun `maxPriorityQueueOf - peek returns null for empty queue`() { + // Arrange + val queue = maxPriorityQueueOf() + + // Act + val element = queue.peek() + + // Assert + assertThat(element).isNull() + } + + @Test + fun `maxPriorityQueueOf - peek returns the largest element without removing it`() { + // Arrange + val queue = maxPriorityQueueOf() + queue.add('C') + queue.add('A') + queue.add('D') + queue.add('B') + + // Act + val element1 = queue.peek() + val element2 = queue.peek() + + // Assert + assertThat(queue.size).isEqualTo(4) + assertThat(element1).isEqualTo('D') + assertThat(element2).isEqualTo('D') // Subsequent peeks return the same element + assertThat(queue.size).isEqualTo(4) + } + + @Test + fun `maxPriorityQueueOf - add and poll elements in reverse natural order`() { + // Arrange + val queue = maxPriorityQueueOf() + queue.add(5) + queue.add(1) + queue.add(10) + queue.add(3) + + // Act & Assert + assertThat(queue.poll()).isEqualTo(10) + assertThat(queue.poll()).isEqualTo(5) + assertThat(queue.poll()).isEqualTo(3) + assertThat(queue.poll()).isEqualTo(1) + assertThat(queue.poll()).isNull() + } + + @Test + fun `maxPriorityQueueOf - clear removes all elements from the queue`() { + // Arrange + val queue = maxPriorityQueueOf() + queue.add(10) + queue.add(20) + queue.add(5) + + // Act + queue.clear() + + // Assert + assertThat(queue.isEmpty()).isTrue() + assertThat(queue.size).isEqualTo(0) + assertThat(queue.peek()).isNull() + assertThat(queue.poll()).isNull() + } +} diff --git a/core/file/README.md b/core/file/README.md new file mode 100644 index 0000000000000000000000000000000000000000..a670d70c1f84589e2450e16261b746070b7f4175 --- /dev/null +++ b/core/file/README.md @@ -0,0 +1,120 @@ +# Thunderbird Core File Module + +This module provides a simple, consistent API for common file operations across Android and JVM platforms. + +## Architecture + +The file system layer is split into two levels: + +- Public low-level I/O: `FileSystemManager` opens `RawSource`/`RawSink` for a given `Uri`. + - Android actual: `AndroidFileSystemManager` + - JVM actual: `JvmFileSystemManager` +- Public high-level facade: `FileManager` for common operations (currently: copy). + - Default implementation: `DefaultFileManager` delegating to internal commands +- Internal commands: e.g., `CopyCommand(source, dest)` implement operations using `FileSystemManager`. + - Hidden from public API; return `Outcome` internally to preserve error context. +- `RawSource`/`RawSink` come from `kotlinx-io` and are referenced in the public API. + +### Core Components + +```mermaid +classDiagram + class FileManager { + +copy(source: Uri, dest: Uri): Outcome + } + + class DefaultFileManager { + -fs: FileSystemManager + } + + class FileSystemManager { + +openSource(uri: Uri): RawSource? + +openSink(uri: Uri, mode: WriteMode = WriteMode.Truncate): RawSink? + } + + class CopyCommand { + -source: Uri + -destination: Uri + +invoke(fs: FileSystemManager): Outcome + } + + class FileOperationError { + } + + DefaultFileManager ..> FileSystemManager + CopyCommand --> FileSystemManager + DefaultFileManager ..> CopyCommand : delegates +``` + +## Getting Started + +### Dependency setup + +Add the module to your Gradle build. Then, depending on your platform, provide an actual `FileSystemManager` and wire a `FileManager`: + +```kotlin +// Koin example (Android) +single { AndroidFileSystemManager(androidContext().contentResolver) } +single { DefaultFileManager(get()) } +``` + +For JVM-only tools/tests: + +```kotlin +val fs: FileSystemManager = JvmFileSystemManager() +val fileManager: FileManager = DefaultFileManager(fs) +``` + +## Public API + +- FileManager + - `suspend fun copy(sourceUri: Uri, destinationUri: Uri): Outcome` +- FileSystemManager + - `fun openSource(uri: Uri): RawSource?` + - `fun openSink(uri: Uri, mode: WriteMode = WriteMode.Truncate): RawSink?` + - Behavior: + - Sinks default to overwrite/truncate. Pass `WriteMode.Append` to append where supported. + - Returns null when the URI cannot be opened (e.g., missing permissions, unsupported scheme). + - Thread-safety: Implementations are stateless and safe to use from multiple threads, but the returned streams must be used/closed by the caller. +- `enum class WriteMode { Truncate, Append }` + +## URI type + +The API uses a KMP‑friendly `Uri` type (com.eygraber.uri.Uri). On Android, convert a platform URI using the provided extension: + +```kotlin +val kmpUri = androidUri.toKmpUri() +``` + +To build URIs in tests or common code, you can parse a string: + +```kotlin +val source = "file:///path/to/file.txt".toKmpUri() +``` + +## Supported URIs (by platform) + +- Android (AndroidFileSystemManager): + - `content://` via `ContentResolver` + - `file://` via `ContentResolver` +- JVM (JvmFileSystemManager): + - `file://` URIs only (non-`file:` schemes are not supported and will return null). +- iOS: No actual yet in this repository, but the API is compatible. An iOS actual can use `NSFileManager`/`NSURL`. + +## Error handling best practices + +- `openSource(uri)`/`openSink(uri)` return null on failure. Always check for null and handle gracefully (e.g., show a message, request permissions). +- On Android, failures are frequently due to missing URI permissions; prefer SAF pickers and persist permissions when needed. + +## Performance and buffering + +- Internal copy uses a buffered loop (`BUFFER_SIZE = 8_192L`). +- Streams are flushed and closed to avoid leaks. +- Public `openSource`/`openSink` are not suspending; perform I/O on an appropriate dispatcher/thread when needed. + +## Limitations and notes + +- Android: Ensure the app holds read/write permissions for the target URI (e.g., via SAF and optionally `takePersistableUriPermission`). +- JVM: Only `file:` URIs are supported by `JvmFileSystemManager`. +- iOS: No actual yet. The public API is prepared for an iOS actual using `NSFileManager`/`NSURL`. + diff --git a/core/file/build.gradle.kts b/core/file/build.gradle.kts new file mode 100644 index 0000000000000000000000000000000000000000..ee369256b9f1652c81babeec7642834d4ad7dd38 --- /dev/null +++ b/core/file/build.gradle.kts @@ -0,0 +1,22 @@ +plugins { + id(ThunderbirdPlugins.Library.kmp) +} + +android { + namespace = "net.thunderbird.core.file" +} + +kotlin { + sourceSets { + commonMain.dependencies { + api(libs.uri) + + implementation(projects.core.outcome) + + implementation(libs.kotlinx.io.core) + } + androidUnitTest.dependencies { + implementation(libs.robolectric) + } + } +} diff --git a/core/file/src/androidMain/kotlin/net/thunderbird/core/file/AndroidFileSystemManager.kt b/core/file/src/androidMain/kotlin/net/thunderbird/core/file/AndroidFileSystemManager.kt new file mode 100644 index 0000000000000000000000000000000000000000..613d1820e4920fec025a16cdad9fc279aa774ff8 --- /dev/null +++ b/core/file/src/androidMain/kotlin/net/thunderbird/core/file/AndroidFileSystemManager.kt @@ -0,0 +1,29 @@ +package net.thunderbird.core.file + +import android.content.ContentResolver +import com.eygraber.uri.Uri +import com.eygraber.uri.toAndroidUri +import kotlinx.io.RawSink +import kotlinx.io.RawSource +import kotlinx.io.asSink +import kotlinx.io.asSource + +/** + * Android implementation of [FileSystemManager] that uses [ContentResolver] to perform file operations. + */ +class AndroidFileSystemManager( + private val contentResolver: ContentResolver, +) : FileSystemManager { + override fun openSink(uri: Uri, mode: WriteMode): RawSink? { + // Map WriteMode to ContentResolver open modes: "wt" (truncate) or "wa" (append) + val androidMode = when (mode) { + WriteMode.Truncate -> "wt" + WriteMode.Append -> "wa" + } + return contentResolver.openOutputStream(uri.toAndroidUri(), androidMode)?.asSink() + } + + override fun openSource(uri: Uri): RawSource? { + return contentResolver.openInputStream(uri.toAndroidUri())?.asSource() + } +} diff --git a/core/file/src/androidUnitTest/kotlin/net/thunderbird/core/file/AndroidFileSystemManagerTest.kt b/core/file/src/androidUnitTest/kotlin/net/thunderbird/core/file/AndroidFileSystemManagerTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..60113b0eda70a1e6ffa4a551baeceb9a8472e642 --- /dev/null +++ b/core/file/src/androidUnitTest/kotlin/net/thunderbird/core/file/AndroidFileSystemManagerTest.kt @@ -0,0 +1,134 @@ +package net.thunderbird.core.file + +import android.content.Context +import android.net.Uri +import assertk.assertThat +import assertk.assertions.isEqualTo +import com.eygraber.uri.toKmpUri +import kotlinx.io.Buffer +import org.junit.Rule +import org.junit.Test +import org.junit.rules.TemporaryFolder +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.RuntimeEnvironment +import org.robolectric.annotation.Config + +@RunWith(RobolectricTestRunner::class) +@Config(manifest = Config.NONE) +class AndroidFileSystemManagerTest { + + private val appContext: Context = RuntimeEnvironment.getApplication() + + private val testSubject = AndroidFileSystemManager(appContext.contentResolver) + + @JvmField + @Rule + val folder = TemporaryFolder() + + @Test + fun openSinkAndOpenSource_writeAndReadFileContentRoundtrip() { + // Arrange + val tempFile = folder.newFile("tb-file-fs-test-android.txt") + val uri: Uri = Uri.fromFile(tempFile) + val testText = "Hello Thunderbird Android!" + + // Act + val sink = checkNotNull(testSubject.openSink(uri.toKmpUri())) + val writeBuffer = Buffer().apply { write(testText.encodeToByteArray()) } + sink.write(writeBuffer, writeBuffer.size) + sink.flush() + sink.close() + + val source = checkNotNull(testSubject.openSource(uri.toKmpUri())) + val readBuffer = Buffer() + source.readAtMostTo(readBuffer, 1024) + val bytes = ByteArray(readBuffer.size.toInt()) + for (i in bytes.indices) { + bytes[i] = readBuffer.readByte() + } + val result = bytes.decodeToString() + source.close() + + // Assert + assertThat(result).isEqualTo(testText) + } + + @Test + fun openSink_withAppend_shouldAppendToExistingContent() { + // Arrange + val tempFile = folder.newFile("tb-file-fs-test-android-append.txt") + val uri: Uri = Uri.fromFile(tempFile) + val initial = "Hello" + val extra = " Android" + + // Write initial content (truncate by default) + run { + val sink = checkNotNull(testSubject.openSink(uri.toKmpUri())) + val buf = Buffer().apply { write(initial.encodeToByteArray()) } + sink.write(buf, buf.size) + sink.flush() + sink.close() + } + + // Append extra content + run { + val sink = checkNotNull(testSubject.openSink(uri.toKmpUri(), WriteMode.Append)) + val buf = Buffer().apply { write(extra.encodeToByteArray()) } + sink.write(buf, buf.size) + sink.flush() + sink.close() + } + + // Read back + val source = checkNotNull(testSubject.openSource(uri.toKmpUri())) + val readBuffer = Buffer() + source.readAtMostTo(readBuffer, 1024) + val bytes = ByteArray(readBuffer.size.toInt()) + repeat(bytes.size) { i -> bytes[i] = readBuffer.readByte() } + val result = bytes.decodeToString() + source.close() + + // Assert + assertThat(result).isEqualTo(initial + extra) + } + + @Test + fun openSink_withTruncate_shouldOverwriteExistingContent() { + // Arrange + val tempFile = folder.newFile("tb-file-fs-test-android-truncate.txt") + val uri: Uri = Uri.fromFile(tempFile) + val first = "First" + val second = "Second" + + // Write first content + run { + val sink = checkNotNull(testSubject.openSink(uri.toKmpUri(), WriteMode.Truncate)) + val buf = Buffer().apply { write(first.encodeToByteArray()) } + sink.write(buf, buf.size) + sink.flush() + sink.close() + } + + // Overwrite with second content + run { + val sink = checkNotNull(testSubject.openSink(uri.toKmpUri(), WriteMode.Truncate)) + val buf = Buffer().apply { write(second.encodeToByteArray()) } + sink.write(buf, buf.size) + sink.flush() + sink.close() + } + + // Read back + val source = checkNotNull(testSubject.openSource(uri.toKmpUri())) + val readBuffer = Buffer() + source.readAtMostTo(readBuffer, 1024) + val bytes = ByteArray(readBuffer.size.toInt()) + repeat(bytes.size) { i -> bytes[i] = readBuffer.readByte() } + val result = bytes.decodeToString() + source.close() + + // Assert + assertThat(result).isEqualTo(second) + } +} diff --git a/core/file/src/commonMain/kotlin/net/thunderbird/core/file/DefaultFileManager.kt b/core/file/src/commonMain/kotlin/net/thunderbird/core/file/DefaultFileManager.kt new file mode 100644 index 0000000000000000000000000000000000000000..700371bb4454e7fe9817806363451394973c7a21 --- /dev/null +++ b/core/file/src/commonMain/kotlin/net/thunderbird/core/file/DefaultFileManager.kt @@ -0,0 +1,15 @@ +package net.thunderbird.core.file + +import com.eygraber.uri.Uri +import net.thunderbird.core.file.command.CopyCommand +import net.thunderbird.core.outcome.Outcome + +/** + * Default implementation that delegates to internal commands. + */ +class DefaultFileManager( + private val fileSystemManager: FileSystemManager, +) : FileManager { + override suspend fun copy(sourceUri: Uri, destinationUri: Uri): Outcome = + CopyCommand(sourceUri, destinationUri).invoke(fileSystemManager) +} diff --git a/core/file/src/commonMain/kotlin/net/thunderbird/core/file/FileManager.kt b/core/file/src/commonMain/kotlin/net/thunderbird/core/file/FileManager.kt new file mode 100644 index 0000000000000000000000000000000000000000..4f214653ef6eeeced40b37f71f0fa68b5df9cded --- /dev/null +++ b/core/file/src/commonMain/kotlin/net/thunderbird/core/file/FileManager.kt @@ -0,0 +1,18 @@ +package net.thunderbird.core.file + +import com.eygraber.uri.Uri +import net.thunderbird.core.outcome.Outcome + +/** + * File manager for common file operations. + */ +interface FileManager { + /** + * Copy data from [sourceUri] to [destinationUri]. + * + * @param sourceUri The [Uri] of the source file. + * @param destinationUri The [Uri] of the destination file. + * @return [Outcome] with [Unit] on success or [FileOperationError] on failure. + */ + suspend fun copy(sourceUri: Uri, destinationUri: Uri): Outcome +} diff --git a/core/file/src/commonMain/kotlin/net/thunderbird/core/file/FileOperationError.kt b/core/file/src/commonMain/kotlin/net/thunderbird/core/file/FileOperationError.kt new file mode 100644 index 0000000000000000000000000000000000000000..6b15604d36fe024b91dc34a24b445c772546c266 --- /dev/null +++ b/core/file/src/commonMain/kotlin/net/thunderbird/core/file/FileOperationError.kt @@ -0,0 +1,20 @@ +package net.thunderbird.core.file + +import com.eygraber.uri.Uri + +/** + * Common file operation errors. + */ +sealed interface FileOperationError { + /** Endpoint couldn't be opened or accessed. */ + data class Unavailable(val uri: Uri, val message: String? = null) : FileOperationError + + /** Failed while reading from the source. */ + data class ReadFailed(val uri: Uri, val message: String? = null) : FileOperationError + + /** Failed while writing to the destination. */ + data class WriteFailed(val uri: Uri, val message: String? = null) : FileOperationError + + /** Fallback when the error type can't be determined. */ + data class Unknown(val message: String? = null) : FileOperationError +} diff --git a/core/file/src/commonMain/kotlin/net/thunderbird/core/file/FileSystemManager.kt b/core/file/src/commonMain/kotlin/net/thunderbird/core/file/FileSystemManager.kt new file mode 100644 index 0000000000000000000000000000000000000000..f37f0fa3b5996de9b8cc9394a4abb9c03149d374 --- /dev/null +++ b/core/file/src/commonMain/kotlin/net/thunderbird/core/file/FileSystemManager.kt @@ -0,0 +1,31 @@ +package net.thunderbird.core.file + +import com.eygraber.uri.Uri +import kotlinx.io.RawSink +import kotlinx.io.RawSource + +/** + * An interface for file system operations that are platform-specific. + */ +interface FileSystemManager { + /** + * Opens a sink for writing to a URI. + * + * Implementations must honor the requested [mode]: + * - [WriteMode.Truncate]: overwrite existing content (truncate) or create if missing + * - [WriteMode.Append]: append to existing content or create if missing + * + * @param uri The URI to open a sink for + * @param mode The write mode (truncate/append), defaults to [WriteMode.Truncate] + * @return A sink for writing to the URI, or null if the URI couldn't be opened + */ + fun openSink(uri: Uri, mode: WriteMode = WriteMode.Truncate): RawSink? + + /** + * Opens a source for reading from a URI. + * + * @param uri The URI to open a source for + * @return A source for reading from the URI, or null if the URI couldn't be opened + */ + fun openSource(uri: Uri): RawSource? +} diff --git a/core/file/src/commonMain/kotlin/net/thunderbird/core/file/WriteMode.kt b/core/file/src/commonMain/kotlin/net/thunderbird/core/file/WriteMode.kt new file mode 100644 index 0000000000000000000000000000000000000000..1d6f0a7f6894f7847cb11cd249cf529a00aa0d47 --- /dev/null +++ b/core/file/src/commonMain/kotlin/net/thunderbird/core/file/WriteMode.kt @@ -0,0 +1,12 @@ +package net.thunderbird.core.file + +/** + * Indicates how a sink should be opened for writing. + * + * - [Truncate]: Overwrite existing content or create if missing + * - [Append]: Append to existing content or create if missing + */ +enum class WriteMode { + Truncate, + Append, +} diff --git a/core/file/src/commonMain/kotlin/net/thunderbird/core/file/command/CopyCommand.kt b/core/file/src/commonMain/kotlin/net/thunderbird/core/file/command/CopyCommand.kt new file mode 100644 index 0000000000000000000000000000000000000000..bdfd624cf185883002eb9342802eed3f2885cd6c --- /dev/null +++ b/core/file/src/commonMain/kotlin/net/thunderbird/core/file/command/CopyCommand.kt @@ -0,0 +1,64 @@ +package net.thunderbird.core.file.command + +import com.eygraber.uri.Uri +import kotlinx.io.Buffer +import net.thunderbird.core.file.FileOperationError +import net.thunderbird.core.file.FileSystemManager +import net.thunderbird.core.file.WriteMode +import net.thunderbird.core.outcome.Outcome + +/** + * Copies data from [sourceUri] to [destinationUri] using buffered I/O. + */ +internal class CopyCommand( + private val sourceUri: Uri, + private val destinationUri: Uri, +) : FileCommand { + override suspend fun invoke(fs: FileSystemManager): Outcome { + // Open endpoints + val source = fs.openSource(sourceUri) + ?: return Outcome.Failure( + FileOperationError.Unavailable(sourceUri, "Unable to open source: $sourceUri"), + ) + val sink = fs.openSink(destinationUri, WriteMode.Truncate) + ?: return Outcome.Failure( + FileOperationError.Unavailable(destinationUri, "Unable to open destination: $destinationUri"), + ) + + return try { + val buffer = Buffer() + while (true) { + val read = try { + source.readAtMostTo(buffer, BUFFER_SIZE) + } catch (e: Exception) { + return Outcome.Failure(FileOperationError.ReadFailed(sourceUri, e.message), cause = e) + } + if (read <= 0L) break + try { + sink.write(buffer, read) + } catch (e: Exception) { + return Outcome.Failure(FileOperationError.WriteFailed(destinationUri, e.message), cause = e) + } + } + try { + sink.flush() + } catch (e: Exception) { + return Outcome.Failure(FileOperationError.WriteFailed(destinationUri, e.message), cause = e) + } + Outcome.Success(Unit) + } catch (e: Exception) { + Outcome.Failure(FileOperationError.Unknown(e.message), cause = e) + } finally { + try { + source.close() + } catch (_: Exception) {} + try { + sink.close() + } catch (_: Exception) {} + } + } + + private companion object { + const val BUFFER_SIZE = 8_192L + } +} diff --git a/core/file/src/commonMain/kotlin/net/thunderbird/core/file/command/FileCommand.kt b/core/file/src/commonMain/kotlin/net/thunderbird/core/file/command/FileCommand.kt new file mode 100644 index 0000000000000000000000000000000000000000..69f26cfb6f63f875e997019712a623db79af4def --- /dev/null +++ b/core/file/src/commonMain/kotlin/net/thunderbird/core/file/command/FileCommand.kt @@ -0,0 +1,14 @@ +package net.thunderbird.core.file.command + +import net.thunderbird.core.file.FileOperationError +import net.thunderbird.core.file.FileSystemManager +import net.thunderbird.core.outcome.Outcome + +/** + * A command that performs a file operation using the provided [FileSystemManager]. + * + * @param T The type of the result produced by the command. + */ +internal fun interface FileCommand { + suspend operator fun invoke(fs: FileSystemManager): Outcome +} diff --git a/core/file/src/commonTest/kotlin/net/thunderbird/core/file/FakeFileSystemManager.kt b/core/file/src/commonTest/kotlin/net/thunderbird/core/file/FakeFileSystemManager.kt new file mode 100644 index 0000000000000000000000000000000000000000..ff61e3f50bb7c3b6d5c116cd1056312f4b3e19aa --- /dev/null +++ b/core/file/src/commonTest/kotlin/net/thunderbird/core/file/FakeFileSystemManager.kt @@ -0,0 +1,68 @@ +package net.thunderbird.core.file + +import com.eygraber.uri.Uri +import kotlinx.io.Buffer +import kotlinx.io.RawSink +import kotlinx.io.RawSource + +/** + * In-memory fake implementation of FileSystemManager for common tests. + * Stores data in a simple map keyed by URI string. + */ +class FakeFileSystemManager : FileSystemManager { + + private val storage = mutableMapOf() + + override fun openSink(uri: Uri, mode: WriteMode): RawSink? { + val key = uri.toString() + return object : RawSink { + private val collected = mutableListOf().apply { + if (mode == WriteMode.Append) { + storage[key]?.forEach { add(it) } + } + } + + override fun write(source: Buffer, byteCount: Long) { + // Read exactly byteCount bytes from source and collect + val count = byteCount.toInt() + repeat(count) { + if (source.size <= 0L) return + collected += source.readByte() + } + } + + override fun flush() { + storage[key] = collected.toByteArray() + } + + override fun close() { + // ensure data is stored + flush() + } + } + } + + override fun openSource(uri: Uri): RawSource? { + val key = uri.toString() + val bytes = storage[key] ?: return null + return object : RawSource { + private val buffer = Buffer().apply { write(bytes) } + override fun readAtMostTo(sink: Buffer, byteCount: Long): Long { + val toRead = minOf(byteCount, buffer.size) + if (toRead <= 0L) return 0L + sink.write(buffer, toRead) + return toRead + } + + override fun close() { + // no-op + } + } + } + + fun put(uriString: String, content: ByteArray) { + storage[uriString] = content + } + + fun get(uriString: String): ByteArray? = storage[uriString] +} diff --git a/core/file/src/commonTest/kotlin/net/thunderbird/core/file/command/CopyCommandTest.kt b/core/file/src/commonTest/kotlin/net/thunderbird/core/file/command/CopyCommandTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..79b3e68594e774842ef5cb04a728cdc3101627ad --- /dev/null +++ b/core/file/src/commonTest/kotlin/net/thunderbird/core/file/command/CopyCommandTest.kt @@ -0,0 +1,44 @@ +package net.thunderbird.core.file.command + +import assertk.assertThat +import assertk.assertions.isEqualTo +import com.eygraber.uri.toKmpUri +import kotlin.test.Test +import kotlinx.coroutines.test.runTest +import net.thunderbird.core.file.FakeFileSystemManager +import net.thunderbird.core.file.FileOperationError +import net.thunderbird.core.outcome.Outcome + +class CopyCommandTest { + + private val fs = FakeFileSystemManager() + private val testSubject = CopyCommand( + sourceUri = "mem://source".toKmpUri(), + destinationUri = "mem://dest".toKmpUri(), + ) + + @Test + fun `execute should copy bytes from source to destination`() = runTest { + // Arrange + val content = "Thunderbird common copy test".encodeToByteArray() + fs.put("mem://source", content) + + // Act + val result = testSubject(fs) + + // Assert + assertThat(result.isSuccess).isEqualTo(true) + assertThat(fs.get("mem://dest")?.decodeToString()).isEqualTo("Thunderbird common copy test") + } + + @Test + fun `execute should fail when source cannot be opened`() = runTest { + // Arrange - no source preloaded + + // Act + val result = testSubject(fs) + + // Assert + assertThat(result is Outcome.Failure).isEqualTo(true) + } +} diff --git a/core/file/src/jvmMain/kotlin/net/thunderbird/core/file/JvmFileSystemManager.kt b/core/file/src/jvmMain/kotlin/net/thunderbird/core/file/JvmFileSystemManager.kt new file mode 100644 index 0000000000000000000000000000000000000000..e5e2e3ce58f774052f9608ffaa375479bba68f8f --- /dev/null +++ b/core/file/src/jvmMain/kotlin/net/thunderbird/core/file/JvmFileSystemManager.kt @@ -0,0 +1,41 @@ +package net.thunderbird.core.file + +import com.eygraber.uri.Uri +import com.eygraber.uri.toURI +import java.io.File +import java.io.FileInputStream +import java.io.FileOutputStream +import kotlinx.io.RawSink +import kotlinx.io.RawSource +import kotlinx.io.asSink +import kotlinx.io.asSource + +/** + * JVM implementation of [FileSystemManager] using java.io streams. + */ +class JvmFileSystemManager : FileSystemManager { + override fun openSink(uri: Uri, mode: WriteMode): RawSink? { + // Only support simple file paths for JVM implementation + return try { + val file = File(uri.toURI()) + // create parent directories if necessary + file.parentFile?.mkdirs() + val append = when (mode) { + WriteMode.Truncate -> false + WriteMode.Append -> true + } + FileOutputStream(file, append).asSink() + } catch (_: Throwable) { + null + } + } + + override fun openSource(uri: Uri): RawSource? { + return try { + val file = File(uri.toURI()) + FileInputStream(file).asSource() + } catch (_: Throwable) { + null + } + } +} diff --git a/core/file/src/jvmTest/kotlin/net/thunderbird/core/file/JvmFileSystemManagerTest.kt b/core/file/src/jvmTest/kotlin/net/thunderbird/core/file/JvmFileSystemManagerTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..596272f21fd117aa37d51515696c96fb7b683633 --- /dev/null +++ b/core/file/src/jvmTest/kotlin/net/thunderbird/core/file/JvmFileSystemManagerTest.kt @@ -0,0 +1,125 @@ +package net.thunderbird.core.file + +import assertk.assertThat +import assertk.assertions.isEqualTo +import com.eygraber.uri.Uri +import java.io.File +import kotlinx.io.Buffer +import org.junit.Rule +import org.junit.Test +import org.junit.rules.TemporaryFolder + +class JvmFileSystemManagerTest { + + private val testSubject = JvmFileSystemManager() + + @JvmField + @Rule + val folder = TemporaryFolder() + + @Test + fun `openSink and openSource should write and read file content roundtrip`() { + // Arrange + val tempFile: File = folder.newFile("tb-file-fs-test.txt") + val testText = "Hello Thunderbird!" + val uri = Uri.parse(tempFile.toURI().toString()) + val sink = checkNotNull(testSubject.openSink(uri)) + + // Act + val writeBuffer = Buffer().apply { write(testText.encodeToByteArray()) } + sink.write(writeBuffer, writeBuffer.size) + sink.flush() + sink.close() + + val source = checkNotNull(testSubject.openSource(uri)) + val readBuffer = Buffer() + source.readAtMostTo(readBuffer, 1024) + val bytes = ByteArray(readBuffer.size.toInt()) + for (i in bytes.indices) { + bytes[i] = readBuffer.readByte() + } + val result = bytes.decodeToString() + source.close() + + // Assert + assertThat(result).isEqualTo(testText) + } + + @Test + fun `openSink with Append should append to existing content`() { + // Arrange + val tempFile: File = folder.newFile("tb-file-fs-append.txt") + val uri = Uri.parse(tempFile.toURI().toString()) + val initial = "Hello" + val extra = " World" + + // Write initial content (truncate by default) + run { + val sink = checkNotNull(testSubject.openSink(uri)) + val buf = Buffer().apply { write(initial.encodeToByteArray()) } + sink.write(buf, buf.size) + sink.flush() + sink.close() + } + + // Append extra content + run { + val sink = checkNotNull(testSubject.openSink(uri, WriteMode.Append)) + val buf = Buffer().apply { write(extra.encodeToByteArray()) } + sink.write(buf, buf.size) + sink.flush() + sink.close() + } + + // Read back + val source = checkNotNull(testSubject.openSource(uri)) + val readBuffer = Buffer() + source.readAtMostTo(readBuffer, 1024) + val bytes = ByteArray(readBuffer.size.toInt()) + repeat(bytes.size) { i -> bytes[i] = readBuffer.readByte() } + val result = bytes.decodeToString() + source.close() + + // Assert + assertThat(result).isEqualTo(initial + extra) + } + + @Test + fun `openSink with Truncate should overwrite existing content`() { + // Arrange + val tempFile: File = folder.newFile("tb-file-fs-truncate.txt") + val uri = Uri.parse(tempFile.toURI().toString()) + val first = "First" + val second = "Second" + + // Write first content + run { + val sink = checkNotNull(testSubject.openSink(uri, WriteMode.Truncate)) + val buf = Buffer().apply { write(first.encodeToByteArray()) } + sink.write(buf, buf.size) + sink.flush() + sink.close() + } + + // Overwrite with second content + run { + val sink = checkNotNull(testSubject.openSink(uri, WriteMode.Truncate)) + val buf = Buffer().apply { write(second.encodeToByteArray()) } + sink.write(buf, buf.size) + sink.flush() + sink.close() + } + + // Read back + val source = checkNotNull(testSubject.openSource(uri)) + val readBuffer = Buffer() + source.readAtMostTo(readBuffer, 1024) + val bytes = ByteArray(readBuffer.size.toInt()) + repeat(bytes.size) { i -> bytes[i] = readBuffer.readByte() } + val result = bytes.decodeToString() + source.close() + + // Assert + assertThat(result).isEqualTo(second) + } +} diff --git a/core/logging/impl-file/build.gradle.kts b/core/logging/impl-file/build.gradle.kts index cc2a55ff65bde9f7d2fdcb2aaa2738c6f983e554..0a9c444bf11a62d3535a4710666052e2d4642aaa 100644 --- a/core/logging/impl-file/build.gradle.kts +++ b/core/logging/impl-file/build.gradle.kts @@ -9,8 +9,15 @@ android { kotlin { sourceSets { commonMain.dependencies { - implementation(libs.kotlinx.io.core) implementation(projects.core.logging.api) + implementation(projects.core.file) + implementation(projects.core.outcome) + + implementation(libs.kotlinx.io.core) + implementation(libs.uri) + } + androidUnitTest.dependencies { + implementation(libs.robolectric) } } } diff --git a/core/logging/impl-file/src/androidMain/kotlin/net/thunderbird/core/logging/file/AndroidFileLogSink.kt b/core/logging/impl-file/src/androidMain/kotlin/net/thunderbird/core/logging/file/AndroidFileLogSink.kt index df564228c954a18e6ce6a8c53561f984ca7311e9..7e4bc0fe1433d2b6dcefd1b4aed16821a78402cf 100644 --- a/core/logging/impl-file/src/androidMain/kotlin/net/thunderbird/core/logging/file/AndroidFileLogSink.kt +++ b/core/logging/impl-file/src/androidMain/kotlin/net/thunderbird/core/logging/file/AndroidFileLogSink.kt @@ -1,7 +1,9 @@ package net.thunderbird.core.logging.file +import androidx.core.net.toUri +import com.eygraber.uri.Uri +import com.eygraber.uri.toKmpUri import java.io.File -import java.io.FileInputStream import java.io.FileOutputStream import kotlin.coroutines.CoroutineContext import kotlin.time.ExperimentalTime @@ -16,19 +18,19 @@ import kotlinx.datetime.LocalDateTime import kotlinx.datetime.TimeZone import kotlinx.datetime.toLocalDateTime import kotlinx.io.Buffer -import kotlinx.io.RawSink import kotlinx.io.asSink +import net.thunderbird.core.file.FileManager import net.thunderbird.core.logging.LogEvent import net.thunderbird.core.logging.LogLevel +import net.thunderbird.core.outcome.Outcome -private const val BUFFER_SIZE = 8192 // 8KB buffer size private const val LOG_BUFFER_COUNT = 4 open class AndroidFileLogSink( override val level: LogLevel, fileName: String, fileLocation: String, - private val fileSystemManager: FileSystemManager, + private val fileManager: FileManager, coroutineContext: CoroutineContext = Dispatchers.IO, ) : FileLogSink { @@ -93,14 +95,18 @@ open class AndroidFileLogSink( } } - override suspend fun export(uriString: String) { + override suspend fun export(uri: Uri) { if (accumulatedLogs.isNotEmpty()) { writeToLogFile() } - val sink = fileSystemManager.openSink(uriString, "wt") - ?: error("Error opening contentUri for writing") - copyInternalFileToExternal(sink) + val sourceUri = logFile.toUri().toKmpUri() + val result = fileManager.copy(sourceUri = sourceUri, destinationUri = uri) + if (result is Outcome.Failure) { + error( + "Error copying log to destination: ${result.error}", + ) + } // Clear the log file after export val outputStream = FileOutputStream(logFile) @@ -116,25 +122,4 @@ open class AndroidFileLogSink( outputStream.close() } } - - private fun copyInternalFileToExternal(sink: RawSink) { - val inputStream = FileInputStream(logFile) - - try { - val buffer = Buffer() - val byteArray = ByteArray(BUFFER_SIZE) - var bytesRead: Int - - while (inputStream.read(byteArray).also { bytesRead = it } != -1) { - buffer.write(byteArray, 0, bytesRead) - sink.write(buffer, buffer.size) - buffer.clear() - } - - sink.flush() - } finally { - inputStream.close() - sink.close() - } - } } diff --git a/core/logging/impl-file/src/androidMain/kotlin/net/thunderbird/core/logging/file/AndroidFileSystemManager.kt b/core/logging/impl-file/src/androidMain/kotlin/net/thunderbird/core/logging/file/AndroidFileSystemManager.kt deleted file mode 100644 index fe61e2ec87c9129a480c7de59fb587e4e94fc92b..0000000000000000000000000000000000000000 --- a/core/logging/impl-file/src/androidMain/kotlin/net/thunderbird/core/logging/file/AndroidFileSystemManager.kt +++ /dev/null @@ -1,19 +0,0 @@ -package net.thunderbird.core.logging.file - -import android.content.ContentResolver -import android.net.Uri -import androidx.core.net.toUri -import kotlinx.io.RawSink -import kotlinx.io.asSink - -/** - * Android implementation of [FileSystemManager] that uses [ContentResolver] to perform file operations. - */ -class AndroidFileSystemManager( - private val contentResolver: ContentResolver, -) : FileSystemManager { - override fun openSink(uriString: String, mode: String): RawSink? { - val uri: Uri = uriString.toUri() - return contentResolver.openOutputStream(uri, mode)?.asSink() - } -} diff --git a/core/logging/impl-file/src/androidMain/kotlin/net/thunderbird/core/logging/file/FileLogSink.android.kt b/core/logging/impl-file/src/androidMain/kotlin/net/thunderbird/core/logging/file/FileLogSink.android.kt index dd131394a8fe273e5d82ef055490ce8e233bea46..2726c5c715e4439d70f0fe4014a7c69e08729b70 100644 --- a/core/logging/impl-file/src/androidMain/kotlin/net/thunderbird/core/logging/file/FileLogSink.android.kt +++ b/core/logging/impl-file/src/androidMain/kotlin/net/thunderbird/core/logging/file/FileLogSink.android.kt @@ -1,12 +1,18 @@ package net.thunderbird.core.logging.file +import net.thunderbird.core.file.FileManager import net.thunderbird.core.logging.LogLevel actual fun FileLogSink( level: LogLevel, fileName: String, fileLocation: String, - fileSystemManager: FileSystemManager, + fileManager: FileManager, ): FileLogSink { - return AndroidFileLogSink(level, fileName, fileLocation, fileSystemManager) + return AndroidFileLogSink( + level = level, + fileName = fileName, + fileLocation = fileLocation, + fileManager = fileManager, + ) } diff --git a/core/logging/impl-file/src/androidUnitTest/kotlin/net/thunderbird/core/logging/file/AndroidFileLogSinkTest.android.kt b/core/logging/impl-file/src/androidUnitTest/kotlin/net/thunderbird/core/logging/file/AndroidFileLogSinkTest.android.kt index 60674583cfe92f2a38e22a865cdab134b7708f3e..9407c624ff6907e6412a11abc54017e3e761896e 100644 --- a/core/logging/impl-file/src/androidUnitTest/kotlin/net/thunderbird/core/logging/file/AndroidFileLogSinkTest.android.kt +++ b/core/logging/impl-file/src/androidUnitTest/kotlin/net/thunderbird/core/logging/file/AndroidFileLogSinkTest.android.kt @@ -3,6 +3,7 @@ package net.thunderbird.core.logging.file import assertk.assertThat import assertk.assertions.isEqualTo import assertk.assertions.isNotNull +import com.eygraber.uri.toKmpUri import java.io.File import kotlin.test.Test import kotlin.time.ExperimentalTime @@ -18,8 +19,13 @@ import net.thunderbird.core.logging.LogLevel import org.junit.Before import org.junit.Rule import org.junit.rules.TemporaryFolder +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config @OptIn(ExperimentalCoroutinesApi::class) +@RunWith(RobolectricTestRunner::class) +@Config(manifest = Config.NONE) class AndroidFileLogSinkTest { @JvmField @@ -29,19 +35,19 @@ class AndroidFileLogSinkTest { private val initialTimestamp = 1234567890L private lateinit var logFile: File private lateinit var fileLocation: String - private lateinit var fileManager: FakeFileSystemManager + private lateinit var fileManager: FakeFileManager private lateinit var testSubject: AndroidFileLogSink @Before fun setUp() { fileLocation = folder.newFolder().absolutePath logFile = File(fileLocation, "test_log.txt") - fileManager = FakeFileSystemManager() + fileManager = FakeFileManager() testSubject = AndroidFileLogSink( level = LogLevel.INFO, fileName = "test_log", fileLocation = fileLocation, - fileSystemManager = fileManager, + fileManager = fileManager, coroutineContext = UnconfinedTestDispatcher(), ) } @@ -137,7 +143,7 @@ class AndroidFileLogSinkTest { runBlocking { // Act testSubject.flushAndCloseBuffer() - val exportUri = "content://test/export.txt" + val exportUri = "content://test/export.txt".toKmpUri() testSubject.export(exportUri) } @@ -182,7 +188,7 @@ class AndroidFileLogSinkTest { assertThat(logFile.readText()) .isEqualTo(logString1) runBlocking { - val exportUri = "content://test/export.txt" + val exportUri = "content://test/export.txt".toKmpUri() testSubject.export(exportUri) } diff --git a/core/logging/impl-file/src/androidUnitTest/kotlin/net/thunderbird/core/logging/file/FakeFileManager.kt b/core/logging/impl-file/src/androidUnitTest/kotlin/net/thunderbird/core/logging/file/FakeFileManager.kt new file mode 100644 index 0000000000000000000000000000000000000000..ccdd21359cbfb4c7ffd44b2017b3227e2bc059cd --- /dev/null +++ b/core/logging/impl-file/src/androidUnitTest/kotlin/net/thunderbird/core/logging/file/FakeFileManager.kt @@ -0,0 +1,35 @@ +package net.thunderbird.core.logging.file + +import com.eygraber.uri.Uri +import com.eygraber.uri.toAndroidUri +import java.io.File +import net.thunderbird.core.file.FileManager +import net.thunderbird.core.file.FileOperationError +import net.thunderbird.core.outcome.Outcome + +/** + * Fake FileManager that captures content copied from a local file source URI. + */ +class FakeFileManager : FileManager { + var exportedContent: String? = null + + override suspend fun copy( + sourceUri: Uri, + destinationUri: Uri, + ): Outcome { + return try { + val androidUri = sourceUri.toAndroidUri() + val content = when (androidUri.scheme) { + "file" -> { + val path = requireNotNull(androidUri.path) { "File URI without path: $androidUri" } + File(path).readText(Charsets.UTF_8) + } + else -> error("Unsupported scheme for FakeFileManager source: ${androidUri.scheme}") + } + exportedContent = content + Outcome.Success(Unit) + } catch (t: Throwable) { + Outcome.Failure(FileOperationError.Unknown(t.message), cause = t) + } + } +} diff --git a/core/logging/impl-file/src/androidUnitTest/kotlin/net/thunderbird/core/logging/file/FakeFileSystemManager.kt b/core/logging/impl-file/src/androidUnitTest/kotlin/net/thunderbird/core/logging/file/FakeFileSystemManager.kt deleted file mode 100644 index cdd9e18a468c4105fafa0586eb8b0f3f5e219f2d..0000000000000000000000000000000000000000 --- a/core/logging/impl-file/src/androidUnitTest/kotlin/net/thunderbird/core/logging/file/FakeFileSystemManager.kt +++ /dev/null @@ -1,32 +0,0 @@ -package net.thunderbird.core.logging.file - -import java.io.ByteArrayOutputStream -import java.nio.charset.StandardCharsets -import kotlinx.io.Buffer -import kotlinx.io.RawSink - -class FakeFileSystemManager : FileSystemManager { - - var exportedContent: String? = null - private val outputStream = ByteArrayOutputStream() - - override fun openSink(uriString: String, mode: String): RawSink? { - return object : RawSink { - override fun write(source: Buffer, byteCount: Long) { - val bytes = ByteArray(byteCount.toInt()) - - for (i in 0 until byteCount.toInt()) { - bytes[i] = source.readByte() - } - - outputStream.write(bytes) - - exportedContent = String(outputStream.toByteArray(), StandardCharsets.UTF_8) - } - - override fun flush() = Unit - - override fun close() = Unit - } - } -} diff --git a/core/logging/impl-file/src/commonMain/kotlin/net/thunderbird/core/logging/file/FileLogSink.kt b/core/logging/impl-file/src/commonMain/kotlin/net/thunderbird/core/logging/file/FileLogSink.kt index 1a368dd26fd59c7181472a507f7aa67b811e05f1..9fca3b9dbe7df740d0f3e92abc45a359694a3b90 100644 --- a/core/logging/impl-file/src/commonMain/kotlin/net/thunderbird/core/logging/file/FileLogSink.kt +++ b/core/logging/impl-file/src/commonMain/kotlin/net/thunderbird/core/logging/file/FileLogSink.kt @@ -1,15 +1,17 @@ package net.thunderbird.core.logging.file +import com.eygraber.uri.Uri +import net.thunderbird.core.file.FileManager import net.thunderbird.core.logging.LogLevel import net.thunderbird.core.logging.LogSink interface FileLogSink : LogSink { /** * Exports from the logging method to the requested external file - * @param uriString The [String] for the URI to export the log to + * @param uri The [String] for the URI to export the log to * **/ - suspend fun export(uriString: String) + suspend fun export(uri: Uri) /** * On a crash or close, flushes buffer to file fo avoid log loss @@ -26,11 +28,12 @@ interface FileLogSink : LogSink { * @param level The minimum [LogLevel] for messages to be logged. * @param fileName The [String] fileName to log to * @param fileLocation The [String] fileLocation for the log file - * @param fileSystemManager The [FileSystemManager] abstraction for opening the file stream + * @param fileManager The [FileManager] to handle file operations + * @return A [FileLogSink] instance for logging to a file. */ expect fun FileLogSink( level: LogLevel, fileName: String, fileLocation: String, - fileSystemManager: FileSystemManager, + fileManager: FileManager, ): FileLogSink diff --git a/core/logging/impl-file/src/commonMain/kotlin/net/thunderbird/core/logging/file/FileSystemManager.kt b/core/logging/impl-file/src/commonMain/kotlin/net/thunderbird/core/logging/file/FileSystemManager.kt deleted file mode 100644 index aaca95a03dce3c9725ddc1438dca3b12ad9f23a5..0000000000000000000000000000000000000000 --- a/core/logging/impl-file/src/commonMain/kotlin/net/thunderbird/core/logging/file/FileSystemManager.kt +++ /dev/null @@ -1,17 +0,0 @@ -package net.thunderbird.core.logging.file - -import kotlinx.io.RawSink - -/** - * An interface for file system operations that are platform-specific. - */ -interface FileSystemManager { - /** - * Opens a sink for writing to a URI. - * - * @param uriString The URI string to open a sink for - * @param mode The mode to open the sink in (e.g., "wt" for write text) - * @return A sink for writing to the URI, or null if the URI couldn't be opened - */ - fun openSink(uriString: String, mode: String): RawSink? -} diff --git a/core/logging/impl-file/src/jvmMain/kotlin/net/thunderbird/core/logging/file/FileLogSink.jvm.kt b/core/logging/impl-file/src/jvmMain/kotlin/net/thunderbird/core/logging/file/FileLogSink.jvm.kt index 2ceb50437deef3a1da3b490e90853d355b002ed2..ae960a83959ba834420a956513516bb914b08708 100644 --- a/core/logging/impl-file/src/jvmMain/kotlin/net/thunderbird/core/logging/file/FileLogSink.jvm.kt +++ b/core/logging/impl-file/src/jvmMain/kotlin/net/thunderbird/core/logging/file/FileLogSink.jvm.kt @@ -1,20 +1,13 @@ package net.thunderbird.core.logging.file +import net.thunderbird.core.file.FileManager import net.thunderbird.core.logging.LogLevel -/** - * A [LogSink] implementation that logs messages to a specified internal file. - * - * This sink uses the platform-specific implementations to handle logging. - * - * @param level The minimum [LogLevel] for messages to be logged. - * @param fileName The [String] fileName to log to - */ actual fun FileLogSink( level: LogLevel, fileName: String, fileLocation: String, - fileSystemManager: FileSystemManager, + fileManager: FileManager, ): FileLogSink { return JvmFileLogSink(level, fileName, fileLocation) } diff --git a/core/logging/impl-file/src/jvmMain/kotlin/net/thunderbird/core/logging/file/JvmFileLogSink.kt b/core/logging/impl-file/src/jvmMain/kotlin/net/thunderbird/core/logging/file/JvmFileLogSink.kt index 49f27e7ce5f0fac56c301355ffa10deb420b8637..2114fb51a81fcc58230a22164913a627046f4655 100644 --- a/core/logging/impl-file/src/jvmMain/kotlin/net/thunderbird/core/logging/file/JvmFileLogSink.kt +++ b/core/logging/impl-file/src/jvmMain/kotlin/net/thunderbird/core/logging/file/JvmFileLogSink.kt @@ -1,5 +1,6 @@ package net.thunderbird.core.logging.file +import com.eygraber.uri.Uri import net.thunderbird.core.logging.LogEvent import net.thunderbird.core.logging.LogLevel @@ -14,7 +15,7 @@ internal class JvmFileLogSink( event.throwable?.printStackTrace() } - override suspend fun export(uriString: String) { + override suspend fun export(uri: Uri) { // TODO: Implementation https://github.com/thunderbird/thunderbird-android/issues/9435 } diff --git a/core/logging/impl-file/src/jvmMain/kotlin/net/thunderbird/core/logging/file/JvmFileSystemManager.kt b/core/logging/impl-file/src/jvmMain/kotlin/net/thunderbird/core/logging/file/JvmFileSystemManager.kt deleted file mode 100644 index fb3179fc358d15e72e0f3ffc98410820003c27d1..0000000000000000000000000000000000000000 --- a/core/logging/impl-file/src/jvmMain/kotlin/net/thunderbird/core/logging/file/JvmFileSystemManager.kt +++ /dev/null @@ -1,13 +0,0 @@ -package net.thunderbird.core.logging.file - -import kotlinx.io.RawSink - -/** - * Android implementation of [FileSystemManager] that uses [ContentResolver] to perform file operations. - */ -class JvmFileSystemManager() : FileSystemManager { - override fun openSink(uriString: String, mode: String): RawSink? { - // TODO: Implementation https://github.com/thunderbird/thunderbird-android/issues/9435 - return TODO("Provide the return value") - } -} diff --git a/core/preference/api/src/commonMain/kotlin/net/thunderbird/core/preference/display/visualSettings/DisplayVisualSettings.kt b/core/preference/api/src/commonMain/kotlin/net/thunderbird/core/preference/display/visualSettings/DisplayVisualSettings.kt index fd9060108de76b33eb7d40a982e113d6dddffa31..3dc3a52f897adb9346ff8e851fac47edafdd31ff 100644 --- a/core/preference/api/src/commonMain/kotlin/net/thunderbird/core/preference/display/visualSettings/DisplayVisualSettings.kt +++ b/core/preference/api/src/commonMain/kotlin/net/thunderbird/core/preference/display/visualSettings/DisplayVisualSettings.kt @@ -3,12 +3,13 @@ package net.thunderbird.core.preference.display.visualSettings const val DISPLAY_SETTINGS_DEFAULT_IS_SHOW_CONTACT_NAME = false const val DISPLAY_SETTINGS_DEFAULT_IS_SHOW_CONTACT_PICTURE = true const val DISPLAY_SETTINGS_DEFAULT_IS_CHANGE_CONTACT_NAME_COLOR = true -const val DISPLAY_SETTINGS_DEFAULT_IS_COLORIZE_MISSING_CONTACT_PICTURE = false +const val DISPLAY_SETTINGS_DEFAULT_IS_COLORIZE_MISSING_CONTACT_PICTURE = true const val DISPLAY_SETTINGS_DEFAULT_IS_USE_BACKGROUND_AS_INDICATOR = false const val DISPLAY_SETTINGS_DEFAULT_IS_USE_MESSAGE_VIEW_FIXED_WIDTH_FONT = false const val DISPLAY_SETTINGS_DEFAULT_IS_AUTO_FIT_WIDTH = true const val DISPLAY_SETTINGS_DEFAULT_IS_SHOW_ANIMATION = true const val DISPLAY_SETTINGS_DEFAULT_IS_SHOW_CORRESPONDENT_NAMES = true +const val DISPLAY_SETTINGS_DEFAULT_MESSAGE_LIST_PREVIEW_LINES = 2 data class DisplayVisualSettings( val isShowAnimations: Boolean = DISPLAY_SETTINGS_DEFAULT_IS_SHOW_ANIMATION, @@ -20,4 +21,5 @@ data class DisplayVisualSettings( val isUseBackgroundAsUnreadIndicator: Boolean = DISPLAY_SETTINGS_DEFAULT_IS_USE_BACKGROUND_AS_INDICATOR, val isUseMessageViewFixedWidthFont: Boolean = DISPLAY_SETTINGS_DEFAULT_IS_USE_MESSAGE_VIEW_FIXED_WIDTH_FONT, val isAutoFitWidth: Boolean = DISPLAY_SETTINGS_DEFAULT_IS_AUTO_FIT_WIDTH, + val messageListPreviewLines: Int = DISPLAY_SETTINGS_DEFAULT_MESSAGE_LIST_PREVIEW_LINES, ) diff --git a/core/preference/api/src/commonMain/kotlin/net/thunderbird/core/preference/display/visualSettings/DisplayVisualSettingsPreferenceManager.kt b/core/preference/api/src/commonMain/kotlin/net/thunderbird/core/preference/display/visualSettings/DisplayVisualSettingsPreferenceManager.kt index 01396769bd8f37b6dd88abe4c52bd537b6cf1948..22535fe0b3063f0f886c480cdb34de7eb5948edb 100644 --- a/core/preference/api/src/commonMain/kotlin/net/thunderbird/core/preference/display/visualSettings/DisplayVisualSettingsPreferenceManager.kt +++ b/core/preference/api/src/commonMain/kotlin/net/thunderbird/core/preference/display/visualSettings/DisplayVisualSettingsPreferenceManager.kt @@ -11,5 +11,6 @@ const val KEY_USE_BACKGROUND_AS_UNREAD_INDICATOR = "isUseBackgroundAsUnreadIndic const val KEY_MESSAGE_VIEW_FIXED_WIDTH_FONT = "messageViewFixedWidthFont" const val KEY_AUTO_FIT_WIDTH = "autofitWidth" const val KEY_SHOW_CONTACT_PICTURE = "showContactPicture" +const val KEY_MESSAGE_LIST_VIEW_PREVIEW_LINES = "messageListPreviewLines" interface DisplayVisualSettingsPreferenceManager : PreferenceManager diff --git a/core/preference/api/src/commonMain/kotlin/net/thunderbird/core/preference/notification/NotificationPreference.kt b/core/preference/api/src/commonMain/kotlin/net/thunderbird/core/preference/notification/NotificationPreference.kt index 43cc2a6a873b2b4f84890e12c3c8a6625698c191..07b660b99468731dbdb6a5ab71fad0ae1e89f081 100644 --- a/core/preference/api/src/commonMain/kotlin/net/thunderbird/core/preference/notification/NotificationPreference.kt +++ b/core/preference/api/src/commonMain/kotlin/net/thunderbird/core/preference/notification/NotificationPreference.kt @@ -3,9 +3,12 @@ package net.thunderbird.core.preference.notification const val NOTIFICATION_PREFERENCE_DEFAULT_IS_QUIET_TIME_ENABLED = false const val NOTIFICATION_PREFERENCE_DEFAULT_QUIET_TIME_STARTS = "21:00" const val NOTIFICATION_PREFERENCE_DEFAULT_QUIET_TIME_END = "7:00" +const val NOTIFICATION_PREFERENCE_DEFAULT_IS_NOTIFICATION_DURING_QUIET_TIME_ENABLED = true data class NotificationPreference( val isQuietTimeEnabled: Boolean = NOTIFICATION_PREFERENCE_DEFAULT_IS_QUIET_TIME_ENABLED, val quietTimeStarts: String = NOTIFICATION_PREFERENCE_DEFAULT_QUIET_TIME_STARTS, val quietTimeEnds: String = NOTIFICATION_PREFERENCE_DEFAULT_QUIET_TIME_END, + val isNotificationDuringQuietTimeEnabled: Boolean = + NOTIFICATION_PREFERENCE_DEFAULT_IS_NOTIFICATION_DURING_QUIET_TIME_ENABLED, ) diff --git a/core/preference/api/src/commonMain/kotlin/net/thunderbird/core/preference/notification/NotificationPreferenceManager.kt b/core/preference/api/src/commonMain/kotlin/net/thunderbird/core/preference/notification/NotificationPreferenceManager.kt index e9a402a65846f4f399112202bad2a1b3e319eef3..b28e1ab536cce9002fbfb2313a4b5f669e1df1ca 100644 --- a/core/preference/api/src/commonMain/kotlin/net/thunderbird/core/preference/notification/NotificationPreferenceManager.kt +++ b/core/preference/api/src/commonMain/kotlin/net/thunderbird/core/preference/notification/NotificationPreferenceManager.kt @@ -5,5 +5,6 @@ import net.thunderbird.core.preference.PreferenceManager const val KEY_QUIET_TIME_ENDS = "quietTimeEnds" const val KEY_QUIET_TIME_STARTS = "quietTimeStarts" const val KEY_QUIET_TIME_ENABLED = "quietTimeEnabled" +const val KEY_NOTIFICATION_DURING_QUIET_TIME_ENABLED = "notificationDuringQuietTimeEnabled" interface NotificationPreferenceManager : PreferenceManager diff --git a/core/preference/impl/src/commonMain/kotlin/net/thunderbird/core/preference/display/visualSettings/DefaultDisplayVisualSettingsPreferenceManager.kt b/core/preference/impl/src/commonMain/kotlin/net/thunderbird/core/preference/display/visualSettings/DefaultDisplayVisualSettingsPreferenceManager.kt index 4f12c1498226a8c25c2f1811b6c42cde8b30bf41..836c70036d254e94a3c990086ed02fd03859abd4 100644 --- a/core/preference/impl/src/commonMain/kotlin/net/thunderbird/core/preference/display/visualSettings/DefaultDisplayVisualSettingsPreferenceManager.kt +++ b/core/preference/impl/src/commonMain/kotlin/net/thunderbird/core/preference/display/visualSettings/DefaultDisplayVisualSettingsPreferenceManager.kt @@ -70,6 +70,10 @@ class DefaultDisplayVisualSettingsPreferenceManager( KEY_SHOW_CONTACT_PICTURE, DISPLAY_SETTINGS_DEFAULT_IS_SHOW_CONTACT_PICTURE, ), + messageListPreviewLines = storage.getInt( + KEY_MESSAGE_LIST_VIEW_PREVIEW_LINES, + DISPLAY_SETTINGS_DEFAULT_MESSAGE_LIST_PREVIEW_LINES, + ), ) private fun writeConfig(config: DisplayVisualSettings) { @@ -103,6 +107,10 @@ class DefaultDisplayVisualSettingsPreferenceManager( KEY_SHOW_CORRESPONDENT_NAMES, config.isShowCorrespondentNames, ) + storageEditor.putInt( + KEY_MESSAGE_LIST_VIEW_PREVIEW_LINES, + config.messageListPreviewLines, + ) storageEditor.commit().also { commited -> logger.verbose(TAG) { "writeConfig: storageEditor.commit() resulted in: $commited" } } diff --git a/core/preference/impl/src/commonMain/kotlin/net/thunderbird/core/preference/notification/DefaultNotificationPreferenceManager.kt b/core/preference/impl/src/commonMain/kotlin/net/thunderbird/core/preference/notification/DefaultNotificationPreferenceManager.kt index 9549c3af62d1596ee008921d20d0e4b3fa23ddf1..96121c53ab35c2885a6c0096cba6b33ad18f995e 100644 --- a/core/preference/impl/src/commonMain/kotlin/net/thunderbird/core/preference/notification/DefaultNotificationPreferenceManager.kt +++ b/core/preference/impl/src/commonMain/kotlin/net/thunderbird/core/preference/notification/DefaultNotificationPreferenceManager.kt @@ -38,6 +38,10 @@ class DefaultNotificationPreferenceManager( key = KEY_QUIET_TIME_ENDS, defValue = NOTIFICATION_PREFERENCE_DEFAULT_QUIET_TIME_END, ), + isNotificationDuringQuietTimeEnabled = storage.getBoolean( + key = KEY_NOTIFICATION_DURING_QUIET_TIME_ENABLED, + defValue = NOTIFICATION_PREFERENCE_DEFAULT_IS_NOTIFICATION_DURING_QUIET_TIME_ENABLED, + ), ), ) @@ -54,6 +58,10 @@ class DefaultNotificationPreferenceManager( KEY_QUIET_TIME_ENABLED, config.isQuietTimeEnabled, ) + storageEditor.putBoolean( + KEY_NOTIFICATION_DURING_QUIET_TIME_ENABLED, + config.isNotificationDuringQuietTimeEnabled, + ) storageEditor.commit().also { commited -> logger.verbose(TAG) { "writeConfig: storageEditor.commit() resulted in: $commited" } } diff --git a/core/ui/compose/common/build.gradle.kts b/core/ui/compose/common/build.gradle.kts index c64b04956f28af7ec64b4688c272b45f6577e74a..931e1048718a25839a46b986f56e26a848c66a40 100644 --- a/core/ui/compose/common/build.gradle.kts +++ b/core/ui/compose/common/build.gradle.kts @@ -5,6 +5,12 @@ plugins { android { namespace = "app.k9mail.core.ui.compose.common" resourcePrefix = "core_ui_common_" + + testOptions { + unitTests { + isIncludeAndroidResources = true + } + } } dependencies { diff --git a/core/ui/compose/designsystem/build.gradle.kts b/core/ui/compose/designsystem/build.gradle.kts index 664748c56e1548b8437a9f0c106dac9ede576474..5a4b42306a492a7167cb17f08a4721e67acc3a35 100644 --- a/core/ui/compose/designsystem/build.gradle.kts +++ b/core/ui/compose/designsystem/build.gradle.kts @@ -6,6 +6,12 @@ plugins { android { namespace = "app.k9mail.core.ui.compose.designsystem" resourcePrefix = "designsystem_" + + testOptions { + unitTests { + isIncludeAndroidResources = true + } + } } dependencies { diff --git a/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/atom/icon/Icons.kt b/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/atom/icon/Icons.kt index 4717174e30706dffa4a82760fddb38a5d8562a0b..b6cf73e696710e2ff0bc9705b54a528d583e9fb3 100644 --- a/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/atom/icon/Icons.kt +++ b/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/atom/icon/Icons.kt @@ -144,4 +144,6 @@ object Icons { val VisibilityOff: ImageVector get() = MaterialIcons.Filled.VisibilityOff } + + object DualTone } diff --git a/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/atom/text/TextBodyMedium.kt b/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/atom/text/TextBodyMedium.kt index e7bbc1b37da7c7aca1e9329fa0caca995d064a60..65a89395c4a5e88d8df273f75d63cf3bc15ef4f9 100644 --- a/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/atom/text/TextBodyMedium.kt +++ b/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/atom/text/TextBodyMedium.kt @@ -4,6 +4,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.TextLayoutResult import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import app.k9mail.core.ui.compose.theme2.MainTheme @@ -17,6 +18,7 @@ fun TextBodyMedium( textAlign: TextAlign? = null, overflow: TextOverflow = TextOverflow.Clip, maxLines: Int = Int.MAX_VALUE, + onTextLayout: (TextLayoutResult) -> Unit = {}, ) { Material3Text( text = text, @@ -26,6 +28,7 @@ fun TextBodyMedium( overflow = overflow, maxLines = maxLines, style = MainTheme.typography.bodyMedium, + onTextLayout = onTextLayout, ) } @@ -37,6 +40,7 @@ fun TextBodyMedium( textAlign: TextAlign? = null, overflow: TextOverflow = TextOverflow.Clip, maxLines: Int = Int.MAX_VALUE, + onTextLayout: (TextLayoutResult) -> Unit = {}, ) { Material3Text( text = text, @@ -46,5 +50,6 @@ fun TextBodyMedium( overflow = overflow, maxLines = maxLines, style = MainTheme.typography.bodyMedium, + onTextLayout = onTextLayout, ) } diff --git a/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/BannerInlineNotificationCard.kt b/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/BannerInlineNotificationCard.kt index 7995435ce55181a1808d40690645a64f48399f10..921bb431022da894017adc1b589aed4114fe433f 100644 --- a/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/BannerInlineNotificationCard.kt +++ b/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/BannerInlineNotificationCard.kt @@ -14,6 +14,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Shape import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.TextLayoutResult import androidx.compose.ui.text.style.TextOverflow import app.k9mail.core.ui.compose.designsystem.atom.card.CardColors import app.k9mail.core.ui.compose.designsystem.atom.card.CardOutlined @@ -54,6 +55,7 @@ internal fun BannerInlineNotificationCard( border: BorderStroke = BannerNotificationCardDefaults.errorCardBorder(), shape: Shape = BannerNotificationCardDefaults.bannerInlineShape, behaviour: BannerInlineNotificationCardBehaviour = BannerNotificationCardDefaults.bannerInlineBehaviour, + onSupportingTextOverflow: (hasVisualOverflow: Boolean) -> Unit = {}, ) { val maxLines = when (behaviour) { BannerInlineNotificationCardBehaviour.Clipped -> 2 @@ -74,6 +76,11 @@ internal fun BannerInlineNotificationCard( supportingText = supportingText, behaviour = behaviour, maxLines = maxLines, + onTextOverflow = { hasVisualOverflow -> + if (behaviour == BannerInlineNotificationCardBehaviour.Clipped) { + onSupportingTextOverflow(hasVisualOverflow) + } + }, ) }, actions = actions, @@ -186,11 +193,12 @@ private fun BannerInlineNotificationTitle( } @Composable -fun BannerInlineNotificationSupportingText( +private fun BannerInlineNotificationSupportingText( supportingText: CharSequence, behaviour: BannerInlineNotificationCardBehaviour, maxLines: Int, modifier: Modifier = Modifier, + onTextOverflow: (hasVisualOverflow: Boolean) -> Unit = {}, ) { val clippedSupportingText = remember(supportingText, behaviour) { when (behaviour) { @@ -200,12 +208,16 @@ fun BannerInlineNotificationSupportingText( else -> supportingText } } + val onTextLayout = remember<(TextLayoutResult) -> Unit>(onTextOverflow) { + { textLayoutResult -> onTextOverflow(textLayoutResult.hasVisualOverflow) } + } when (clippedSupportingText) { is String -> TextBodyMedium( text = clippedSupportingText, maxLines = maxLines, overflow = TextOverflow.Ellipsis, modifier = modifier, + onTextLayout = onTextLayout, ) is AnnotatedString -> TextBodyMedium( @@ -213,6 +225,7 @@ fun BannerInlineNotificationSupportingText( maxLines = maxLines, overflow = TextOverflow.Ellipsis, modifier = modifier, + onTextLayout = onTextLayout, ) else -> TextBodyMedium( @@ -220,6 +233,7 @@ fun BannerInlineNotificationSupportingText( maxLines = maxLines, overflow = TextOverflow.Ellipsis, modifier = modifier, + onTextLayout = onTextLayout, ) } } diff --git a/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/ErrorBannerInlineNotificationCard.kt b/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/ErrorBannerInlineNotificationCard.kt index 25bb7da9a3f092c18bedfbaae4dfb298990a2b4a..ec31b09809990b7d4c895c1cfc8d5a6ba1e373a4 100644 --- a/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/ErrorBannerInlineNotificationCard.kt +++ b/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/ErrorBannerInlineNotificationCard.kt @@ -25,6 +25,7 @@ fun ErrorBannerInlineNotificationCard( actions: @Composable RowScope.() -> Unit, modifier: Modifier = Modifier, behaviour: BannerInlineNotificationCardBehaviour = BannerNotificationCardDefaults.bannerInlineBehaviour, + onSupportingTextOverflow: (hasVisualOverflow: Boolean) -> Unit = {}, ) { BannerInlineNotificationCard( icon = { Icon(imageVector = Icons.Outlined.Report) }, @@ -35,5 +36,6 @@ fun ErrorBannerInlineNotificationCard( behaviour = behaviour, colors = BannerNotificationCardDefaults.errorCardColors(), border = BannerNotificationCardDefaults.errorCardBorder(), + onSupportingTextOverflow = onSupportingTextOverflow, ) } diff --git a/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/InfoBannerInlineNotificationCard.kt b/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/InfoBannerInlineNotificationCard.kt index e835d7d18c8c5d235e94bd2d2f42fca8164174da..4a536bfd5632ce7efcd984adaa2e6eba6ad6bd20 100644 --- a/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/InfoBannerInlineNotificationCard.kt +++ b/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/InfoBannerInlineNotificationCard.kt @@ -25,6 +25,7 @@ fun InfoBannerInlineNotificationCard( actions: @Composable RowScope.() -> Unit, modifier: Modifier = Modifier, behaviour: BannerInlineNotificationCardBehaviour = BannerNotificationCardDefaults.bannerInlineBehaviour, + onSupportingTextOverflow: (hasVisualOverflow: Boolean) -> Unit = {}, ) { BannerInlineNotificationCard( icon = { Icon(imageVector = Icons.Outlined.Info) }, @@ -35,5 +36,6 @@ fun InfoBannerInlineNotificationCard( behaviour = behaviour, colors = BannerNotificationCardDefaults.infoCardColors(), border = BannerNotificationCardDefaults.infoCardBorder(), + onSupportingTextOverflow = onSupportingTextOverflow, ) } diff --git a/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/SuccessBannerInlineNotificationCard.kt b/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/SuccessBannerInlineNotificationCard.kt index 102c7c253d76cd28d7616d38ba774a2d1a2e841c..597bb92955126990a918d9e2e2bb235358a6fcc5 100644 --- a/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/SuccessBannerInlineNotificationCard.kt +++ b/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/SuccessBannerInlineNotificationCard.kt @@ -25,6 +25,7 @@ fun SuccessBannerInlineNotificationCard( actions: @Composable RowScope.() -> Unit, modifier: Modifier = Modifier, behaviour: BannerInlineNotificationCardBehaviour = BannerNotificationCardDefaults.bannerInlineBehaviour, + onSupportingTextOverflow: (hasVisualOverflow: Boolean) -> Unit = {}, ) { BannerInlineNotificationCard( icon = { Icon(imageVector = Icons.Outlined.CheckCircle) }, @@ -35,5 +36,6 @@ fun SuccessBannerInlineNotificationCard( behaviour = behaviour, colors = BannerNotificationCardDefaults.successCardColors(), border = BannerNotificationCardDefaults.successCardBorder(), + onSupportingTextOverflow = onSupportingTextOverflow, ) } diff --git a/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/WarningBannerInlineNotificationCard.kt b/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/WarningBannerInlineNotificationCard.kt index 24cded285b5b958ad3fa978a2076506c2c56d1a6..253456f35adc91928d316a2db286e4a207e7d151 100644 --- a/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/WarningBannerInlineNotificationCard.kt +++ b/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/organism/banner/inline/WarningBannerInlineNotificationCard.kt @@ -26,6 +26,7 @@ fun WarningBannerInlineNotificationCard( actions: @Composable RowScope.() -> Unit, modifier: Modifier = Modifier, behaviour: BannerInlineNotificationCardBehaviour = BannerNotificationCardDefaults.bannerInlineBehaviour, + onSupportingTextOverflow: (hasVisualOverflow: Boolean) -> Unit = {}, ) { BannerInlineNotificationCard( icon = { Icon(imageVector = Icons.Outlined.Warning) }, @@ -36,5 +37,6 @@ fun WarningBannerInlineNotificationCard( behaviour = behaviour, colors = BannerNotificationCardDefaults.warningCardColors(), border = BannerNotificationCardDefaults.warningCardBorder(), + onSupportingTextOverflow = onSupportingTextOverflow, ) } diff --git a/core/ui/compose/designsystem/src/main/kotlin/net/thunderbird/core/ui/compose/designsystem/atom/icon/dualtone/Warning.kt b/core/ui/compose/designsystem/src/main/kotlin/net/thunderbird/core/ui/compose/designsystem/atom/icon/dualtone/Warning.kt new file mode 100644 index 0000000000000000000000000000000000000000..e5f23ba12702e511c3b55f6e85053e941e58cd8a --- /dev/null +++ b/core/ui/compose/designsystem/src/main/kotlin/net/thunderbird/core/ui/compose/designsystem/atom/icon/dualtone/Warning.kt @@ -0,0 +1,220 @@ +package net.thunderbird.core.ui.compose.designsystem.atom.icon.dualtone + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Column +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.path +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import app.k9mail.core.ui.compose.designsystem.atom.icon.Icon +import app.k9mail.core.ui.compose.designsystem.atom.icon.Icons + +@Suppress("MagicNumber", "UnusedReceiverParameter") +val Icons.DualTone.Warning: ImageVector + get() { + val current = _warningDualTone + if (current != null) return current + + return ImageVector.Builder( + name = "app.k9mail.core.ui.compose.theme2.MainTheme.WarningDualTone", + defaultWidth = 24.0.dp, + defaultHeight = 24.0.dp, + viewportWidth = 24.0f, + viewportHeight = 24.0f, + ).apply { + path( + fill = SolidColor(Color(0xFF4C4D58)), + fillAlpha = 0.2f, + strokeAlpha = 0.2f, + ) { + moveTo(x = 20.2f, y = 20.25f) + horizontalLineTo(x = 3.8f) + arcToRelative( + a = 1.5f, + b = 1.5f, + theta = 0.0f, + isMoreThanHalf = false, + isPositiveArc = true, + dx1 = -1.35f, + dy1 = -2.24f, + ) + lineToRelative(dx = 8.2f, dy = -14.24f) + arcToRelative( + a = 1.57f, + b = 1.57f, + theta = 0.0f, + isMoreThanHalf = false, + isPositiveArc = true, + dx1 = 2.7f, + dy1 = 0.0f, + ) + lineToRelative(dx = 8.2f, dy = 14.24f) + arcToRelative( + a = 1.5f, + b = 1.5f, + theta = 0.0f, + isMoreThanHalf = false, + isPositiveArc = true, + dx1 = -1.35f, + dy1 = 2.24f, + ) + } + path( + fill = SolidColor(Color(0xFF4C4D58)), + ) { + moveTo(x = 22.2f, y = 17.63f) + lineTo(x = 14.0f, y = 3.4f) + arcToRelative( + a = 2.32f, + b = 2.32f, + theta = 0.0f, + isMoreThanHalf = false, + isPositiveArc = false, + dx1 = -4.0f, + dy1 = 0.0f, + ) + lineTo(x = 1.8f, y = 17.63f) + arcToRelative( + a = 2.2f, + b = 2.2f, + theta = 0.0f, + isMoreThanHalf = false, + isPositiveArc = false, + dx1 = 0.0f, + dy1 = 2.23f, + ) + arcToRelative( + a = 2.3f, + b = 2.3f, + theta = 0.0f, + isMoreThanHalf = false, + isPositiveArc = false, + dx1 = 2.0f, + dy1 = 1.14f, + ) + horizontalLineToRelative(dx = 16.4f) + arcToRelative( + a = 2.3f, + b = 2.3f, + theta = 0.0f, + isMoreThanHalf = false, + isPositiveArc = false, + dx1 = 2.3f, + dy1 = -2.25f, + ) + arcToRelative( + a = 2.0f, + b = 2.0f, + theta = 0.0f, + isMoreThanHalf = false, + isPositiveArc = false, + dx1 = -0.3f, + dy1 = -1.12f, + ) + moveToRelative(dx = -1.3f, dy = 1.48f) + arcToRelative( + a = 0.8f, + b = 0.8f, + theta = 0.0f, + isMoreThanHalf = false, + isPositiveArc = true, + dx1 = -0.7f, + dy1 = 0.39f, + ) + horizontalLineTo(x = 3.8f) + arcToRelative( + a = 0.8f, + b = 0.8f, + theta = 0.0f, + isMoreThanHalf = false, + isPositiveArc = true, + dx1 = -0.7f, + dy1 = -0.4f, + ) + arcToRelative( + a = 0.7f, + b = 0.7f, + theta = 0.0f, + isMoreThanHalf = false, + isPositiveArc = true, + dx1 = 0.0f, + dy1 = -0.72f, + ) + lineToRelative(dx = 8.2f, dy = -14.24f) + arcToRelative( + a = 0.82f, + b = 0.82f, + theta = 0.0f, + isMoreThanHalf = false, + isPositiveArc = true, + dx1 = 1.4f, + dy1 = 0.0f, + ) + lineToRelative(dx = 8.2f, dy = 14.24f) + arcToRelative( + a = 0.7f, + b = 0.7f, + theta = 0.0f, + isMoreThanHalf = false, + isPositiveArc = true, + dx1 = 0.0f, + dy1 = 0.73f, + ) + moveToRelative(dx = -9.65f, dy = -5.61f) + verticalLineTo(y = 9.75f) + arcToRelative( + a = 0.75f, + b = 0.75f, + theta = 0.0f, + isMoreThanHalf = true, + isPositiveArc = true, + dx1 = 1.5f, + dy1 = 0.0f, + ) + verticalLineToRelative(dy = 3.75f) + arcToRelative( + a = 0.75f, + b = 0.75f, + theta = 0.0f, + isMoreThanHalf = false, + isPositiveArc = true, + dx1 = -1.5f, + dy1 = 0.0f, + ) + moveToRelative(dx = 1.88f, dy = 3.38f) + arcToRelative( + a = 1.13f, + b = 1.13f, + theta = 0.0f, + isMoreThanHalf = true, + isPositiveArc = true, + dx1 = -2.26f, + dy1 = 0.0f, + ) + arcToRelative( + a = 1.13f, + b = 1.13f, + theta = 0.0f, + isMoreThanHalf = false, + isPositiveArc = true, + dx1 = 2.26f, + dy1 = 0.0f, + ) + } + }.build().also { _warningDualTone = it } + } + +@Suppress("ObjectPropertyName") +private var _warningDualTone: ImageVector? = null + +@Preview(showBackground = true) +@Composable +private fun Preview() { + Column { + Image(imageVector = Icons.DualTone.Warning, contentDescription = null) + Icon(imageVector = Icons.DualTone.Warning, contentDescription = null, tint = Color.Red) + } +} diff --git a/core/ui/compose/designsystem/src/main/res/values-ht/strings.xml b/core/ui/compose/designsystem/src/main/res/values-ht/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/core/ui/compose/designsystem/src/main/res/values-ht/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/core/ui/compose/designsystem/src/main/res/values-kn/strings.xml b/core/ui/compose/designsystem/src/main/res/values-kn/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..55344e51920f3dcbb968d32ee2281e029d1571bf --- /dev/null +++ b/core/ui/compose/designsystem/src/main/res/values-kn/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/core/ui/compose/designsystem/src/main/res/values-mnw/strings.xml b/core/ui/compose/designsystem/src/main/res/values-mnw/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..e8e4ac678331dcfc9cccf3bef4c08e838fbdca6c --- /dev/null +++ b/core/ui/compose/designsystem/src/main/res/values-mnw/strings.xml @@ -0,0 +1,4 @@ + + + ပၞုက်လိက်ဓလုက် + diff --git a/core/ui/compose/designsystem/src/main/res/values-sl/strings.xml b/core/ui/compose/designsystem/src/main/res/values-sl/strings.xml index 23cc55b65869dcb9c9443c06b7e6f2d2812775ff..479d417967f94c72a57bb9112990c212699583a4 100644 --- a/core/ui/compose/designsystem/src/main/res/values-sl/strings.xml +++ b/core/ui/compose/designsystem/src/main/res/values-sl/strings.xml @@ -2,7 +2,7 @@ Skrij geslo Pokaži geslo - Elektronski naslov + E-poštni naslov Geslo Poskusi znova - \ No newline at end of file + diff --git a/core/ui/compose/preference/src/debug/kotlin/net/thunderbird/core/ui/compose/preference/ui/components/list/PreferenceItemColorViewPreview.kt b/core/ui/compose/preference/src/debug/kotlin/net/thunderbird/core/ui/compose/preference/ui/components/list/PreferenceItemColorViewPreview.kt deleted file mode 100644 index ee50ff30f313841298fcb7eed3d686598efd12fe..0000000000000000000000000000000000000000 --- a/core/ui/compose/preference/src/debug/kotlin/net/thunderbird/core/ui/compose/preference/ui/components/list/PreferenceItemColorViewPreview.kt +++ /dev/null @@ -1,17 +0,0 @@ -package net.thunderbird.core.ui.compose.preference.ui.components.list - -import androidx.compose.runtime.Composable -import androidx.compose.ui.tooling.preview.Preview -import app.k9mail.core.ui.compose.designsystem.PreviewWithThemes -import net.thunderbird.core.ui.compose.preference.ui.fake.FakePreferenceData - -@Composable -@Preview(showBackground = true) -internal fun PreferenceItemColorViewPreview() { - PreviewWithThemes { - PreferenceItemColorView( - preference = FakePreferenceData.colorPreference, - onClick = {}, - ) - } -} diff --git a/core/ui/compose/preference/src/debug/kotlin/net/thunderbird/core/ui/compose/preference/ui/components/list/PreferenceItemSingleChoiceCompactViewPreview.kt b/core/ui/compose/preference/src/debug/kotlin/net/thunderbird/core/ui/compose/preference/ui/components/list/PreferenceItemSingleChoiceCompactViewPreview.kt deleted file mode 100644 index c0a5b2a0239e1eae1f1d57fa3fbf696caca9a3e4..0000000000000000000000000000000000000000 --- a/core/ui/compose/preference/src/debug/kotlin/net/thunderbird/core/ui/compose/preference/ui/components/list/PreferenceItemSingleChoiceCompactViewPreview.kt +++ /dev/null @@ -1,17 +0,0 @@ -package net.thunderbird.core.ui.compose.preference.ui.components.list - -import androidx.compose.runtime.Composable -import androidx.compose.ui.tooling.preview.Preview -import app.k9mail.core.ui.compose.designsystem.PreviewWithThemes -import net.thunderbird.core.ui.compose.preference.ui.fake.FakePreferenceData - -@Composable -@Preview(showBackground = true) -internal fun PreferenceItemSingleChoiceCompactViewPreview() { - PreviewWithThemes { - PreferenceItemSingleChoiceCompactView( - preference = FakePreferenceData.singleChoiceCompactPreference, - onClick = {}, - ) - } -} diff --git a/core/ui/compose/preference/src/debug/kotlin/net/thunderbird/core/ui/compose/preference/ui/components/list/PreferenceItemSingleChoiceViewPreview.kt b/core/ui/compose/preference/src/debug/kotlin/net/thunderbird/core/ui/compose/preference/ui/components/list/PreferenceItemSingleChoiceViewPreview.kt deleted file mode 100644 index c3868d2bf6e5f577c28ac604f90ddce162d84c56..0000000000000000000000000000000000000000 --- a/core/ui/compose/preference/src/debug/kotlin/net/thunderbird/core/ui/compose/preference/ui/components/list/PreferenceItemSingleChoiceViewPreview.kt +++ /dev/null @@ -1,28 +0,0 @@ -package net.thunderbird.core.ui.compose.preference.ui.components.list - -import androidx.compose.runtime.Composable -import androidx.compose.ui.tooling.preview.Preview -import app.k9mail.core.ui.compose.designsystem.PreviewWithThemes -import net.thunderbird.core.ui.compose.preference.ui.fake.FakePreferenceData - -@Composable -@Preview(showBackground = true) -internal fun PreferenceItemSingleChoiceViewPreview() { - PreviewWithThemes { - PreferenceItemSingleChoiceView( - preference = FakePreferenceData.singleChoicePreference.copy(description = { null }), - onPreferenceChange = {}, - ) - } -} - -@Composable -@Preview(showBackground = true) -internal fun PreferenceItemSingleChoiceViewWithDescriptionPreview() { - PreviewWithThemes { - PreferenceItemSingleChoiceView( - preference = FakePreferenceData.singleChoicePreference, - onPreferenceChange = {}, - ) - } -} diff --git a/core/ui/compose/preference/src/debug/kotlin/net/thunderbird/core/ui/compose/preference/ui/components/list/PreferenceItemSwitchViewPreview.kt b/core/ui/compose/preference/src/debug/kotlin/net/thunderbird/core/ui/compose/preference/ui/components/list/PreferenceItemSwitchViewPreview.kt deleted file mode 100644 index a540d38c34dbc6aa054a8813999275908735e4fd..0000000000000000000000000000000000000000 --- a/core/ui/compose/preference/src/debug/kotlin/net/thunderbird/core/ui/compose/preference/ui/components/list/PreferenceItemSwitchViewPreview.kt +++ /dev/null @@ -1,50 +0,0 @@ -package net.thunderbird.core.ui.compose.preference.ui.components.list - -import androidx.compose.runtime.Composable -import androidx.compose.ui.tooling.preview.Preview -import app.k9mail.core.ui.compose.designsystem.PreviewWithThemes -import net.thunderbird.core.ui.compose.preference.ui.fake.FakePreferenceData - -@Composable -@Preview(showBackground = true) -internal fun Preview_Switch_On_Enabled() { - PreviewWithThemes { - PreferenceItemSwitchView( - preference = FakePreferenceData.switchPreference, - onPreferenceChange = {}, - ) - } -} - -@Composable -@Preview(showBackground = true) -internal fun Preview_Switch_Off_Enabled() { - PreviewWithThemes { - PreferenceItemSwitchView( - preference = FakePreferenceData.switchPreference.copy(value = false), - onPreferenceChange = {}, - ) - } -} - -@Composable -@Preview(showBackground = true) -internal fun Preview_Switch_On_Disabled() { - PreviewWithThemes { - PreferenceItemSwitchView( - preference = FakePreferenceData.switchPreference.copy(enabled = false), - onPreferenceChange = {}, - ) - } -} - -@Composable -@Preview(showBackground = true) -internal fun Preview_Switch_Off_Disabled() { - PreviewWithThemes { - PreferenceItemSwitchView( - preference = FakePreferenceData.switchPreference.copy(value = false, enabled = false), - onPreferenceChange = {}, - ) - } -} diff --git a/core/ui/compose/preference/src/debug/kotlin/net/thunderbird/core/ui/compose/preference/ui/components/list/PreferenceItemTextViewPreview.kt b/core/ui/compose/preference/src/debug/kotlin/net/thunderbird/core/ui/compose/preference/ui/components/list/PreferenceItemTextViewPreview.kt deleted file mode 100644 index d76833eab562840f89cb402470eddf17dd45ac54..0000000000000000000000000000000000000000 --- a/core/ui/compose/preference/src/debug/kotlin/net/thunderbird/core/ui/compose/preference/ui/components/list/PreferenceItemTextViewPreview.kt +++ /dev/null @@ -1,17 +0,0 @@ -package net.thunderbird.core.ui.compose.preference.ui.components.list - -import androidx.compose.runtime.Composable -import androidx.compose.ui.tooling.preview.Preview -import app.k9mail.core.ui.compose.designsystem.PreviewWithThemes -import net.thunderbird.core.ui.compose.preference.ui.fake.FakePreferenceData - -@Composable -@Preview(showBackground = true) -internal fun PreferenceItemTextViewPreview() { - PreviewWithThemes { - PreferenceItemTextView( - preference = FakePreferenceData.textPreference, - onClick = {}, - ) - } -} diff --git a/core/ui/compose/preference/src/debug/kotlin/net/thunderbird/core/ui/compose/preference/ui/fake/FakePreferenceData.kt b/core/ui/compose/preference/src/debug/kotlin/net/thunderbird/core/ui/compose/preference/ui/fake/FakePreferenceData.kt deleted file mode 100644 index bd6f17234d761e4236ddaed88317d4a71e3fa4d9..0000000000000000000000000000000000000000 --- a/core/ui/compose/preference/src/debug/kotlin/net/thunderbird/core/ui/compose/preference/ui/fake/FakePreferenceData.kt +++ /dev/null @@ -1,78 +0,0 @@ -package net.thunderbird.core.ui.compose.preference.ui.fake - -import app.k9mail.core.ui.compose.designsystem.atom.icon.Icons -import kotlinx.collections.immutable.persistentListOf -import net.thunderbird.core.ui.compose.preference.api.PreferenceSetting -import net.thunderbird.core.ui.compose.preference.api.PreferenceSetting.SingleChoice.Choice -import net.thunderbird.core.ui.compose.preference.api.PreferenceSetting.SingleChoiceCompact.CompactChoice - -internal object FakePreferenceData { - - val textPreference = PreferenceSetting.Text( - id = "text", - icon = { Icons.Outlined.Delete }, - title = { "Title" }, - description = { "Description" }, - value = "Value", - ) - - val colorPreference = PreferenceSetting.Color( - id = "color", - icon = { Icons.Outlined.Delete }, - title = { "Title" }, - description = { "Description" }, - value = 0xFFFF0000.toInt(), - colors = persistentListOf( - 0xFFFF0000.toInt(), - 0xFF00FF00.toInt(), - 0xFF0000FF.toInt(), - ), - ) - - private val choices = persistentListOf( - Choice("1") { "Choice 1" }, - Choice("2") { "Choice 2" }, - Choice("3") { "Choice 3" }, - ) - - val singleChoicePreference = PreferenceSetting.SingleChoice( - id = "single_choice", - title = { "Title" }, - description = { "Description" }, - value = choices[1], - options = choices, - ) - - private val compactChoices = persistentListOf( - CompactChoice("1") { "Compact Choice 1" }, - CompactChoice("2") { "Compact Choice 2" }, - CompactChoice("3") { "Compact Choice 3" }, - CompactChoice("1") { "Compact Choice 4" }, - CompactChoice("2") { "Compact Choice 5" }, - CompactChoice("3") { "Compact Choice 6" }, - ) - - val singleChoiceCompactPreference = PreferenceSetting.SingleChoiceCompact( - id = "single_choice_compact", - title = { "Title" }, - icon = { Icons.Outlined.Info }, - description = { "Description" }, - value = compactChoices[1], - options = compactChoices, - ) - - val switchPreference = PreferenceSetting.Switch( - id = "switch", - title = { "Title" }, - description = { "Description" }, - enabled = true, - value = true, - ) - - val preferences = persistentListOf( - textPreference, - colorPreference, - switchPreference, - singleChoicePreference, - ) -} diff --git a/core/ui/compose/preference/src/main/kotlin/net/thunderbird/core/ui/compose/preference/api/Preference.kt b/core/ui/compose/preference/src/main/kotlin/net/thunderbird/core/ui/compose/preference/api/Preference.kt deleted file mode 100644 index f4e4d117439638962018aa2f18b74238d312113f..0000000000000000000000000000000000000000 --- a/core/ui/compose/preference/src/main/kotlin/net/thunderbird/core/ui/compose/preference/api/Preference.kt +++ /dev/null @@ -1,125 +0,0 @@ -package net.thunderbird.core.ui.compose.preference.api - -import android.os.Parcelable -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.vector.ImageVector -import kotlinx.collections.immutable.ImmutableList -import kotlinx.parcelize.IgnoredOnParcel -import kotlinx.parcelize.Parcelize -import net.thunderbird.core.ui.compose.preference.api.PreferenceSetting.SingleChoice.Choice -import net.thunderbird.core.ui.compose.preference.api.PreferenceSetting.SingleChoiceCompact.CompactChoice - -/** - * A preference that can be displayed in a preference screen. - */ -sealed interface Preference : Parcelable { - val id: String -} - -/** - * A preference that holds a value of type [T]. - */ -sealed interface PreferenceSetting : Preference { - val value: T - val requiresEditView: Boolean - - @Parcelize - data class Text( - override val id: String, - val title: () -> String, - val description: () -> String? = { null }, - val icon: () -> ImageVector? = { null }, - override val value: String, - ) : PreferenceSetting { - @IgnoredOnParcel - override val requiresEditView: Boolean = true - } - - @Parcelize - data class Color( - override val id: String, - val title: () -> String, - val description: () -> String? = { null }, - val icon: () -> ImageVector? = { null }, - override val value: Int, - val colors: ImmutableList, - ) : PreferenceSetting { - @IgnoredOnParcel - override val requiresEditView: Boolean = true - } - - @Parcelize - data class SingleChoice( - override val id: String, - val title: () -> String, - val description: () -> String? = { null }, - override val value: Choice, - val options: ImmutableList, - ) : PreferenceSetting { - @IgnoredOnParcel - override val requiresEditView: Boolean = false - - @Parcelize - data class Choice( - val id: String, - val title: () -> String, - ) : Parcelable - } - - @Parcelize - data class SingleChoiceCompact( - override val id: String, - val title: () -> String, - val description: () -> String? = { null }, - val icon: () -> ImageVector? = { null }, - override val value: CompactChoice, - val options: ImmutableList, - ) : PreferenceSetting { - @IgnoredOnParcel - override val requiresEditView: Boolean = true - - @Parcelize - data class CompactChoice( - val id: String, - val title: () -> String, - ) : Parcelable - } - - @Parcelize - data class Switch( - override val id: String, - val title: () -> String, - val description: () -> String? = { null }, - val enabled: Boolean, - override val value: Boolean, - ) : PreferenceSetting { - @IgnoredOnParcel - override val requiresEditView: Boolean = false - } -} - -/** - * A preference that does not hold a value. It is used to display a section, a divider or custom UI. - */ -sealed interface PreferenceDisplay : Preference { - - @Parcelize - data class Custom( - override val id: String, - val customUi: @Composable (Modifier) -> Unit, - ) : PreferenceDisplay - - @Parcelize - data class SectionHeader( - override val id: String, - val title: () -> String, - val color: () -> Color = { Color.Unspecified }, - ) : PreferenceDisplay - - @Parcelize - data class SectionDivider( - override val id: String, - ) : PreferenceDisplay -} diff --git a/core/ui/compose/preference/src/main/kotlin/net/thunderbird/core/ui/compose/preference/ui/PreferenceView.kt b/core/ui/compose/preference/src/main/kotlin/net/thunderbird/core/ui/compose/preference/ui/PreferenceView.kt deleted file mode 100644 index d8a4f4d1f3d32d88d4b6bbe0a2ced265532631b6..0000000000000000000000000000000000000000 --- a/core/ui/compose/preference/src/main/kotlin/net/thunderbird/core/ui/compose/preference/ui/PreferenceView.kt +++ /dev/null @@ -1,36 +0,0 @@ -package net.thunderbird.core.ui.compose.preference.ui - -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import kotlinx.collections.immutable.ImmutableList -import net.thunderbird.core.ui.compose.preference.api.Preference -import net.thunderbird.core.ui.compose.preference.api.PreferenceSetting - -/** - * A view that displays a list of preferences. - * - * @param title The title of the view. - * @param subtitle The subtitle of the view (optional). - * @param preferences The list of preferences to display. - * @param onPreferenceChange The callback to be invoked when a preference is changed. - * @param onBack The callback to be invoked when the back button is clicked. - * @param modifier The modifier to be applied to the view. - */ -@Composable -fun PreferenceView( - title: String, - preferences: ImmutableList, - onPreferenceChange: (PreferenceSetting<*>) -> Unit, - onBack: () -> Unit, - modifier: Modifier = Modifier, - subtitle: String? = null, -) { - PreferenceViewWithDialog( - title = title, - subtitle = subtitle, - preferences = preferences, - onPreferenceChange = onPreferenceChange, - onBack = onBack, - modifier = modifier, - ) -} diff --git a/core/ui/compose/preference/src/main/kotlin/net/thunderbird/core/ui/compose/preference/ui/components/dialog/PreferenceDialog.kt b/core/ui/compose/preference/src/main/kotlin/net/thunderbird/core/ui/compose/preference/ui/components/dialog/PreferenceDialog.kt deleted file mode 100644 index 7f7a305b24afbb3f8b9cbf5c78456fc69431d0f9..0000000000000000000000000000000000000000 --- a/core/ui/compose/preference/src/main/kotlin/net/thunderbird/core/ui/compose/preference/ui/components/dialog/PreferenceDialog.kt +++ /dev/null @@ -1,54 +0,0 @@ -package net.thunderbird.core.ui.compose.preference.ui.components.dialog - -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import net.thunderbird.core.ui.compose.preference.api.Preference -import net.thunderbird.core.ui.compose.preference.api.PreferenceSetting - -@Composable -internal fun PreferenceDialog( - preference: Preference, - onConfirmClick: (PreferenceSetting<*>) -> Unit, - onDismissClick: () -> Unit, - onDismissRequest: () -> Unit, - modifier: Modifier = Modifier, -) { - require(preference is PreferenceSetting<*>) { - "Unsupported preference type: ${preference::class.java.simpleName}" - } - - when (preference) { - is PreferenceSetting.Text -> { - PreferenceDialogTextView( - preference = preference, - onConfirmClick = onConfirmClick, - onDismissClick = onDismissClick, - onDismissRequest = onDismissRequest, - modifier = modifier, - ) - } - - is PreferenceSetting.Color -> { - PreferenceDialogColorView( - preference = preference, - onConfirmClick = onConfirmClick, - onDismissClick = onDismissClick, - onDismissRequest = onDismissRequest, - modifier = modifier, - ) - } - - is PreferenceSetting.SingleChoiceCompact -> { - PreferenceDialogSingleChoiceCompactView( - preference = preference, - onConfirmClick = onConfirmClick, - onDismissClick = onDismissClick, - onDismissRequest = onDismissRequest, - modifier = modifier, - ) - } - - // No dialog needed - is PreferenceSetting.SingleChoice, is PreferenceSetting.Switch -> Unit - } -} diff --git a/core/ui/compose/preference/src/main/kotlin/net/thunderbird/core/ui/compose/preference/ui/components/list/PreferenceItem.kt b/core/ui/compose/preference/src/main/kotlin/net/thunderbird/core/ui/compose/preference/ui/components/list/PreferenceItem.kt deleted file mode 100644 index 24349e5e734b5b419769c12fe04e3e7bc6dba1f2..0000000000000000000000000000000000000000 --- a/core/ui/compose/preference/src/main/kotlin/net/thunderbird/core/ui/compose/preference/ui/components/list/PreferenceItem.kt +++ /dev/null @@ -1,77 +0,0 @@ -package net.thunderbird.core.ui.compose.preference.ui.components.list - -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import net.thunderbird.core.ui.compose.preference.api.Preference -import net.thunderbird.core.ui.compose.preference.api.PreferenceDisplay -import net.thunderbird.core.ui.compose.preference.api.PreferenceSetting - -@Composable -internal fun PreferenceItem( - preference: Preference, - onClick: () -> Unit, - onPreferenceChange: (PreferenceSetting<*>) -> Unit, - modifier: Modifier = Modifier, -) { - when (preference) { - // PreferenceSetting - is PreferenceSetting.Text -> { - PreferenceItemTextView( - preference = preference, - onClick = onClick, - modifier = modifier, - ) - } - - is PreferenceSetting.Color -> { - PreferenceItemColorView( - preference = preference, - onClick = onClick, - modifier = modifier, - ) - } - - is PreferenceSetting.SingleChoice -> { - PreferenceItemSingleChoiceView( - preference = preference, - onPreferenceChange = onPreferenceChange, - modifier = modifier, - ) - } - - is PreferenceSetting.Switch -> { - PreferenceItemSwitchView( - preference = preference, - onPreferenceChange = onPreferenceChange, - modifier = modifier, - ) - } - - is PreferenceSetting.SingleChoiceCompact -> PreferenceItemSingleChoiceCompactView( - preference = preference, - onClick = onClick, - modifier = modifier, - ) - - // PreferenceDisplay - is PreferenceDisplay.Custom -> { - PreferenceItemCustomView( - preference = preference, - modifier = modifier, - ) - } - - is PreferenceDisplay.SectionHeader -> { - PreferenceItemSectionHeaderView( - preference = preference, - modifier = modifier, - ) - } - - is PreferenceDisplay.SectionDivider -> { - PreferenceItemSectionDividerView( - modifier = modifier, - ) - } - } -} diff --git a/core/ui/compose/preference/src/main/kotlin/net/thunderbird/core/ui/compose/preference/ui/components/list/PreferenceItemCustomView.kt b/core/ui/compose/preference/src/main/kotlin/net/thunderbird/core/ui/compose/preference/ui/components/list/PreferenceItemCustomView.kt deleted file mode 100644 index bc1227cd7b2c9eb45807878dc2535d875838ba3c..0000000000000000000000000000000000000000 --- a/core/ui/compose/preference/src/main/kotlin/net/thunderbird/core/ui/compose/preference/ui/components/list/PreferenceItemCustomView.kt +++ /dev/null @@ -1,13 +0,0 @@ -package net.thunderbird.core.ui.compose.preference.ui.components.list - -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import net.thunderbird.core.ui.compose.preference.api.PreferenceDisplay - -@Composable -internal fun PreferenceItemCustomView( - preference: PreferenceDisplay.Custom, - modifier: Modifier = Modifier, -) { - preference.customUi(modifier) -} diff --git a/core/ui/compose/preference/src/main/kotlin/net/thunderbird/core/ui/compose/preference/ui/components/list/PreferenceItemTextView.kt b/core/ui/compose/preference/src/main/kotlin/net/thunderbird/core/ui/compose/preference/ui/components/list/PreferenceItemTextView.kt deleted file mode 100644 index a07672cfb848e3c95565e82091ad8f2e162dc1b3..0000000000000000000000000000000000000000 --- a/core/ui/compose/preference/src/main/kotlin/net/thunderbird/core/ui/compose/preference/ui/components/list/PreferenceItemTextView.kt +++ /dev/null @@ -1,23 +0,0 @@ -package net.thunderbird.core.ui.compose.preference.ui.components.list - -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import app.k9mail.core.ui.compose.designsystem.atom.text.TextBodyMedium -import app.k9mail.core.ui.compose.designsystem.atom.text.TextTitleMedium -import net.thunderbird.core.ui.compose.preference.api.PreferenceSetting - -@Composable -internal fun PreferenceItemTextView( - preference: PreferenceSetting.Text, - onClick: () -> Unit, - modifier: Modifier = Modifier, -) { - PreferenceItemLayout( - onClick = onClick, - icon = preference.icon(), - modifier = modifier, - ) { - TextTitleMedium(text = preference.title()) - TextBodyMedium(text = preference.value) - } -} diff --git a/core/ui/compose/preference/src/main/kotlin/net/thunderbird/core/ui/compose/preference/ui/components/list/PreferenceList.kt b/core/ui/compose/preference/src/main/kotlin/net/thunderbird/core/ui/compose/preference/ui/components/list/PreferenceList.kt deleted file mode 100644 index b27d95d4e5c7e242c0c21a9101f11820278c8061..0000000000000000000000000000000000000000 --- a/core/ui/compose/preference/src/main/kotlin/net/thunderbird/core/ui/compose/preference/ui/components/list/PreferenceList.kt +++ /dev/null @@ -1,33 +0,0 @@ -package net.thunderbird.core.ui.compose.preference.ui.components.list - -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.itemsIndexed -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import kotlinx.collections.immutable.ImmutableList -import net.thunderbird.core.ui.compose.preference.api.Preference -import net.thunderbird.core.ui.compose.preference.api.PreferenceSetting - -@Composable -internal fun PreferenceList( - preferences: ImmutableList, - onItemClick: (index: Int, item: Preference) -> Unit, - onPreferenceChange: (PreferenceSetting<*>) -> Unit, - modifier: Modifier = Modifier, -) { - LazyColumn( - modifier = modifier, - ) { - itemsIndexed(preferences) { index, item -> - PreferenceItem( - preference = item, - onClick = { - onItemClick(index, item) - }, - onPreferenceChange = onPreferenceChange, - modifier = Modifier.fillMaxWidth(), - ) - } - } -} diff --git a/core/ui/compose/preference/src/main/res/values/strings.xml b/core/ui/compose/preference/src/main/res/values/strings.xml deleted file mode 100644 index 3d01935e6516164e8a8546a7dc29afbdce7b5976..0000000000000000000000000000000000000000 --- a/core/ui/compose/preference/src/main/res/values/strings.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - Accept - Cancel - diff --git a/core/ui/legacy/theme2/k9mail/src/main/res/drawable/ic_logo_k9_white.xml b/core/ui/legacy/theme2/k9mail/src/main/res/drawable/ic_logo_k9_white.xml new file mode 100644 index 0000000000000000000000000000000000000000..a1f0d0b8a8bd0608f284249c73a5d3be461f6fbb --- /dev/null +++ b/core/ui/legacy/theme2/k9mail/src/main/res/drawable/ic_logo_k9_white.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/ui/legacy/theme2/thunderbird/src/main/res/drawable/ic_logo_thunderbird_white.xml b/core/ui/legacy/theme2/thunderbird/src/main/res/drawable/ic_logo_thunderbird_white.xml new file mode 100644 index 0000000000000000000000000000000000000000..a2efb445b2ad24b38767c754753341f13e176704 --- /dev/null +++ b/core/ui/legacy/theme2/thunderbird/src/main/res/drawable/ic_logo_thunderbird_white.xml @@ -0,0 +1,21 @@ + + + + + + + diff --git a/core/ui/setting/api/build.gradle.kts b/core/ui/setting/api/build.gradle.kts new file mode 100644 index 0000000000000000000000000000000000000000..13b3b9a15087aba2e93a7753ba4aaccb83139636 --- /dev/null +++ b/core/ui/setting/api/build.gradle.kts @@ -0,0 +1,7 @@ +plugins { + id(ThunderbirdPlugins.Library.kmpCompose) +} + +android { + namespace = "net.thunderbird.core.ui.setting" +} diff --git a/core/ui/setting/api/src/commonMain/kotlin/net/thunderbird/core/ui/setting/Setting.kt b/core/ui/setting/api/src/commonMain/kotlin/net/thunderbird/core/ui/setting/Setting.kt new file mode 100644 index 0000000000000000000000000000000000000000..5cb7ef6d613c7e718c249513ea883a82c8e19514 --- /dev/null +++ b/core/ui/setting/api/src/commonMain/kotlin/net/thunderbird/core/ui/setting/Setting.kt @@ -0,0 +1,8 @@ +package net.thunderbird.core.ui.setting + +/** + * A setting that can be displayed in a setting screen. + */ +sealed interface Setting { + val id: String +} diff --git a/core/ui/setting/api/src/commonMain/kotlin/net/thunderbird/core/ui/setting/SettingDecoration.kt b/core/ui/setting/api/src/commonMain/kotlin/net/thunderbird/core/ui/setting/SettingDecoration.kt new file mode 100644 index 0000000000000000000000000000000000000000..200a133fb764c2f3053437905d1adbddcb07cd88 --- /dev/null +++ b/core/ui/setting/api/src/commonMain/kotlin/net/thunderbird/core/ui/setting/SettingDecoration.kt @@ -0,0 +1,37 @@ +package net.thunderbird.core.ui.setting + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color + +/** + * A setting decoration could be used for enhancing the UI of a settings screen. It does not hold any value. + * + * Examples include section headers, dividers, or custom UI components. + */ +sealed interface SettingDecoration : Setting { + + /** + * A setting that displays custom UI. + */ + data class Custom( + override val id: String, + val customUi: @Composable (Modifier) -> Unit, + ) : SettingDecoration + + /** + * A setting that displays a section header. + */ + data class SectionHeader( + override val id: String, + val title: () -> String, + val color: () -> Color = { Color.Unspecified }, + ) : SettingDecoration + + /** + * A setting that displays a divider. + */ + data class SectionDivider( + override val id: String, + ) : SettingDecoration +} diff --git a/core/ui/setting/api/src/commonMain/kotlin/net/thunderbird/core/ui/setting/SettingValue.kt b/core/ui/setting/api/src/commonMain/kotlin/net/thunderbird/core/ui/setting/SettingValue.kt new file mode 100644 index 0000000000000000000000000000000000000000..91165b4710a7adcedbe6311b8edf2b136e71b744 --- /dev/null +++ b/core/ui/setting/api/src/commonMain/kotlin/net/thunderbird/core/ui/setting/SettingValue.kt @@ -0,0 +1,139 @@ +package net.thunderbird.core.ui.setting + +import androidx.compose.ui.graphics.vector.ImageVector +import kotlinx.collections.immutable.ImmutableList +import net.thunderbird.core.ui.setting.SettingValue.CompactSelectSingleOption.CompactOption +import net.thunderbird.core.ui.setting.SettingValue.SelectSingleOption.Option + +/** + * A setting that holds a value of type [T]. + */ +sealed interface SettingValue : Setting { + val value: T + val requiresEditView: Boolean + + /** + * A setting that holds a string value. + * + * This requires an edit view to modify the value. + * + * @param id The unique identifier for the setting. + * @param title A lambda that returns the title of the setting. + * @param description A lambda that returns the description of the setting. Default is null. + * @param icon A lambda that returns the icon of the setting as an [ImageVector]. Default is null. + * @param value The current value of the setting. + */ + data class Text( + override val id: String, + val title: () -> String, + val description: () -> String? = { null }, + val icon: () -> ImageVector? = { null }, + override val value: String, + ) : SettingValue { + override val requiresEditView: Boolean = true + } + + /** + * A setting that holds a color value. + * + * This requires an edit view to select a color from the provided list of colors. + * + * @param id The unique identifier for the setting. + * @param title A lambda that returns the title of the setting. + * @param description A lambda that returns the description of the setting. Default is null. + * @param icon A lambda that returns the icon of the setting as an [ImageVector]. Default is null. + * @param value The current color value of the setting, represented as an integer. + */ + data class Color( + override val id: String, + val title: () -> String, + val description: () -> String? = { null }, + val icon: () -> ImageVector? = { null }, + override val value: Int, + val colors: ImmutableList, + ) : SettingValue { + override val requiresEditView: Boolean = true + } + + /** + * A setting that allows the user to select a single option from a list of options. + * + * The options are displayed in a compact manner, suitable for scenarios where space is limited. + * The number of options must be between 2 and 4. + * + * This requires no edit view to modify the value. The selection can be made directly from the setting item. + * + * @param id The unique identifier for the setting. + * @param title A lambda that returns the title of the setting. + * @param description A lambda that returns the description of the setting. Default is null. + * @param value The currently selected option. + * @param options The list of available options to choose from. + */ + data class CompactSelectSingleOption( + override val id: String, + val title: () -> String, + val description: () -> String? = { null }, + override val value: CompactOption, + val options: ImmutableList>, + ) : SettingValue> { + override val requiresEditView: Boolean = false + + init { + require(options.size >= 2) { "There must be at least two options." } + require(options.size <= 4) { "There can be at most four options." } + } + + data class CompactOption( + val id: String, + val title: () -> String, + val value: T, + ) + } + + /** + * A setting that allows the user to select a single option from a list of options. + * + * Requires an edit view to select the option from the provided list of options. + * + * @param id The unique identifier for the setting. + * @param title A lambda that returns the title of the setting. + * @param description A lambda that returns the description of the setting. Default is null. + * @param icon A lambda that returns the icon of the setting as an [ImageVector]. Default is null. + * @param value The currently selected option. + * @param options The list of available options to choose from. + */ + data class SelectSingleOption( + override val id: String, + val title: () -> String, + val description: () -> String? = { null }, + val icon: () -> ImageVector? = { null }, + override val value: Option, + val options: ImmutableList