Compare commits

...

34 Commits

Author SHA1 Message Date
Arnau Mora
e2d5f8b7ac Replace Weblate engage WebView with a button (#2016)
* Replace Weblate engage WebView with a button

Signed-off-by: Arnau Mora <arnyminerz@proton.me>

* Move engagement button to the top

Signed-off-by: Arnau Mora <arnyminerz@proton.me>

---------

Signed-off-by: Arnau Mora <arnyminerz@proton.me>
2026-02-18 13:48:05 +01:00
Sunik Kupfer
f183676fc2 Add account to beforeSync validation (#2011)
Add account to SyncValidators beforeSync
2026-02-18 10:38:17 +01:00
Ricki Hirner
8838db25c5 Issue templates: add needs triage (#2008)
Update issue template labels

- Change qualified feature request label from "enhancement" to "needs-triage"
- Change qualified bug report label from "bug" to "needs-triage"
2026-02-16 17:43:09 +01:00
dependabot[bot]
515360876e Bump the app-dependencies group with 6 updates (#2007)
Bumps the app-dependencies group with 6 updates:

| Package | From | To |
| --- | --- | --- |
| androidx.activity:activity-compose | `1.12.3` | `1.12.4` |
| androidx.compose:compose-bom | `2026.01.01` | `2026.02.00` |
| androidx.paging:paging-runtime-ktx | `3.4.0` | `3.4.1` |
| androidx.paging:paging-compose | `3.4.0` | `3.4.1` |
| com.android.application | `9.0.0` | `9.0.1` |
| com.android.library | `9.0.0` | `9.0.1` |


Updates `androidx.activity:activity-compose` from 1.12.3 to 1.12.4

Updates `androidx.compose:compose-bom` from 2026.01.01 to 2026.02.00

Updates `androidx.paging:paging-runtime-ktx` from 3.4.0 to 3.4.1

Updates `androidx.paging:paging-compose` from 3.4.0 to 3.4.1

Updates `androidx.paging:paging-compose` from 3.4.0 to 3.4.1

Updates `com.android.application` from 9.0.0 to 9.0.1

Updates `com.android.library` from 9.0.0 to 9.0.1

Updates `com.android.library` from 9.0.0 to 9.0.1

---
updated-dependencies:
- dependency-name: androidx.activity:activity-compose
  dependency-version: 1.12.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: app-dependencies
- dependency-name: androidx.compose:compose-bom
  dependency-version: 2026.02.00
  dependency-type: direct:production
  dependency-group: app-dependencies
- dependency-name: androidx.paging:paging-runtime-ktx
  dependency-version: 3.4.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: app-dependencies
- dependency-name: androidx.paging:paging-compose
  dependency-version: 3.4.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: app-dependencies
- dependency-name: androidx.paging:paging-compose
  dependency-version: 3.4.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: app-dependencies
- dependency-name: com.android.application
  dependency-version: 9.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: app-dependencies
- dependency-name: com.android.library
  dependency-version: 9.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: app-dependencies
- dependency-name: com.android.library
  dependency-version: 9.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: app-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-16 17:01:40 +01:00
Sunik Kupfer
78bf028938 Remove unused launcher colors (#2000)
Rename colors.xml to launcher_colors.xml and remove unused colors

Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
2026-02-16 10:43:26 +01:00
Ricki Hirner
24de99a4fa Remove @rfc2822 as code owner (#2002)
- Delete global CODEOWNERS rule for @rfc2822
- Keep Dependabot ownership for Gradle files
2026-02-16 10:29:29 +01:00
Arnau Mora
6518ad2066 Add SyncValidator (#1987)
* Add `SyncValidator`

Signed-off-by: Arnau Mora <arnyminerz@proton.me>

* Use `SyncValidator` in `Syncer`

Signed-off-by: Arnau Mora <arnyminerz@proton.me>

* Adjust kdoc

Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>

---------

Signed-off-by: Arnau Mora <arnyminerz@proton.me>
Signed-off-by: Arnau Mora Gras <arnyminerz@proton.me>
2026-02-11 12:20:57 +01:00
Ricki Hirner
795616a613 Reduce HTTP User-Agent string (#1998)
Refactor HTTP user agent string

- Simplify user agent to include only app name, version, and package name
2026-02-11 11:30:48 +01:00
Ricki Hirner
2799bf33f7 [CI] Fix paths and configuration after subproject split (#1997)
* Update release workflow configuration

- Update Java version environment variable naming
- Enable submodule checkout during build
- Fix APK file path for release artifacts
- Use consistent Java version reference in workflow

* Update AVD cache key path

- Change cache key reference from `app/build.gradle.kts` to `app-ose/build.gradle.kts` for AVD cache in test workflow

* Move signing configs before build types

- Reorder signingConfigs block to appear before buildTypes
- Ensure signingConfig reference in release build type comes after signingConfigs definition

* Don't checkout submodules
2026-02-10 17:04:52 +01:00
Ricki Hirner
ff3780ee01 Split subprojects: fix ProGuard configuration (#1995)
* Fix ProGuard rules for subprojects

- Rename `proguard-rules-release.pro` to `core-proguard-rules.pro`
- Include ProGuard rules in the core library's build configuration
- Remove redundant R8 usage comments and flags from the rules file

* Add ProGuard rules for release build

- Create new ProGuard rules file for release builds
- Disable obfuscation with `-dontobfuscate`
- Enable usage reporting to `build/reports/r8-usage.txt`
- Reference keep rules from core module
2026-02-10 14:56:46 +01:00
Ricki Hirner
63422b6e0e Update release workflow configuration
- Add Gradle cache encryption key
- Disable build cache for deterministic builds
- Update build command to target OSE app bundle
2026-02-10 12:24:02 +01:00
Ricki Hirner
ba2cc5c46b Update version to 4.5.10-alpha.1
- Bump version code to 405100000
- Update version name to 4.5.10-alpha.1
2026-02-10 12:06:05 +01:00
Weblate (bot)
7e7e56e35c Translations update from Hosted Weblate (#1986)
* Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (430 of 430 strings)

Translation: davx5/DAVx⁵ app strings (main)
Translate-URL: https://hosted.weblate.org/projects/davx5/davx5-ose-strings/pt_BR/

* Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (430 of 430 strings)

Translation: davx5/DAVx⁵ app strings (main)
Translate-URL: https://hosted.weblate.org/projects/davx5/davx5-ose-strings/zh_Hans/

* Translated using Weblate (Estonian)

Currently translated at 100.0% (430 of 430 strings)

Translation: davx5/DAVx⁵ app strings (main)
Translate-URL: https://hosted.weblate.org/projects/davx5/davx5-ose-strings/et/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (430 of 430 strings)

Translation: davx5/DAVx⁵ app strings (main)
Translate-URL: https://hosted.weblate.org/projects/davx5/davx5-ose-strings/nl/

* Added translation using Weblate (Lithuanian)

* Translated using Weblate (Lithuanian)

Currently translated at 7.6% (33 of 430 strings)

Translation: davx5/DAVx⁵ app strings (main)
Translate-URL: https://hosted.weblate.org/projects/davx5/davx5-ose-strings/lt/

* Translated using Weblate (Georgian)

Currently translated at 84.6% (364 of 430 strings)

Translation: davx5/DAVx⁵ app strings (main)
Translate-URL: https://hosted.weblate.org/projects/davx5/davx5-ose-strings/ka/

* Translated using Weblate (Romanian)

Currently translated at 100.0% (430 of 430 strings)

Translation: davx5/DAVx⁵ app strings (main)
Translate-URL: https://hosted.weblate.org/projects/davx5/davx5-ose-strings/ro/

* Translated using Weblate (Italian)

Currently translated at 88.1% (379 of 430 strings)

Translation: davx5/DAVx⁵ app strings (main)
Translate-URL: https://hosted.weblate.org/projects/davx5/davx5-ose-strings/it/

* Translated using Weblate (Italian)

Currently translated at 100.0% (4 of 4 strings)

Translation: davx5/DAVx⁵ app metadata (for F-Droid)
Translate-URL: https://hosted.weblate.org/projects/davx5/davx5-ose-fastlane/it/

* Translated using Weblate (Estonian)

Currently translated at 100.0% (437 of 437 strings)

Translation: davx5/DAVx⁵ app strings (main)
Translate-URL: https://hosted.weblate.org/projects/davx5/davx5-ose-strings/et/

* Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (437 of 437 strings)

Translation: davx5/DAVx⁵ app strings (main)
Translate-URL: https://hosted.weblate.org/projects/davx5/davx5-ose-strings/zh_Hans/

* Translated using Weblate (Dutch)

Currently translated at 100.0% (437 of 437 strings)

Translation: davx5/DAVx⁵ app strings (main)
Translate-URL: https://hosted.weblate.org/projects/davx5/davx5-ose-strings/nl/

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (437 of 437 strings)

Translation: davx5/DAVx⁵ app strings (main)
Translate-URL: https://hosted.weblate.org/projects/davx5/davx5-ose-strings/pt_BR/

* Translated using Weblate (German)

Currently translated at 100.0% (437 of 437 strings)

Translation: davx5/DAVx⁵ app strings (main)
Translate-URL: https://hosted.weblate.org/projects/davx5/davx5-ose-strings/de/

* Translated using Weblate (Romanian)

Currently translated at 100.0% (437 of 437 strings)

Translation: davx5/DAVx⁵ app strings (main)
Translate-URL: https://hosted.weblate.org/projects/davx5/davx5-ose-strings/ro/

---------

Co-authored-by: LucasMZ <git@lucasmz.dev>
Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Co-authored-by: Priit Jõerüüt <jrthwlate@users.noreply.hosted.weblate.org>
Co-authored-by: Stephan Paternotte <stephan@paternottes.net>
Co-authored-by: Vaclovas Intas <Gateway_31@protonmail.com>
Co-authored-by: Temuri Doghonadze <temuri.doghonadze@gmail.com>
Co-authored-by: Igor Sorocean <sorocean.igor@gmail.com>
Co-authored-by: Alì Mortacci <newscpq@vivaldi.net>
Co-authored-by: nautilusx <translate@disroot.org>
2026-02-10 11:59:10 +01:00
Ricki Hirner
1b8f215ffc Update intro page factory module name
- Rename `Global` interface to `IntroPageFactoryModule` for clarity
2026-02-10 11:56:43 +01:00
Ricki Hirner
e796448bad Split subprojects: fix aboutLibraries (bitfireAT/davx5#794)
Fix aboutLibraries plugin

- Add aboutLibraries plugin to root build.gradle.kts
- Apply aboutLibraries plugin in app-non-ose module
2026-02-10 11:55:16 +01:00
Ricki Hirner
bb6be3c9cc [CI] Rename main branch references (#1993)
Rename main branch references

- Update branch name from `main-ose` to `main` in test-dev workflow
- Remove deprecated dependency-submission workflow
- Add JAVA_VERSION environment variable in release workflow
- Replace hardcoded Java version with JAVA_VERSION variable in test-dev and release workflows
- Update comment in release workflow for cache cleanup clarity
2026-02-10 11:42:22 +01:00
Ricki Hirner
a436e8181a [CI] Fix tests after splitting into subprojects (#1991)
* Update dependency submission workflow

- Enable submodule checkout in GitHub Actions workflow
- Ensures subprojects are properly included during dependency analysis

* Update test workflow for split projects

- Set Java version as variable
- Replace `app` with `app-ose` in Gradle tasks
- Remove Android environment caching
- Update configuration cache population tasks
- Add unit and instrumented tests for `app-ose`
- Simplify cache handling by removing redundant steps

* Updated tests to only run for core module (app-ose has no unit tests)

* Remove CodeQL job
2026-02-10 11:17:15 +01:00
Ricki Hirner
ea81b929ca Fix tests with latest Kotlin 2026-02-09 23:16:55 +01:00
Ricki Hirner
55202dff87 Fix tests after subproject split
- Replace TestTasksAppWatcherModule with TestStartupPluginsModule to provide empty set of startup plugins
2026-02-09 22:49:08 +01:00
dependabot[bot]
fb2c8cdd68 Bump the app-dependencies group with 7 updates (#1985)
Bumps the app-dependencies group with 7 updates:

| Package | From | To |
| --- | --- | --- |
| [com.google.dagger:hilt-android](https://github.com/google/dagger) | `2.59` | `2.59.1` |
| [com.google.dagger:hilt-android-compiler](https://github.com/google/dagger) | `2.59` | `2.59.1` |
| [com.google.dagger:hilt-android-testing](https://github.com/google/dagger) | `2.59` | `2.59.1` |
| [com.google.dagger.hilt.android](https://github.com/google/dagger) | `2.59` | `2.59.1` |
| [org.jetbrains.kotlin:kotlin-stdlib](https://github.com/JetBrains/kotlin) | `2.2.21` | `2.3.10` |
| [org.jetbrains.kotlin.plugin.compose](https://github.com/JetBrains/kotlin) | `2.2.21` | `2.3.10` |
| [org.jetbrains.kotlin.plugin.serialization](https://github.com/JetBrains/kotlin) | `2.2.21` | `2.3.10` |


Updates `com.google.dagger:hilt-android` from 2.59 to 2.59.1
- [Release notes](https://github.com/google/dagger/releases)
- [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md)
- [Commits](https://github.com/google/dagger/compare/dagger-2.59...dagger-2.59.1)

Updates `com.google.dagger:hilt-android-compiler` from 2.59 to 2.59.1
- [Release notes](https://github.com/google/dagger/releases)
- [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md)
- [Commits](https://github.com/google/dagger/compare/dagger-2.59...dagger-2.59.1)

Updates `com.google.dagger:hilt-android-testing` from 2.59 to 2.59.1
- [Release notes](https://github.com/google/dagger/releases)
- [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md)
- [Commits](https://github.com/google/dagger/compare/dagger-2.59...dagger-2.59.1)

Updates `com.google.dagger.hilt.android` from 2.59 to 2.59.1
- [Release notes](https://github.com/google/dagger/releases)
- [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md)
- [Commits](https://github.com/google/dagger/compare/dagger-2.59...dagger-2.59.1)

Updates `com.google.dagger:hilt-android-compiler` from 2.59 to 2.59.1
- [Release notes](https://github.com/google/dagger/releases)
- [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md)
- [Commits](https://github.com/google/dagger/compare/dagger-2.59...dagger-2.59.1)

Updates `com.google.dagger:hilt-android-testing` from 2.59 to 2.59.1
- [Release notes](https://github.com/google/dagger/releases)
- [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md)
- [Commits](https://github.com/google/dagger/compare/dagger-2.59...dagger-2.59.1)

Updates `org.jetbrains.kotlin:kotlin-stdlib` from 2.2.21 to 2.3.10
- [Release notes](https://github.com/JetBrains/kotlin/releases)
- [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md)
- [Commits](https://github.com/JetBrains/kotlin/compare/v2.2.21...v2.3.10)

Updates `org.jetbrains.kotlin.plugin.compose` from 2.2.21 to 2.3.10
- [Release notes](https://github.com/JetBrains/kotlin/releases)
- [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md)
- [Commits](https://github.com/JetBrains/kotlin/compare/v2.2.21...v2.3.10)

Updates `org.jetbrains.kotlin.plugin.serialization` from 2.2.21 to 2.3.10
- [Release notes](https://github.com/JetBrains/kotlin/releases)
- [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md)
- [Commits](https://github.com/JetBrains/kotlin/compare/v2.2.21...v2.3.10)

Updates `org.jetbrains.kotlin.plugin.compose` from 2.2.21 to 2.3.10
- [Release notes](https://github.com/JetBrains/kotlin/releases)
- [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md)
- [Commits](https://github.com/JetBrains/kotlin/compare/v2.2.21...v2.3.10)

Updates `com.google.dagger.hilt.android` from 2.59 to 2.59.1
- [Release notes](https://github.com/google/dagger/releases)
- [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md)
- [Commits](https://github.com/google/dagger/compare/dagger-2.59...dagger-2.59.1)

Updates `org.jetbrains.kotlin.plugin.serialization` from 2.2.21 to 2.3.10
- [Release notes](https://github.com/JetBrains/kotlin/releases)
- [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md)
- [Commits](https://github.com/JetBrains/kotlin/compare/v2.2.21...v2.3.10)

---
updated-dependencies:
- dependency-name: com.google.dagger:hilt-android
  dependency-version: 2.59.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: app-dependencies
- dependency-name: com.google.dagger:hilt-android-compiler
  dependency-version: 2.59.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: app-dependencies
- dependency-name: com.google.dagger:hilt-android-testing
  dependency-version: 2.59.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: app-dependencies
- dependency-name: com.google.dagger.hilt.android
  dependency-version: 2.59.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: app-dependencies
- dependency-name: com.google.dagger:hilt-android-compiler
  dependency-version: 2.59.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: app-dependencies
- dependency-name: com.google.dagger:hilt-android-testing
  dependency-version: 2.59.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: app-dependencies
- dependency-name: org.jetbrains.kotlin:kotlin-stdlib
  dependency-version: 2.3.10
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: app-dependencies
- dependency-name: org.jetbrains.kotlin.plugin.compose
  dependency-version: 2.3.10
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: app-dependencies
- dependency-name: org.jetbrains.kotlin.plugin.serialization
  dependency-version: 2.3.10
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: app-dependencies
- dependency-name: org.jetbrains.kotlin.plugin.compose
  dependency-version: 2.3.10
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: app-dependencies
- dependency-name: com.google.dagger.hilt.android
  dependency-version: 2.59.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: app-dependencies
- dependency-name: org.jetbrains.kotlin.plugin.serialization
  dependency-version: 2.3.10
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: app-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-09 21:02:58 +01:00
Ricki Hirner
a9b24e5c45 Apply Gradle plugins once in root build.gradle.kts (bitfireAT/davx5#789) 2026-02-09 18:12:46 +01:00
Ricki Hirner
a55ce927f7 Better DI modules (#1982)
* Rename "app" subproject to core

* Split core and app-ose

* Update test workflows

* Update test configuration

- Add managed device for testing
- Set device to "Pixel 3" with API level 34
- Use AOSP system image source

* Add OpenID AppAuth library

* Fix core instrumentation tests

* Move WorkManagerInitializer from core to app-ose AndroidManifest

* Don't run app-ose tests yet because there are none

* Refactor App Initialization

- Introduce `CoreApp` for common initialization logic
- Refactor `App` to extend `CoreApp` and handle WorkManager configuration

* Update package references and permissions

- Update references from `com.davx5.ose.App` to `at.bitfire.davdroid.CoreApp`
- Enable archive naming in `app-ose/build.gradle.kts`
- Remove redundant permission declarations in `core/src/main/AndroidManifest.xml`

* Remove build.gradle.kts and update settings.gradle.kts

- Remove `build.gradle.kts` file
- Update `settings.gradle.kts` to use `gradlePluginPortal` for plugins
- Set `repositoriesMode` to `PREFER_SETTINGS`
- Add comments for clarity in `settings.gradle.kts`

* Update AndroidManifest to set install location to internal only (again)

* Refactor DI modules and qualifiers

- Move `ColorSchemeScopes` to `ColorSchemeQualifiers`
- Rename `CustomCertManagerModule` to `Cert4AndroidModule`
- Move `CoroutineScopes` to `CoroutineQualifiers`
- Add `ApplicationScope` qualifier to `CoroutineQualifiers`
- Remove redundant DI module declarations
- Add new `CoreSettingsProvidersModule`
- Add new `StartupPluginsModule`
- Add new `UncaughtExceptionHandlerModule`
- Add new `AuthorizationServiceModule`
- Add new `AppLicenseInfoProviderModule`
- Add new `IntroPageFactoryModule`
- Add new `LoginTypesProviderModule`
- Add new `AccountsDrawerHandlerModule`
2026-02-09 12:22:16 +01:00
Ricki Hirner
7861cffa2e Split app into core and app-ose subprojects (#1975)
* Rename "app" subproject to core

* Split core and app-ose

* Update test workflows

* Update test configuration

- Add managed device for testing
- Set device to "Pixel 3" with API level 34
- Use AOSP system image source

* Add OpenID AppAuth library

* Fix core instrumentation tests

* Move WorkManagerInitializer from core to app-ose AndroidManifest

* Don't run app-ose tests yet because there are none

* Refactor App Initialization

- Introduce `CoreApp` for common initialization logic
- Refactor `App` to extend `CoreApp` and handle WorkManager configuration

* Update package references and permissions

- Update references from `com.davx5.ose.App` to `at.bitfire.davdroid.CoreApp`
- Enable archive naming in `app-ose/build.gradle.kts`
- Remove redundant permission declarations in `core/src/main/AndroidManifest.xml`

* Remove build.gradle.kts and update settings.gradle.kts

- Remove `build.gradle.kts` file
- Update `settings.gradle.kts` to use `gradlePluginPortal` for plugins
- Set `repositoriesMode` to `PREFER_SETTINGS`
- Add comments for clarity in `settings.gradle.kts`

* Update AndroidManifest to set install location to internal only (again)

* Update CoreApp to be abstract

- Change `CoreApp` from open to abstract class.
2026-02-09 11:54:54 +01:00
Ricki Hirner
eab054d1c3 Move OSE code to separate package (#1974)
- Move DebugInfoCrashHandler.kt to com.davx5.ose
- Move StandardLoginTypePage.kt to com.davx5.ose.ui.setup
- Move StandardLoginTypesProvider.kt to com.davx5.ose.ui.setup
- Move CustomCertManagerModule.kt to com.davx5.ose.di
- Move OseIntroPageFactory.kt to com.davx5.ose.ui.intro
- Move OseColorSchemesModule.kt to com.davx5.ose.di
- Move OseFlavorModule.kt to com.davx5.ose.di
- Move OpenSourceLicenseInfoProvider.kt to com.davx5.ose.ui.about
- Move OseTheme.kt to com.davx5.ose.ui
2026-02-05 17:21:57 +01:00
Ricki Hirner
5e84648fb4 Replace BuildConfig.allowCustomCerts by DI (#1971)
* Update IntroScreen colors

- Replace M3ColorScheme with MaterialTheme.colorScheme
- Update background and icon colors to use MaterialTheme

* Update color scheme references

- Replace `M3ColorScheme.primaryLight` with `MaterialTheme.colorScheme.primary` in `WelcomePage.kt` and `AccountsDrawerHandler.kt`.

* Update AppTheme to accept custom color schemes

- Add `lightColorScheme` and `darkColorScheme` parameters
- Replace hardcoded color schemes with the new parameters

* Add color scheme dependency injection

- Add `LightColorScheme` and `DarkColorScheme` qualifiers
- Create `OseColorSchemes` module for providing color schemes
- Update `AppTheme` to use injected color schemes

* Update glance material dependency to material3

- Update `androidx.glance.material` to `androidx.glance.material3`
- Adjust imports and usage in `IconSyncButtonWidget.kt` and `LabeledSyncButtonWidget.kt` to use `GlanceTheme` and `ColorProviders` for color schemes
- Replace deprecated `ColorProvider` with `GlanceTheme.colors` for primary and onPrimary colors

* Refactor widget receivers and widgets to use dependency injection more properly

- Update `LabeledSyncButtonWidgetReceiver` and `IconSyncButtonWidgetReceiver` to use Hilt for dependency injection.
- Inject `SyncWidgetModel`, `LightColorScheme`, and `DarkColorScheme` into both widget receivers.
- Remove the use of `EntryPoint` and `EntryPointAccessors` from `LabeledSyncButtonWidget` and `IconSyncButtonWidget`.
- Pass injected dependencies directly to the widget constructors.

* Rename ThemeColors to OseTheme

- Update imports and references to use OseTheme
- Rename object M3ColorScheme to OseTheme

* Move AppTheme to ui.composable package because it's a reusable Composable

* Update AboutApp to use dynamic version info instead of BuildConfig

- Pass versionName and versionCode from AboutModel to AboutApp
- Remove dependency on BuildConfig in AboutApp
- Update AboutApp_Preview with sample version info

* Update URI statistics parameters

- Update `withStatParams` to include package name and version
- Replace `BuildConfig.APPLICATION_ID` with `context.packageName`
- Add context parameter to `withStatParams` in various activities

* Don't depend on BuildConfig for application name and version

- Introduce `ProductIds` for managing product IDs and User-Agent
- Update various classes to use `ProductIds` for product ID generation
- Move `TextTable` class from `at.bitfire.davdroid` to `at.bitfire.davdroid.util`

* Refactor OAuth classes for dependency injection

- Convert `OAuthFastmail` and `OAuthGoogle` to injectable classes
- Update `FastmailLoginModel` and `GoogleLoginModel` to use injected instances
- Move `redirectUri` initialization to `OAuthIntegration` constructor

* Adapt DI

- Move CustomCertManagerModule to ose configuration
- Move coroutine scopes to scope package

* minor changes

* Remove custom certificate build config

- Remove `allowCustomCerts` build config field
- Replace `@Singleton` with `@Reusable` in CustomCertManagerModule

* Update imports and LogcatHandler initialization

- Update imports to use scoped dispatchers
- Replace BuildConfig.APPLICATION_ID with javaClass.name in LogcatHandler initialization
2026-02-05 13:59:31 +01:00
Ricki Hirner
490abcb88a Reduce BuildConfig dependencies (#1969)
* Update IntroScreen colors

- Replace M3ColorScheme with MaterialTheme.colorScheme
- Update background and icon colors to use MaterialTheme

* Update color scheme references

- Replace `M3ColorScheme.primaryLight` with `MaterialTheme.colorScheme.primary` in `WelcomePage.kt` and `AccountsDrawerHandler.kt`.

* Update AppTheme to accept custom color schemes

- Add `lightColorScheme` and `darkColorScheme` parameters
- Replace hardcoded color schemes with the new parameters

* Add color scheme dependency injection

- Add `LightColorScheme` and `DarkColorScheme` qualifiers
- Create `OseColorSchemes` module for providing color schemes
- Update `AppTheme` to use injected color schemes

* Update glance material dependency to material3

- Update `androidx.glance.material` to `androidx.glance.material3`
- Adjust imports and usage in `IconSyncButtonWidget.kt` and `LabeledSyncButtonWidget.kt` to use `GlanceTheme` and `ColorProviders` for color schemes
- Replace deprecated `ColorProvider` with `GlanceTheme.colors` for primary and onPrimary colors

* Refactor widget receivers and widgets to use dependency injection more properly

- Update `LabeledSyncButtonWidgetReceiver` and `IconSyncButtonWidgetReceiver` to use Hilt for dependency injection.
- Inject `SyncWidgetModel`, `LightColorScheme`, and `DarkColorScheme` into both widget receivers.
- Remove the use of `EntryPoint` and `EntryPointAccessors` from `LabeledSyncButtonWidget` and `IconSyncButtonWidget`.
- Pass injected dependencies directly to the widget constructors.

* Rename ThemeColors to OseTheme

- Update imports and references to use OseTheme
- Rename object M3ColorScheme to OseTheme

* Move AppTheme to ui.composable package because it's a reusable Composable

* Update AboutApp to use dynamic version info instead of BuildConfig

- Pass versionName and versionCode from AboutModel to AboutApp
- Remove dependency on BuildConfig in AboutApp
- Update AboutApp_Preview with sample version info

* Update URI statistics parameters

- Update `withStatParams` to include package name and version
- Replace `BuildConfig.APPLICATION_ID` with `context.packageName`
- Add context parameter to `withStatParams` in various activities

* Don't depend on BuildConfig for application name and version

- Introduce `ProductIds` for managing product IDs and User-Agent
- Update various classes to use `ProductIds` for product ID generation
- Move `TextTable` class from `at.bitfire.davdroid` to `at.bitfire.davdroid.util`

* Refactor OAuth classes for dependency injection

- Convert `OAuthFastmail` and `OAuthGoogle` to injectable classes
- Update `FastmailLoginModel` and `GoogleLoginModel` to use injected instances
- Move `redirectUri` initialization to `OAuthIntegration` constructor
2026-02-05 12:20:21 +01:00
Ricki Hirner
cca12e79d8 [UI] Properly provide color schemes over DI (#1966)
* Update IntroScreen colors

- Replace M3ColorScheme with MaterialTheme.colorScheme
- Update background and icon colors to use MaterialTheme

* Update color scheme references

- Replace `M3ColorScheme.primaryLight` with `MaterialTheme.colorScheme.primary` in `WelcomePage.kt` and `AccountsDrawerHandler.kt`.

* Update AppTheme to accept custom color schemes

- Add `lightColorScheme` and `darkColorScheme` parameters
- Replace hardcoded color schemes with the new parameters

* Add color scheme dependency injection

- Add `LightColorScheme` and `DarkColorScheme` qualifiers
- Create `OseColorSchemes` module for providing color schemes
- Update `AppTheme` to use injected color schemes

* Update glance material dependency to material3

- Update `androidx.glance.material` to `androidx.glance.material3`
- Adjust imports and usage in `IconSyncButtonWidget.kt` and `LabeledSyncButtonWidget.kt` to use `GlanceTheme` and `ColorProviders` for color schemes
- Replace deprecated `ColorProvider` with `GlanceTheme.colors` for primary and onPrimary colors

* Refactor widget receivers and widgets to use dependency injection more properly

- Update `LabeledSyncButtonWidgetReceiver` and `IconSyncButtonWidgetReceiver` to use Hilt for dependency injection.
- Inject `SyncWidgetModel`, `LightColorScheme`, and `DarkColorScheme` into both widget receivers.
- Remove the use of `EntryPoint` and `EntryPointAccessors` from `LabeledSyncButtonWidget` and `IconSyncButtonWidget`.
- Pass injected dependencies directly to the widget constructors.

* Rename ThemeColors to OseTheme

- Update imports and references to use OseTheme
- Rename object M3ColorScheme to OseTheme

* Move AppTheme to ui.composable package because it's a reusable Composable

* Always use Light Color Scheme for certain intro UI

- Inject `lightColorScheme` in `IntroActivity`
- Pass `lightColorScheme` to `IntroScreen`
- Use `lightColorScheme` for background and color in `IntroScreen` and `WelcomePage`

* Minor syntax
2026-02-05 11:43:55 +01:00
Ricki Hirner
915cf73027 Update version to 4.5.9 2026-02-04 10:58:57 +01:00
Ricki Hirner
53773eaf83 Go back to 4.5.9-rc.2 (4.5.9 with version code 405090003 was never released) 2026-02-03 16:00:55 +01:00
Ricki Hirner
9cd685982d Update synctools to correctly process tel: URIs in vCards (#1963) 2026-02-03 15:59:46 +01:00
Sunik Kupfer
d4902e84ce [synctools] Tasks rewrite: Use reader/writer (#1959)
* Update synctools; Use writer/reader

Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>

* Update synctools

Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>

---------

Signed-off-by: Sunik Kupfer <kupfer@bitfire.at>
2026-02-03 15:22:15 +01:00
dependabot[bot]
ec485fcfa5 Bump the app-dependencies group with 8 updates (#1961)
Bumps the app-dependencies group with 8 updates:

| Package | From | To |
| --- | --- | --- |
| gradle-wrapper | `9.3.0` | `9.3.1` |
| androidx.activity:activity-compose | `1.12.2` | `1.12.3` |
| androidx.compose:compose-bom | `2026.01.00` | `2026.01.01` |
| androidx.paging:paging-runtime-ktx | `3.3.6` | `3.4.0` |
| androidx.paging:paging-compose | `3.3.6` | `3.4.0` |
| androidx.work:work-runtime-ktx | `2.11.0` | `2.11.1` |
| androidx.work:work-testing | `2.11.0` | `2.11.1` |
| [com.google.devtools.ksp](https://github.com/google/ksp) | `2.3.4` | `2.3.5` |


Updates `gradle-wrapper` from 9.3.0 to 9.3.1

Updates `androidx.activity:activity-compose` from 1.12.2 to 1.12.3

Updates `androidx.compose:compose-bom` from 2026.01.00 to 2026.01.01

Updates `androidx.paging:paging-runtime-ktx` from 3.3.6 to 3.4.0

Updates `androidx.paging:paging-compose` from 3.3.6 to 3.4.0

Updates `androidx.paging:paging-compose` from 3.3.6 to 3.4.0

Updates `androidx.work:work-runtime-ktx` from 2.11.0 to 2.11.1

Updates `androidx.work:work-testing` from 2.11.0 to 2.11.1

Updates `androidx.work:work-testing` from 2.11.0 to 2.11.1

Updates `com.google.devtools.ksp` from 2.3.4 to 2.3.5
- [Release notes](https://github.com/google/ksp/releases)
- [Commits](https://github.com/google/ksp/compare/2.3.4...2.3.5)

---
updated-dependencies:
- dependency-name: gradle-wrapper
  dependency-version: 9.3.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: app-dependencies
- dependency-name: androidx.activity:activity-compose
  dependency-version: 1.12.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: app-dependencies
- dependency-name: androidx.compose:compose-bom
  dependency-version: 2026.01.01
  dependency-type: direct:production
  dependency-group: app-dependencies
- dependency-name: androidx.paging:paging-runtime-ktx
  dependency-version: 3.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: app-dependencies
- dependency-name: androidx.paging:paging-compose
  dependency-version: 3.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: app-dependencies
- dependency-name: androidx.paging:paging-compose
  dependency-version: 3.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: app-dependencies
- dependency-name: androidx.work:work-runtime-ktx
  dependency-version: 2.11.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: app-dependencies
- dependency-name: androidx.work:work-testing
  dependency-version: 2.11.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: app-dependencies
- dependency-name: androidx.work:work-testing
  dependency-version: 2.11.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: app-dependencies
- dependency-name: com.google.devtools.ksp
  dependency-version: 2.3.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: app-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-03 14:57:10 +01:00
Ricki Hirner
5709aaa2e5 Bump version to 4.5.9 2026-02-03 12:12:05 +01:00
Ricki Hirner
a19c397ef6 Sync files with davx5 repo (#1958)
* Sync changes with davx5 repo

* Remove unnecessary test launcher icons
2026-02-02 12:30:04 +01:00
556 changed files with 1744 additions and 1242 deletions

3
.github/CODEOWNERS vendored
View File

@@ -3,6 +3,3 @@
# Dependabot
gradle/** @bitfireAT/app-dev
# everything else
* @rfc2822

View File

@@ -1,7 +1,7 @@
name: Qualified Bug Report
description: "For qualified bug reports. (Use Discussions if unsure.)"
type: bug
labels: ["bug"]
labels: ["needs-triage"]
body:
- type: checkboxes
attributes:

View File

@@ -1,7 +1,7 @@
name: Qualified Feature Request
description: "For qualified feature requests. (Use Discussions if unsure.)"
type: feature
labels: ["enhancement"]
labels: ["needs-triage"]
body:
- type: checkboxes
attributes:

View File

@@ -1,50 +0,0 @@
name: "CodeQL"
on:
push:
branches: [ main-ose ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ main-ose ]
schedule:
- cron: '22 10 * * 1'
concurrency:
group: codeql-${{ github.ref }}
cancel-in-progress: true
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
steps:
- name: Checkout repository
uses: actions/checkout@v6
- uses: actions/setup-java@v5
with:
distribution: temurin
java-version: 21
- uses: gradle/actions/setup-gradle@v5
with:
cache-encryption-key: ${{ secrets.gradle_encryption_key }}
cache-read-only: true # gradle user home cache is generated by test jobs
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v4
with:
languages: java-kotlin
build-mode: manual # autobuild uses older JDK
- name: Build # we must not use build cache here
run: ./gradlew --no-daemon --configuration-cache app:assembleDebug
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v4
with:
category: "/language:${{matrix.language}}"

View File

@@ -1,24 +0,0 @@
name: Dependency Submission
on:
push:
branches: [ 'main-ose' ]
permissions:
contents: write
jobs:
dependency-submission:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-java@v5
with:
distribution: temurin
java-version: 21
- name: Generate and submit dependency graph
uses: gradle/actions/dependency-submission@v5
with:
cache-encryption-key: ${{ secrets.gradle_encryption_key }}
dependency-graph-exclude-configurations: '.*[Tt]est.* .*[cC]heck.*'

View File

@@ -9,6 +9,7 @@ concurrency:
cancel-in-progress: true
env:
java-version: 21
prerelease: ${{ contains(github.ref_name, '-alpha') || contains(github.ref_name, '-beta') || contains(github.ref_name, '-rc') }}
jobs:
@@ -23,15 +24,17 @@ jobs:
- uses: actions/setup-java@v5
with:
distribution: temurin
java-version: 21
java-version: ${{ env.java-version }}
- uses: gradle/actions/setup-gradle@v5
with:
cache-encryption-key: ${{ secrets.gradle_encryption_key }}
- name: Prepare keystore
run: echo ${{ secrets.android_keystore_base64 }} | base64 -d >$GITHUB_WORKSPACE/keystore.jks
- name: Build signed package
# Use build cache to speed up building of build variants, but clean caches from previous tests before
run: ./gradlew --build-cache --configuration-cache --no-daemon app:clean app:assembleRelease
# don't use build cache to guarantee deterministic, fresh builds
run: ./gradlew --no-build-cache --configuration-cache --no-daemon app:clean app-ose:assembleRelease
env:
ANDROID_KEYSTORE: ${{ github.workspace }}/keystore.jks
ANDROID_KEYSTORE_PASSWORD: ${{ secrets.android_keystore_password }}
@@ -42,6 +45,6 @@ jobs:
uses: softprops/action-gh-release@v2
with:
prerelease: ${{ env.prerelease }}
files: app/build/outputs/apk/ose/release/*.apk
files: app-ose/build/outputs/apk/ose/release/*.apk
fail_on_unmatched_files: true
generate_release_notes: true

View File

@@ -2,7 +2,7 @@ name: Development tests
on:
push:
branches:
- 'main-ose'
- 'main'
pull_request:
concurrency:
@@ -18,6 +18,7 @@ env:
GRADLE_BUILDCACHE_USERNAME: ${{ secrets.gradle_buildcache_username }}
GRADLE_BUILDCACHE_PASSWORD: ${{ secrets.gradle_buildcache_password }}
GRADLE_OPTS: -Dorg.gradle.caching=true -Dorg.gradle.configuration-cache=true
JAVA_VERSION: 21
jobs:
compile:
@@ -28,31 +29,17 @@ jobs:
- uses: actions/setup-java@v5
with:
distribution: temurin
java-version: 21
java-version: ${{ env.JAVA_VERSION }}
# See https://community.gradle.org/github-actions/docs/setup-gradle/ for more information
- uses: gradle/actions/setup-gradle@v5
with:
cache-encryption-key: ${{ secrets.gradle_encryption_key }}
cache-read-only: false # allow branches to update their configuration cache
cache-read-only: false # allow to update the cache
gradle-home-cache-excludes: caches/build-cache-1 # don't cache local build cache because we use a remote cache
- name: Cache Android environment
uses: actions/cache@v5
with:
path: ~/.config/.android # needs to be cached so that configuration cache can work
key: android-${{ hashFiles('app/build.gradle.kts') }}
- name: Compile
run: ./gradlew app:compileOseDebugSource
# Cache configurations for the other jobs (including assemble for CodeQL)
- name: Populate configuration cache
run: |
./gradlew --dry-run app:assembleDebug
./gradlew --dry-run app:lintOseDebug
./gradlew --dry-run app:testOseDebugUnitTest
./gradlew --dry-run app:virtualOseDebugAndroidTest
run: ./gradlew app-ose:assembleDebug
unit_tests:
needs: compile
@@ -63,23 +50,18 @@ jobs:
- uses: actions/setup-java@v5
with:
distribution: temurin
java-version: 21
java-version: ${{ env.JAVA_VERSION }}
- uses: gradle/actions/setup-gradle@v5
with:
cache-encryption-key: ${{ secrets.gradle_encryption_key }}
cache-read-only: true
- name: Restore Android environment
uses: actions/cache/restore@v5
with:
path: ~/.config/.android
key: android-${{ hashFiles('app/build.gradle.kts') }}
- name: Lint checks
run: ./gradlew app:lintOseDebug
run: ./gradlew core:lintDebug app:lintOseDebug
- name: Unit tests
run: ./gradlew app:testOseDebugUnitTest
# currently no unit tests for app-ose
run: ./gradlew core:testDebugUnitTest
instrumented_tests:
needs: compile
@@ -90,18 +72,12 @@ jobs:
- uses: actions/setup-java@v5
with:
distribution: temurin
java-version: 21
java-version: ${{ env.JAVA_VERSION }}
- uses: gradle/actions/setup-gradle@v5
with:
cache-encryption-key: ${{ secrets.gradle_encryption_key }}
cache-read-only: true
- name: Restore Android environment
uses: actions/cache/restore@v5
with:
path: ~/.config/.android
key: android-${{ hashFiles('app/build.gradle.kts') }}
# gradle and Android SDK often take more space than what is available on the default runner.
# We try to free a few GB here to make gradle-managed devices more reliable.
- name: Free some disk space
@@ -115,8 +91,8 @@ jobs:
id: restore-avd
uses: actions/cache/restore@v5
with:
path: ~/.config/.android/avd # where AVD is stored
key: avd-${{ hashFiles('app/build.gradle.kts') }} # gradle-managed devices are defined there
path: ~/.config/.android/avd # where AVD is stored
key: avd-${{ hashFiles('app-ose/build.gradle.kts') }} # gradle-managed devices are defined there
# Enable virtualization for Android emulator
- name: Enable KVM group perms
@@ -126,11 +102,12 @@ jobs:
sudo udevadm trigger --name-match=kvm
- name: Instrumented tests
run: ./gradlew app:virtualOseDebugAndroidTest
# currently no instrumented tests for app-ose
run: ./gradlew core:virtualDebugAndroidTest
- name: Cache AVD
uses: actions/cache/save@v5
if: steps.restore-avd.outputs.cache-hit != 'true'
with:
path: ~/.config/.android/avd # where AVD is stored
key: avd-${{ hashFiles('app/build.gradle.kts') }} # gradle-managed devices are defined there
path: ~/.config/.android/avd # where AVD is stored
key: avd-${{ hashFiles('app-ose/build.gradle.kts') }} # gradle-managed devices are defined there

130
app-ose/build.gradle.kts Normal file
View File

@@ -0,0 +1,130 @@
/*
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.compose.compiler)
alias(libs.plugins.hilt)
alias(libs.plugins.ksp)
alias(libs.plugins.mikepenz.aboutLibraries.android)
}
android {
compileSdk = 36
defaultConfig {
minSdk = 24 // Android 7.0
targetSdk = 36 // Android 16
applicationId = "at.bitfire.davdroid"
versionCode = 405100000
versionName = "4.5.10-alpha.1"
base.archivesName = "davx5-$versionCode-$versionName"
// currently no instrumentation tests for app-ose, so no testInstrumentationRunner
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
compileOptions {
isCoreLibraryDesugaringEnabled = true
}
buildFeatures {
compose = true
}
// Java namespace for our classes (not to be confused with Android package ID)
namespace = "com.davx5.ose"
flavorDimensions += "distribution"
productFlavors {
create("ose") {
dimension = "distribution"
versionNameSuffix = "-ose"
}
}
androidResources {
generateLocaleConfig = true
}
@Suppress("UnstableApiUsage")
testOptions {
managedDevices {
localDevices {
create("virtual") {
device = "Pixel 3"
// TBD: API level 35 and higher causes network tests to fail sometimes, see https://github.com/bitfireAT/davx5-ose/issues/1525
// Suspected reason: https://developer.android.com/about/versions/15/behavior-changes-all#background-network-access
apiLevel = 34
systemImageSource = "aosp-atd"
}
}
}
}
signingConfigs {
create("bitfire") {
storeFile = file(System.getenv("ANDROID_KEYSTORE") ?: "/dev/null")
storePassword = System.getenv("ANDROID_KEYSTORE_PASSWORD")
keyAlias = System.getenv("ANDROID_KEY_ALIAS")
keyPassword = System.getenv("ANDROID_KEY_PASSWORD")
}
}
buildTypes {
getByName("release") {
isMinifyEnabled = true
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules-release.pro")
isShrinkResources = true
// must be after signingConfigs {} block
signingConfig = signingConfigs.findByName("bitfire")
}
}
}
dependencies {
// include core subproject (manages its own dependencies itself, however from same version catalog)
implementation(project(":core"))
// Kotlin / Android
implementation(libs.kotlin.stdlib)
implementation(libs.kotlinx.coroutines)
coreLibraryDesugaring(libs.android.desugaring)
// Hilt
implementation(libs.hilt.android.base)
ksp(libs.androidx.hilt.compiler)
ksp(libs.hilt.android.compiler)
// support libs
implementation(libs.androidx.core)
implementation(libs.androidx.hilt.work)
implementation(libs.androidx.lifecycle.viewmodel.base)
implementation(libs.androidx.lifecycle.viewmodel.compose)
implementation(libs.androidx.work.base)
// Jetpack Compose
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.compose.material3)
debugImplementation(libs.androidx.compose.ui.tooling)
implementation(libs.androidx.compose.ui.toolingPreview)
// own libraries
implementation(libs.bitfire.cert4android)
// third-party libs
implementation(libs.guava)
implementation(libs.okhttp.base)
implementation(libs.openid.appauth)
}

View File

@@ -0,0 +1,5 @@
-dontobfuscate
-printusage build/reports/r8-usage.txt
# keep rules are taken from core/core-proguard-rules.pro

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:installLocation="internalOnly">
<application android:name=".App">
<!-- Required for Hilt/WorkManager integration. See
- https://developer.android.com/develop/background-work/background-tasks/persistent/configuration/custom-configuration#remove-default
- https://developer.android.com/training/dependency-injection/hilt-jetpack#workmanager
However, we must not disable AndroidX startup completely, as it's needed by other libraries like okhttp. -->
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<meta-data
android:name="androidx.work.WorkManagerInitializer"
android:value="androidx.startup"
tools:node="remove" />
</provider>
</application>
</manifest>

View File

@@ -0,0 +1,30 @@
/*
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
package com.davx5.ose
import androidx.work.Configuration
import at.bitfire.davdroid.CoreApp
import dagger.hilt.android.HiltAndroidApp
/**
* Actual implementation of Application, used for Hilt. Delegates to [CoreApp].
*/
@HiltAndroidApp
class App: CoreApp(), Configuration.Provider {
/**
* Required for Hilt/WorkManager integration, see:
* https://developer.android.com/training/dependency-injection/hilt-jetpack#workmanager
*
* This requires to remove the androidx.work.WorkManagerInitializer from App Startup
* in the AndroidManifest, see:
* https://developer.android.com/develop/background-work/background-tasks/persistent/configuration/custom-configuration#remove-default
*/
override val workManagerConfiguration: Configuration
get() = Configuration.Builder()
.setWorkerFactory(workerFactory)
.build()
}

View File

@@ -1,8 +1,8 @@
/***************************************************************************************************
/*
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
**************************************************************************************************/
*/
package at.bitfire.davdroid
package com.davx5.ose
import android.content.Context
import at.bitfire.davdroid.ui.DebugInfoActivity

View File

@@ -0,0 +1,19 @@
/*
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
package com.davx5.ose.di
import at.bitfire.davdroid.ui.AccountsDrawerHandler
import at.bitfire.davdroid.ui.OseAccountsDrawerHandler
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ActivityComponent
@Module
@InstallIn(ActivityComponent::class)
interface AccountsDrawerHandlerModule {
@Binds
fun accountsDrawerHandler(impl: OseAccountsDrawerHandler): AccountsDrawerHandler
}

View File

@@ -0,0 +1,19 @@
/*
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
package com.davx5.ose.di
import at.bitfire.davdroid.ui.about.AboutActivity
import com.davx5.ose.ui.about.OpenSourceLicenseInfoProvider
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ViewModelComponent
@Module
@InstallIn(ViewModelComponent::class)
interface AppLicenseInfoProviderModule {
@Binds
fun appLicenseInfoProvider(impl: OpenSourceLicenseInfoProvider): AboutActivity.AppLicenseInfoProvider
}

View File

@@ -2,63 +2,60 @@
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
package at.bitfire.davdroid.di
package com.davx5.ose.di
import android.content.Context
import at.bitfire.cert4android.CustomCertManager
import at.bitfire.cert4android.CustomCertStore
import at.bitfire.cert4android.SettingsProvider
import at.bitfire.davdroid.BuildConfig
import at.bitfire.davdroid.settings.Settings
import at.bitfire.davdroid.settings.SettingsManager
import at.bitfire.davdroid.ui.ForegroundTracker
import dagger.Module
import dagger.Provides
import dagger.Reusable
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import okhttp3.internal.tls.OkHostnameVerifier
import java.util.Optional
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
/**
* cert4android integration module
*/
class CustomCertManagerModule {
@Module
@InstallIn(SingletonComponent::class)
class Cert4AndroidModule {
@Provides
@Singleton
fun customCertStore(@ApplicationContext context: Context): Optional<CustomCertStore> =
Optional.of(CustomCertStore.getInstance(context))
@Provides
@Reusable
fun customCertManager(
@ApplicationContext context: Context,
customCertStore: Optional<CustomCertStore>,
settings: SettingsManager
): Optional<CustomCertManager> =
if (BuildConfig.allowCustomCerts)
Optional.of(CustomCertManager(
certStore = CustomCertStore.getInstance(context),
settings = object : SettingsProvider {
Optional.of(
CustomCertManager(
certStore = customCertStore.get(),
settings = object : SettingsProvider {
override val appInForeground: Boolean
get() = ForegroundTracker.inForeground.value
override val appInForeground: Boolean
get() = ForegroundTracker.inForeground.value
override val trustSystemCerts: Boolean
get() = !settings.getBoolean(Settings.DISTRUST_SYSTEM_CERTIFICATES)
override val trustSystemCerts: Boolean
get() = !settings.getBoolean(Settings.DISTRUST_SYSTEM_CERTIFICATES)
}
))
else
Optional.empty()
}
))
@Provides
@Singleton
@Reusable
fun customHostnameVerifier(
customCertManager: Optional<CustomCertManager>
): Optional<CustomCertManager.HostnameVerifier> =
if (BuildConfig.allowCustomCerts && customCertManager.isPresent) {
val hostnameVerifier = customCertManager.get().HostnameVerifier(OkHostnameVerifier)
Optional.of(hostnameVerifier)
} else
Optional.empty()
Optional.of(customCertManager.get().HostnameVerifier(OkHostnameVerifier))
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
package com.davx5.ose.di
import androidx.compose.material3.ColorScheme
import at.bitfire.davdroid.di.qualifier.DarkColorScheme
import at.bitfire.davdroid.di.qualifier.LightColorScheme
import at.bitfire.davdroid.ui.OseTheme
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
@Module
@InstallIn(SingletonComponent::class)
class ColorSchemesModule {
@Provides
@LightColorScheme
fun lightColorScheme(): ColorScheme = OseTheme.lightScheme
@Provides
@DarkColorScheme
fun darkColorScheme(): ColorScheme = OseTheme.darkScheme
}

View File

@@ -0,0 +1,19 @@
/*
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
package com.davx5.ose.di
import at.bitfire.davdroid.ui.intro.IntroPageFactory
import com.davx5.ose.ui.intro.OseIntroPageFactory
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
@Module
@InstallIn(SingletonComponent::class)
interface IntroPageFactoryModule {
@Binds
fun introPageFactory(impl: OseIntroPageFactory): IntroPageFactory
}

View File

@@ -0,0 +1,21 @@
/*
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
package com.davx5.ose.di
import at.bitfire.davdroid.ui.setup.LoginTypesProvider
import at.bitfire.davdroid.ui.setup.StandardLoginTypesProvider
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
@Module
@InstallIn(SingletonComponent::class)
interface LoginTypesProviderModule {
@Binds
fun loginTypesProvider(impl: StandardLoginTypesProvider): LoginTypesProvider
}

View File

@@ -2,9 +2,9 @@
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
package at.bitfire.davdroid.ui.about
package com.davx5.ose.ui.about
import android.app.Application
import android.content.Context
import android.text.Spanned
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@@ -14,13 +14,16 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.tooling.preview.Preview
import androidx.core.text.HtmlCompat
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.compose.viewModel
import at.bitfire.davdroid.di.qualifier.IoDispatcher
import at.bitfire.davdroid.ui.UiUtils.toAnnotatedString
import at.bitfire.davdroid.ui.about.AboutActivity
import com.google.common.io.CharStreams
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.launch
import javax.inject.Inject
@@ -40,13 +43,16 @@ class OpenSourceLicenseInfoProvider @Inject constructor(): AboutActivity.AppLice
@HiltViewModel
class Model @Inject constructor(app: Application): AndroidViewModel(app) {
class Model @Inject constructor(
@ApplicationContext private val context: Context,
@IoDispatcher private val ioDispatcher: CoroutineDispatcher
): ViewModel() {
var gpl by mutableStateOf<Spanned?>(null)
init {
viewModelScope.launch(Dispatchers.IO) {
app.resources.assets.open("gplv3.html").use { inputStream ->
viewModelScope.launch(ioDispatcher) {
context.resources.assets.open("gplv3.html").use { inputStream ->
val raw = CharStreams.toString(inputStream.bufferedReader())
gpl = HtmlCompat.fromHtml(raw, HtmlCompat.FROM_HTML_MODE_LEGACY)
}

View File

@@ -2,8 +2,15 @@
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
package at.bitfire.davdroid.ui.intro
package com.davx5.ose.ui.intro
import at.bitfire.davdroid.ui.intro.BackupsPage
import at.bitfire.davdroid.ui.intro.BatteryOptimizationsPage
import at.bitfire.davdroid.ui.intro.IntroPageFactory
import at.bitfire.davdroid.ui.intro.OpenSourcePage
import at.bitfire.davdroid.ui.intro.PermissionsIntroPage
import at.bitfire.davdroid.ui.intro.TasksIntroPage
import at.bitfire.davdroid.ui.intro.WelcomePage
import javax.inject.Inject
class OseIntroPageFactory @Inject constructor(

1
app/src/.gitignore vendored
View File

@@ -1 +0,0 @@
espressoTest

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -1,22 +0,0 @@
/*
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
package at.bitfire.davdroid
import at.bitfire.synctools.icalendar.ical4jVersion
import ezvcard.Ezvcard
/**
* Brand-specific constants like (non-theme) colors, homepage URLs etc.
*/
object Constants {
const val DAVDROID_GREEN_RGBA = 0xFF8bc34a.toInt()
// product IDs for iCalendar/vCard
val iCalProdId = "DAVx5/${BuildConfig.VERSION_NAME} ical4j/$ical4jVersion"
const val vCardProdId = "+//IDN bitfire.at//DAVx5/${BuildConfig.VERSION_NAME} ez-vcard/${Ezvcard.VERSION}"
}

View File

@@ -1,45 +0,0 @@
/*
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
package at.bitfire.davdroid.ui.composable
import android.content.Intent
import android.view.ViewGroup
import android.webkit.WebResourceRequest
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.intl.Locale
import androidx.compose.ui.viewinterop.AndroidView
import io.ktor.http.HttpHeaders
@Composable
fun WebViewCompat(
url: String,
modifier: Modifier = Modifier,
layoutParams: ViewGroup.LayoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
) {
AndroidView(
modifier = modifier,
factory = { context ->
WebView(context).apply {
this.layoutParams = layoutParams
webViewClient = object : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {
val intent = Intent(Intent.ACTION_VIEW, request.url)
context.startActivity(intent)
return true
}
}
loadUrl(url, mapOf(
HttpHeaders.AcceptLanguage to Locale.current.toLanguageTag()
))
}
}
)
}

View File

@@ -1,12 +0,0 @@
/*
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
package at.bitfire.davdroid.ui.widget
import androidx.glance.appwidget.GlanceAppWidget
import androidx.glance.appwidget.GlanceAppWidgetReceiver
class IconSyncButtonWidgetReceiver : GlanceAppWidgetReceiver() {
override val glanceAppWidget: GlanceAppWidget = IconSyncButtonWidget()
}

View File

@@ -1,12 +0,0 @@
/*
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
package at.bitfire.davdroid.ui.widget
import androidx.glance.appwidget.GlanceAppWidget
import androidx.glance.appwidget.GlanceAppWidgetReceiver
class LabeledSyncButtonWidgetReceiver : GlanceAppWidgetReceiver() {
override val glanceAppWidget: GlanceAppWidget = LabeledSyncButtonWidget()
}

View File

@@ -1,483 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources xmlns:tools="http://schemas.android.com/tools">
<!--common strings-->
<string name="account_invalid">Konto nicht (mehr) vorhanden</string>
<string name="account_title_address_book">DAVx⁵-Adressbuch</string>
<string name="account_prefs_use_app">Konto nicht hier ändern! Um Konten zu verwalten, stattdessen direkt die App nutzen.</string>
<string name="dialog_delete">Löschen</string>
<string name="dialog_remove">Entfernen</string>
<string name="dialog_deny">Abbrechen</string>
<string name="dialog_enable">Aktivieren</string>
<string name="field_required">Feld wird benötigt</string>
<string name="help">Hilfe</string>
<string name="navigate_up">Aufwärts navigieren</string>
<string name="options_menu">Auswahlmenü</string>
<string name="share">Teilen</string>
<string name="sync_started">Synchronisierung gestartet/eingereiht</string>
<string name="database_destructive_migration_title">Datenbank beschädigt</string>
<string name="database_destructive_migration_text">Alle Konten wurden lokal entfernt.</string>
<string name="notification_channel_debugging">Fehlersuche</string>
<string name="notification_channel_general">Andere wichtige Mitteilungen</string>
<string name="notification_channel_status">Weniger wichtige Statusmitteilungen</string>
<string name="notification_channel_sync">Synchronisierung</string>
<string name="notification_channel_sync_errors">Synchronisierungsfehler</string>
<string name="notification_channel_sync_errors_desc">Fehler, die zum Abbruch der Synchronisierung führen, wie z.B. unerwartete Serverantworten</string>
<string name="notification_channel_sync_warnings">Synchronisierungswarnungen</string>
<string name="notification_channel_sync_warnings_desc">Nicht fatale Synchronisierungsprobleme wie bestimmte ungültige Dateien</string>
<string name="notification_channel_sync_io_errors">Netzwerk- und E/A-Fehler</string>
<string name="notification_channel_sync_io_errors_desc">Zeitüberschreitungen, Verbindungsprobleme, usw. (oft vorübergehend)</string>
<!--IntroActivity-->
<string name="intro_slogan1">Dein Leben. Deine Daten.</string>
<string name="intro_slogan2">Deine Entscheidung.</string>
<string name="intro_battery_title">Regelmäßige Sync-Intervalle</string>
<string name="intro_battery_text">Zur Synchronisierung in regelmäßigen Intervallen muss %s im Hintergrund laufen dürfen; ansonsten kann Android die Synchronisierung jederzeit aussetzen.</string>
<string name="intro_battery_dont_show">Ich brauche keine regelmäßigen Sync-Intervalle.*</string>
<string name="intro_autostart_title">%s-Kompatibilität</string>
<string name="intro_autostart_text">Herstellerspezifische Firmware blockiert möglicherweise die Synchronisierung. Wenn Sie davon betroffen sind, können Sie dies nur manuell beheben.</string>
<string name="intro_autostart_dont_show">Ich habe die Einstellungen gemacht, nicht mehr erinnern.*</string>
<string name="intro_leave_unchecked">* Nicht anwählen, um später erinnert zu werden. Kann unter App-Einstellungen / %s zurückgesetzt werden.</string>
<string name="intro_more_info">Mehr Infos</string>
<string name="intro_tasks_jtx">jtx Board</string>
<string name="intro_tasks_jtx_info"><![CDATA[Unterstützt Synchronisierung von Aufgaben, Journalen und Notizen.]]></string>
<string name="intro_tasks_title">Unterstützung für Aufgaben</string>
<string name="intro_tasks_text1">Falls der Server Aufgaben unterstützt, können sie mit einer unterstützten App synchronisiert werden:</string>
<string name="intro_tasks_opentasks">OpenTasks</string>
<string name="intro_tasks_opentasks_info">Wird anscheinend nicht weiterentwickelt nicht empfohlen.</string>
<string name="intro_tasks_tasks_org">Tasks.org</string>
<string name="intro_tasks_tasks_org_info"><![CDATA[Einige Funktionen <a href="https://www.davx5.com/faq/tasks/advanced-task-features">werden nicht unterstützt</a>.]]></string>
<string name="intro_tasks_no_app_store">Kein App-Store verfügbar</string>
<string name="intro_tasks_dont_show">Ich brauche keine Unterstützung für Aufgaben.*</string>
<string name="intro_open_source_title">Open-Source-Software</string>
<string name="intro_open_source_text">Wir freuen uns, dass Sie die Open-Source-Software %s verwenden. Entwicklung, Wartung und Support sind viel Arbeit. Ziehen Sie daher bitte in Betracht, mitzuhelfen (dazu gibt es viele Möglichkeiten) oder zu spenden. Vielen Dank!</string>
<string name="intro_open_source_details">Infos zum Mithelfen/Spenden</string>
<string name="intro_open_source_dont_show">Nicht daran erinnern für</string>
<plurals name="intro_open_source_dont_show_months">
<item quantity="one">%d Monat</item>
<item quantity="other">%d Monate</item>
</plurals>
<string name="intro_next">Weiter</string>
<!--PermissionsActivity-->
<string name="permissions_title">Berechtigungsverwaltung</string>
<string name="permissions_text">%s benötigt Berechtigungen, um ordnungsgemäß zu funktionieren.</string>
<string name="permissions_all_title">Alles darunter</string>
<string name="permissions_all_status_off">Hiermit können alle Funktionen aktiviert werden (empfohlen)</string>
<string name="permissions_all_status_on">Alle Berechtigungen gewährt</string>
<string name="permissions_contacts_title">Kontakte-Berechtigungen</string>
<string name="permissions_contacts_status_off">Keine Kontakte-Synchronisierung (nicht empfohlen)</string>
<string name="permissions_contacts_status_on">Kontakte-Synchronisierung möglich</string>
<string name="permissions_calendar_title">Kalender-Berechtigungen</string>
<string name="permissions_calendar_status_off">Keine Kalender-Synchronisierung (nicht empfohlen)</string>
<string name="permissions_calendar_status_on">Kalender-Synchronisierung möglich</string>
<string name="permissions_notification_title">Benachrichtigungsberechtigung</string>
<string name="permissions_notification_status_off">Benachrichtigungen deaktiviert (nicht empfohlen)</string>
<string name="permissions_notification_status_on">Benachrichtigungen aktiviert</string>
<string name="permissions_jtx_title">jtx Board-Berechtigungen</string>
<string name="permissions_opentasks_title">OpenTasks-Berechtigungen</string>
<string name="permissions_tasksorg_title">Tasks-Berechtigungen</string>
<string name="permissions_tasks_status_off">Keine Aufgaben-Synchronisierung</string>
<string name="permissions_tasks_status_on">Aufgaben-Synchronisierung möglich</string>
<string name="permissions_autoreset_title">Berechtigungen behalten</string>
<string name="permissions_autoreset_status_off">Berechtigungen können automatisch entzogen werden (nicht empfohlen)</string>
<string name="permissions_autoreset_status_on">Berechtigungen werden nicht automatisch entzogen</string>
<string name="permissions_autoreset_instruction">Berechtigungen &gt; \"Berechtigungen entfernen, wenn die App nicht verwendet wird\" abwählen</string>
<string name="permissions_app_settings_hint">Wenn ein Schalter nicht funktioniert, App-Einstellungen / Berechtigungen verwenden.</string>
<string name="permissions_app_settings">App-Einstellungen</string>
<!--WifiPermissionsActivity-->
<string name="wifi_permissions_label">WLAN-SSID-Berechtigungen</string>
<string name="wifi_permissions_intro">Um auf den aktuellen WLAN-Namen (SSID) zugreifen zu können, müssen folgende Bedingungen erfüllt werden:</string>
<string name="wifi_permissions_location_permission">Exakter Standort-Berechtigung</string>
<string name="wifi_permissions_location_permission_on">Standort-Zugriff erlaubt</string>
<string name="wifi_permissions_location_permission_off">Standort-Zugriff verweigert</string>
<string name="wifi_permissions_background_location_permission">Hintergrund-Standort-Berechtigung</string>
<string name="wifi_permissions_background_location_permission_label">Immer zulassen</string>
<string name="wifi_permissions_background_location_permission_on">Standort-Zugriff eingestellt auf: %s</string>
<string name="wifi_permissions_background_location_permission_off">Standort-Zugriff nicht eingestellt auf: %s</string>
<string name="wifi_permissions_background_location_disclaimer">%s benutzt Standortdaten (nur WLAN-SSID) ausschließlich, um die Synchronisierung auf ein bestimmtes WLAN zu beschränken. Dies geschieht auch dann, wenn die Synchronisierung im Hintergrund ausgeführt wird.</string>
<string name="wifi_permissions_background_location_disclaimer2">Alle Standortdaten (nur WLAN-SSID) werden nur lokal verwendet und nicht an Dritte weitergegeben.</string>
<string name="wifi_permissions_location_enabled">Standort-Dienst immer aktiviert</string>
<string name="wifi_permissions_location_enabled_on">Standort-Dienst aktiv</string>
<string name="wifi_permissions_location_enabled_off">Standort-Dienst inaktiv</string>
<!--AboutActivity-->
<string name="about_translations">Übersetzungen</string>
<string name="about_libraries">Bibliotheken</string>
<string name="about_version">Version %1$s (%2$d)</string>
<string name="about_copyright">© Ricki Hirner, Bernhard Stockmann (bitfire web engineering GmbH) und Mitwirkende</string>
<string name="about_license_info_no_warranty">Dieses Programm wird OHNE JEDE GEWÄHRLEISTUNG bereitgestellt. Es ist freie Software Sie können es also unter bestimmten Bedingungen weiterverbreiten.</string>
<!--global settings-->
<string name="logging_couldnt_create_file">Protokolldatei konnte nicht angelegt werden</string>
<string name="logging_notification_text">Alle %s-Aktivitäten werden protokolliert</string>
<string name="logging_notification_view_share">Anzeigen/teilen</string>
<string name="logging_notification_disable">Deaktivieren</string>
<!--AccountsScreen-->
<string name="navigation_drawer_subtitle">CalDAV/CardDAV-Sync-Adapter</string>
<string name="navigation_drawer_about">Über / Lizenz</string>
<string name="navigation_drawer_beta_feedback">Beta-Rückmeldung</string>
<string name="install_browser">Bitte installieren Sie einen Web-Browser</string>
<string name="navigation_drawer_settings">Einstellungen</string>
<string name="navigation_drawer_news_updates">Aktuelles</string>
<string name="navigation_drawer_tools">Werkzeuge</string>
<string name="navigation_drawer_external_links">Externe Links</string>
<string name="navigation_drawer_website">Homepage</string>
<string name="navigation_drawer_manual">Handbuch</string>
<string name="navigation_drawer_faq">FAQ</string>
<string name="navigation_drawer_managed">Für Organisationen</string>
<string name="navigation_drawer_community">Community</string>
<string name="navigation_drawer_support_project">Projekt unterstützen</string>
<string name="navigation_drawer_contribute">Einen Beitrag leisten</string>
<string name="navigation_drawer_privacy_policy">Datenschutzerklärung</string>
<string name="account_list_welcome">Willkommen bei DAVx⁵!</string>
<string name="account_list_empty">Verbinden Sie sich mit Ihrem Server und synchronisieren Sie Ihre Kalender und Kontakte.</string>
<string name="accounts_sync_all">Alle Konten synchronisieren</string>
<!--Sync warnings-->
<string name="sync_warning_no_notification_permission">Benachrichtigungen deaktiviert. Sie werden nicht über Fehler bei der Synchronisierung informiert.</string>
<string name="sync_warning_no_internet">Automatische Synchronisation nicht aktiv (keine überprüfte Internetverbindung).</string>
<string name="sync_warning_manage_connections">Verbindungen steuern</string>
<string name="sync_warning_datasaver_enabled">Datensparen aktiviert. Hintergrundsynchronisierung ist eingeschränkt.</string>
<string name="sync_warning_manage_datasaver">Datensparen verwalten</string>
<string name="sync_warning_battery_saver_enabled">Energiesparmodus aktiviert. Synchronisierung kann eingeschränkt sein.</string>
<string name="sync_warning_manage_battery_saver">Energieeinstellungen verwalten</string>
<string name="sync_warning_low_storage">Wenig Speicherplatz. Android wird lokale Änderungen nicht sofort synchronisieren, sondern bei der nächsten regulären Synchronisierung.</string>
<string name="sync_warning_manage_storage">Speicherplatz verwalten</string>
<string name="sync_warning_calendar_storage_disabled_title">Kalender-Provider fehlt</string>
<string name="sync_warning_calendar_storage_disabled_description">Haben Sie die »Kalender«-System-App deaktiviert?</string>
<string name="sync_warning_contacts_storage_disabled_title">Kontakte-Provider fehlt</string>
<string name="sync_warning_contacts_storage_disabled_description">Haben Sie die »Kontakte«-System-App deaktiviert?</string>
<string name="sync_warning_manage_apps">Apps verwalten</string>
<!--RefreshCollectionsWorker-->
<string name="refresh_collections_worker_refresh_failed">Diensterkennung fehlgeschlagen</string>
<string name="refresh_collections_worker_refresh_couldnt_refresh">Ordnerliste konnte nicht aktualisiert werden</string>
<!--Foreground service used by WorkManager on Android <12-->
<string name="foreground_service_notify_title">Läuft im Vordergrund</string>
<string name="foreground_service_notify_text">Auf manchen Geräten für die automatische Synchronisierung benötigt</string>
<!--AppSettingsActivity-->
<string name="app_settings">Einstellungen</string>
<string name="app_settings_debug">Fehlersuche</string>
<string name="app_settings_show_debug_info">Informationen zur Fehlersuche</string>
<string name="app_settings_show_debug_info_details">Einstellungsdetails und Logs anzeigen/teilen</string>
<string name="app_settings_logging">Ausführliche Protokollierung</string>
<string name="app_settings_logging_on">Logging ist aktiv. Sie können die Logs in den Debuginformationen anzeigen.</string>
<string name="app_settings_logging_off">Keine Protokollierung</string>
<string name="app_settings_battery_optimization">Akku-Optimierung</string>
<string name="app_settings_battery_optimization_exempted">App ist ausgenommen (empfohlen)</string>
<string name="app_settings_battery_optimization_optimized">Akku-Einschränkungen gelten (nicht empfohlen)</string>
<string name="app_settings_connection">Verbindung</string>
<string name="app_settings_proxy">Proxy-Typ</string>
<string-array name="app_settings_proxy_types">
<item>System-Standard</item>
<item>Kein Proxy</item>
<item>HTTP</item>
<item>SOCKS (für Orbot)</item>
</string-array>
<string name="app_settings_proxy_host">Proxy-Rechnername</string>
<string name="app_settings_proxy_port">Proxy-Port</string>
<string name="app_settings_security">Sicherheit</string>
<string name="app_settings_security_app_permissions">App-Berechtigungen</string>
<string name="app_settings_security_app_permissions_summary">Für die Synchronisierung benötigte Berechtigungen prüfen</string>
<string name="app_settings_distrust_system_certs">Systemzertifikaten nicht vertrauen</string>
<string name="app_settings_distrust_system_certs_on">System- und installierten CAs wird nicht vertraut</string>
<string name="app_settings_distrust_system_certs_off">System- und installierten CAs wird vertraut (empfohlen)</string>
<string name="app_settings_distrust_system_certs_dialog_message">Wenn diese Einstellung aktiv ist, werden Systemzertifikate als nicht vertrauenswürdig erachtet. Das bedeutet, dass Sie jedes Zertifikat (auch wenn der Server sein Zertifikat auffrischt) von Hand akzeptieren müssen; sonst werden Kontoeinrichtung und Synchronisierung nicht funktionieren.</string>
<string name="app_settings_reset_certificates">Zertifikat-Vertrauen zurücksetzen</string>
<string name="app_settings_reset_certificates_summary">Setzt angenommene/abgelehnte Zertifikate zurück</string>
<string name="app_settings_reset_certificates_success">Angenommene/abgelehnte Zertifikate zurückgesetzt</string>
<string name="app_settings_user_interface">Oberfläche</string>
<string name="app_settings_notification_settings">Benachrichtigungseinstellungen</string>
<string name="app_settings_notification_settings_summary">Benachrichtigungskanäle und -einstellungen verwalten</string>
<string name="app_settings_theme_title">Aussehen wählen</string>
<string-array name="app_settings_theme_names">
<item>wie System</item>
<item>heller Stil</item>
<item>dunkler Stil</item>
</string-array>
<string name="app_settings_reset_hints">Hinweise zurücksetzen</string>
<string name="app_settings_reset_hints_summary">Hinweise, die deaktiviert wurden, wieder anzeigen</string>
<string name="app_settings_reset_hints_success">Alle Hinweise werden wieder angezeigt</string>
<string name="app_settings_integration">Integration</string>
<string name="app_settings_tasks_provider">Aufgaben-App</string>
<string name="app_settings_tasks_provider_none">Keine kompatible Aufgaben-App gefunden</string>
<string name="app_settings_unifiedpush">UnifiedPush (experimentell)</string>
<string name="app_settings_unifiedpush_disable">Keiner (Push deaktivieren)</string>
<string name="app_settings_unifiedpush_choose_distributor">Anbieter auswählen</string>
<string name="app_settings_unifiedpush_no_distributor">Kein Push-Anbieter installiert</string>
<string name="app_settings_unifiedpush_no_endpoint">Kein Endpunkt konfiguriert</string>
<string name="app_settings_unifiedpush_ready">Bereit, Push-Mitteilungen über %s zu empfangen</string>
<string name="app_settings_unifiedpush_distributor_fcm">FCM (Google Play)</string>
<string name="app_settings_unifiedpush_encrypted">Push-Nachrichten sind immer verschlüsselt.</string>
<!--AccountScreen-->
<string name="account_invalid_account">Konto wurde entfernt</string>
<string name="account_carddav">CardDAV</string>
<string name="account_caldav">CalDAV</string>
<string name="account_webcal">Webcal</string>
<string name="account_missing_permissions">Für die Synchronisierung dieser Ordner sind zusätzliche Berechtigungen erforderlich.</string>
<string name="account_manage_permissions">Berechtigungen verwalten</string>
<string name="account_synchronize_now">Jetzt synchronisieren</string>
<string name="account_settings">Konto-Einstellungen</string>
<string name="account_rename">Konto umbenennen</string>
<string name="account_rename_new_name_description">Nicht gespeicherte lokale Daten können verloren gehen. Nach dem Umbenennen ist eine erneute Synchronisierung erforderlich.</string>
<string name="account_rename_new_name">Neuer Kontoname</string>
<string name="account_rename_rename">Umbenennen</string>
<string name="account_rename_exists_already">Kontoname bereits verwendet</string>
<string name="account_rename_couldnt_rename">Konto konnte nicht umbenannt werden</string>
<string name="account_delete">Konto löschen</string>
<string name="account_delete_confirmation_title">Konto wirklich löschen?</string>
<string name="account_delete_confirmation_text">Alle Adressbücher, Kalender und Aufgabenlisten werden vom Gerät (nicht am Server) gelöscht.</string>
<string name="account_synchronize_this_collection">Diesen Ordner synchronisieren</string>
<string name="account_read_only">schreibgeschützt</string>
<string name="account_calendar">Kalender</string>
<string name="account_contacts">Kontakte</string>
<string name="account_journal">Journal</string>
<string name="account_task_list">Aufgaben</string>
<string name="account_only_personal">Nur eigene anzeigen</string>
<string name="account_refresh_collections">Liste aktualisieren</string>
<string name="account_webcal_external_app">Webcal-Abonnements können mit externen Apps synchronisiert werden.</string>
<string name="account_no_webcal_handler_found">Keine Webcal-App gefunden</string>
<string name="account_install_icsx5">ICSx⁵ installieren</string>
<!--AddAccountActivity-->
<string name="login_title">Konto hinzufügen</string>
<string name="login_privacy_hint"><![CDATA[Alle Daten werden nur zwischen Ihrem Server und Ihrem Gerät übertragen. %1$s wird sie nirgendwohin sonst schicken. Siehe die <a href="%2$s">Datenschutzbestimmungen</a>.]]></string>
<string name="login_generic_login">Allgemeine Anmeldung</string>
<string name="login_provider_login">Provider-spezifische Anmeldung</string>
<string name="login_continue">Fortfahren</string>
<string name="login_login">Anmelden</string>
<string name="login_type_email">Mit E-Mail-Adresse anmelden</string>
<string name="login_email_address">E-Mail-Adresse</string>
<string name="login_email_address_error">Gültige E-Mail-Adresse benötigt</string>
<string name="login_email_address_info"><![CDATA[Die E-Mail-Domäne wird als Basis-URL verwendet. <a href="%s">Dienst-Erkennung</a> erfolgt über DNS-Einträge und well-known-URLs.]]></string>
<string name="login_password">Passwort</string>
<string name="login_password_hide">Passwort ausblenden</string>
<string name="login_password_show">Passwort anzeigen</string>
<string name="login_password_optional">Passwort (optional)</string>
<string name="login_type_url">Mit URL und Benutzername anmelden</string>
<string name="login_user_name">Benutzername</string>
<string name="login_user_name_optional">Benutzername (optional)</string>
<string name="login_base_url">Basis-URL</string>
<string name="login_base_url_info"><![CDATA[Basis-URL wird direkt geprüft, aber es erfolgt auch <a href="%s">Dienst-Erkennung</a> über DNS-Einträge und well-known-URLs.]]></string>
<string name="login_select_certificate">Zertifikat auswählen</string>
<string name="login_add_account">Konto hinzufügen</string>
<string name="login_account_name">Kontoname</string>
<string name="login_account_avoid_apostrophe">Das Verwenden von Apostrophen (\') scheint auf einigen Geräten Probleme zu verursachen.</string>
<string name="login_account_name_info">Verwenden Sie Ihre E-Mail-Adresse als Kontonamen, da Android den Kontonamen als ORGANIZER einsetzt. Es kann allerdings keine zwei Konten mit dem gleichen Namen geben.</string>
<string name="login_account_contact_group_method">Kontaktgruppen-Methode:</string>
<string name="login_account_name_required">Kontoname wird benötigt</string>
<string name="login_account_name_already_taken">Kontoname bereits verwendet</string>
<string name="login_account_not_added">Konto konnte nicht hinzugefügt werden</string>
<string name="login_finish">Abschließen</string>
<string name="login_type_advanced">Erweiterte Anmeldung</string>
<string name="login_no_client_certificate_optional">Kein Client-Zertifikat (optional)</string>
<string name="login_client_certificate_selected">Client-Zertifikat: %s</string>
<string name="login_no_certificate_found">Kein Zertifikat gefunden</string>
<string name="login_install_certificate">Zertifikat installieren </string>
<string name="login_fastmail">Fastmail</string>
<string name="login_fastmail_account">Fastmail-Konto</string>
<string name="login_fastmail_sign_in">Mit Fastmail anmelden</string>
<string name="login_type_google">Google-Kontakte / -Kalender</string>
<string name="login_google_account">Google-Konto</string>
<string name="login_google">Mit Google anmelden</string>
<string name="login_google_client_id">Client-ID (optional)</string>
<string name="login_google_client_privacy_policy"><![CDATA[%1$s überträgt Ihre Google-Kontakte und -Kalenderdaten zur Synchronisierung mit diesem Gerät. Siehe auch unsere <a href="%2$s">Datenschutzrichtlinie</a> für mehr Informationen.]]></string>
<string name="login_google_client_limited_use"><![CDATA[%1$s richtet sich nach der <a href="%2$s">Google API Services Nutzerdaten-Richtlinie</a>, inklusive der eingeschränkten Nutzungsbedingungen.]]></string>
<string name="login_oauth_couldnt_obtain_auth_code">Authentifizierungscode konnte nicht abgerufen werden</string>
<string name="login_type_nextcloud">Nextcloud</string>
<string name="login_nextcloud_login_with_nextcloud">Mit Nextcloud anmelden</string>
<string name="login_nextcloud_login_flow_text">Dadurch wird der Nextcloud-Anmeldevorgang in einem Webbrowser gestartet.</string>
<string name="login_nextcloud_login_flow_server_address">Nextcloud-Serveradresse</string>
<string name="login_nextcloud_login_flow_sign_in">Anmeldung</string>
<string name="login_nextcloud_login_flow_no_login_url">Login-URL konnte nicht abgerufen werden</string>
<string name="login_nextcloud_login_flow_no_login_data">Anmeldedaten konnten nicht abgerufen werden</string>
<string name="login_configuration_detection">Ressourcen-Erkennung</string>
<string name="login_querying_server">Server wird abgefragt. Bitte warten …</string>
<string name="login_no_service">Es konnte weder ein CalDAV- noch ein CardDAV-Dienst gefunden werden.</string>
<string name="login_no_service_info">Die Basis-URL scheint keine erreichbare CalDAV/CardDAV-URL zu sein und die Diensterkennung war nicht erfolgreich.</string>
<string name="login_see_tested_services"><![CDATA[Bitte beachten Sie das Handbuch Ihres Dienstanbieters und <a href="%s">unsere Liste der getesteten Dienste</a> und deren Basis-URLs.]]></string>
<string name="login_check_credentials">Bitte überprüfen Sie auch die Authentifizierung (normalerweise Benutzername und Passwort).</string>
<string name="login_logs_available">Weitere technische Informationen sind in den Protokollen verfügbar.</string>
<string name="login_view_logs">Protokoll anzeigen</string>
<!--AccountSettingsActivity-->
<string name="settings_sync">Synchronisierung</string>
<string name="settings_sync_interval_contacts">Häufigkeit der Kontakte-Synchronisierung</string>
<string name="settings_sync_summary_manually">Nur manuell</string>
<string name="settings_sync_summary_periodically" tools:ignore="PluralsCandidate">Alle %d Minuten + sofort bei lokalen Änderungen</string>
<string name="settings_sync_interval_calendars">Häufigkeit der Kalender-Synchronisierung</string>
<string name="settings_sync_interval_tasks">Häufigkeit der Aufgaben-Synchronisierung</string>
<string-array name="settings_sync_interval_names">
<item>Nur manuell</item>
<item>Alle 15 Minuten</item>
<item>Alle 30 Minuten</item>
<item>Jede Stunde</item>
<item>Alle 2 Stunden</item>
<item>Alle 4 Stunden</item>
<item>Einmal am Tag</item>
</string-array>
<string name="settings_sync_wifi_only">Nur über WLAN synchronisieren</string>
<string name="settings_sync_wifi_only_on">Synchronisierung nur bei aktiver WLAN-Verbindung</string>
<string name="settings_sync_wifi_only_off">Verbindungstyp wird nicht beachtet</string>
<string name="settings_sync_wifi_only_ssids">WLAN-SSID-Beschränkung</string>
<string name="settings_sync_wifi_only_ssids_on">Synchronisierung nur über %s</string>
<string name="settings_sync_wifi_only_ssids_off">Alle WLAN-Verbindungen werden verwendet</string>
<string name="settings_sync_wifi_only_ssids_message">Erlaubte WLAN-Namen (SSIDs), mit Komma getrennt (leer lassen für alle)</string>
<string name="settings_sync_wifi_only_ssids_permissions_required">WLAN-SSID-Einschränkung benötigt weitere Einstellungen</string>
<string name="settings_sync_wifi_only_ssids_permissions_action">Verwalten</string>
<string name="settings_ignore_vpns">VPN erfordert zugrundeliegendes Internet</string>
<string name="settings_ignore_vpns_on">VPN ohne zugrundeliegende überprüfte Internetverbindung reicht für Synchronisierung nicht aus (empfohlen)</string>
<string name="settings_ignore_vpns_off">VPN ohne zugrundeliegende überprüfte Internetverbindung reicht für Synchronisierung aus</string>
<string name="settings_authentication">Anmeldeinformationen</string>
<string name="settings_username">Benutzername</string>
<string name="settings_password">Passwort oder App-Passwort</string>
<string name="settings_app_password_hint"><![CDATA[Möglicherweise möchten Sie ein <a href="%1$s">App-Passwort</a> verwenden.]]></string>
<string name="settings_new_password">Neues Passwort</string>
<string name="settings_password_summary">Aktualisieren Sie Ihr Passwort gemäß den Server-Einstellungen.</string>
<string name="settings_reauthorize_oauth">Erneut authentifizieren (OAuth)</string>
<string name="settings_reauthorize_oauth_summary">Verwenden, wenn der Zugriff widerrufen wurde</string>
<string name="settings_reauthorize_oauth_success">Authentifizierung erfolgreich</string>
<string name="settings_certificate_alias">Client-Zertifikat</string>
<string name="settings_certificate_alias_empty">Kein Zertifikat verfügbar oder ausgewählt</string>
<string name="settings_certificate_install">Zertifikat installieren </string>
<string name="settings_caldav">CalDAV</string>
<string name="settings_sync_time_range_past">Abrufbeschränkung vergangener Termine</string>
<string name="settings_sync_time_range_past_none">Alle Termine werden synchronisiert</string>
<plurals name="settings_sync_time_range_past_days">
<item quantity="one">Termine, die mehr als einen Tag in der Vergangenheit liegen, werden ignoriert</item>
<item quantity="other">Termine, die mehr als %d Tage in der Vergangenheit liegen, werden ignoriert</item>
</plurals>
<string name="settings_sync_time_range_past_message">Termine, die mehr als diese Anzahl von Tagen in der Vergangenheit liegen, werden ignoriert (kann 0 sein). Feld leer lassen, um alle Termine zu synchronisieren.</string>
<string name="settings_default_alarm">Standard-Erinnerung</string>
<plurals name="settings_default_alarm_on">
<item quantity="one">Standard-Erinnerung eine Minute vor dem Ereignis</item>
<item quantity="other">Standard-Erinnerung %d Minuten vor dem Ereignis</item>
</plurals>
<string name="settings_default_alarm_off">Keine Standard-Erinnerungen</string>
<string name="settings_default_alarm_message">Wenn Standard-Erinnerungen für Termine ohne Erinnerung erzeugt werden sollen: gewünschte Anzahl der Minuten vor dem Ereignis. Leer lassen, um Standard-Erinnerungen zu deaktivieren.</string>
<string name="settings_manage_calendar_colors">Kalenderfarben verwalten</string>
<string name="settings_manage_calendar_colors_on">Kalenderfarben werden bei jeder Synchronisierung neu gesetzt</string>
<string name="settings_manage_calendar_colors_off">Kalenderfarben können von anderen Apps festgesetzt werden</string>
<string name="settings_event_colors">Unterstützung für Terminfarben</string>
<string name="settings_event_colors_on">Terminfarben werden synchronisiert</string>
<string name="settings_event_colors_off">Terminfarben werden nicht synchronisiert</string>
<string name="settings_carddav">CardDAV</string>
<string name="settings_contact_group_method">Kontaktgruppen-Methode</string>
<string-array name="settings_contact_group_method_entries">
<item>Gruppen sind eigene vCards</item>
<item>Gruppen sind Kategorien der Kontakte</item>
</string-array>
<!--CreateAddressBookScreen, CreateCalendarScreen-->
<string name="create_addressbook">Adressbuch erstellen</string>
<string name="create_addressbook_maybe_not_supported">Das Erstellen von Adressbüchern über CardDAV wird vom Server möglicherweise nicht unterstützt.</string>
<string name="create_calendar">Kalender anlegen</string>
<string name="create_calendar_time_zone_optional">Standard-Zeitzone (optional)</string>
<string name="create_calendar_time_zone_none"></string>
<string name="create_calendar_type">Mögliche Kalendereinträge</string>
<string name="create_calendar_type_vevent">Termine</string>
<string name="create_calendar_type_vtodo">Aufgaben</string>
<string name="create_calendar_type_vjournal">Notizen / Journal</string>
<string name="create_calendar_maybe_not_supported">Das Erstellen von Kalendern über CardDAV wird vom Server möglicherweise nicht unterstützt.</string>
<string name="create_collection_color">Farbe</string>
<string name="create_collection_display_name">Titel</string>
<string name="create_collection_home_set">Speicherort</string>
<string name="create_collection_description_optional">Beschreibung (optional)</string>
<string name="create_collection_create">Erstellen</string>
<!--CollectionScreen-->
<string name="collection_datatype_contacts">Kontakte</string>
<string name="collection_datatype_events">Termine</string>
<string name="collection_datatype_tasks">Aufgaben</string>
<string name="collection_delete">Ordner löschen</string>
<string name="collection_delete_warning">Dieser Ordner (%s) und alle enthaltenen Daten werden dauerhaft entfernt, sowohl lokal als auch auf dem Server.</string>
<string name="collection_synchronization">Synchronisierung</string>
<string name="collection_synchronization_on">Synchronisierung aktiviert</string>
<string name="collection_synchronization_off">Synchronisierung deaktiviert</string>
<string name="collection_read_only">Schreibgeschützt</string>
<string name="collection_read_only_by_server">Schreibgeschützt (durch Server)</string>
<string name="collection_read_only_by_setting">Schreibgeschützt (laut Richtlinie)</string>
<string name="collection_read_only_forced">Schreibgeschützt (nur lokal)</string>
<string name="collection_read_write">Lesen/Schreiben</string>
<string name="collection_title">Titel</string>
<string name="collection_description">Beschreibung</string>
<string name="collection_owner">Besitzende Entität</string>
<string name="collection_push_support">Push-Unterstützung</string>
<string name="collection_push_web_push">Server bietet Push-Unterstützung</string>
<string name="collection_push_subscribed_at">Um %1$s angemeldet, läuft ab %2$s</string>
<string name="collection_last_sync">Letzte Synchronisierung (%s)</string>
<string name="collection_url">Adresse (URL)</string>
<!--debugging and DebugInfoActivity-->
<string name="debug_info_title">Informationen zur Fehlersuche</string>
<string name="debug_info_archive_caption">ZIP-Archiv</string>
<string name="debug_info_archive_subtitle">Beinhaltet Debug-Info und Logs</string>
<string name="debug_info_archive_text">Das Archiv teilen, um es zu einem Rechner zu übertragen, per Email zu verschicken oder an ein Support-Ticket anzuhängen.</string>
<string name="debug_info_archive_share">Archiv teilen</string>
<string name="debug_info_attached">Debug-Informationen sind dieser Nachricht beigelegt (benötigt Unterstützung für Anhänge in der empfangenden App).</string>
<string name="debug_info_http_error">HTTP-Fehler</string>
<string name="debug_info_server_error">Serverfehler</string>
<string name="debug_info_webdav_error">WebDAV-Fehler</string>
<string name="debug_info_io_error">E/A-Fehler</string>
<string name="debug_info_http_403_description">Die Anfrage wurde vom Server abgelehnt.</string>
<string name="debug_info_http_404_description">Die angeforderte Ressource existiert nicht (mehr).</string>
<string name="debug_info_http_405_description">Der Server erlaubt die angeforderte Art der Operation nicht.</string>
<string name="debug_info_http_5xx_description">Es trat ein serverseitiges Problem auf. Wenden Sie sich bitte an den Server-Support.</string>
<string name="debug_info_unexpected_error">Es trat ein unerwarteter Fehler auf. Einzelheiten dazu finden Sie in der Debug-Info.</string>
<string name="debug_info_view_details">Details anzeigen</string>
<string name="debug_info_subtitle">Debug-Informationen wurden gesammelt</string>
<string name="debug_info_involved_caption">Beteiligte Ressourcen</string>
<string name="debug_info_involved_subtitle">Im Zusammenhang mit dem Problem</string>
<string name="debug_info_involved_remote">Entfernte Ressource:</string>
<string name="debug_info_involved_local">Lokale Ressource:</string>
<string name="debug_info_logs_caption">Protokoll</string>
<string name="debug_info_logs_subtitle">Ausführliches Protokoll verfügbar</string>
<string name="debug_info_logs_view">Logs anzeigen</string>
<string name="debug_info_copy_remote_url">URL kopieren</string>
<string name="debug_info_view_local_resource">Ressource überprüfen</string>
<string name="debug_info_privacy_warning_title">Datenschutzhinweis</string>
<string name="debug_info_privacy_warning_description">Protokolle und Debug-Informationen können private Daten enthalten. Seien Sie sich dessen bewusst, wenn Sie diese öffentlich weitergeben.</string>
<string name="debug_info_can_not_view_resource">Ressource kann nicht angezeigt werden</string>
<!--ExceptionInfoFragment-->
<string name="exception">Ein Fehler ist aufgetreten.</string>
<string name="exception_httpexception">Ein HTTP-Fehler ist aufgetreten.</string>
<string name="exception_ioexception">Ein E/A-Fehler ist aufgetreten.</string>
<string name="exception_show_details">Details anzeigen</string>
<!--WebDAV accounts-->
<string name="webdav_mounts_title">WebDAV-Zugänge</string>
<string name="webdav_mounts_quota_used_available">Speicher belegt: %1$s / verfügbar: %2$s</string>
<string name="webdav_mounts_share_content">Inhalt teilen</string>
<string name="webdav_mounts_unmount">Aushängen</string>
<string name="webdav_add_mount_title">WebDAV-Zugang hinzufügen</string>
<string name="webdav_mounts_empty">Greifen Sie mit einem WebDAV-Zugang direkt auf Ihre Cloud-Dateien zu!</string>
<string name="webdav_add_mount_empty_more_info"><![CDATA[In der Anleitung erfahren Sie mehr darüber, <a href="%1$s">wie WebDAV-Zugänge funktionieren</a>.]]></string>
<string name="webdav_add_mount_display_name">Anzeigename</string>
<string name="webdav_add_mount_url">WebDAV-Adresse</string>
<string name="webdav_add_mount_url_invalid">Ungültige Adresse</string>
<string name="webdav_add_mount_mountpoint_displayname">Einhängepunkt und Anzeigename</string>
<string name="webdav_add_mount_authentication">Anmeldeinformationen</string>
<string name="webdav_add_mount_username">Anmeldename</string>
<string name="webdav_add_mount_password">Passwort</string>
<string name="webdav_add_mount_username_optional">Benutzername (optional)</string>
<string name="webdav_add_mount_password_optional">Passwort (optional)</string>
<string name="webdav_add_mount_add">Einhängen</string>
<string name="webdav_add_mount_no_support">Kein WebDAV-Dienst unter dieser Adresse</string>
<string name="webdav_remove_mount_title">Einhängepunkt entfernen</string>
<string name="webdav_remove_mount_text">Verbindungsdetails werden verloren gehen, es werden aber keine Dateien gelöscht.</string>
<string name="webdav_notification_access">WebDAV-Dateizugriff</string>
<string name="webdav_notification_download">WebDAV-Download</string>
<string name="webdav_notification_upload">WebDAV-Upload</string>
<string name="webdav_provider_root_title">WebDAV-Zugang</string>
<!--sync-->
<string name="sync_error_permissions">DAVx⁵-Berechtigungen</string>
<string name="sync_error_permissions_text">Zusätzliche Berechtigungen benötigt</string>
<string name="sync_error_tasks_too_old">%s zu alt</string>
<string name="sync_error_tasks_required_version">Benötigte Mindestversion: %1$s</string>
<string name="sync_error_authentication_failed">Anmeldungsfehler (Login-Daten überprüfen)</string>
<string name="sync_error_io">Netzwerk- oder E/A-Fehler %s</string>
<string name="sync_error_http_dav">HTTP-Serverfehler %s</string>
<string name="sync_error_local_storage">Lokaler Speicherfehler %s</string>
<string name="sync_error_retry_limit_reached">Weicher Fehler (maximale Anzahl an Wiederholungen erreicht)</string>
<string name="sync_invalid_contact">Ungültigen Kontakt vom Server erhalten</string>
<string name="sync_invalid_event">Ungültigen Termin vom Server erhalten</string>
<string name="sync_invalid_task">Ungültige Aufgabe vom Server erhalten</string>
<string name="sync_invalid_resources_ignoring">Eine/mehrere ungültige Ressourcen ignoriert</string>
<string name="sync_notification_pending_push_title">Synchronisierung ausstehend</string>
<string name="sync_notification_pending_push_message">Daten auf dem Server haben sich geändert</string>
<!--widgets-->
<string name="widget_sync_all">Alles synchronisieren</string>
<string name="widget_sync_all_accounts">Alle Konten synchronisieren</string>
<string name="widget_labeled_sync_label">Beschriftete Sync-Taste</string>
<string name="widget_icon_sync_label">Sync-Taste-Symbol</string>
<string name="widget_sync_description">Antippen, um die Synchronisierung manuell durchzuführen.</string>
<!--cert4android-->
</resources>

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="primaryColor">#7cb342</color>
<color name="primaryLightColor">#aee571</color>
<color name="primaryDarkColor">#4b830d</color>
</resources>

View File

@@ -2,11 +2,13 @@
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
plugins {
// These lines make sure that the plugins are applied in the same version to all subprojects.
alias(libs.plugins.android.application) apply false
alias(libs.plugins.android.library) apply false
alias(libs.plugins.compose.compiler) apply false
alias(libs.plugins.hilt) apply false
alias(libs.plugins.ksp) apply false
alias(libs.plugins.mikepenz.aboutLibraries.android) apply false
}

View File

View File

@@ -3,7 +3,7 @@
*/
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.android.library)
alias(libs.plugins.compose.compiler)
alias(libs.plugins.hilt)
alias(libs.plugins.kotlin.serialization)
@@ -16,20 +16,12 @@ android {
compileSdk = 36
defaultConfig {
applicationId = "at.bitfire.davdroid"
versionCode = 405090002
versionName = "4.5.9-rc.1"
base.archivesName = "davx5-ose-$versionName"
minSdk = 24 // Android 7.0
targetSdk = 36 // Android 16
// whether the build supports and allows to use custom certificates
buildConfigField("boolean", "allowCustomCerts", "true")
testInstrumentationRunner = "at.bitfire.davdroid.HiltTestRunner"
// include these rules in the app that uses the core library
consumerProguardFile("core-proguard-rules.pro")
}
java {
@@ -53,37 +45,9 @@ android {
// Java namespace for our classes (not to be confused with Android package ID)
namespace = "at.bitfire.davdroid"
flavorDimensions += "distribution"
productFlavors {
create("ose") {
dimension = "distribution"
versionNameSuffix = "-ose"
}
}
sourceSets {
getByName("androidTest") {
assets.srcDir("$projectDir/schemas")
}
}
signingConfigs {
create("bitfire") {
storeFile = file(System.getenv("ANDROID_KEYSTORE") ?: "/dev/null")
storePassword = System.getenv("ANDROID_KEYSTORE_PASSWORD")
keyAlias = System.getenv("ANDROID_KEY_ALIAS")
keyPassword = System.getenv("ANDROID_KEY_PASSWORD")
}
}
buildTypes {
getByName("release") {
isMinifyEnabled = true
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules-release.pro")
isShrinkResources = true
signingConfig = signingConfigs.findByName("bitfire")
isMinifyEnabled = false
}
}
@@ -91,10 +55,6 @@ android {
disable += arrayOf("GoogleAppIndexingWarning", "ImpliedQuantity", "MissingQuantity", "MissingTranslation", "ExtraTranslation", "RtlEnabled", "RtlHardcoded", "Typos")
}
androidResources {
generateLocaleConfig = true
}
packaging {
resources {
// multiple (test) dependencies have LICENSE files at same location
@@ -102,6 +62,12 @@ android {
}
}
sourceSets {
getByName("androidTest") {
assets.srcDir("$projectDir/schemas")
}
}
@Suppress("UnstableApiUsage")
testOptions {
managedDevices {
@@ -130,7 +96,7 @@ aboutLibraries {
}
dependencies {
// core
// Kotlin / Android
implementation(libs.kotlin.stdlib)
implementation(libs.kotlinx.coroutines)
coreLibraryDesugaring(libs.android.desugaring)
@@ -167,7 +133,7 @@ dependencies {
// Glance Widgets
implementation(libs.androidx.glance.base)
implementation(libs.androidx.glance.material)
implementation(libs.androidx.glance.material3)
// Jetpack Room
implementation(libs.androidx.room.runtime)

View File

@@ -1,13 +1,4 @@
# R8 usage for DAVx⁵:
# shrinking yes (only in release builds)
# optimization yes (on by R8 defaults)
# full-mode no (see gradle.properties)
# obfuscation no (open-source)
-dontobfuscate
-printusage build/reports/r8-usage.txt
# keep rules
-keep class at.bitfire.** { *; } # all DAVx5 code is required
-keep class org.xmlpull.** { *; }

View File

View File

@@ -10,7 +10,6 @@ import android.os.Build
import android.os.Bundle
import androidx.test.runner.AndroidJUnitRunner
import at.bitfire.davdroid.di.TestCoroutineDispatchersModule
import at.bitfire.davdroid.test.BuildConfig
import at.bitfire.synctools.log.LogcatHandler
import dagger.hilt.android.testing.HiltTestApplication
import java.util.logging.Level
@@ -29,7 +28,7 @@ class HiltTestRunner : AndroidJUnitRunner() {
val rootLogger = Logger.getLogger("")
rootLogger.level = Level.ALL
rootLogger.handlers.forEach { rootLogger.removeHandler(it) }
rootLogger.addHandler(LogcatHandler(BuildConfig.APPLICATION_ID))
rootLogger.addHandler(LogcatHandler(javaClass.name))
// MockK requirements
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P)

View File

@@ -28,11 +28,11 @@ class AutoMigration16Test: DatabaseMigrationTest(toVersion = 16) {
""".trimIndent()
db.execSQL(
"INSERT INTO service (id, accountName, type) VALUES (?, ?, ?)",
arrayOf(1, "test", Service.Companion.TYPE_CALDAV)
arrayOf<Any>(1, "test", Service.Companion.TYPE_CALDAV)
)
db.execSQL(
"INSERT INTO collection (id, serviceId, type, url, privWriteContent, privUnbind, forceReadOnly, sync, timezone) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
arrayOf(1, 1, TYPE_CALENDAR, "https://example.com", true, true, false, false, minimalVTimezone)
arrayOf<Any>(1, 1, TYPE_CALENDAR, "https://example.com", true, true, false, false, minimalVTimezone)
)
}
) { db ->
@@ -47,11 +47,11 @@ class AutoMigration16Test: DatabaseMigrationTest(toVersion = 16) {
prepare = { db ->
db.execSQL(
"INSERT INTO service (id, accountName, type) VALUES (?, ?, ?)",
arrayOf(1, "test", Service.Companion.TYPE_CALDAV)
arrayOf<Any>(1, "test", Service.Companion.TYPE_CALDAV)
)
db.execSQL(
"INSERT INTO collection (id, serviceId, type, url, privWriteContent, privUnbind, forceReadOnly, sync, timezone) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
arrayOf(1, 1, TYPE_CALENDAR, "https://example.com", true, true, false, false, "Some Garbage Content")
arrayOf<Any>(1, 1, TYPE_CALENDAR, "https://example.com", true, true, false, false, "Some Garbage Content")
)
}
) { db ->
@@ -66,11 +66,11 @@ class AutoMigration16Test: DatabaseMigrationTest(toVersion = 16) {
prepare = { db ->
db.execSQL(
"INSERT INTO service (id, accountName, type) VALUES (?, ?, ?)",
arrayOf(1, "test", Service.Companion.TYPE_CALDAV)
arrayOf<Any>(1, "test", Service.Companion.TYPE_CALDAV)
)
db.execSQL(
"INSERT INTO collection (id, serviceId, type, url, privWriteContent, privUnbind, forceReadOnly, sync) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
arrayOf(1, 1, TYPE_CALENDAR, "https://example.com", true, true, false, false)
arrayOf<Any>(1, 1, TYPE_CALENDAR, "https://example.com", true, true, false, false)
)
}
) { db ->

View File

@@ -0,0 +1,28 @@
/*
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
package at.bitfire.davdroid.di
import at.bitfire.cert4android.CustomCertManager
import at.bitfire.cert4android.CustomCertStore
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import java.util.Optional
@Module
@InstallIn(SingletonComponent::class)
class Cert4AndroidModule {
@Provides
fun customCertManager(): Optional<CustomCertManager> = Optional.empty()
@Provides
fun customHostnameVerifier(): Optional<CustomCertManager.HostnameVerifier> = Optional.empty()
@Provides
fun customCertStore(): Optional<CustomCertStore> = Optional.empty()
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/
package at.bitfire.davdroid.di
import androidx.compose.material3.ColorScheme
import at.bitfire.davdroid.di.qualifier.DarkColorScheme
import at.bitfire.davdroid.di.qualifier.LightColorScheme
import at.bitfire.davdroid.ui.OseTheme
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
@Module
@InstallIn(SingletonComponent::class)
class ColorSchemesModule {
@Provides
@LightColorScheme
fun lightColorScheme(): ColorScheme = OseTheme.lightScheme
@Provides
@DarkColorScheme
fun darkColorScheme(): ColorScheme = OseTheme.darkScheme
}

View File

@@ -5,6 +5,10 @@
package at.bitfire.davdroid.di
import at.bitfire.davdroid.di.TestCoroutineDispatchersModule.standardTestDispatcher
import at.bitfire.davdroid.di.qualifier.DefaultDispatcher
import at.bitfire.davdroid.di.qualifier.IoDispatcher
import at.bitfire.davdroid.di.qualifier.MainDispatcher
import at.bitfire.davdroid.di.qualifier.SyncDispatcher
import dagger.Module
import dagger.Provides
import dagger.hilt.components.SingletonComponent

View File

@@ -7,9 +7,9 @@ package at.bitfire.davdroid.di
import at.bitfire.davdroid.ui.AccountsDrawerHandler
import at.bitfire.davdroid.ui.OseAccountsDrawerHandler
import at.bitfire.davdroid.ui.about.AboutActivity
import at.bitfire.davdroid.ui.about.OpenSourceLicenseInfoProvider
import at.bitfire.davdroid.ui.about.FakeAppLicenseInfoProvider
import at.bitfire.davdroid.ui.intro.FakeIntroPageFactory
import at.bitfire.davdroid.ui.intro.IntroPageFactory
import at.bitfire.davdroid.ui.intro.OseIntroPageFactory
import at.bitfire.davdroid.ui.setup.LoginTypesProvider
import at.bitfire.davdroid.ui.setup.StandardLoginTypesProvider
import dagger.Binds
@@ -35,7 +35,7 @@ interface OseModules {
@InstallIn(ViewModelComponent::class)
interface ForViewModels {
@Binds
fun appLicenseInfoProvider(impl: OpenSourceLicenseInfoProvider): AboutActivity.AppLicenseInfoProvider
fun appLicenseInfoProvider(impl: FakeAppLicenseInfoProvider): AboutActivity.AppLicenseInfoProvider
@Binds
fun loginTypesProvider(impl: StandardLoginTypesProvider): LoginTypesProvider
@@ -45,7 +45,7 @@ interface OseModules {
@InstallIn(SingletonComponent::class)
interface Global {
@Binds
fun introPageFactory(impl: OseIntroPageFactory): IntroPageFactory
fun introPageFactory(impl: FakeIntroPageFactory): IntroPageFactory
}
}

View File

@@ -5,20 +5,20 @@
package at.bitfire.davdroid.di
import at.bitfire.davdroid.startup.StartupPlugin
import at.bitfire.davdroid.startup.TasksAppWatcher
import dagger.Module
import dagger.hilt.components.SingletonComponent
import dagger.hilt.testing.TestInstallIn
import dagger.multibindings.Multibinds
// remove TasksAppWatcherModule from Android tests
@Module
@TestInstallIn(
components = [SingletonComponent::class],
replaces = [TasksAppWatcher.TasksAppWatcherModule::class]
replaces = [StartupPluginsModule::class]
)
abstract class TestTasksAppWatcherModule {
// provides empty set of plugins
abstract class TestStartupPluginsModule {
// provides empty set of startup plugins so that nothing interferes with tests
@Multibinds
abstract fun empty(): Set<StartupPlugin>
}

Some files were not shown because too many files have changed in this diff Show More